public byte[] Rebuild(bool checksumAdjustment) { // create a Motorola Byte Order buffer for the new table WoffBuffer headBuffer = new WoffBuffer(SizeOfTable); // populate the buffer headBuffer.SetFixed(this.TableVersionNumber, (uint)FieldOffsets.TableVersionNumber); headBuffer.SetFixed(this.FontRevision, (uint)FieldOffsets.FontRevision); headBuffer.SetUInt(this.CheckSumAdjustment, (uint)FieldOffsets.CheckSumAdjustment); headBuffer.SetUInt(this.MagicNumber, (uint)FieldOffsets.MagicNumber); headBuffer.SetUShort(this.Flags, (uint)FieldOffsets.Flags); headBuffer.SetUShort(this.UnitsPerEm, (uint)FieldOffsets.UnitsPerEm); headBuffer.SetLong(this.Created, (uint)FieldOffsets.Created); headBuffer.SetLong(this.Modified, (uint)FieldOffsets.Modified); headBuffer.SetShort(this.XMin, (uint)FieldOffsets.XMin); headBuffer.SetShort(this.YMin, (uint)FieldOffsets.YMin); headBuffer.SetShort(this.XMax, (uint)FieldOffsets.XMax); headBuffer.SetShort(this.YMax, (uint)FieldOffsets.YMax); headBuffer.SetUShort(this.MacStyle, (uint)FieldOffsets.MacStyle); headBuffer.SetUShort(this.LowestRecPPEM, (uint)FieldOffsets.LowestRecPPEM); headBuffer.SetShort(this.FontDirectionHint, (uint)FieldOffsets.FontDirectionHint); headBuffer.SetShort(this.IndexToLocFormat, (uint)FieldOffsets.IndexToLocFormat); headBuffer.SetShort(this.GlyphDataFormat, (uint)FieldOffsets.GlyphDataFormat); if (checksumAdjustment) { // For checksum adjustment, we set this value to 0 headBuffer.SetUInt(0, (uint)FieldOffsets.CheckSumAdjustment); } return(headBuffer.GetBuffer()); }
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 NameRecord Clone() { ushort offset = 0; WoffBuffer bufTable = new WoffBuffer(SizeOf); NameRecord cloned = new NameRecord(offset, bufTable); cloned.PlatformID = this.PlatformID; cloned.EncodingID = this.EncodingID; cloned.LanguageID = this.LanguageID; cloned.NameID = this.NameID; cloned.StringLength = this.StringLength; cloned.StringOffset = this.StringOffset; if (_nameBytes != null) { byte[] nameBytes = new byte[_nameBytes.Length]; Buffer.BlockCopy(_nameBytes, 0, nameBytes, 0, _nameBytes.Length); cloned.NameBytes = nameBytes; } if (_nameString != null) { cloned.NameString = new string(_nameString.ToCharArray()); } return(cloned); }
/// <summary> /// Initializes a new non-resizable instance of the <see cref="WoffWriter"/> class /// based on the specified region (index) of a byte array. /// </summary> /// <param name="buffer">The array of unsigned bytes from which to create this stream.</param> /// <param name="index">The index into buffer at which the stream begins.</param> /// <param name="count">The length of the stream in bytes.</param> public WoffWriter(byte[] buffer, int index, int count) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer), "ArgumentNull_Buffer"); } if (index < 0) { throw new ArgumentOutOfRangeException(nameof(index), "ArgumentOutOfRange_NeedNonNegNum"); } if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count), "ArgumentOutOfRange_NeedNonNegNum"); } if (buffer.Length - index < count) { throw new ArgumentException("Argument_InvalidOffLen"); } _converter = new WoffBuffer(WoffBuffer.SizeOfLong * 2); // 16-bytes if (buffer.Length == 0) { _buffer = new MemoryStream(); _isExpandable = true; } else { _buffer = new MemoryStream(buffer, index, count, true, true); } }
/// <summary> /// Initializes a new instance of the <see cref="WoffReader"/> class with the specified bytes stream. /// </summary> /// <param name="buffer">A object containing the bytes stream.</param> public WoffReader(byte[] buffer) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer), "The buffer parameter is required and cannot be null."); } _buffer = new WoffBuffer(buffer); }
public void ChecksumAdjustment(byte[] headersBuffer, uint headerOffset, uint headerLength, uint tablesChecksum = 0) { Debug.Assert(_headIndex != -1); if (_headIndex == -1) { return; } var headTable = _woffTables[_headIndex] as WoffTableHead; Debug.Assert(headTable != null); if (headTable == null) { return; } // Compute the checksum of the font's header Debug.Assert(headerLength != 0); Debug.Assert(headersBuffer != null && headersBuffer.Length != 0); var headerPadding = (uint)WoffBuffer.CalcPadBytes((int)headerLength, 4); var buffer = headersBuffer; if (headerPadding > 0) { var paddedLength = headerLength + headerPadding; buffer = new byte[paddedLength]; Buffer.BlockCopy(headersBuffer, 0, buffer, 0, headersBuffer.Length); } uint nLongs = (headerLength + 3) / 4; uint headerChecksum = 0; for (uint i = 0; i < nLongs; i += 4) { headerChecksum += WoffBuffer.GetUIntBE(buffer, i); } // Compute the checksum of the font by summing the checksum of the header and tables var fontChecksum = headerChecksum; if (tablesChecksum == 0) { tablesChecksum = headerChecksum; for (ushort i = 0; i < _woffDirs.Count; i++) { tablesChecksum += _woffDirs[i].OrigChecksum; } } fontChecksum += headerChecksum; // Finally, update the 'head' table's checkSumAdjustment. headTable.CheckSumAdjustment = 0xB1B0AFBA - fontChecksum; }
public WoffTableHead(WoffFont woffFont, WoffTableDirectory woffDir) : base(woffFont, woffDir) { var buffer = woffDir.OrigTable; if (buffer != null && buffer.Length >= SizeOfTable) { var length = buffer.Length; _tableBuffer = new WoffBuffer((uint)length); _tableBuffer.Copy(buffer); } }
public WoffTableName(WoffFont woffFont, WoffTableDirectory woffDir) : base(woffFont, woffDir) { var buffer = woffDir.OrigTable; if (buffer != null && buffer.Length >= 6) { var length = buffer.Length; _tableBuffer = new WoffBuffer((uint)length); _tableBuffer.Copy(buffer); } _unicodeNoBOM = new UnicodeEncoding(true, false); }
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); }
/// Initializes a new non-resizable instance of the <see cref="WoffWriter"/> class /// based on the specified byte array. /// </summary> /// <param name="buffer">The array of unsigned bytes from which to create the current stream.</param> public WoffWriter(byte[] buffer) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer), "ArgumentNull_Buffer"); } _converter = new WoffBuffer(WoffBuffer.SizeOfLong * 2); // 16-bytes if (buffer.Length == 0) { _buffer = new MemoryStream(); _isExpandable = true; } else { _buffer = new MemoryStream(buffer, 0, buffer.Length, true, true); } }
/// <summary> /// Initializes a new instance of the <see cref="WoffWriter"/> class with a non-resizable /// capacity initialized as specified. /// </summary> /// <param name="capacity">The initial size of the internal array in bytes.</param> public WoffWriter(uint capacity) { if (capacity < 0) { throw new ArgumentOutOfRangeException(nameof(capacity)); } _converter = new WoffBuffer(WoffBuffer.SizeOfLong * 2); // 16-bytes if (capacity == 0) { _buffer = new MemoryStream(); _isExpandable = true; } else { _buffer = new MemoryStream(new byte[capacity], 0, (int)capacity, true, true); } }
protected override bool ReconstructTable() { var headBuffer = _woffDir.OrigTable; if (headBuffer == null || headBuffer.Length < SizeOfTable) { return(false); } var length = headBuffer.Length; _tableBuffer = new WoffBuffer((uint)length); _tableBuffer.Copy(headBuffer); // For checksum adjustment, we set this value to 0 _tableBuffer.SetUInt(0, (uint)FieldOffsets.CheckSumAdjustment); _woffDir.OrigTable = headBuffer; _woffDir.OrigLength = (uint)headBuffer.Length; return(true); }
private bool SerializeHmtx(IList <ushort> advanceWidths, IList <short> lsbs, int numOfHMetrics, int numOfGlyphs) { var hmtxBufferSize = 2 * numOfGlyphs + 2 * numOfHMetrics; var writer = new WoffWriter(hmtxBufferSize); for (int i = 0; i < numOfGlyphs; i++) { if (i < numOfHMetrics) { writer.WriteUInt16(advanceWidths[i]); } writer.WriteInt16(lsbs[i]); } var tableBuffer = writer.GetBuffer(); var hmtxBuffer = new WoffBuffer(tableBuffer); _woffDir.OrigTable = tableBuffer; _woffDir.OrigLength = (uint)tableBuffer.Length; return(true); }
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); }
public uint CalculateChecksum() { Debug.Assert(_origLength != 0); Debug.Assert(_origTable != null && _origTable.Length != 0); var padBytesLength = (uint)WoffBuffer.CalcPadBytes((int)_origLength, 4); if (padBytesLength != 0) { _padding = padBytesLength; } var origLength = _origLength; var buffer = _origTable; if (_padding > 0) { origLength = _origLength + _padding; buffer = new byte[origLength]; Buffer.BlockCopy(_origTable, 0, buffer, 0, _origTable.Length); } uint nLongs = (_origLength + 3) / 4; uint sum = 0; //for (uint i = 0; i < nLongs; i++) //{ // sum += WoffBuffer.GetUIntBE(buffer, i * 4); //} for (uint i = 0; i < nLongs; i += 4) { sum += WoffBuffer.GetUIntBE(buffer, i); } return(sum); }
public static bool BinaryEqual(WoffBuffer buf1, WoffBuffer buf2) { bool bEqual = true; if (buf1.GetLength() != buf2.GetLength()) { bEqual = false; } else { byte[] b1 = buf1.GetBuffer(); byte[] b2 = buf2.GetBuffer(); for (int i = 0; i < b1.Length; i++) { if (b1[i] != b2[i]) { bEqual = false; break; } } } return(bEqual); }
/// <summary> /// Initializes a new instance of the <see cref="WoffWriter"/> class with an expandable /// capacity initialized to zero. /// </summary> public WoffWriter() { _buffer = new MemoryStream(); _converter = new WoffBuffer(WoffBuffer.SizeOfLong * 2); // 16-bytes _isExpandable = 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); }
public NameRecord(ushort offset, WoffBuffer bufTable) { _offsetNameRecord = offset; _tableBuffer = bufTable; }
protected override bool ReconstructTable() { var headBuffer = _woffDir.OrigTable; if (headBuffer == null || headBuffer.Length < 6) { return(false); } var length = headBuffer.Length; _tableBuffer = new WoffBuffer((uint)length); _tableBuffer.Copy(headBuffer); var fullFontName = this.GetNameString(); var fontFamilyName = this.GetFamilyString(); var postScriptName = this.GetPostScriptString(); // Check if the FullFontName and FontFamilyName are stripped from the compressed table data // Some tools (such as the dvisvgm – A fast DVI to SVG converter) strip both leaving only the PostScriptName if (!string.IsNullOrWhiteSpace(fullFontName) && !string.IsNullOrWhiteSpace(fontFamilyName)) { return(true); } var fixFullFontName = string.IsNullOrWhiteSpace(fullFontName); var fixFontFamilyName = string.IsNullOrWhiteSpace(fontFamilyName); // For the fix, we will just duplicate an existing name record, find out which one. ushort searchRecord = 0; if (!fixFullFontName) { searchRecord = (ushort)NameIdentifiers.FullFontName; } else if (!fixFontFamilyName) { searchRecord = (ushort)NameIdentifiers.FontFamilyName; } else if (!string.IsNullOrWhiteSpace(postScriptName)) { searchRecord = (ushort)NameIdentifiers.PostScriptName; } else { // We cannot fix it... return(true); } int numRecords = this.NumberNameRecords; List <NameRecord> nameRecords = new List <NameRecord>(numRecords); for (uint i = 0; i < numRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { byte[] nameBytes = GetEncodedString(nr); if (nameBytes != null && nameBytes.Length != 0) { nr.NameBytes = nameBytes; nr.NameString = DecodeString(nr.PlatformID, nr.EncodingID, nameBytes); nameRecords.Add(nr); if (searchRecord == nr.NameID) { if (fixFontFamilyName) { var nrFontFamily = nr.Clone(); nrFontFamily.NameID = (ushort)NameIdentifiers.FontFamilyName; nameRecords.Add(nrFontFamily); } if (fixFullFontName) { var nrFullFont = nr.Clone(); nrFullFont.NameID = (ushort)NameIdentifiers.FullFontName; nameRecords.Add(nrFullFont); } } } } } numRecords = nameRecords.Count; List <byte[]> bytesNameString = new List <byte[]>(); uint lengthOfStrings = 0; ushort offsetToStrings = (ushort)(6 + (numRecords * 12)); for (int i = 0; i < numRecords; i++) { var nrc = nameRecords[i]; byte[] byteString = nrc.NameBytes; bytesNameString.Add(byteString); lengthOfStrings += (ushort)byteString.Length; } // create a Motorola Byte Order buffer for the new table var tableBuffer = new WoffBuffer((uint)((ushort)FieldOffsets.NameRecords + numRecords * 12 + lengthOfStrings)); // populate the buffer tableBuffer.SetUShort(this.FormatSelector, (uint)FieldOffsets.FormatSelector); tableBuffer.SetUShort((ushort)numRecords, (uint)FieldOffsets.NumberNameRecords); tableBuffer.SetUShort(offsetToStrings, (uint)FieldOffsets.OffsetToStrings); ushort nOffset = 0; // Write the NameRecords and Strings for (int i = 0; i < numRecords; i++) { byte[] namBytes = bytesNameString[i]; uint startOffset = (uint)((ushort)(FieldOffsets.NameRecords) + i * NameRecord.SizeOf); tableBuffer.SetUShort((nameRecords[i]).PlatformID, startOffset + (ushort)NameRecord.FieldOffsets.PlatformID); tableBuffer.SetUShort((nameRecords[i]).EncodingID, startOffset + (ushort)NameRecord.FieldOffsets.EncodingID); tableBuffer.SetUShort((nameRecords[i]).LanguageID, startOffset + (ushort)NameRecord.FieldOffsets.LanguageID); tableBuffer.SetUShort((nameRecords[i]).NameID, startOffset + (ushort)NameRecord.FieldOffsets.NameID); tableBuffer.SetUShort((ushort)namBytes.Length, startOffset + (ushort)NameRecord.FieldOffsets.StringLength); tableBuffer.SetUShort(nOffset, startOffset + (ushort)NameRecord.FieldOffsets.StringOffset); //Write the string to the buffer for (int j = 0; j < namBytes.Length; j++) { tableBuffer.SetByte(namBytes[j], (uint)(offsetToStrings + nOffset + j)); } nOffset += (ushort)namBytes.Length; } _tableBuffer = tableBuffer; var nameBuffer = _tableBuffer.GetBuffer(); _woffDir.OrigTable = nameBuffer; _woffDir.OrigLength = (uint)nameBuffer.Length; _woffDir.RecalculateChecksum(); return(true); }
private bool WriteWoff1(Stream stream) { if (stream == null || _woffHeader == null || _woffDirs == null || _woffDirs.Count == 0) { return(false); } var numTables = _woffHeader.NumTables; var searchRange = (ushort)(WoffUtils.MaxPower2LE(numTables) * TableSize); var entrySelector = WoffUtils.Log2(WoffUtils.MaxPower2LE(numTables)); var rangeShift = (ushort)(numTables * TableSize - searchRange); int offset = 0; // Write the font offset table... var headerBuffer = new byte[HeaderSize]; // uint32: sfntVersion 0x00010000 or 0x4F54544F ('OTTO') offset += WoffBuffer.WriteUInt32BE(headerBuffer, offset, _woffHeader.Flavor); // uint16: numTables Number of tables. offset += WoffBuffer.WriteUInt16BE(headerBuffer, offset, _woffHeader.NumTables); // uint16 searchRange (Maximum power of 2 <= numTables) x 16. offset += WoffBuffer.WriteUInt16BE(headerBuffer, offset, searchRange); // uint16: entrySelector Log2(maximum power of 2 <= numTables). offset += WoffBuffer.WriteUInt16BE(headerBuffer, offset, entrySelector); // uint16: rangeShift NumTables x 16-searchRange. offset += WoffBuffer.WriteUInt16BE(headerBuffer, offset, rangeShift); stream.Write(headerBuffer, 0, (int)HeaderSize); uint tablesOffset = HeaderSize + numTables * TableSize; var tableBuffer = new byte[TableSize]; for (int i = 0; i < numTables; i++) { offset = 0; var woffDir = _woffDirs[i]; // Tag: tableTag Table identifier. offset += WoffBuffer.WriteUInt32BE(tableBuffer, offset, woffDir.Tag); // uint32: checkSum CheckSum for this table. offset += WoffBuffer.WriteUInt32BE(tableBuffer, offset, woffDir.OrigChecksum); // Offset32 offset Offset from beginning of TrueType font file. offset += WoffBuffer.WriteUInt32BE(tableBuffer, offset, tablesOffset); // uint32 length Length of this table. offset += WoffBuffer.WriteUInt32BE(tableBuffer, offset, woffDir.OrigLength); stream.Write(tableBuffer, 0, (int)TableSize); tablesOffset += woffDir.OrigLength; if (tablesOffset % 4 != 0) { tablesOffset += 4 - (tablesOffset % 4); } } var paddingBuffer = new byte[4]; for (int i = 0; i < numTables; i++) { var woffDir = _woffDirs[i]; stream.Write(woffDir.OrigTable, 0, (int)woffDir.OrigLength); stream.Write(paddingBuffer, 0, (int)woffDir.Padding); } 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 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 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); }
public bool Serialize(WoffWriter writer, WoffIndexer pointsWriter, out uint glyphSize) { glyphSize = 0; if (writer == null) { return(false); } uint startOffset = writer.Offset; // 1. Write the Glyph Header writer.WriteInt16(_numContours); // int16 numberOfContours for number of contours: >= 0 is simple glyph, < 0 composite glyph. writer.WriteInt16(_xMin); // int16 xMin Minimum x for coordinate data. writer.WriteInt16(_yMin); // int16 yMin Minimum y for coordinate data. writer.WriteInt16(_xMax); // int16 xMax Maximum x for coordinate data. writer.WriteInt16(_yMax); // int16 yMax Maximum y for coordinate data. // 2. Write the Simple Glyph Description, if applicable if (_glyphType == WoffGlyphType.Simple) { // uint16 endPtsOfContours[numberOfContours] // Array of point indices for the last point of each contour, in increasing numeric order. Debug.Assert(_endPtsOfContours != null && _endPtsOfContours.Length == _numContours); if (_endPtsOfContours == null || _endPtsOfContours.Length != _numContours) { Debug.Assert(false, "Invalid condition."); return(false); } for (short i = 0; i < _numContours; i++) { writer.WriteUInt16(_endPtsOfContours[i]); } // uint16 instructionLength Total number of bytes for instructions. // If instructionLength is zero, no instructions are present for this glyph, // and this field is followed directly by the flags field.instructionLength writer.WriteUInt16(_instructionLength); // uint8 instructions[instructionLength] Array of instruction byte code for the glyph. if (_instructionLength != 0) { Debug.Assert(_instructions != null && _instructions.Length == _instructionLength); if (_instructions == null || _instructions.Length != _instructionLength) { Debug.Assert(false, "Invalid condition."); return(false); } writer.Write(_instructions); } // Pack the points Debug.Assert(_numPoints == _contours.Count); int pointsCapacity = 5 * _numPoints; // Size without the application of packing. if (pointsWriter == null) { pointsWriter = new WoffIndexer(pointsCapacity); } else { pointsWriter.Offset = 0; } uint pointsLength = 0; if (PackPoints(pointsWriter, (uint)pointsCapacity, ref pointsLength) == false) { Debug.Assert(false, "Invalid condition."); return(false); } // Serialize the points... writer.Write(pointsWriter.GetBuffer(), 0, (int)pointsLength); } // Write the Simple Glyph Description, if applicable else if (_glyphType == WoffGlyphType.Composite) { Debug.Assert(_componentLength != 0); Debug.Assert(_components != null && _componentLength == _components.Length); if (_componentLength == 0 || _components == null || _componentLength != _components.Length) { Debug.Assert(false, "Invalid condition."); return(false); } // Serialize the Composite Glyph data... writer.Write(_components, 0, _componentLength); } // NOTE: Without the padding the serialization of the glyph fails! var padBytesLength = WoffBuffer.CalcPadBytes((int)writer.Offset, 4); if (padBytesLength > 0) { var paddingBuffer = new byte[4]; writer.Write(paddingBuffer, 0, padBytesLength); } uint endOffset = writer.Offset; if (endOffset <= startOffset) { Debug.Assert(false, "Invalid condition."); return(false); } glyphSize = endOffset - startOffset; 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); }
public bool Read(Stream stream) { if (stream == null) { return(false); } Debug.Assert(_woffVersion == WoffUtils.Woff1Version || _woffVersion == WoffUtils.Woff2Version); var headerSize = this.HeaderSize; var header = new byte[headerSize]; var sizeRead = stream.Read(header, 0, headerSize); Debug.Assert(sizeRead == headerSize); var bufferSize = header.Length; _signature = WoffBuffer.ReadUInt32BE(header, 0); _flavor = WoffBuffer.ReadUInt32BE(header, 4); _length = WoffBuffer.ReadUInt32BE(header, 8); _numTables = WoffBuffer.ReadUInt16BE(header, 12); _reserved = WoffBuffer.ReadUInt16BE(header, 14); _totalSfntSize = WoffBuffer.ReadUInt32BE(header, 16); if (_woffVersion == WoffUtils.Woff1Version) { _majorVersion = WoffBuffer.ReadUInt16BE(header, 20); _minorVersion = WoffBuffer.ReadUInt16BE(header, 22); _metaOffset = WoffBuffer.ReadUInt32BE(header, 24); _metaLength = WoffBuffer.ReadUInt32BE(header, 28); _metaOrigLength = WoffBuffer.ReadUInt32BE(header, 32); _privateOffset = WoffBuffer.ReadUInt32BE(header, 36); _privateLength = WoffBuffer.ReadUInt32BE(header, 40); } else { _totalCompressedSize = WoffBuffer.ReadUInt32BE(header, 20); _majorVersion = WoffBuffer.ReadUInt16BE(header, 24); _minorVersion = WoffBuffer.ReadUInt16BE(header, 26); _metaOffset = WoffBuffer.ReadUInt32BE(header, 28); _metaLength = WoffBuffer.ReadUInt32BE(header, 32); _metaOrigLength = WoffBuffer.ReadUInt32BE(header, 36); _privateOffset = WoffBuffer.ReadUInt32BE(header, 40); _privateLength = WoffBuffer.ReadUInt32BE(header, 44); } // The signature field in the WOFF-1 header must contain the "magic number" 0x774F4646. // If the field does not contain this value, user agents must reject the file as invalid. Debug.Assert((bufferSize == WoffUtils.Woff1HeaderSize) ? _signature == WoffUtils.Woff1Signature : _signature == WoffUtils.Woff2Signature); // The header includes a reserved field; this must be set to zero. // If this field is non-zero, a conforming user agent must reject the file as invalid. Debug.Assert(_reserved == 0); return(true); }