fontconfig/src/fcstr.c

1248 lines
24 KiB
C
Raw Normal View History

2002-02-15 00:34:13 +01:00
/*
2003-03-05 06:51:27 +01:00
* $RCSId: xc/lib/fontconfig/src/fcstr.c,v 1.10 2002/08/31 22:17:32 keithp Exp $
2002-02-15 00:34:13 +01:00
*
2004-12-07 02:14:46 +01:00
* Copyright © 2000 Keith Packard
2002-02-15 00:34:13 +01:00
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <sys/mman.h>
2002-02-15 00:34:13 +01:00
#include "fcint.h"
FcChar8 *
FcStrCopy (const FcChar8 *s)
2002-02-15 00:34:13 +01:00
{
FcChar8 *r;
2002-02-15 00:34:13 +01:00
if (!s)
return 0;
r = (FcChar8 *) malloc (strlen ((char *) s) + 1);
2002-02-15 00:34:13 +01:00
if (!r)
return 0;
FcMemAlloc (FC_MEM_STRING, strlen ((char *) s) + 1);
strcpy ((char *) r, (char *) s);
2002-02-15 00:34:13 +01:00
return r;
}
FcChar8 *
FcStrPlus (const FcChar8 *s1, const FcChar8 *s2)
2002-02-15 00:34:13 +01:00
{
int l = strlen ((char *)s1) + strlen ((char *) s2) + 1;
FcChar8 *s = malloc (l);
2002-02-15 00:34:13 +01:00
if (!s)
return 0;
FcMemAlloc (FC_MEM_STRING, l);
strcpy ((char *) s, (char *) s1);
strcat ((char *) s, (char *) s2);
2002-02-15 00:34:13 +01:00
return s;
}
void
FcStrFree (FcChar8 *s)
2002-02-15 00:34:13 +01:00
{
FcMemFree (FC_MEM_STRING, strlen ((char *) s) + 1);
2002-02-15 00:34:13 +01:00
free (s);
}
#include "../fc-case/fccase.h"
#define FcCaseFoldUpperCount(cf) \
((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count)
#define FC_STR_CANON_BUF_LEN 1024
typedef struct _FcCaseWalker {
const FcChar8 *read;
const FcChar8 *src;
int len;
FcChar8 utf8[FC_MAX_CASE_FOLD_CHARS + 1];
} FcCaseWalker;
static void
FcStrCaseWalkerInit (const FcChar8 *src, FcCaseWalker *w)
{
w->src = src;
w->read = 0;
w->len = strlen (src);
}
static FcChar8
FcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r)
{
FcChar32 ucs4;
int slen;
slen = FcUtf8ToUcs4 (w->src - 1, &ucs4, w->len + 1);
if (slen <= 0)
return r;
if (FC_MIN_FOLD_CHAR <= ucs4 && ucs4 <= FC_MAX_FOLD_CHAR)
{
int min = 0;
int max = FC_NUM_CASE_FOLD;
while (min <= max)
{
int mid = (min + max) >> 1;
FcChar32 low = fcCaseFold[mid].upper;
FcChar32 high = low + FcCaseFoldUpperCount (&fcCaseFold[mid]);
if (high <= ucs4)
min = mid + 1;
else if (ucs4 < low)
max = mid - 1;
else
{
const FcCaseFold *fold = &fcCaseFold[mid];
int dlen;
switch (fold->method) {
case FC_CASE_FOLD_EVEN_ODD:
if ((ucs4 & 1) != (fold->upper & 1))
return r;
/* fall through ... */
default:
dlen = FcUcs4ToUtf8 (ucs4 + fold->offset, w->utf8);
break;
case FC_CASE_FOLD_FULL:
dlen = fold->count;
memcpy (w->utf8, fcCaseFoldChars + fold->offset, dlen);
break;
}
/* consume rest of src utf-8 bytes */
w->src += slen - 1;
w->len -= slen - 1;
/* read from temp buffer */
w->utf8[dlen] = '\0';
w->read = w->utf8;
return *w->read++;
}
}
}
return r;
}
static FcChar8
FcStrCaseWalkerNext (FcCaseWalker *w)
{
FcChar8 r;
if (w->read)
{
if ((r = *w->read++))
return r;
w->read = 0;
}
r = *w->src++;
--w->len;
if ((r & 0xc0) == 0xc0)
return FcStrCaseWalkerLong (w, r);
if ('A' <= r && r <= 'Z')
r = r - 'A' + 'a';
return r;
}
static FcChar8
FcStrCaseWalkerNextIgnoreBlanks (FcCaseWalker *w)
{
FcChar8 r;
if (w->read)
{
if ((r = *w->read++))
return r;
w->read = 0;
}
do
{
r = *w->src++;
--w->len;
} while (r == ' ');
if ((r & 0xc0) == 0xc0)
return FcStrCaseWalkerLong (w, r);
if ('A' <= r && r <= 'Z')
r = r - 'A' + 'a';
return r;
}
FcChar8 *
FcStrDowncase (const FcChar8 *s)
{
FcCaseWalker w;
int len = 0;
FcChar8 *dst, *d;
FcStrCaseWalkerInit (s, &w);
while (FcStrCaseWalkerNext (&w))
len++;
d = dst = malloc (len + 1);
if (!d)
return 0;
FcMemAlloc (FC_MEM_STRING, len + 1);
FcStrCaseWalkerInit (s, &w);
while ((*d++ = FcStrCaseWalkerNext (&w)));
return dst;
}
2002-02-15 00:34:13 +01:00
int
FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
2002-02-15 00:34:13 +01:00
{
FcCaseWalker w1, w2;
FcChar8 c1, c2;
if (s1 == s2) return 0;
FcStrCaseWalkerInit (s1, &w1);
FcStrCaseWalkerInit (s2, &w2);
2002-02-15 00:34:13 +01:00
for (;;)
{
c1 = FcStrCaseWalkerNext (&w1);
c2 = FcStrCaseWalkerNext (&w2);
if (!c1 || (c1 != c2))
2002-02-15 00:34:13 +01:00
break;
2002-07-07 01:47:44 +02:00
}
return (int) c1 - (int) c2;
}
int
FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
{
FcCaseWalker w1, w2;
FcChar8 c1, c2;
if (s1 == s2) return 0;
FcStrCaseWalkerInit (s1, &w1);
FcStrCaseWalkerInit (s2, &w2);
2002-07-07 01:47:44 +02:00
for (;;)
{
c1 = FcStrCaseWalkerNextIgnoreBlanks (&w1);
c2 = FcStrCaseWalkerNextIgnoreBlanks (&w2);
if (!c1 || (c1 != c2))
2002-02-15 00:34:13 +01:00
break;
}
return (int) c1 - (int) c2;
2002-02-15 00:34:13 +01:00
}
int
FcStrCmp (const FcChar8 *s1, const FcChar8 *s2)
{
FcChar8 c1, c2;
if (s1 == s2)
return 0;
for (;;)
{
c1 = *s1++;
c2 = *s2++;
2003-03-05 07:09:36 +01:00
if (!c1 || c1 != c2)
break;
}
return (int) c1 - (int) c2;
}
/*
* Return a hash value for a string
*/
FcChar32
FcStrHashIgnoreCase (const FcChar8 *s)
{
FcChar32 h = 0;
FcCaseWalker w;
FcChar8 c;
FcStrCaseWalkerInit (s, &w);
while ((c = FcStrCaseWalkerNext (&w)))
h = ((h << 3) ^ (h >> 3)) ^ c;
return h;
}
/*
* Is the head of s1 equal to s2?
*/
static FcBool
FcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
{
FcCaseWalker w1, w2;
FcChar8 c1, c2;
FcStrCaseWalkerInit (s1, &w1);
FcStrCaseWalkerInit (s2, &w2);
for (;;)
{
c1 = FcStrCaseWalkerNextIgnoreBlanks (&w1);
c2 = FcStrCaseWalkerNextIgnoreBlanks (&w2);
if (!c1 || (c1 != c2))
break;
}
return c1 == c2 || !c2;
}
/*
* Does s1 contain an instance of s2 (ignoring blanks and case)?
*/
const FcChar8 *
FcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
{
while (*s1)
{
if (FcStrIsAtIgnoreBlanksAndCase (s1, s2))
return s1;
s1++;
}
return 0;
}
/*
* Is the head of s1 equal to s2?
*/
static FcBool
FcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
{
FcCaseWalker w1, w2;
FcChar8 c1, c2;
FcStrCaseWalkerInit (s1, &w1);
FcStrCaseWalkerInit (s2, &w2);
for (;;)
{
c1 = FcStrCaseWalkerNext (&w1);
c2 = FcStrCaseWalkerNext (&w2);
if (!c1 || (c1 != c2))
break;
}
return c1 == c2 || !c2;
}
/*
* Does s1 contain an instance of s2 (ignoring blanks and case)?
*/
const FcChar8 *
FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
{
while (*s1)
{
if (FcStrIsAtIgnoreCase (s1, s2))
return s1;
s1++;
}
return 0;
}
const FcChar8 *
FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
{
FcCaseWalker w1, w2;
FcChar8 c1, c2;
const FcChar8 *cur;
if (!s1 || !s2)
return 0;
if (s1 == s2)
return s1;
FcStrCaseWalkerInit (s1, &w1);
FcStrCaseWalkerInit (s2, &w2);
c2 = FcStrCaseWalkerNext (&w2);
for (;;)
{
cur = w1.src;
c1 = FcStrCaseWalkerNext (&w1);
if (!c1)
break;
if (c1 == c2)
{
FcCaseWalker w1t = w1;
FcCaseWalker w2t = w2;
FcChar8 c1t, c2t;
for (;;)
{
c1t = FcStrCaseWalkerNext (&w1t);
c2t = FcStrCaseWalkerNext (&w2t);
if (!c2t)
return cur;
if (c2t != c1t)
break;
}
}
}
return 0;
}
const FcChar8 *
FcStrStr (const FcChar8 *s1, const FcChar8 *s2)
{
FcChar8 c1, c2;
const FcChar8 * p = s1;
const FcChar8 * b = s2;
if (!s1 || !s2)
return 0;
if (s1 == s2)
return s1;
again:
c2 = *s2++;
if (!c2)
return 0;
for (;;)
{
p = s1;
c1 = *s1++;
if (!c1 || c1 == c2)
break;
}
if (c1 != c2)
return 0;
for (;;)
{
c1 = *s1;
c2 = *s2;
if (c1 && c2 && c1 != c2)
{
s1 = p + 1;
s2 = b;
goto again;
}
if (!c2)
return p;
if (!c1)
return 0;
++ s1;
++ s2;
}
return 0;
}
2002-02-15 00:34:13 +01:00
int
2002-08-24 22:08:53 +02:00
FcUtf8ToUcs4 (const FcChar8 *src_orig,
FcChar32 *dst,
int len)
2002-02-15 00:34:13 +01:00
{
2002-08-24 22:08:53 +02:00
const FcChar8 *src = src_orig;
FcChar8 s;
int extra;
FcChar32 result;
2002-02-15 00:34:13 +01:00
if (len == 0)
return 0;
s = *src++;
len--;
if (!(s & 0x80))
{
result = s;
extra = 0;
}
else if (!(s & 0x40))
{
return -1;
}
else if (!(s & 0x20))
{
result = s & 0x1f;
extra = 1;
}
else if (!(s & 0x10))
{
result = s & 0xf;
extra = 2;
}
else if (!(s & 0x08))
{
result = s & 0x07;
extra = 3;
}
else if (!(s & 0x04))
{
result = s & 0x03;
extra = 4;
}
else if ( ! (s & 0x02))
{
result = s & 0x01;
extra = 5;
}
else
{
return -1;
}
if (extra > len)
return -1;
while (extra--)
{
result <<= 6;
s = *src++;
if ((s & 0xc0) != 0x80)
return -1;
result |= s & 0x3f;
}
*dst = result;
return src - src_orig;
}
FcBool
2002-08-24 22:08:53 +02:00
FcUtf8Len (const FcChar8 *string,
int len,
int *nchar,
int *wchar)
2002-02-15 00:34:13 +01:00
{
int n;
int clen;
FcChar32 c;
FcChar32 max;
n = 0;
max = 0;
while (len)
{
clen = FcUtf8ToUcs4 (string, &c, len);
if (clen <= 0) /* malformed UTF8 string */
return FcFalse;
if (c > max)
max = c;
string += clen;
len -= clen;
n++;
}
*nchar = n;
if (max >= 0x10000)
*wchar = 4;
else if (max > 0x100)
*wchar = 2;
else
*wchar = 1;
return FcTrue;
}
int
FcUcs4ToUtf8 (FcChar32 ucs4,
FcChar8 dest[FC_UTF8_MAX_LEN])
{
int bits;
FcChar8 *d = dest;
if (ucs4 < 0x80) { *d++= ucs4; bits= -6; }
else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; }
else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; }
else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; }
else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; }
else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; }
else return 0;
for ( ; bits >= 0; bits-= 6) {
*d++= ((ucs4 >> bits) & 0x3F) | 0x80;
}
return d - dest;
}
#define GetUtf16(src,endian) \
((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \
(FcChar16) ((src)[endian == FcEndianBig ? 1 : 0]))
int
2002-08-24 22:08:53 +02:00
FcUtf16ToUcs4 (const FcChar8 *src_orig,
FcEndian endian,
FcChar32 *dst,
int len) /* in bytes */
{
2002-08-24 22:08:53 +02:00
const FcChar8 *src = src_orig;
FcChar16 a, b;
FcChar32 result;
if (len < 2)
return 0;
a = GetUtf16 (src, endian); src += 2; len -= 2;
/*
* Check for surrogate
*/
if ((a & 0xfc00) == 0xd800)
{
if (len < 2)
return 0;
b = GetUtf16 (src, endian); src += 2; len -= 2;
/*
* Check for invalid surrogate sequence
*/
if ((b & 0xfc00) != 0xdc00)
return 0;
result = ((((FcChar32) a & 0x3ff) << 10) |
((FcChar32) b & 0x3ff)) + 0x10000;
}
else
result = a;
*dst = result;
return src - src_orig;
}
FcBool
2002-08-24 22:08:53 +02:00
FcUtf16Len (const FcChar8 *string,
FcEndian endian,
int len, /* in bytes */
int *nchar,
int *wchar)
{
int n;
int clen;
FcChar32 c;
FcChar32 max;
n = 0;
max = 0;
while (len)
{
clen = FcUtf16ToUcs4 (string, endian, &c, len);
if (clen <= 0) /* malformed UTF8 string */
return FcFalse;
if (c > max)
max = c;
string += clen;
len -= clen;
n++;
}
*nchar = n;
if (max >= 0x10000)
*wchar = 4;
else if (max > 0x100)
*wchar = 2;
else
*wchar = 1;
return FcTrue;
}
void
FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size)
{
buf->buf = init;
buf->allocated = FcFalse;
buf->failed = FcFalse;
buf->len = 0;
buf->size = size;
}
void
FcStrBufDestroy (FcStrBuf *buf)
{
if (buf->allocated)
{
FcMemFree (FC_MEM_STRBUF, buf->size);
free (buf->buf);
FcStrBufInit (buf, 0, 0);
}
}
FcChar8 *
FcStrBufDone (FcStrBuf *buf)
{
FcChar8 *ret;
ret = malloc (buf->len + 1);
if (ret)
{
FcMemAlloc (FC_MEM_STRING, buf->len + 1);
memcpy (ret, buf->buf, buf->len);
ret[buf->len] = '\0';
}
FcStrBufDestroy (buf);
return ret;
}
FcBool
FcStrBufChar (FcStrBuf *buf, FcChar8 c)
{
if (buf->len == buf->size)
{
FcChar8 *new;
int size;
if (buf->allocated)
{
size = buf->size * 2;
new = realloc (buf->buf, size);
}
else
{
size = buf->size + 1024;
new = malloc (size);
if (new)
{
buf->allocated = FcTrue;
memcpy (new, buf->buf, buf->len);
}
}
if (!new)
{
buf->failed = FcTrue;
return FcFalse;
}
if (buf->size)
FcMemFree (FC_MEM_STRBUF, buf->size);
FcMemAlloc (FC_MEM_STRBUF, size);
buf->size = size;
buf->buf = new;
}
buf->buf[buf->len++] = c;
return FcTrue;
}
FcBool
FcStrBufString (FcStrBuf *buf, const FcChar8 *s)
{
FcChar8 c;
while ((c = *s++))
if (!FcStrBufChar (buf, c))
return FcFalse;
return FcTrue;
}
FcBool
FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len)
{
while (len-- > 0)
if (!FcStrBufChar (buf, *s++))
return FcFalse;
return FcTrue;
}
FcBool
FcStrUsesHome (const FcChar8 *s)
{
return *s == '~';
}
FcChar8 *
FcStrCopyFilename (const FcChar8 *s)
{
FcChar8 *new;
if (*s == '~')
{
FcChar8 *home = FcConfigHome ();
2003-02-06 20:30:32 +01:00
int size;
if (!home)
return 0;
2003-02-06 20:30:32 +01:00
size = strlen ((char *) home) + strlen ((char *) s);
new = (FcChar8 *) malloc (size);
if (!new)
return 0;
FcMemAlloc (FC_MEM_STRING, size);
strcpy ((char *) new, (char *) home);
strcat ((char *) new, (char *) s + 1);
}
else
{
int size = strlen ((char *) s) + 1;
new = (FcChar8 *) malloc (size);
if (!new)
return 0;
FcMemAlloc (FC_MEM_STRING, size);
strcpy ((char *) new, (const char *) s);
}
return new;
}
FcChar8 *
FcStrLastSlash (const FcChar8 *path)
{
FcChar8 *slash;
slash = (FcChar8 *) strrchr ((const char *) path, '/');
#ifdef _WIN32
{
FcChar8 *backslash;
backslash = (FcChar8 *) strrchr ((const char *) path, '\\');
if (!slash || (backslash && backslash > slash))
slash = backslash;
}
#endif
return slash;
}
FcChar8 *
FcStrDirname (const FcChar8 *file)
{
FcChar8 *slash;
FcChar8 *dir;
slash = FcStrLastSlash (file);
if (!slash)
return FcStrCopy ((FcChar8 *) ".");
dir = malloc ((slash - file) + 1);
if (!dir)
return 0;
FcMemAlloc (FC_MEM_STRING, (slash - file) + 1);
strncpy ((char *) dir, (const char *) file, slash - file);
dir[slash - file] = '\0';
return dir;
}
FcChar8 *
FcStrBasename (const FcChar8 *file)
{
FcChar8 *slash;
slash = FcStrLastSlash (file);
if (!slash)
return FcStrCopy (file);
return FcStrCopy (slash + 1);
}
FcStrSet *
FcStrSetCreate (void)
{
FcStrSet *set = malloc (sizeof (FcStrSet));
if (!set)
return 0;
FcMemAlloc (FC_MEM_STRSET, sizeof (FcStrSet));
set->ref = 1;
set->num = 0;
set->size = 0;
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
set->storage = FcStorageDynamic;
set->u.strs = 0;
return set;
}
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
static FcChar8 * strset_buf = 0;
static int strset_buf_ptr = 0, strset_buf_count = 0;
static int * strset_idx = 0;
static int strset_idx_ptr = 0, strset_idx_count = 0;
static FcStrSet * strsets = 0;
static int strset_ptr = 0, strset_count = 0;
void FcStrSetClearStatic()
{
strset_buf = 0; strset_buf_ptr = 0; strset_buf_count = 0;
strset_idx = 0; strset_idx_ptr = 0; strset_idx_count = 0;
strsets = 0; strset_ptr = 0; strset_count = 0;
}
FcChar8 *
FcStrSetGet (const FcStrSet *set, int i)
{
int index;
switch (set->storage)
{
case FcStorageStatic:
index = strset_idx[set->u.stridx_offset];
if (index == -1)
return 0;
return &strset_buf[index];
case FcStorageDynamic:
return set->u.strs[i];
default:
return 0;
}
}
FcStrSet *
FcStrSetPtrU (const FcStrSetPtr set)
{
switch (set.storage)
{
case FcStorageStatic:
return &strsets[set.u.stat];
case FcStorageDynamic:
return (FcStrSet *)set.u.dyn;
default:
return 0;
}
}
FcStrSetPtr
FcStrSetPtrCreateDynamic (const FcStrSet * set)
{
FcStrSetPtr new;
new.storage = FcStorageDynamic;
new.u.dyn = (FcStrSet *)set;
return new;
}
static FcBool
_FcStrSetAppend (FcStrSet *set, FcChar8 *s)
{
if (FcStrSetMember (set, s))
{
FcStrFree (s);
return FcTrue;
}
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
if (set->num == set->size || set->storage == FcStorageStatic)
{
FcChar8 **strs = malloc ((set->size + 2) * sizeof (FcChar8 *));
if (!strs)
return FcFalse;
FcMemAlloc (FC_MEM_STRSET, (set->size + 2) * sizeof (FcChar8 *));
set->size = set->size + 1;
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
if (set->storage == FcStorageDynamic)
{
if (set->num)
memcpy (strs, set->u.strs, set->num * sizeof (FcChar8 *));
if (set->u.strs)
free (set->u.strs);
}
else
{
if (set->num)
memcpy (strs, strset_idx+set->u.stridx_offset,
set->num * sizeof (FcChar8 *));
set->storage = FcStorageDynamic;
}
set->u.strs = strs;
}
set->u.strs[set->num++] = s;
set->u.strs[set->num] = 0;
return FcTrue;
}
FcBool
FcStrSetMember (FcStrSet *set, const FcChar8 *s)
{
int i;
for (i = 0; i < set->num; i++)
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
if (!FcStrCmp (FcStrSetGet(set, i), s))
return FcTrue;
return FcFalse;
}
FcBool
FcStrSetEqual (FcStrSet *sa, FcStrSet *sb)
{
int i;
if (sa->num != sb->num)
return FcFalse;
for (i = 0; i < sa->num; i++)
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
if (!FcStrSetMember (sb, FcStrSetGet(sa, i)))
return FcFalse;
return FcTrue;
}
FcBool
FcStrSetAdd (FcStrSet *set, const FcChar8 *s)
{
FcChar8 *new = FcStrCopy (s);
if (!new)
return FcFalse;
if (!_FcStrSetAppend (set, new))
{
FcStrFree (new);
return FcFalse;
}
return FcTrue;
}
FcBool
FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
{
FcChar8 *new = FcStrCopyFilename (s);
if (!new)
return FcFalse;
if (!_FcStrSetAppend (set, new))
{
FcStrFree (new);
return FcFalse;
}
return FcTrue;
}
FcBool
FcStrSetDel (FcStrSet *set, const FcChar8 *s)
{
int i;
for (i = 0; i < set->num; i++)
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
if (!FcStrCmp (FcStrSetGet(set, i), s))
{
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
if (set->storage == FcStorageDynamic)
FcStrFree (set->u.strs[i]);
/*
* copy remaining string pointers and trailing
* NULL
*/
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
memmove (FcStrSetGet(set, i), FcStrSetGet(set, i+1),
(set->num - i) * sizeof (FcChar8 *));
set->num--;
return FcTrue;
}
return FcFalse;
}
void
FcStrSetDestroy (FcStrSet *set)
{
if (--set->ref == 0)
{
int i;
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
if (set->storage == FcStorageDynamic)
{
for (i = 0; i < set->num; i++)
FcStrFree (set->u.strs[i]);
FcMemFree (FC_MEM_STRSET, (set->size) * sizeof (FcChar8 *));
if (set->u.strs)
free (set->u.strs);
FcMemFree (FC_MEM_STRSET, sizeof (FcStrSet));
}
free (set);
}
}
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
static int _FcStrSetSort_helper (const void * a, const void * b)
{
return FcStrCmp (&strset_buf[(int)a],
&strset_buf[(int)b]);
}
void
FcStrSetSort (FcStrSet * set)
{
switch (set->storage)
{
case FcStorageDynamic:
qsort (set->u.strs, set->num, sizeof (FcChar8 *),
(int (*)(const void *, const void *)) FcStrCmp);
break;
case FcStorageStatic:
qsort (strset_idx+set->u.stridx_offset, set->num, sizeof (int),
_FcStrSetSort_helper);
break;
default:
break;
}
}
FcBool
FcStrSetPrepareSerialize (const FcStrSet *set)
{
int i;
if (!set)
return FcTrue;
strset_count ++;
strset_idx_count += set->num;
for (i = 0; i < set->num; i++)
{
if (FcStrSetGet(set, i))
strset_buf_count += strlen(FcStrSetGet(set, i));
}
return FcTrue;
}
FcStrSetPtr
FcStrSetSerialize (FcStrSet *set)
{
FcStrSet * new;
FcStrSetPtr newp;
int i;
if (!strsets)
{
strsets = malloc (strset_count * sizeof(FcStrSet));
if (!strsets) goto bail1;
strset_idx = malloc (strset_idx_count * sizeof(int));
if (!strset_idx) goto bail2;
strset_buf = malloc (strset_buf_count * sizeof (FcChar8));
if (!strset_buf) goto bail3;
}
if (!set)
return FcStrSetPtrCreateDynamic(0);
newp.storage = FcStorageStatic;
newp.u.stat = strset_ptr;
new = &strsets[strset_ptr++];
new->ref = set->ref;
new->num = set->num;
new->size = set->num;
new->storage = FcStorageStatic;
new->u.stridx_offset = strset_idx_ptr;
for (i = 0; i < set->num; i++)
{
FcChar8 * s = FcStrSetGet(set, i);
if (s)
{
memcpy(strset_buf+strset_buf_ptr, s,
strlen((char *)s));
strset_idx[strset_idx_ptr++] = strset_buf_ptr;
strset_buf_ptr += strlen((char *)s)+1;
}
else
strset_idx[strset_idx_ptr++] = -1;
}
if (strset_ptr > strset_count || strset_idx_ptr > strset_idx_count)
return FcStrSetPtrCreateDynamic(0);
// problem with multiple ptrs to the same StrSet.
// should hash StrSets or something.
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
// FcStrSetDestroy (set);
return newp;
bail3:
free (strset_idx);
bail2:
free (strsets);
bail1:
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)
{
FcStrList *list;
list = malloc (sizeof (FcStrList));
if (!list)
return 0;
FcMemAlloc (FC_MEM_STRLIST, sizeof (FcStrList));
list->set = set;
set->ref++;
list->n = 0;
return list;
}
FcChar8 *
FcStrListNext (FcStrList *list)
{
if (list->n >= list->set->num)
return 0;
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
return FcStrSetGet(list->set, list->n++);
}
void
FcStrListDone (FcStrList *list)
{
FcStrSetDestroy (list->set);
FcMemFree (FC_MEM_STRLIST, sizeof (FcStrList));
free (list);
}