From 95af7447dba7c54ed162b667c0bb2ea6500e8f32 Mon Sep 17 00:00:00 2001 From: Akira TAGOH Date: Mon, 4 Feb 2013 16:03:29 +0900 Subject: [PATCH] Bug 50733 - Add font-file hash? Add "hash" object which contains SHA256 hash value (so far) computed from the font file. --- fontconfig/fontconfig.h | 1 + src/Makefile.am | 1 + src/fcfreetype.c | 9 ++ src/fchash.c | 265 ++++++++++++++++++++++++++++++++++++++++ src/fcint.h | 7 ++ src/fcobjs.h | 1 + 6 files changed, 284 insertions(+) create mode 100644 src/fchash.c diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h index dc2532f..ff52a61 100644 --- a/fontconfig/fontconfig.h +++ b/fontconfig/fontconfig.h @@ -115,6 +115,7 @@ typedef int FcBool; #define FC_FONT_FEATURES "fontfeatures" /* String */ #define FC_NAMELANG "namelang" /* String RFC 3866 langs */ #define FC_PRGNAME "prgname" /* String */ +#define FC_HASH "hash" /* String */ #define FC_CACHE_SUFFIX ".cache-" FC_CACHE_VERSION #define FC_DIR_CACHE_FILE "fonts.cache-" FC_CACHE_VERSION diff --git a/src/Makefile.am b/src/Makefile.am index 8fb8b64..9fd7dd8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -139,6 +139,7 @@ libfontconfig_la_SOURCES = \ fcformat.c \ fcfreetype.c \ fcfs.c \ + fchash.c \ fcinit.c \ fclang.c \ fclist.c \ diff --git a/src/fcfreetype.c b/src/fcfreetype.c index faf3c35..111f784 100644 --- a/src/fcfreetype.c +++ b/src/fcfreetype.c @@ -1123,6 +1123,8 @@ FcFreeTypeQueryFace (const FT_Face face, FcChar8 *style = 0; int st; + FcChar8 *hashstr; + pat = FcPatternCreate (); if (!pat) goto bail0; @@ -1634,6 +1636,13 @@ FcFreeTypeQueryFace (const FT_Face face, if (!FcPatternAddBool (pat, FC_DECORATIVE, decorative)) goto bail1; + hashstr = FcHashGetSHA256DigestFromFile (file); + if (!hashstr) + goto bail1; + if (!FcPatternAddString (pat, FC_HASH, hashstr)) + goto bail1; + free (hashstr); + /* * Compute the unicode coverage for the font */ diff --git a/src/fchash.c b/src/fchash.c new file mode 100644 index 0000000..827b20f --- /dev/null +++ b/src/fchash.c @@ -0,0 +1,265 @@ +/* + * fontconfig/src/fchash.c + * + * Copyright © 2003 Keith Packard + * Copyright © 2013 Red Hat, Inc. + * Red Hat Author(s): Akira TAGOH + * + * 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 the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "fcint.h" +#include +#include + +#define ROTRN(w, v, n) ((((FcChar32)v) >> n) | (((FcChar32)v) << (w - n))) +#define ROTR32(v, n) ROTRN(32, v, n) +#define SHR(v, n) (v >> n) +#define Ch(x, y, z) ((x & y) ^ (~x & z)) +#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) +#define SS0(x) (ROTR32(x, 2) ^ ROTR32(x, 13) ^ ROTR32(x, 22)) +#define SS1(x) (ROTR32(x, 6) ^ ROTR32(x, 11) ^ ROTR32(x, 25)) +#define ss0(x) (ROTR32(x, 7) ^ ROTR32(x, 18) ^ SHR(x, 3)) +#define ss1(x) (ROTR32(x, 17) ^ ROTR32(x, 19) ^ SHR(x, 10)) + + +static FcChar32 * +FcHashInitSHA256Digest (void) +{ + int i; + static const FcChar32 h[] = { + 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, + 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL + }; + FcChar32 *ret = malloc (sizeof (FcChar32) * 8); + + if (!ret) + return NULL; + + for (i = 0; i < 8; i++) + ret[i] = h[i]; + + return ret; +} + +static void +FcHashComputeSHA256Digest (FcChar32 *hash, + const char *block) +{ + static const FcChar32 k[] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL + }; + FcChar32 w[64], i, j, t1, t2; + FcChar32 a, b, c, d, e, f, g, h; + +#define H(n) (hash[n]) + + a = H(0); + b = H(1); + c = H(2); + d = H(3); + e = H(4); + f = H(5); + g = H(6); + h = H(7); + + for (i = 0; i < 16; i++) + { + j = (block[(i * 4) + 0] & 0xff) << (8 * 3); + j |= (block[(i * 4) + 1] & 0xff) << (8 * 2); + j |= (block[(i * 4) + 2] & 0xff) << (8 * 1); + j |= (block[(i * 4) + 3] & 0xff); + w[i] = j; + } + for (i = 16; i < 64; i++) + w[i] = ss1(w[i - 2]) + w[i - 7] + ss0(w[i - 15]) + w[i - 16]; + + for (i = 0; i < 64; i++) + { + t1 = h + SS1(e) + Ch(e, f, g) + k[i] + w[i]; + t2 = SS0(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + H(0) += a; + H(1) += b; + H(2) += c; + H(3) += d; + H(4) += e; + H(5) += f; + H(6) += g; + H(7) += h; + +#undef H +} + +static FcChar8 * +FcHashSHA256ToString (FcChar32 *hash) +{ + FcChar8 *ret = NULL; + static const char hex[] = "0123456789abcdef"; + int i, j; + + if (hash) + { + ret = malloc (sizeof (FcChar8) * (8 * 8 + 7 + 1)); + if (!ret) + return NULL; + memcpy (ret, "sha256:", 7); +#define H(n) hash[n] + for (i = 0; i < 8; i++) + { + FcChar32 v = H(i); + + for (j = 0; j < 8; j++) + ret[7 + (i * 8) + j] = hex[(v >> (28 - j * 4)) & 0xf]; + } + ret[7 + i * 8] = 0; +#undef H + free (hash); + } + + return ret; +} + +FcChar8 * +FcHashGetSHA256Digest (const FcChar8 *input_strings, + size_t len) +{ + size_t i, round_len = len / 64; + char block[64]; + FcChar32 *ret = FcHashInitSHA256Digest (); + + if (!ret) + return NULL; + + for (i = 0; i < round_len; i++) + { + FcHashComputeSHA256Digest (ret, (const char *)&input_strings[i * 64]); + } + /* padding */ + if ((len % 64) != 0) + memcpy (block, &input_strings[len / 64], len % 64); + memset (&block[len % 64], 0, 64 - (len % 64)); + block[len % 64] = 0x80; + if ((64 - (len % 64)) < 9) + { + /* process a block once */ + FcHashComputeSHA256Digest (ret, block); + memset (block, 0, 64); + } + /* set input size at the end */ + len *= 8; + block[63 - 0] = len & 0xff; + block[63 - 1] = (len >> 8) & 0xff; + block[63 - 2] = (len >> 16) & 0xff; + block[63 - 3] = (len >> 24) & 0xff; + block[63 - 4] = (len >> 32) & 0xff; + block[63 - 5] = (len >> 40) & 0xff; + block[63 - 6] = (len >> 48) & 0xff; + block[63 - 7] = (len >> 56) & 0xff; + FcHashComputeSHA256Digest (ret, block); + + return FcHashSHA256ToString (ret); +} + +FcChar8 * +FcHashGetSHA256DigestFromFile (const FcChar8 *filename) +{ + FILE *fp = fopen ((const char *)filename, "rb"); + char ibuf[64]; + FcChar32 *ret; + size_t len; + struct stat st; + + if (!fp) + return NULL; + + if (FcStat (filename, &st)) + goto bail0; + + ret = FcHashInitSHA256Digest (); + if (!ret) + return NULL; + + while (!feof (fp)) + { + if ((len = fread (ibuf, sizeof (char), 64, fp)) < 64) + { + long v; + + /* add a padding */ + memset (&ibuf[len], 0, 64 - len); + ibuf[len] = 0x80; + if ((64 - len) < 9) + { + /* process a block once */ + FcHashComputeSHA256Digest (ret, ibuf); + memset (ibuf, 0, 64); + } + /* set input size at the end */ + v = (long)st.st_size * 8; + ibuf[63 - 0] = v & 0xff; + ibuf[63 - 1] = (v >> 8) & 0xff; + ibuf[63 - 2] = (v >> 16) & 0xff; + ibuf[63 - 3] = (v >> 24) & 0xff; + ibuf[63 - 4] = (v >> 32) & 0xff; + ibuf[63 - 5] = (v >> 40) & 0xff; + ibuf[63 - 6] = (v >> 48) & 0xff; + ibuf[63 - 7] = (v >> 56) & 0xff; + FcHashComputeSHA256Digest (ret, ibuf); + break; + } + else + { + FcHashComputeSHA256Digest (ret, ibuf); + } + } + fclose (fp); + + return FcHashSHA256ToString (ret); + +bail0: + fclose (fp); + return NULL; +} diff --git a/src/fcint.h b/src/fcint.h index fceb8cc..b5ff382 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -812,6 +812,13 @@ FcFontSetSerializeAlloc (FcSerialize *serialize, const FcFontSet *s); FcPrivate FcFontSet * FcFontSetSerialize (FcSerialize *serialize, const FcFontSet * s); +/* fchash.c */ +FcPrivate FcChar8 * +FcHashGetSHA256Digest (const FcChar8 *input_strings, + size_t len); +FcPrivate FcChar8 * +FcHashGetSHA256DigestFromFile (const FcChar8 *filename); + /* fcxml.c */ FcPrivate void FcTestDestroy (FcTest *test); diff --git a/src/fcobjs.h b/src/fcobjs.h index ad803eb..3cb2349 100644 --- a/src/fcobjs.h +++ b/src/fcobjs.h @@ -43,4 +43,5 @@ FC_OBJECT (LCD_FILTER, FcTypeInteger) FC_OBJECT (NAMELANG, FcTypeString) FC_OBJECT (FONT_FEATURES, FcTypeString) FC_OBJECT (PRGNAME, FcTypeString) +FC_OBJECT (HASH, FcTypeString) /* ^-------------- Add new objects here. */