Completed
Push — master ( ee8496...2ad19d )
by Rafael S.
01:37
created

T_IMPORT ➔ getSubChunk_   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 1
rs 10
c 0
b 0
f 0
cc 3
nc 2
nop 2
1
/*
2
 * riff-chunks: Read and write the chunks of RIFF and RIFX files.
3
 * https://github.com/rochars/riff-chunks
4
 *
5
 * Copyright (c) 2017-2018 Rafael da Silva Rocha.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining
8
 * a copy of this software and associated documentation files (the
9
 * "Software"), to deal in the Software without restriction, including
10
 * without limitation the rights to use, copy, modify, merge, publish,
11
 * distribute, sublicense, and/or sell copies of the Software, and to
12
 * permit persons to whom the Software is furnished to do so, subject to
13
 * the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be
16
 * included in all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 *
26
 */
27
28
/**
29
 * @fileoverview The riff-chunks public API and private methods.
30
 */
31
32
/** @module riffChunks */
33
34
import {pack, unpack, unpackFrom} from 'byte-data';
35
36
/** @private */
37
const uInt32_ = {'bits': 32};
38
/** @private */
39
const fourCC_ = {'bits': 32, 'char': true};
40
/** @type {number} */
41
let head_ = 0;
42
43
/**
44
 * Return the chunks of a RIFF/RIFX file.
45
 * @param {!Uint8Array|!Array<number>} buffer The file bytes.
46
 * @return {!Object} The RIFF chunks.
47
 */
48
function riffIndex(buffer) {
49
    head_ = 0;
50
    let chunkId = getChunkId_(buffer, 0);
51
    uInt32_['be'] = chunkId == 'RIFX';
52
    let format = unpackFrom(buffer, fourCC_, 8);
53
    head_ += 4;
54
    return {
55
        'chunkId': chunkId,
56
        'chunkSize': getChunkSize_(buffer, 0),
57
        'format': format,
58
        'subChunks': getSubChunksIndex_(buffer)
59
    };
60
}
61
62
/**
63
 * Return the sub chunks of a RIFF file.
64
 * @param {!Uint8Array|!Array<number>} buffer the RIFF file bytes.
65
 * @return {!Array<Object>} The subchunks of a RIFF/RIFX or LIST chunk.
66
 * @private
67
 */
68
function getSubChunksIndex_(buffer) {
69
    let chunks = [];
70
    let i = head_;
71
    while(i <= buffer.length - 8) {
72
        chunks.push(getSubChunkIndex_(buffer, i));
73
        i += 8 + chunks[chunks.length - 1]['chunkSize'];
74
        i = i % 2 ? i + 1 : i;
75
    }
76
    return chunks;
77
}
78
79
/**
80
 * Return a sub chunk from a RIFF file.
81
 * @param {!Uint8Array|!Array<number>} buffer the RIFF file bytes.
82
 * @param {number} index The start index of the chunk.
83
 * @return {!Object} A subchunk of a RIFF/RIFX or LIST chunk.
84
 * @private
85
 */
86
function getSubChunkIndex_(buffer, index) {
87
    let chunk = {
88
        'chunkId': getChunkId_(buffer, index),
89
        'chunkSize': getChunkSize_(buffer, index),
90
    };
91
    if (chunk['chunkId'] == 'LIST') {
92
        chunk['format'] = unpackFrom(buffer, fourCC_, index + 8);
93
        head_ += 4;
94
        chunk['subChunks'] = getSubChunksIndex_(buffer);
95
    } else {
96
        let realChunkSize = chunk['chunkSize'] % 2 ?
97
            chunk['chunkSize'] + 1 : chunk['chunkSize'];
98
        head_ = index + 8 + realChunkSize;
99
        chunk['chunkData'] = {
100
            'start': index + 8,
101
            'end': head_
102
        };
103
    }
104
    return chunk;
105
}
106
107
/**
108
 * Pack a RIFF/RIFX file.
109
 * @param {!Object} chunks A object like the return of riffChunks.read().
110
 * @param {boolean} list An optional param indicating if the chunk is LIST.
111
 *      'LIST' chunks should not be rendered as Uint8Array.
112
 * @return {!Array<number>|!Uint8Array} The bytes as Uint8Array when chunkId is
113
 *      'RIFF'/'RIFX' or as Array<number> when chunkId is 'LIST'.
114
 */
115
function write(chunks, list=false) {
116
    uInt32_['be'] = chunks['chunkId'] == 'RIFX';
117
    let bytes = pack(chunks['chunkId'], fourCC_).concat(
118
        pack(chunks['chunkSize'], uInt32_),
119
        pack(chunks['format'], fourCC_),
120
        writeSubChunks_(chunks['subChunks']));
121
    if (!list) {
122
        bytes = new Uint8Array(bytes);
123
    }
124
    return bytes;
125
}
126
127
/**
128
 * Return the chunks of a RIFF/RIFX file.
129
 * @param {!Uint8Array|!Array<number>} buffer The file bytes.
130
 * @return {!Object} The RIFF chunks.
131
 */
132
function read(buffer) {
133
    buffer = [].slice.call(buffer);
134
    let chunkId = getChunkId_(buffer, 0);
135
    uInt32_['be'] = chunkId == 'RIFX';
136
    let format = unpack(buffer.slice(8, 12), fourCC_);
137
    let chunkSize = getChunkSize_(buffer, 0);
138
    let subChunks = getSubChunks_(buffer);
139
    return {
140
        'chunkId': chunkId,
141
        'chunkSize': chunkSize,
142
        'format': format,
143
        'subChunks': subChunks
144
    };
145
}
146
147
/**
148
 * Pack the sub chunks of a RIFF file.
149
 * @param {!Array<!Object>} chunks The chunks.
150
 * @return {!Array<number>} The chunk bytes.
151
 * @private
152
 */
153
function writeSubChunks_(chunks) {
154
    let subChunks = [];
155
    let i = 0;
156
    while (i < chunks.length) {
157
        if (chunks[i]['chunkId'] == 'LIST') {
158
            subChunks = subChunks.concat(write(chunks[i], true));
159
        } else {
160
            subChunks = subChunks.concat(
161
                pack(chunks[i]['chunkId'], fourCC_),
162
                pack(chunks[i]['chunkSize'], uInt32_),
163
                chunks[i]['chunkData']);
164
        }
165
        i++;
166
    }
167
    return subChunks;
168
}
169
170
/**
171
 * Return the sub chunks of a RIFF file.
172
 * @param {!Uint8Array|!Array<number>} buffer the RIFF file bytes.
173
 * @return {!Array<Object>} The subchunks of a RIFF/RIFX or LIST chunk.
174
 * @private
175
 */
176
function getSubChunks_(buffer) {
177
    let chunks = [];
178
    let i = 12;
179
    while(i <= buffer.length - 8) {
180
        chunks.push(getSubChunk_(buffer, i));
181
        i += 8 + chunks[chunks.length - 1]['chunkSize'];
182
        i = i % 2 ? i + 1 : i;
183
    }
184
    return chunks;
185
}
186
187
/**
188
 * Return a sub chunk from a RIFF file.
189
 * @param {!Uint8Array|!Array<number>} buffer the RIFF file bytes.
190
 * @param {number} index The start index of the chunk.
191
 * @return {!Object} A subchunk of a RIFF/RIFX or LIST chunk.
192
 * @private
193
 */
194
function getSubChunk_(buffer, index) {
195
    let chunk = {
196
        'chunkId': getChunkId_(buffer, index),
197
        'chunkSize': getChunkSize_(buffer, index),
198
    };
199
    if (chunk['chunkId'] == 'LIST') {
200
        chunk['format'] = unpack(
201
            buffer.slice(index + 8, index + 12), fourCC_);
202
        chunk['subChunks'] = getSubChunks_(buffer.slice(index));
203
    } else {
204
        let slc = chunk['chunkSize'] % 2 ? chunk['chunkSize'] + 1 : chunk['chunkSize'];
205
        chunk['chunkData'] = buffer.slice(
206
            index + 8, index + 8 + slc);
207
    }
208
    return chunk;
209
}
210
211
/**
212
 * Return the fourCC_ of a chunk.
213
 * @param {!Uint8Array|!Array<number>} buffer the RIFF file bytes.
214
 * @param {number} index The start index of the chunk.
215
 * @return {string} The id of the chunk.
216
 * @private
217
 */
218
function getChunkId_(buffer, index) {
219
    head_ += 4;
220
    return unpackFrom(buffer, fourCC_, index);
221
}
222
223
/**
224
 * Return the size of a chunk.
225
 * @param {!Uint8Array|!Array<number>} buffer the RIFF file bytes.
226
 * @param {number} index The start index of the chunk.
227
 * @return {number} The size of the chunk without the id and size fields.
228
 * @private
229
 */
230
function getChunkSize_(buffer, index) {
231
    head_ += 4;
232
    return unpackFrom(buffer, uInt32_, index + 4);
233
}
234
235
export {read, write, riffIndex};
236