| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /** |
| * @author Viskov Nikolay |
| */ |
| |
| #include <stdio.h> |
| #include <string> |
| #include <string.h> |
| #include <stdlib.h> |
| #if defined(LINUX) |
| #include <ctype.h> |
| #endif |
| #include "T1Font.h" |
| #include "T1Glyph.h" |
| |
| T1Font::T1Font(fwchar_t *family, StyleName sn, fchar* pathToFile):Font() { |
| //this->_famName = family; |
| _style = sn; |
| |
| fullName = NULL; |
| |
| FILE *inputFile; |
| |
| if( inputFile = fopen(pathToFile, "rb")) { |
| |
| try { |
| initFont(inputFile); |
| } catch (fchar*) { |
| //printf("%s", str); |
| } |
| |
| fclose(inputFile); |
| |
| //set default ascent and descent |
| _ascent = 649; |
| _descent = 195; |
| |
| |
| fchar path[MAX_STR_LENGTH]; |
| size_t length = strlen(pathToFile) - 3; |
| |
| strncpy(path, pathToFile, length); |
| strcpy(path + length, "afm"); |
| |
| if( inputFile = fopen(path, "rb")) { |
| |
| try { |
| parseAFM(inputFile); |
| } catch (...) { |
| //printf("%s", str); |
| } |
| |
| fclose(inputFile); |
| } |
| |
| } |
| |
| } |
| |
| T1Font::~T1Font(void) { |
| |
| for( Type1Map::iterator iter = subrsMap.begin(); iter != subrsMap.end(); iter++ ) { |
| delete iter->second; |
| } |
| |
| for( Type1Map::iterator iter = charStringMap.begin(); iter != charStringMap.end(); iter++ ) { |
| delete iter->second; |
| } |
| |
| /*for( Type1AFMMap::iterator iter = afmMap.begin(); iter != afmMap.end(); iter++ ) { |
| delete[] iter->second; |
| }*/ |
| |
| delete fullName; |
| } |
| |
| Glyph* T1Font::createGlyph(ufshort unicode, ufshort size) { |
| |
| /*ffloat floatMas[4]; |
| |
| Type1AFMMap::iterator iter = afmMap.find(unicode); |
| |
| //return iter == glyphCodeMap.end()? NULL : (ufshort)iter->second; |
| |
| memcpy(floatMas, _boundingBox, 4 * sizeof(ffloat)); |
| |
| if (iter != afmMap.end()) { |
| //printf("%s\n", iter->second); |
| fchar* curValue = strstr( iter->second, " B "); |
| if (curValue != NULL) { |
| |
| curValue += 3; |
| |
| floatMas[0] = (ffloat) atof(curValue); |
| //printf("0 = %f\n", floatMas[0]); |
| |
| while (*(++curValue) != ' ') { |
| } |
| |
| floatMas[1] = (ffloat) atof(curValue); |
| //printf("1 = %f\n", floatMas[1]); |
| |
| while (*(++curValue) != ' ') { |
| } |
| |
| floatMas[2] = (ffloat) atof(curValue); |
| //printf("2 = %f\n", floatMas[2]); |
| |
| while (*(++curValue) != ' ') { |
| } |
| |
| floatMas[3] = (ffloat) atof(curValue); |
| //printf("3 = %f\n", floatMas[3]); |
| } |
| }*/ |
| |
| Glyph *glyph = new T1Glyph(&(this->charStringMap), &(this->subrsMap), unicode, size, size / matrixScale, _boundingBox); |
| |
| return glyph; |
| } |
| |
| //TODO: owerwrite this: |
| fwchar_t* T1Font::getPSName() { |
| return fullName; |
| } |
| |
| ffloat* T1Font::getLineMetrics() { |
| /* |
| * metrics[0] - ascent<p> |
| * metrics[1] - descent<p> |
| * metrics[2] - external leading<p> |
| * metrics[3] - underline thickness<p> |
| * metrics[4] - underline offset<p> |
| * metrics[5] - strikethrough thickness<p> |
| * metrics[6] - strikethrough offset<p> |
| * metrics[7] - maximum fchar width<p>*/ |
| |
| ffloat* floatMas = new ffloat[FONT_METRICS_QUANTITY]; |
| |
| floatMas[0] = _ascent / matrixScale; //ascent |
| floatMas[1] = _descent / matrixScale; //descent |
| floatMas[2] = (_height - _ascent - _descent) / matrixScale;//_externalLeading; |
| |
| floatMas[3] = _underlineThickness / matrixScale; |
| floatMas[4] = _underlineOffset / matrixScale; |
| |
| floatMas[5] = _underlineThickness / matrixScale;//_strikeOutSize; |
| floatMas[6] = -_ascent/(2 * matrixScale);//_strikeOutOffset; |
| |
| floatMas[7] = ((ffloat)(_boundingBox[3] - _boundingBox[1])) / matrixScale; |
| |
| return floatMas; |
| } |
| |
| bool T1Font::canDisplay(ufshort ch) { |
| return this->charStringMap.find(ch) != this->charStringMap.end(); |
| } |
| |
| ufshort T1Font::getUnicodeByIndex(ufshort index) { |
| Type1GlyphCodeMap::iterator iter = glyphCodeMap.find(index); |
| |
| return iter == glyphCodeMap.end()? 0 : (ufshort)iter->second; |
| } |
| |
| void error(){ |
| //printf("invalidfont"); |
| throw "invalidfont"; |
| } |
| |
| inline ufshort hexCharToUShort(fchar ch){ |
| return ch >= '0' && ch <= '9' ? ch - '0' : |
| ch >= 'A' && ch <= 'F' ? ch - 'A' + 10 : |
| ch >= 'a' && ch <= 'f' ? ch - 'a' + 10 : |
| 0; |
| } |
| |
| void static getNextLine(fchar* str, FILE* font) { |
| ufshort count = 0; |
| ufchar ch = ' '; |
| |
| while (!feof(font) && (ch == ' ' || ch == '\n' || ch == '\r')) { |
| ch = getc(font); |
| } |
| |
| str[count] = ch; |
| while (!feof(font) && ch != '\r' && ch != '\n') { |
| str[++count] = (ch = getc(font)); |
| } |
| |
| str[count] = '\0'; |
| } |
| |
| static ufchar getNextChar(FILE* font) { |
| ufchar ch; |
| do { |
| ch = getc(font); |
| } while (ch == '\r' || ch == '\n'); |
| |
| return ch; |
| } |
| |
| static ufchar decryptNextSimbol(FILE* font, ufshort* r, bool isASCII) { |
| ufchar clipher = (ufchar)( |
| isASCII ? |
| (ufchar) ((hexCharToUShort(getNextChar(font)) << 4 ) + (hexCharToUShort(getNextChar(font)))) : |
| getc(font) |
| ); |
| |
| ufchar plain = (ufchar)(clipher ^ (*r >> 8)); |
| *r = ( (ufchar)clipher + *r ) * C1 + C2; |
| return plain; |
| } |
| |
| void static decodeASCIILine(fchar* str, ufshort* r, ufshort n, ufshort length) { |
| fchar* p = str; |
| ufchar plain; |
| ufchar clipher; |
| ufshort count = 0; |
| length /= 2; |
| |
| while(count < length) { |
| clipher = (ufchar)((hexCharToUShort(*p) << 4 ) + (hexCharToUShort(*(p + 1)))); |
| |
| plain = (ufchar)(clipher ^ (*r >> 8)); |
| *r = ( (ufchar)clipher + *r ) * C1 + C2; |
| |
| if (count >= n) { |
| str[count - n] = plain; |
| } |
| |
| count ++; |
| |
| p+= 2; |
| } |
| str[count - n] = '\0'; |
| } |
| |
| void static decodeBinaryLine(fchar* str, ufshort* r, ufshort n, ufshort length) { |
| fchar* p = str; |
| ufchar plain; |
| ufchar clipher; |
| ufshort count = 0; |
| while(count < length) { |
| clipher = (ufchar)*p; |
| |
| plain = (ufchar)(clipher ^ (*r >> 8)); |
| *r = ( (ufchar)clipher + *r ) * C1 + C2; |
| |
| if (count >= n) { |
| str[count - n] = plain; |
| } |
| |
| count ++; |
| |
| p ++; |
| } |
| str[count - n] = '\0'; |
| } |
| |
| void static decodeLine(fchar* str, ufshort* r, ufshort n, bool isASCII, ufshort length) { |
| |
| if (isASCII) { |
| decodeASCIILine(str,r,n,length); |
| } else { |
| decodeBinaryLine(str,r,n,length); |
| } |
| return; |
| /*fchar* p = str; |
| ufchar plain; |
| ufchar clipher; |
| ufshort count = 0; |
| if (isASCII) { |
| length /= 2; |
| } |
| while(count < length) { |
| clipher = (ufchar)(isASCII ? ((hexCharToUShort(*p) << 4 ) + (hexCharToUShort(*(p + 1)))) : *p); |
| |
| plain = (ufchar)(clipher ^ (*r >> 8)); |
| *r = ( (ufchar)clipher + *r ) * C1 + C2; |
| |
| //printf("%u ---- %u,%u\n", clipher, plain, *r); |
| if (count >= n) { |
| str[count - n] = plain; |
| } |
| |
| count ++; |
| |
| p+= isASCII ? 2 : 1; |
| } |
| str[count - n] = '\0';//*/ |
| } |
| |
| void static getNextDecodeLine(fchar* str, FILE* font, ufshort* r, bool isASCII) { |
| ufshort count = 0; |
| ufchar plain; |
| while(!feof(font)) { |
| plain = decryptNextSimbol(font, r, isASCII); |
| |
| str[count ++] = plain; |
| |
| if (plain == '\r' || plain == '\n') { |
| break; |
| } |
| } |
| |
| str[count] = '\0'; |
| } |
| |
| void static getNextDecodeLexeme(fchar* str, FILE* font, ufshort* r, bool isASCII) { |
| ufchar ch; |
| ufshort count = 0; |
| |
| while (!feof(font) && ((ch = decryptNextSimbol(font, r, isASCII)) == ' ' || ch == '\n' || ch == '\r')) { |
| } |
| |
| str[count ++] = ch; |
| while (!feof(font) && (ch = decryptNextSimbol(font, r, isASCII)) != ' ' && ch != '\n' && ch != '\r') { |
| str[count ++] = ch; |
| } |
| |
| str[count] = '\0'; |
| } |
| |
| void static getNextLexeme(fchar* str, FILE* font) { |
| ufchar ch; |
| ufshort count = 0; |
| |
| while (!feof(font) && ((ch = getc(font)) == ' ' || ch == '\n' || ch == '\r' && ch != '{')) { |
| } |
| |
| str[count ++] = ch; |
| while (!feof(font) && (ch = getc(font)) != ' ' && ch != '\n' && ch != '\r' && ch != '{') { |
| str[count ++] = ch; |
| } |
| |
| str[count] = '\0'; |
| } |
| |
| ufshort static findUnicode(const fchar *str) { |
| |
| ufshort count = 0; |
| ufshort strCount = 0; |
| ufshort lastStrCount = 0; |
| |
| while(true) { |
| if (GLYPH_LIST[count] == str[strCount]) { |
| count ++; |
| strCount ++; |
| //next iteration |
| } else if ((GLYPH_LIST[count] ^ (1 << 7)) == str[strCount]) { |
| strCount ++; |
| if (str[strCount] == '\0') { |
| return (ufshort)((GLYPH_LIST[count + 1] << 8) + GLYPH_LIST[count + 2]); |
| } |
| |
| count = ((GLYPH_LIST[count + 5] << 8) + GLYPH_LIST[count + 6]); |
| |
| lastStrCount = strCount; |
| |
| if (!count) { |
| return FONT_NOT_FOUND_UNICODE_VALUE; |
| } |
| |
| //on next level |
| } else { |
| strCount = lastStrCount; |
| |
| for (;!(GLYPH_LIST[count] & (1 << 7)) ; ) { |
| count ++; |
| } |
| |
| count = ((GLYPH_LIST[count + 3] << 8) + GLYPH_LIST[count + 4]); |
| |
| if (!count) { |
| return FONT_NOT_FOUND_UNICODE_VALUE; |
| } |
| |
| //next on this level |
| } |
| } |
| } |
| |
| ufshort static getUnicode(fchar *name) { |
| if (!strncmp(name, ".notdef", 7)) { |
| return 0; |
| } |
| |
| return findUnicode(name); |
| } |
| |
| void T1Font::parseAFM(FILE *font) { |
| fchar curStr[MAX_STR_LENGTH]; |
| |
| while (!feof(font)) { |
| getNextLexeme(curStr, font); |
| //printf("%s\n",curStr); |
| |
| if (!strcmp(curStr, "EndFontMetrics") || !strcmp(curStr, "StartCharMetrics")) { |
| |
| return; |
| } else if (!strcmp(curStr, "Ascender")) { |
| getNextLexeme(curStr, font); |
| _ascent = (ffloat) fabs(atof(curStr)); |
| //printf("ascend = %f\n", _ascent); |
| |
| } else if (!strcmp(curStr, "Descender")) { |
| getNextLexeme(curStr, font); |
| _descent = (ffloat) fabs(atof(curStr)); |
| //printf("descent = %f\n", _descent); |
| |
| } /*else if (!strcmp(curStr, "StartCharMetrics")) { |
| getNextLexeme(curStr, font); |
| fchar* curValue; |
| fchar psName[MAX_STR_LENGTH]; |
| ufshort count = (ufshort) atoi(curStr); |
| for (ufshort i = 0; i < count; i ++) { |
| getNextLine(curStr, font); |
| |
| //printf("%s\n",curStr); |
| curValue = strstr( curStr, " N "); |
| if (curValue != NULL) { |
| |
| curValue += 3; |
| |
| //printf("%s\n", curValue); |
| |
| ufshort i; |
| for (i = 0; curValue[i] != ' ' && curValue[i] != '\0'; i ++) { |
| psName[i] = curValue[i]; |
| } |
| psName[i] = '\0'; |
| |
| curValue = new fchar[strlen(curStr) + 1]; |
| |
| strcpy(curValue, curStr); |
| |
| //printf("%u = %s = %s\n",findUnicode(psName),curValue,psName); |
| |
| afmMap[getUnicode(psName)] = curValue; |
| } |
| } |
| |
| }*/ else { |
| getNextLine(curStr, font); |
| } |
| } |
| } |
| |
| |
| void T1Font::initFont(FILE *font) { |
| fchar curStr[MAX_STR_LENGTH]; |
| |
| DecodeState state = HEADER; |
| |
| ufshort r = DEF_R_EXEC; |
| ufshort n = 4; |
| |
| ufshort lenIV = DEF_LENIV; |
| ufshort charStringR; |
| |
| ufshort count = 0; |
| ufshort tempShort = 0; |
| ufshort length = 0; |
| ufshort valueLength = 0; |
| |
| matrixScale = 1000; |
| |
| bool isASCII = true; |
| |
| ufchar ch; |
| EncodedValue *curValue; |
| |
| ch = getc(font); |
| |
| if (ch == 0x80 && getc(font) == 0x01) { |
| isASCII = false; |
| } else if (ch == '%' && getc(font) == '!') { |
| isASCII = true; |
| } else { |
| error(); |
| } |
| |
| while (!feof(font)) { |
| switch (state) { |
| case HEADER: { |
| getNextLexeme(curStr, font); |
| |
| if (!strcmp(curStr, "/UnderlinePosition")) { |
| getNextLexeme(curStr, font); |
| _underlineOffset = (ffloat) - atof(curStr); |
| } else if (!strcmp(curStr, "/UnderlineThickness")) { |
| getNextLexeme(curStr, font); |
| _underlineThickness = (ffloat) atof(curStr); |
| } else if (strstr(curStr, "/FontBBox") != NULL) { |
| //getNextLexeme(curStr, font); |
| |
| while (!feof(font) && ((ch = getc(font)) == '{')) { |
| } |
| |
| ungetc(ch, font); |
| |
| getNextLexeme(curStr, font); |
| _boundingBox[0] = (ffloat) atof(curStr); |
| |
| getNextLexeme(curStr, font); |
| _boundingBox[1] = (ffloat) atof(curStr); |
| |
| getNextLexeme(curStr, font); |
| _boundingBox[2] = (ffloat) atof(curStr); |
| |
| getNextLexeme(curStr, font); |
| _boundingBox[3] = (ffloat) atof(curStr); |
| |
| _height = ((ffloat)(_boundingBox[2] -_boundingBox[0])); |
| |
| } else if (!strcmp(curStr, "/FullName")) { |
| //getNextLexeme(curStr, font); |
| |
| while (!feof(font) && ((ch = getc(font)) == '(')) { |
| } |
| |
| curStr[count ++] = ch; |
| while (!feof(font) && (ch = getc(font)) != ')') { |
| curStr[count ++] = ch; |
| } |
| |
| curStr[count] = '\0'; |
| |
| fchar *ptr = curStr; |
| |
| ch = 0; |
| fullName = new fwchar_t[count + 1]; |
| while (*ptr != '\0') { |
| fullName[ch ++] = *ptr; |
| ptr ++; |
| } |
| |
| fullName[ch] = L'\0'; |
| } else if (!strcmp(curStr, "eexec")) { |
| state = PRIVATE_DIR; |
| |
| if (isASCII) { |
| for (count = 0; count < lenIV * 2; count ++) { |
| if (!isascii(ch = getc(font))) { |
| error(); |
| } |
| curStr[count] = ch; |
| } |
| decodeASCIILine(curStr, &r, n, count); |
| } else { |
| for (count = 0; count < 6; count ++) { |
| curStr[count] = getc(font); |
| } |
| |
| if (curStr[0] != (fchar)0x80 || curStr[1] != 0x02) { |
| error(); |
| } |
| for (count = 0; count < lenIV; count ++) { |
| curStr[count] = getc(font); |
| } |
| decodeBinaryLine(curStr, &r, n, count); |
| } |
| } |
| break; |
| } |
| case PRIVATE_DIR: { |
| getNextDecodeLexeme(curStr, font, &r, isASCII); |
| |
| if (!strcmp(curStr, "/Subrs")) { |
| |
| getNextDecodeLexeme(curStr, font, &r, isASCII); |
| valueLength = atoi(curStr); |
| |
| count = 0; |
| state = SUBRS_MASSIVE; |
| getNextDecodeLine(curStr, font, &r, isASCII); |
| } else if (!strcmp(curStr, "/CharStrings")) { |
| |
| getNextDecodeLexeme(curStr, font, &r, isASCII); |
| valueLength = atoi(curStr); |
| |
| count = 0; |
| state = CHAR_STRING; |
| getNextDecodeLine(curStr, font, &r, isASCII); |
| } |
| break; |
| } |
| case SUBRS_MASSIVE: { |
| curValue = new EncodedValue(); |
| getNextDecodeLexeme(curStr, font, &r, isASCII); |
| |
| getNextDecodeLexeme(curStr, font, &r, isASCII); |
| curValue->number = (ufshort) atoi(curStr); |
| |
| getNextDecodeLexeme(curStr, font, &r, isASCII); |
| length = (ufshort) atoi(curStr); |
| curValue->length = length - lenIV; |
| |
| getNextDecodeLexeme(curStr, font, &r, isASCII); |
| |
| for (tempShort = 0; tempShort - length < 0; tempShort ++) { |
| curStr[tempShort] = decryptNextSimbol(font, &r, isASCII); |
| } |
| |
| charStringR = DEF_R_CHARSTRING; |
| decodeBinaryLine(curStr, &charStringR, lenIV, length); |
| |
| curValue->text = new fchar[curValue->length]; |
| for (tempShort = 0; tempShort - curValue->length < 0; tempShort ++) { |
| curValue->text[tempShort] = curStr[tempShort]; |
| } |
| |
| subrsMap[curValue->number] = curValue; |
| |
| getNextDecodeLine(curStr, font, &r, isASCII); |
| |
| if (++count >= valueLength) { |
| state = PRIVATE_DIR; |
| count = 0; |
| } |
| |
| break; |
| } |
| case CHAR_STRING: { |
| getNextDecodeLexeme(curStr, font, &r, isASCII); |
| tempShort = getUnicode(curStr + 1); |
| |
| if (tempShort != FONT_NOT_FOUND_UNICODE_VALUE) { |
| |
| glyphCodeMap[count] = tempShort; |
| |
| curValue = new EncodedValue(); |
| |
| curValue->number = tempShort; |
| |
| getNextDecodeLexeme(curStr, font, &r, isASCII); |
| length = (ufshort) atoi(curStr); |
| curValue->length = length - lenIV; |
| |
| getNextDecodeLexeme(curStr, font, &r, isASCII); |
| for (tempShort = 0; tempShort - length < 0; tempShort ++) { |
| curStr[tempShort] = decryptNextSimbol(font, &r, isASCII); |
| } |
| |
| charStringR = DEF_R_CHARSTRING; |
| decodeBinaryLine(curStr, &charStringR, lenIV, length); |
| |
| curValue->text = new fchar[curValue->length]; |
| for (tempShort = 0; tempShort - curValue->length < 0; tempShort ++) { |
| curValue->text[tempShort] = curStr[tempShort]; |
| } |
| charStringMap[curValue->number] = curValue; |
| } else { |
| getNextDecodeLexeme(curStr, font, &r, isASCII); |
| length = (ufshort) atoi(curStr); |
| |
| getNextDecodeLexeme(curStr, font, &r, isASCII); |
| for (tempShort = 0; tempShort - length < 0; tempShort ++) { |
| decryptNextSimbol(font, &r, isASCII); |
| } |
| } |
| |
| getNextDecodeLine(curStr, font, &r, isASCII); |
| |
| if (++count >= valueLength) { |
| return; |
| } |
| |
| break; |
| } |
| } |
| } |
| } |