Completed
Push — master ( 1ae218...759712 )
by Rafael S.
01:24
created

T_CONST ➔ fixIndex_   B

Complexity

Conditions 5
Paths 2

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 1
rs 8.8571
c 0
b 0
f 0
cc 5
nc 2
nop 2
1
/*
2
 * riff-chunks
3
 * Read and write the chunks of RIFF and RIFX files.
4
 * Copyright (c) 2017-2018 Rafael da Silva Rocha.
5
 * https://github.com/rochars/riff-chunks
6
 *
7
 */
8
9
/** @private */
10
const byteData = require("byte-data");
11
/** @private */
12
const uInt32_ = {"bits": 32};
13
/** @private */
14
const fourCC_ = {"bits": 32, "char": true};
15
16
/**
17
 * Write the bytes of a RIFF/RIFX file.
18
 * @param {!Object} chunks A structure like the return of riffChunks.read().
19
 * @param {boolean} list An optional param indicating if the chunk is LIST.
20
 *      "LIST" chunks should not be rendered as Uint8Array.
21
 * @return {!Array<number>|Uint8Array} The bytes as Uint8Array when chunkId is
22
 *      "RIFF"/"RIFX" or as Array<number> when chunkId is "LIST".
23
 */
24
function write(chunks, list=false) {
25
    uInt32_["be"] = chunks["chunkId"] == "RIFX";
26
    let bytes = byteData.pack(chunks["chunkId"], fourCC_).concat(
27
        byteData.pack(chunks["chunkSize"], uInt32_),
28
        byteData.pack(chunks["format"], fourCC_),
29
        writeSubChunks_(chunks["subChunks"]));
30
    if (!list) {
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} The chunk.
40
 */
41
function read(buffer) {
42
    buffer = [].slice.call(buffer);
43
    let chunkId = getChunkId_(buffer, 0);
44
    uInt32_["be"] = chunkId == "RIFX";
45
    return {
46
        "chunkId": chunkId,
47
        "chunkSize": getChunkSize_(buffer, 0),
48
        "format": byteData.unpack(buffer.slice(8, 12), fourCC_),
49
        "subChunks": getSubChunks_(buffer)
50
    };
51
}
52
53
/**
54
 * Write the sub chunks of a RIFF file.
55
 * @param {!Array<!Object>} chunks The chunks.
56
 * @return {!Array<number>} The chunk bytes.
57
 * @private
58
 */
59
function writeSubChunks_(chunks) {
60
    let subChunks = [];
61
    let i = 0;
62
    while (i < chunks.length) {
63
        if (chunks[i]["chunkId"] == "LIST") {
64
            subChunks = subChunks.concat(write(chunks[i], true));
65
        } else {
66
            subChunks = subChunks.concat(
67
                byteData.pack(chunks[i]["chunkId"], fourCC_),
68
                byteData.pack(chunks[i]["chunkSize"], uInt32_),
69
                chunks[i]["chunkData"]);
70
        }
71
        i++;
72
    }
73
    return subChunks;
74
}
75
76
/**
77
 * Get the sub chunks of a RIFF file.
78
 * @param {!Uint8Array|!Array<number>} buffer the RIFF file bytes.
79
 * @return {!Array<Object>} The subchunks of a RIFF/RIFX or LIST chunk.
80
 * @private
81
 */
82
function getSubChunks_(buffer) {
83
    let chunks = [];
84
    let i = fixIndex_(buffer, 12);
85
    while(i <= buffer.length - 8) {
86
        chunks.push(getSubChunk_(buffer, i));
87
        i += 8 + chunks[chunks.length - 1]["chunkSize"];
88
    }
89
    return chunks;
90
}
91
92
/**
93
 * Get a sub chunk from a RIFF file.
94
 * @param {!Uint8Array|!Array<number>} buffer the RIFF file bytes.
95
 * @param {!number} index The start index of the chunk.
96
 * @return {!Object} A subchunk of a RIFF/RIFX or LIST chunk.
97
 * @private
98
 */
99
function getSubChunk_(buffer, index) {
100
    index = fixIndex_(buffer, index);
101
    let chunk = {
102
        "chunkId": getChunkId_(buffer, index),
103
        "chunkSize": getChunkSize_(buffer, index),
104
    };
105
    if (chunk["chunkId"] == "LIST") {
106
        chunk["format"] = byteData.unpack(
107
            buffer.slice(index + 8, index + 12), fourCC_);
108
        chunk["subChunks"] = getSubChunks_(buffer.slice(index));
109
    } else {
110
        chunk["chunkData"] = buffer.slice(
111
            index + 8, index + 8 + chunk["chunkSize"]);
112
    }
113
    return chunk;
114
}
115
116
/**
117
 * Fix the index for reading the chunkId for files
118
 * with broken size descriptions.
119
 * @param {!Uint8Array|!Array<number>} buffer The buffer.
120
 * @param {!number} i The start index of the chunk.
121
 * @return {!number} The new index.
122
 * @private
123
 */
124
function fixIndex_(buffer, i) {
125
    while (buffer[i] == 0 || buffer[i+1] == 0 ||
0 ignored issues
show
Best Practice introduced by
Comparing buffer.i to 0 using the == operator is not safe. Consider using === instead.
Loading history...
Best Practice introduced by
Comparing buffer.i + 1 to 0 using the == operator is not safe. Consider using === instead.
Loading history...
126
            buffer[i+2] == 0 || buffer[i+3] == 0) {
0 ignored issues
show
Best Practice introduced by
Comparing buffer.i + 3 to 0 using the == operator is not safe. Consider using === instead.
Loading history...
Best Practice introduced by
Comparing buffer.i + 2 to 0 using the == operator is not safe. Consider using === instead.
Loading history...
127
        i++;
128
    }
129
    return i;
130
}
131
132
/**
133
 * Return the fourCC_ of a chunk.
134
 * @param {!Uint8Array|!Array<number>} buffer the RIFF file bytes.
135
 * @param {!number} index The start index of the chunk.
136
 * @return {!string} The id of the chunk.
137
 * @private
138
 */
139
function getChunkId_(buffer, index) {
140
    return byteData.unpack(buffer.slice(index, index + 4), fourCC_);
141
}
142
143
/**
144
 * Return the size of a chunk.
145
 * @param {!Uint8Array|!Array<number>} buffer the RIFF file bytes.
146
 * @param {!number} index The start index of the chunk.
147
 * @return {!number} The size of the chunk without the id and size fields.
148
 * @private
149
 */
150
function getChunkSize_(buffer, index) {
151
    return byteData.unpack(buffer.slice(index + 4, index + 8), uInt32_);
152
}
153
154
module.exports.read = read;
155
module.exports.write = write;
156