fonteditor-core
Version:
fonts (ttf, woff, woff2, eot, svg, otf) parse, write, transform, glyph adjust.
307 lines (256 loc) • 7.14 kB
JavaScript
/**
* @file 数据写入器
* @author mengke01(kekee000@gmail.com)
*/
import {curry} from '../common/lang';
import error from './error';
// 检查数组支持情况
if (typeof ArrayBuffer === 'undefined' || typeof DataView === 'undefined') {
throw new Error('not support ArrayBuffer and DataView');
}
// 数据类型
const dataType = {
Int8: 1,
Int16: 2,
Int32: 4,
Uint8: 1,
Uint16: 2,
Uint32: 4,
Float32: 4,
Float64: 8
};
/**
* 读取器
*
* @constructor
* @param {Array.<byte>} buffer 缓冲数组
* @param {number} offset 起始偏移
* @param {number=} length 数组长度
* @param {boolean=} littleEndian 是否小尾
*/
class Writer {
constructor(buffer, offset, length, littleEndian) {
const bufferLength = buffer.byteLength || buffer.length;
this.offset = offset || 0;
this.length = length || (bufferLength - this.offset);
this.littleEndian = littleEndian || false;
this.view = new DataView(buffer, this.offset, this.length);
}
/**
* 读取指定的数据类型
*
* @param {string} type 数据类型
* @param {number} value value值
* @param {number=} offset 位移
* @param {boolean=} littleEndian 是否小尾
*
* @return {this}
*/
write(type, value, offset, littleEndian) {
// 使用当前位移
if (undefined === offset) {
offset = this.offset;
}
// 使用小尾
if (undefined === littleEndian) {
littleEndian = this.littleEndian;
}
// 扩展方法
if (undefined === dataType[type]) {
return this['write' + type](value, offset, littleEndian);
}
const size = dataType[type];
this.offset = offset + size;
this.view['set' + type](offset, value, littleEndian);
return this;
}
/**
* 写入指定的字节数组
*
* @param {ArrayBuffer} value 写入值
* @param {number=} length 数组长度
* @param {number=} offset 起始偏移
* @return {this}
*/
writeBytes(value, length, offset) {
length = length || value.byteLength || value.length;
let i;
if (!length) {
return this;
}
if (undefined === offset) {
offset = this.offset;
}
if (length < 0 || offset + length > this.length) {
error.raise(10002, this.length, offset + length);
}
const littleEndian = this.littleEndian;
if (value instanceof ArrayBuffer) {
const view = new DataView(value, 0, length);
for (i = 0; i < length; ++i) {
this.view.setUint8(offset + i, view.getUint8(i, littleEndian), littleEndian);
}
}
else {
for (i = 0; i < length; ++i) {
this.view.setUint8(offset + i, value[i], littleEndian);
}
}
this.offset = offset + length;
return this;
}
/**
* 写空数据
*
* @param {number} length 长度
* @param {number=} offset 起始偏移
* @return {this}
*/
writeEmpty(length, offset) {
if (length < 0) {
error.raise(10002, this.length, length);
}
if (undefined === offset) {
offset = this.offset;
}
const littleEndian = this.littleEndian;
for (let i = 0; i < length; ++i) {
this.view.setUint8(offset + i, 0, littleEndian);
}
this.offset = offset + length;
return this;
}
/**
* 写入一个string
*
* @param {string} str 字符串
* @param {number=} length 长度
* @param {number=} offset 偏移
*
* @return {this}
*/
writeString(str = '', length, offset) {
if (undefined === offset) {
offset = this.offset;
}
// eslint-disable-next-line no-control-regex
length = length || str.replace(/[^\x00-\xff]/g, '11').length;
if (length < 0 || offset + length > this.length) {
error.raise(10002, this.length, offset + length);
}
this.seek(offset);
for (let i = 0, l = str.length, charCode; i < l; ++i) {
charCode = str.charCodeAt(i) || 0;
if (charCode > 127) {
// unicode编码可能会超出2字节,
// 写入与编码有关系,此处不做处理
this.writeUint16(charCode);
}
else {
this.writeUint8(charCode);
}
}
this.offset = offset + length;
return this;
}
/**
* 写入一个字符
*
* @param {string} value 字符
* @param {number=} offset 偏移
* @return {this}
*/
writeChar(value, offset) {
return this.writeString(value, offset);
}
/**
* 写入fixed类型
*
* @param {number} value 写入值
* @param {number=} offset 偏移
* @return {number} float
*/
writeFixed(value, offset) {
if (undefined === offset) {
offset = this.offset;
}
this.writeInt32(Math.round(value * 65536), offset);
return this;
}
/**
* 写入长日期
*
* @param {Date} value 日期对象
* @param {number=} offset 偏移
*
* @return {Date} Date对象
*/
writeLongDateTime(value, offset) {
if (undefined === offset) {
offset = this.offset;
}
// new Date(1970, 1, 1).getTime() - new Date(1904, 1, 1).getTime();
const delta = -2077545600000;
if (typeof value === 'undefined') {
value = delta;
}
else if (typeof value.getTime === 'function') {
value = value.getTime();
}
else if (/^\d+$/.test(value)) {
value = +value;
}
else {
value = Date.parse(value);
}
const time = Math.round((value - delta) / 1000);
this.writeUint32(0, offset);
this.writeUint32(time, offset + 4);
return this;
}
/**
* 跳转到指定偏移
*
* @param {number=} offset 偏移
* @return {this}
*/
seek(offset) {
if (undefined === offset) {
this.offset = 0;
}
if (offset < 0 || offset > this.length) {
error.raise(10002, this.length, offset);
}
this._offset = this.offset;
this.offset = offset;
return this;
}
/**
* 跳转到写入头部位置
*
* @return {this}
*/
head() {
this.offset = this._offset || 0;
return this;
}
/**
* 获取缓存的byte数组
*
* @return {ArrayBuffer}
*/
getBuffer() {
return this.view.buffer;
}
/**
* 注销
*/
dispose() {
delete this.view;
}
}
// 直接支持的数据类型
Object.keys(dataType).forEach(type => {
Writer.prototype['write' + type] = curry(Writer.prototype.write, type);
});
export default Writer;