295 lines
6.1 KiB
JavaScript
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)
|
|
}
|
|
|