Пример #1
0
            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);
            }
Пример #2
0
            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);
            }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
        }
Пример #7
0
        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);
        }
Пример #8
0
        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);
        }