joy4/atom/genAtomStruct.js
2015-11-19 08:19:14 +08:00

295 lines
6.1 KiB
JavaScript

var ucfirst = x => x.substr(0,1).toUpperCase() + x.slice(1);
var D = (cls, prop, ...fields) => {
var ctor = function (args) {
this.cls = cls;
Object.assign(this, prop);
fields.forEach((f, i) => this[f] = typeof(args[i]) == 'string' ? ucfirst(args[i]) : args[i]);
if (cls == 'Atom' || cls == 'AtomPtr')
this.type = this.type + 'Atom';
};
global[cls] = (...args) => new ctor(args);
}
D('Int', {basic: true, type: 'int'}, 'name', 'len');
D('Str', {basic: true, type: 'string'}, 'name', 'len');
D('TimeStamp', {basic: true, type: 'TimeStamp'}, 'name', 'len');
D('Bytes', {basic: true, type: '[]byte'}, 'name', 'len');
D('Fixed32', {basic: true, type: 'Fixed32'}, 'name', 'len');
D('Atom', {}, 'type', 'name');
D('AtomPtr', {}, 'type', 'name');
D('Struct', {}, 'type', 'name');
D('StructPtr', {}, 'type', 'name');
D('Arr', {}, 'name', 'elem', 'count');
D('LenArr', {}, 'len', 'name', 'elem', 'isptr');
D('Size', {hide: true}, 'len');
D('_', {type: 'Dummy', hide: true}, 'len');
var atoms = {
fileType: [
'ftyp',
AtomPtr('movie', 'movie'),
],
movie: [
'moov',
AtomPtr('movieHeader', 'header'),
Arr('tracks', AtomPtr('track')),
],
movieHeader: [
'mvhd',
Int('version', 1),
Int('flags', 3),
TimeStamp('cTime', 4),
TimeStamp('mTime', 4),
Int('timeScale', 4),
Int('duration', 4),
Int('preferredRate', 4),
Int('preferredVolume', 2),
_(10),
Bytes('matrix', 36),
TimeStamp('previewTime', 4),
TimeStamp('previewDuration', 4),
TimeStamp('posterTime', 4),
TimeStamp('selectionTime', 4),
TimeStamp('selectionDuration', 4),
TimeStamp('currentTime', 4),
Int('nextTrackId', 4),
],
track: [
'trak',
AtomPtr('trackHeader', 'header'),
AtomPtr('media', 'media'),
],
trackHeader: [
'tkhd',
Int('version', 1),
Int('flags', 3),
TimeStamp('cTime', 4),
TimeStamp('mTime', 4),
Int('trackId', 4),
_(4),
Int('duration', 4),
_(8),
Int('layer', 2),
Int('alternateGroup', 2),
Int('volume', 2),
_(2),
Bytes('matrix', 36),
Fixed32('trackWidth', 4),
Fixed32('trackHeight', 4),
],
media: [
'mdia',
AtomPtr('mediaHeader', 'header'),
AtomPtr('mediaInfo', 'info'),
],
mediaHeader: [
'mdhd',
Int('version', 1),
Int('flags', 3),
TimeStamp('cTime', 4),
TimeStamp('mTime', 4),
Int('timeScale', 4),
Int('duration', 4),
Int('language', 2),
Int('quality', 2),
],
mediaInfo: [
'minf',
AtomPtr('videoMediaInfo', 'video'),
AtomPtr('sampleTable', 'sample'),
],
videoMediaInfo: [
'vmhd',
Int('version', 1),
Int('flags', 3),
Int('graphicsMode', 2),
Arr('opcolor', Int('', 2), 3),
],
sampleTable: [
'stbl',
AtomPtr('sampleDesc', 'sampleDesc'),
AtomPtr('timeToSample', 'timeToSample'),
AtomPtr('compositionOffset', 'compositionOffset'),
AtomPtr('syncSample', 'syncSample'),
AtomPtr('sampleSize', 'sampleSize'),
AtomPtr('chunkOffset', 'chunkOffset'),
],
sampleDesc: [
'stsd',
Int('version', 1),
Int('flags', 3),
LenArr(4, 'entries', Struct('sampleDescEntry')),
],
timeToSample: [
'stts',
Int('version', 1),
Int('flags', 3),
LenArr(4, 'entries', Struct('timeToSampleEntry')),
],
compositionOffset: [
'ctts',
Int('version', 1),
Int('flags', 3),
LenArr(4, 'entries', Struct('compositionOffsetEntry')),
],
syncSample: [
'stss',
Int('version', 1),
Int('flags', 3),
LenArr(4, 'entries', Int('', 4)),
],
sampleSize: [
'stsz',
Int('version', 1),
Int('flags', 3),
LenArr(4, 'entries', Int('', 4)),
],
chunkOffset: [
'stco',
Int('version', 1),
Int('flags', 3),
LenArr(4, 'entries', Int('', 4)),
],
};
var structs = {
sampleDescEntry: [
Size(4),
Str('format', 4),
_(6),
Int('dataRefIdx', 2),
Bytes('data'),
],
timeToSampleEntry: [
Int('count', 4),
Int('duration', 4),
],
compositionOffsetEntry: [
Int('count', 4),
Int('offset', 4),
],
};
var typeStr = field => (
field.cls == 'AtomPtr' || field.cls == 'StructPtr') ? '*'+field.type : field.type;
var dumpStruct = (name, list) => {
console.log(`type ${name} struct {
%s
}`, list
.filter(field => !field.hide)
.map(field => {
if (field.cls == 'Arr' || field.cls == 'LenArr')
return field.name +' []'+typeStr(field.elem);
return field.name+' '+typeStr(field)
}).join('\n')
);
dumpReadFn(name, null, false, list);
};
var dumpReadFn = (type, cc4, retptr, list) => {
var useSize;
if (retptr) {
console.log(`func Read${type}(r io.LimitedReader) (res *${type}, err error) {`);
console.log(`self := &${type}{}`);
} else {
console.log(`func Read${type}(r io.LimitedReader) (self ${type}, err error) {`);
}
list.forEach(field => {
if (field.cls == 'Size') {
useSize = true;
console.log(`size := ReadInt(r, ${field.len})`);
} else if (field.cls == 'Arr') {
var cond = field.count ? `i := 0; i < ${field.count}; i++` : `r.N > 0`;
console.log(`for ${cond} {`);
console.log(`var item ${typeStr(field.elem)}`);
console.log(`if item, err = Read${field.elem.type}(r); err != nil {
return
} else {
self.${field.name} = append(self.${field.name}, item)
}`);
console.log(`}`);
} else if (field.cls == 'LenArr') {
console.log(`if n, err := ReadInt(r, ${field.len}); err != nil {
return nil, err
} else {
for i := 0; i < n; i++ {
self.${field.name} = append(self.${field.name}, item)
}
}`);
} else {
var fn = field.basic ? field.cls : field.type;
var args = field.basic ? 'r, ' + field.len : 'r';
console.log(`if self.${field.name}, err = Read${fn}(${args}); err != nil {
return
}`);
}
});
if (retptr) {
console.log(`res = self`);
}
console.log(`return`);
console.log(`}`);
};
var dumpWriteFn = (name, list) => {
var useSize;
console.log(`func Write${name}(w Writer, atom ${name}) (err error) {`);
list.map(x => {
if (x.type == 'size') {
useSize = true;
return `ReadInt(r, ${x.len})`;
}
});
console.log(`}`);
};
console.log('// THIS FILE IS AUTO GENERATED');
console.log('');
console.log('package atom');
for (var k in atoms) {
var list = atoms[k];
var name = ucfirst(k)+'Atom';
var cc4 = list[0];
list = list.slice(1);
dumpStruct(name, list);
dumpReadFn(name, cc4, true, list);
}
for (var k in structs) {
var list = structs[k];
dumpStruct(ucfirst(k), list)
}