public bool Read(Stream stream, int directoryCount) { int bytesRead = 0; this.NumTables = WoffBuffer.Read255UInt16(stream); if (this.NumTables == 0) { return(false); } this.Flavor = WoffBuffer.ReadUInt32BE(WoffBuffer.ReadBytes(stream, WoffBuffer.SizeOfUInt, out bytesRead), 0); this.TableIndices = new ushort[this.NumTables]; for (ushort i = 0; i < this.NumTables; i++) { this.TableIndices[i] = WoffBuffer.Read255UInt16(stream); if (this.TableIndices[i] >= directoryCount) { Trace.TraceError("Invalid collection font entry: " + this.TableIndices[i]); return(false); } } return(true); }
public bool Read(Stream stream) { int bytesRead = 0; this.Version = WoffBuffer.ReadUInt32BE(WoffBuffer.ReadBytes(stream, WoffBuffer.SizeOfUInt, out bytesRead), 0); this.NumFonts = WoffBuffer.Read255UInt16(stream); if (this.Version == 0x00010000 || this.Version == 0x00020000) { TtcTag = WoffUtils.TtcSignature; this.MajorVersion = (ushort)(this.Version == 0x00010000 ? 1 : 2); return(true); } return(false); }
private bool ReadData(Stream stream) { if (stream == null) { return(false); } int bytesRead = 0; byte[] header = WoffBuffer.ReadBytes(stream, WoffUtils.Woff1DirSize, out bytesRead); _tag = WoffBuffer.ReadUInt32BE(header, 0); _offset = WoffBuffer.ReadUInt32BE(header, 4); _compLength = WoffBuffer.ReadUInt32BE(header, 8); _origLength = WoffBuffer.ReadUInt32BE(header, 12); _origChecksum = WoffBuffer.ReadUInt32BE(header, 16); if (_origLength > 0) { _padding = WoffUtils.CalculatePadding(_origLength); } return(true); }
private bool ReadData(Stream stream, bool isTrueType) { if (stream == null) { return(false); } var tableFlags = WoffTable.TableFlags; int bytesRead = 0; // UInt8: flags table type and flags _flags = (byte)stream.ReadByte(); // The interpretation of the flags field is as follows: // 1. Bits [0..5] contain an index to the "known tag" table, which represents tags likely to appear in fonts int tagIndex = _flags & 0x3F; // If the tag is not present in this table, then the value of this bit field is 63. if (tagIndex >= 63) { // UInt32: tag 4-byte tag (optional) _tag = WoffBuffer.ReadUInt32BE(WoffBuffer.ReadBytes(stream, 4, out bytesRead), 0); var name = WoffBuffer.TagString(_tag); for (int i = 0; i < tableFlags.Count; i++) { if (string.Equals(name, tableFlags[i], StringComparison.Ordinal)) { tagIndex = i; break; } } } else { _tag = WoffBuffer.TagInt(tableFlags[tagIndex]); } // 2. Bits 6 and 7 indicate the preprocessing transformation version number (0-3) that was applied to each table. int transformVersion = (_flags >> 5) & 0x3; // UIntBase128: origLength length of original table if (!WoffBuffer.ReadUIntBase128(stream, out _origLength)) { return(false); } // UIntBase128 transformLength transformed length (if applicable) // _transformLength = _origLength; _compLength = _origLength; _transformLength = 0; // For all tables in a font, except for 'glyf' and 'loca' tables, transformation version 0 // indicates the null transform where the original table data is passed directly to the // Brotli compressor for inclusion in the compressed data stream. if (transformVersion == 0) { // "glyf" : 10, "loca" : 11 if (tagIndex == 10 || tagIndex == 11) { if (!WoffBuffer.ReadUIntBase128(stream, out _transformLength)) { return(false); } _compLength = _transformLength; } } // The transformation version "1", specified below, is optional and can be applied to // eliminate certain redundancies in the hmtx table data. if (transformVersion == 1) { // The transformation version 1 described in this subclause is optional and can only // be used when an input font is TrueType-flavored (i.e. has a glyf table) // "hmtx" : 3 if (tagIndex == 3 && isTrueType) { if (!WoffBuffer.ReadUIntBase128(stream, out _transformLength)) { return(false); } _compLength = _transformLength; } } if (_origLength > 0) { _padding = WoffUtils.CalculatePadding(_origLength); } return(true); }
private bool ReadWoff2Fonts(Stream stream) { // 1. Read the collection font header _collectionHeader = new CollectionHeader(); if (_collectionHeader.Read(stream) == false) { Trace.TraceError("Collection Font Error: Reading of collection header failed."); return(false); } // 2. Read this collection font entries var numFonts = _collectionHeader.NumFonts; _collectionEntries = new List <CollectionFontEntry>(numFonts); for (ushort i = 0; i < numFonts; i++) { var collectionEntry = new CollectionFontEntry(i); if (collectionEntry.Read(stream, _woffDirs.Count) == false) { return(false); } _collectionEntries.Add(collectionEntry); } // 3. TableDirectory: Directory of font tables, containing size and other info. for (ushort i = 0; i < numFonts; i++) { var collectionEntry = _collectionEntries[i]; var woffFont = new WoffFont(_woffHeader, _collectionHeader, collectionEntry); _woffFonts.Add(woffFont); woffFont.BeginDirectory(_woffVersion); for (ushort j = 0; j < collectionEntry.NumTables; j++) { var index = collectionEntry.TableIndices[j]; var woffDir = _woffDirs[index]; woffFont.AddDirectory(woffDir); } } // 4. CompressedFontData: Contents of font tables, compressed for storage in the WOFF2 file. int bytesRead = 0; int bytesCount = (int)_woffHeader.TotalCompressedSize; if (bytesCount != 0) { byte[] compressedBuffer = WoffBuffer.ReadBytes(stream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } bool errorOccurred = false; var memoryStream = new MemoryStream(compressedBuffer); using (var brotliStream = new BrotliInputStream(memoryStream)) { var decompressedStream = new MemoryStream(); brotliStream.CopyTo(decompressedStream); decompressedStream.Seek(0, SeekOrigin.Begin); for (int i = 0; i < _woffHeader.NumTables; i++) { var woffDir = _woffDirs[i]; try { // bytesCount = (int)woffDir.TransformLength; bytesCount = (int)woffDir.CompLength; decompressedStream.Seek(woffDir.Offset, SeekOrigin.Begin); var tableBuffer = WoffBuffer.ReadBytes(decompressedStream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } woffDir.CompTable = tableBuffer; woffDir.OrigTable = tableBuffer; } catch (Exception ex) { errorOccurred = true; Trace.TraceError(ex.Message); } } } if (errorOccurred) { return(false); } } for (ushort i = 0; i < numFonts; i++) { var collectionEntry = _collectionEntries[i]; var woffFont = _woffFonts[i]; _woffFonts.Add(woffFont); woffFont.EndDirectory(); } return(true); }
private bool ReadWoff2Font(Stream stream) { var woffFont = new WoffFont(_woffHeader); _woffFonts.Add(woffFont); woffFont.BeginDirectory(_woffVersion); // 2. TableDirectory: Directory of font tables, containing size and other info. for (ushort i = 0; i < _woffHeader.NumTables; i++) { var woffDir = _woffDirs[i]; woffFont.AddDirectory(woffDir); } // 4. CompressedFontData: Contents of font tables, compressed for storage in the WOFF2 file. int bytesRead = 0; int bytesCount = (int)_woffHeader.TotalCompressedSize; if (bytesCount != 0) { byte[] compressedBuffer = WoffBuffer.ReadBytes(stream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } bool errorOccurred = false; var memoryStream = new MemoryStream(compressedBuffer); using (var brotliStream = new BrotliInputStream(memoryStream)) { var decompressedStream = new MemoryStream(); brotliStream.CopyTo(decompressedStream); decompressedStream.Seek(0, SeekOrigin.Begin); for (int i = 0; i < _woffHeader.NumTables; i++) { var woffDir = _woffDirs[i]; try { // bytesCount = (int)woffDir.TransformLength; bytesCount = (int)woffDir.CompLength; decompressedStream.Seek(woffDir.Offset, SeekOrigin.Begin); var tableBuffer = WoffBuffer.ReadBytes(decompressedStream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } woffDir.CompTable = tableBuffer; woffDir.OrigTable = tableBuffer; } catch (Exception ex) { errorOccurred = true; Trace.TraceError(ex.Message); } } } if (errorOccurred) { return(false); } } woffFont.EndDirectory(); return(true); }
private bool ReadWoff2(Stream stream) { _woffVersion = WoffUtils.Woff2Version; uint sizeRead = 0; // 1. WOFF2Header: File header with basic font type and version, along with offsets // to metadata and private data blocks. _woffHeader = new WoffHeader(WoffUtils.Woff2Version); _woffDirs = null; sizeRead = _woffHeader.HeaderSize; Debug.Assert(sizeRead == WoffUtils.Woff2HeaderSize); if (!_woffHeader.Read(stream)) { return(false); } // 2. TableDirectory: Directory of font tables, containing size and other info. uint offset = 0; _woffDirs = new List <WoffTableDirectory>(_woffHeader.NumTables); for (ushort i = 0; i < _woffHeader.NumTables; i++) { var woffDir = new WoffTableDirectory(i, _woffVersion, offset); if (woffDir.Read(stream, _woffHeader.IsTrueType)) { if (woffDir.IsTransformed) { _isTransformed = true; } _woffDirs.Add(woffDir); offset += woffDir.CompLength; } } // 3. CollectionDirectory: An optional table containing the font fragment descriptions // of font collection entries. if (_woffHeader.IsCollection) { var isLoaded = this.ReadWoff2Fonts(stream); } else { var isLoaded = this.ReadWoff2Font(stream); } // 5. ExtendedMetadata: An optional block of extended metadata, represented in XML format // and compressed for storage in the WOFF2 file. _metadata = new WoffMetadata(_woffHeader.MetaOffset, _woffHeader.MetaLength, _woffHeader.MetaOrigLength); if (_woffHeader.HasMetadata) { stream.Seek(_woffHeader.MetaOffset, SeekOrigin.Begin); int bytesRead = 0; int bytesCount = (int)_woffHeader.MetaLength; var metaBuffer = WoffBuffer.ReadBytes(stream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } _metadata.Data = metaBuffer; _metadata.OrigData = metaBuffer; if (_woffHeader.MetaLength != _woffHeader.MetaOrigLength) { bytesCount = (int)_woffHeader.MetaOrigLength; using (var brotliStream = new BrotliInputStream(new MemoryStream(metaBuffer))) { var origBuffer = WoffBuffer.ReadBytes(brotliStream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } _metadata.OrigData = origBuffer; } } } // 6. PrivateData: An optional block of private data for the font designer, foundry, or vendor to use. _privateData = new WoffPrivateData(_woffHeader.PrivateOffset, _woffHeader.PrivateLength); if (_woffHeader.HasPrivateData) { stream.Seek(_woffHeader.PrivateOffset, SeekOrigin.Begin); int bytesRead = 0; int bytesCount = (int)_woffHeader.PrivateLength; var privateBuffer = WoffBuffer.ReadBytes(stream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } _privateData.Data = privateBuffer; } return(true); }
private bool ReadWoff1(Stream stream) { _woffVersion = WoffUtils.Woff1Version; var woffFont = new WoffFont(_woffHeader); _woffFonts.Add(woffFont); woffFont.BeginDirectory(_woffVersion); _woffHeader = new WoffHeader(WoffUtils.Woff1Version); _woffDirs = null; int sizeRead = 0; sizeRead = _woffHeader.HeaderSize; Debug.Assert(sizeRead == WoffUtils.Woff1HeaderSize); if (!_woffHeader.Read(stream)) { return(false); } _woffDirs = new List <WoffTableDirectory>(_woffHeader.NumTables); // 2. TableDirectory: Directory of font tables, containing size and other info. for (ushort i = 0; i < _woffHeader.NumTables; i++) { var woffDir = new WoffTableDirectory(i, _woffVersion); if (woffDir.Read(stream)) { _woffDirs.Add(woffDir); woffFont.AddDirectory(woffDir); } } for (int i = 0; i < _woffHeader.NumTables; i++) { var woffDir = _woffDirs[i]; stream.Seek(woffDir.Offset, SeekOrigin.Begin); int bytesRead = 0; int bytesCount = (int)woffDir.CompLength; if (bytesCount == 0) { continue; } var tableBuffer = WoffBuffer.ReadBytes(stream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } woffDir.CompTable = tableBuffer; if (woffDir.CompLength == woffDir.OrigLength) { // table data is not compressed woffDir.OrigTable = tableBuffer; } else { bytesCount = (int)woffDir.OrigLength; var origBuffer = new byte[bytesCount]; using (var zlibStream = new ZLibStream(new MemoryStream(tableBuffer), CompressionMode.Decompress, false)) { int bytesStart = 0; do { bytesRead = zlibStream.Read(origBuffer, bytesStart, bytesCount); if (bytesRead == 0) { break; } bytesStart += bytesRead; bytesCount -= bytesRead; } while (bytesCount > 0); } woffDir.OrigTable = origBuffer; } } _metadata = new WoffMetadata(_woffHeader.MetaOffset, _woffHeader.MetaLength, _woffHeader.MetaOrigLength); if (_woffHeader.HasMetadata) { stream.Seek(_woffHeader.MetaOffset, SeekOrigin.Begin); int bytesRead = 0; int bytesCount = (int)_woffHeader.MetaLength; var metaBuffer = WoffBuffer.ReadBytes(stream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } _metadata.Data = metaBuffer; _metadata.OrigData = metaBuffer; if (_woffHeader.MetaLength != _woffHeader.MetaOrigLength) { bytesCount = (int)_woffHeader.MetaOrigLength; var origBuffer = new byte[bytesCount]; using (var zlibStream = new ZLibStream(new MemoryStream(metaBuffer), CompressionMode.Decompress, false)) { int bytesStart = 0; do { bytesRead = zlibStream.Read(origBuffer, bytesStart, bytesCount); if (bytesRead == 0) { break; } bytesStart += bytesRead; bytesCount -= bytesRead; } while (bytesCount > 0); } _metadata.OrigData = origBuffer; } } _privateData = new WoffPrivateData(_woffHeader.PrivateOffset, _woffHeader.PrivateLength); if (_woffHeader.HasPrivateData) { stream.Seek(_woffHeader.PrivateOffset, SeekOrigin.Begin); int bytesRead = 0; int bytesCount = (int)_woffHeader.PrivateLength; var privateBuffer = WoffBuffer.ReadBytes(stream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } _privateData.Data = privateBuffer; } woffFont.EndDirectory(); return(true); }