+ // compute checksums for the loca and glyf tables
+ locaChecksum = glyfChecksum = 0;
+ if (unsortedLoca) {
+ if (locaFmt) {
+ for (j = 0; j <= nGlyphs; ++j) {
+ locaChecksum += locaTable[j].newOffset;
+ }
+ } else {
+ for (j = 0; j <= nGlyphs; j += 2) {
+ locaChecksum += locaTable[j].newOffset << 16;
+ if (j + 1 <= nGlyphs) {
+ locaChecksum += locaTable[j+1].newOffset;
+ }
+ }
+ }
+ pos = tables[seekTable("glyf")].offset;
+ for (j = 0; j < nGlyphs; ++j) {
+ n = locaTable[j].len;
+ if (n > 0) {
+ k = locaTable[j].origOffset;
+ if (checkRegion(pos + k, n)) {
+ glyfChecksum += computeTableChecksum(file + pos + k, n);
+ }
+ }
+ }
+ }
+
+ // construct the new name table
+ if (name) {
+ n = strlen(name);
+ newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3;
+ newNameTab = (char *)gmalloc(newNameLen);
+ memset(newNameTab, 0, newNameLen);
+ newNameTab[0] = 0; // format selector
+ newNameTab[1] = 0;
+ newNameTab[2] = 0; // number of name records
+ newNameTab[3] = 4;
+ newNameTab[4] = 0; // offset to start of string storage
+ newNameTab[5] = 6 + 4*12;
+ next = 0;
+ for (i = 0; i < 4; ++i) {
+ newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft
+ newNameTab[6 + i*12 + 1] = 3;
+ newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode
+ newNameTab[6 + i*12 + 3] = 1;
+ newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English
+ newNameTab[6 + i*12 + 5] = 0x09;
+ newNameTab[6 + i*12 + 6] = 0; // name ID
+ newNameTab[6 + i*12 + 7] = i + 1;
+ newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length
+ newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff);
+ newNameTab[6 + i*12 + 10] = next >> 8; // string offset
+ newNameTab[6 + i*12 + 11] = next & 0xff;
+ if (i+1 == 2) {
+ memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14);
+ next += 14;
+ } else {
+ for (j = 0; j < n; ++j) {
+ newNameTab[6 + 4*12 + next + 2*j] = 0;
+ newNameTab[6 + 4*12 + next + 2*j + 1] = name[j];
+ }
+ next += 2*n;
+ }
+ }
+ } else {
+ newNameLen = 0;
+ newNameTab = NULL;
+ }
+
+ // construct the new cmap table
+ if (codeToGID) {
+ newCmapLen = 44 + 256 * 2;
+ newCmapTab = (char *)gmalloc(newCmapLen);
+ newCmapTab[0] = 0; // table version number = 0
+ newCmapTab[1] = 0;
+ newCmapTab[2] = 0; // number of encoding tables = 1
+ newCmapTab[3] = 1;
+ newCmapTab[4] = 0; // platform ID = Microsoft
+ newCmapTab[5] = 3;
+ newCmapTab[6] = 0; // encoding ID = Unicode
+ newCmapTab[7] = 1;
+ newCmapTab[8] = 0; // offset of subtable
+ newCmapTab[9] = 0;
+ newCmapTab[10] = 0;
+ newCmapTab[11] = 12;
+ newCmapTab[12] = 0; // subtable format = 4
+ newCmapTab[13] = 4;
+ newCmapTab[14] = 0x02; // subtable length
+ newCmapTab[15] = 0x20;
+ newCmapTab[16] = 0; // subtable version = 0
+ newCmapTab[17] = 0;
+ newCmapTab[18] = 0; // segment count * 2
+ newCmapTab[19] = 4;
+ newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount))
+ newCmapTab[21] = 4;
+ newCmapTab[22] = 0; // floor(log2(segCount))
+ newCmapTab[23] = 1;
+ newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount))
+ newCmapTab[25] = 0;
+ newCmapTab[26] = 0x00; // endCount[0]
+ newCmapTab[27] = (char)0xff;
+ newCmapTab[28] = (char)0xff; // endCount[1]
+ newCmapTab[29] = (char)0xff;
+ newCmapTab[30] = 0; // reserved
+ newCmapTab[31] = 0;
+ newCmapTab[32] = 0x00; // startCount[0]
+ newCmapTab[33] = 0x00;
+ newCmapTab[34] = (char)0xff; // startCount[1]
+ newCmapTab[35] = (char)0xff;
+ newCmapTab[36] = 0; // idDelta[0]
+ newCmapTab[37] = 0;
+ newCmapTab[38] = 0; // idDelta[1]
+ newCmapTab[39] = 1;
+ newCmapTab[40] = 0; // idRangeOffset[0]
+ newCmapTab[41] = 4;
+ newCmapTab[42] = 0; // idRangeOffset[1]
+ newCmapTab[43] = 0;
+ for (i = 0; i < 256; ++i) {
+ newCmapTab[44 + 2*i] = codeToGID[i] >> 8;
+ newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff;
+ }
+ } else {
+ newCmapLen = 0;
+ newCmapTab = NULL;
+ }
+