X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=android%2Fproject%2Fxscreensaver%2Fsrc%2Forg%2Fjwz%2Fxscreensaver%2FTTFAnalyzer.java;fp=android%2Fproject%2Fxscreensaver%2Fsrc%2Forg%2Fjwz%2Fxscreensaver%2FTTFAnalyzer.java;h=3d013457955995befe52bc043c91650e732ddf5c;hp=0000000000000000000000000000000000000000;hb=aa75c7476aeaa84cf3abc192b376a8b03c325213;hpb=88cfe534a698a0562e81345957a50714af1453bc diff --git a/android/project/xscreensaver/src/org/jwz/xscreensaver/TTFAnalyzer.java b/android/project/xscreensaver/src/org/jwz/xscreensaver/TTFAnalyzer.java new file mode 100644 index 00000000..3d013457 --- /dev/null +++ b/android/project/xscreensaver/src/org/jwz/xscreensaver/TTFAnalyzer.java @@ -0,0 +1,153 @@ +/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*- + + * Copyright (C) 2011 George Yunaev @ Ulduzsoft + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + + http://www.ulduzsoft.com/2012/01/enumerating-the-fonts-on-android-platform/ + */ + +package org.jwz.xscreensaver; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.HashMap; + +// The class which loads the TTF file, parses it and returns the TTF font name +class TTFAnalyzer +{ + // This function parses the TTF file and returns the font name specified in the file + public String getTtfFontName( String fontFilename ) + { + try + { + // Parses the TTF file format. + // See http://developer.apple.com/fonts/ttrefman/rm06/Chap6.html + m_file = new RandomAccessFile( fontFilename, "r" ); + + // Read the version first + int version = readDword(); + + // The version must be either 'true' (0x74727565) or 0x00010000 or 'OTTO' (0x4f54544f) for CFF style fonts. + if ( version != 0x74727565 && version != 0x00010000 && version != 0x4f54544f) + return null; + + // The TTF file consist of several sections called "tables", and we need to know how many of them are there. + int numTables = readWord(); + + // Skip the rest in the header + readWord(); // skip searchRange + readWord(); // skip entrySelector + readWord(); // skip rangeShift + + // Now we can read the tables + for ( int i = 0; i < numTables; i++ ) + { + // Read the table entry + int tag = readDword(); + readDword(); // skip checksum + int offset = readDword(); + int length = readDword(); + + // Now here' the trick. 'name' field actually contains the textual string name. + // So the 'name' string in characters equals to 0x6E616D65 + if ( tag == 0x6E616D65 ) + { + // Here's the name section. Read it completely into the allocated buffer + byte[] table = new byte[ length ]; + + m_file.seek( offset ); + read( table ); + + // This is also a table. See http://developer.apple.com/fonts/ttrefman/rm06/Chap6name.html + // According to Table 36, the total number of table records is stored in the second word, at the offset 2. + // Getting the count and string offset - remembering it's big endian. + int count = getWord( table, 2 ); + int string_offset = getWord( table, 4 ); + + // Record starts from offset 6 + for ( int record = 0; record < count; record++ ) + { + // Table 37 tells us that each record is 6 words -> 12 bytes, and that the nameID is 4th word so its offset is 6. + // We also need to account for the first 6 bytes of the header above (Table 36), so... + int nameid_offset = record * 12 + 6; + int platformID = getWord( table, nameid_offset ); + int nameid_value = getWord( table, nameid_offset + 6 ); + + // Table 42 lists the valid name Identifiers. We're interested in 4 but not in Unicode encoding (for simplicity). + // The encoding is stored as PlatformID and we're interested in Mac encoding + if ( nameid_value == 4 && platformID == 1 ) + { + // We need the string offset and length, which are the word 6 and 5 respectively + int name_length = getWord( table, nameid_offset + 8 ); + int name_offset = getWord( table, nameid_offset + 10 ); + + // The real name string offset is calculated by adding the string_offset + name_offset = name_offset + string_offset; + + // Make sure it is inside the array + if ( name_offset >= 0 && name_offset + name_length < table.length ) + return new String( table, name_offset, name_length ); + } + } + } + } + + return null; + } + catch (FileNotFoundException e) + { + // Permissions? + return null; + } + catch (IOException e) + { + // Most likely a corrupted font file + return null; + } + } + + // Font file; must be seekable + private RandomAccessFile m_file = null; + + // Helper I/O functions + private int readByte() throws IOException + { + return m_file.read() & 0xFF; + } + + private int readWord() throws IOException + { + int b1 = readByte(); + int b2 = readByte(); + + return b1 << 8 | b2; + } + + private int readDword() throws IOException + { + int b1 = readByte(); + int b2 = readByte(); + int b3 = readByte(); + int b4 = readByte(); + + return b1 << 24 | b2 << 16 | b3 << 8 | b4; + } + + private void read( byte [] array ) throws IOException + { + if ( m_file.read( array ) != array.length ) + throw new IOException(); + } + + // Helper + private int getWord( byte [] array, int offset ) + { + int b1 = array[ offset ] & 0xFF; + int b2 = array[ offset + 1 ] & 0xFF; + + return b1 << 8 | b2; + } +}