Passed
Push — master ( aab506...997830 )
by Rafael S.
01:17
created

index.js ➔ writeSubChunks   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
c 1
b 0
f 0
nc 3
nop 2
dl 0
loc 19
rs 9.4285
1
/*!
2
 * riff-chunks
3
 * Read and write the chunks of RIFF and RIFX files.
4
 * Copyright (c) 2017 Rafael da Silva Rocha.
5
 * https://github.com/rochars/riff-chunks
6
 *
7
 */
8
9
const byteData = require("byte-data");
10
11
/**
12
 * Write the bytes of a RIFF/RIFX file.
13
 * @param {Object} chunks A structure like the return of riffChunks.read().
14
 * @param {boolean} bigEndian if the bytes should be big endian.
15
 *      "RIFX" chunkId will always set bigEndian to true.
16
 * @return {Array<number>|Uint8Array} The:
17
 *      - file bytes as Uint8Array when chunkId is "RIFF" or "RIFX" or
18
 *      - chunk bytes as Array<number> if chunkId is "LIST".
19
 */
20
function write(chunks, bigEndian=false) {
21
    if (!bigEndian) {
22
        bigEndian = chunks.chunkId == "RIFX";
23
    }
24
    let bytes =
25
        byteData.toBytes(chunks.chunkId, 8, byteData.char).concat(
26
                byteData.toBytes(chunks.chunkSize, 32, {'be': bigEndian}),
27
                byteData.toBytes(chunks.format, 8, byteData.char),
28
                writeSubChunks(chunks.subChunks, bigEndian)
29
            );
30
    if (chunks.chunkId == "RIFF" || chunks.chunkId == "RIFX" ) {
31
        bytes = new Uint8Array(bytes);
32
    }
33
    return bytes;
34
}
35
36
/**
37
 * Get the chunks of a RIFF/RIFX file.
38
 * @param {Uint8Array|!Array<number>} buffer The file bytes.
39
 * @return {Object}
40
 */
41
function read(buffer) {
42
    buffer = [].slice.call(buffer);
43
    let chunkId = getChunkId(buffer, 0);
44
    let bigEndian = (chunkId == "RIFX");
45
    let chunkSize = getChunkSize(buffer, 0, bigEndian);
46
    return {
47
        "chunkId": chunkId,
48
        "chunkSize": chunkSize,
49
        "format": byteData.fromBytes(buffer.slice(8, 12), 8, byteData.str),
50
        "subChunks": getSubChunks(buffer, bigEndian)
51
    };
52
}
53
54
/**
55
 * Write the sub chunks of a RIFF file.
56
 * @param {Array<Object>} chunks The chunks.
57
 * @param {boolean} bigEndian true if its RIFX.
58
 * @return {Array<number>}
59
 */
60
function writeSubChunks(chunks, bigEndian) {
61
    let subChunks = [];
62
    let i = 0;
63
    while (i < chunks.length) {
64
        if (chunks[i].chunkId == "LIST") {
65
            subChunks = subChunks.concat(write(chunks[i], bigEndian));
66
        } else {
67
            subChunks = subChunks.concat(
68
                byteData.toBytes(
69
                    chunks[i].chunkId, 8, byteData.char),
70
                byteData.toBytes(
71
                    chunks[i].chunkSize, 32, {'be': bigEndian}),
72
                chunks[i].chunkData
73
            );
74
        }
75
        i++;
76
    }
77
    return subChunks;
78
}
79
80
/**
81
 * Get the sub chunks of a RIFF file.
82
 * @param {Uint8Array|!Array<number>} buffer the RIFF file bytes.
83
 * @param {boolean} bigEndian true if its RIFX.
84
 * @return {Object}
85
 */
86
function getSubChunks(buffer, bigEndian) {
87
    let chunks = [];
88
    let i = 12;
89
    while(i < buffer.length) {
90
        chunks.push(getSubChunk(buffer, i, bigEndian));
91
        i += 8 + chunks[chunks.length - 1].chunkSize;
92
    }
93
    return chunks;
94
}
95
96
function getSubChunk(buffer, index, bigEndian) {
97
    let chunk = {
98
        "chunkId": getChunkId(buffer, index),
99
        "chunkSize": getChunkSize(buffer, index, bigEndian)
100
    };
101
    if (chunk.chunkId == "LIST") {
102
        chunk.format = byteData.fromBytes(
103
            buffer.slice(8, 12), 8, byteData.str);
104
        chunk.subChunks = getSubChunks(
105
            buffer.slice(index, index + chunk.chunkSize), bigEndian);
106
    } else {
107
        chunk.chunkData = buffer.slice(index + 8, index + 8 + chunk.chunkSize);
108
    }
109
    return chunk;
110
}
111
112
/**
113
 * Return the FourCC of a chunk.
114
 * @param {Uint8Array|!Array<number>} buffer the RIFF file bytes.
115
 * @param {number} index The start index of the chunk.
116
 * @return {string}
117
 */
118
function getChunkId(buffer, index) {
119
    return byteData.fromBytes(
120
        buffer.slice(index, index + 4), 8, byteData.str);
121
}
122
123
/**
124
 * Return the size of a chunk.
125
 * @param {Uint8Array|!Array<number>} buffer the RIFF file bytes.
126
 * @param {number} index The start index of the chunk.
127
 * @return {number}
128
 */
129
function getChunkSize(buffer, index, bigEndian) {
130
    return byteData.fromBytes(
131
            buffer.slice(index + 4, index + 8),
132
            32,
133
            {'be': bigEndian, "single": true}
134
        );
135
}
136
137
module.exports.read = read;
138
module.exports.write = write;
139