• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

benrr101 / node-taglib-sharp / 48257345

12 Oct 2023 04:06AM UTC coverage: 92.315% (+0.4%) from 91.944%
48257345

push

appveyor

benrr101
Performer roles (bug fixed), genres

3226 of 4153 branches covered (0.0%)

Branch coverage included in aggregate %.

94 of 94 new or added lines in 2 files covered. (100.0%)

27069 of 28664 relevant lines covered (94.44%)

417.21 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

41.12
/src/mpeg4/mpeg4BoxHeader.ts
1
import Mpeg4BoxType from "./mpeg4BoxType";
1✔
2
import {ByteVector} from "../byteVector";
1✔
3
import {File} from "../file";
4
import {Guards, NumberUtils} from "../utils";
1✔
5

6
/**
7
 *  Provides support for reading and writing headers for ISO/IEC 14496-12 boxes.
8
 */
9
export default class Mpeg4BoxHeader {
1✔
10
    /**
11
     *  Contains the box size.
12
     */
13
    private _boxSize: number;
14

15
    /**
16
     * The type of box represented by the current instance.
17
     */
18
    private _boxType: ByteVector;
19

20
    /**
21
     * The extended type of the box represented by the current instance.
22
     */
23
    private _extendedType: ByteVector;
24

25
    /**
26
     *  Contains the header size.
27
     */
28
    private _headerSize: number;
29

30
    /**
31
     *  Contains the position of the header.
32
     */
33
    private _position: number;
34

35
    /**
36
     * Indicates that the header was read from a file.
37
     */
38
    private _fromDisk: boolean;
39

40
    // #region Constructors
41

42
    private constructor() { /* Private to enforce construction via static methods */ }
43

44
    /**
45
     * Constructs and initializes a new instance of {@link Mpeg4BoxHeader} by reading it from a
46
     * specified seek position in a specified file.
47
     * @param file A {@link File} object to read the new instance from.
48
     * @param position A value specifying the seek position in File at which to start reading.
49
     * @returns A new instance of {@link Mpeg4BoxHeader} by reading it from a specified seek position
50
     *     in a specified file.
51
     */
52
    public static fromFileAndPosition(file: File, position: number): Mpeg4BoxHeader {
53
        Guards.notNullOrUndefined(file, "file");
60✔
54

55
        const header = new Mpeg4BoxHeader();
60✔
56
        header._fromDisk = true;
60✔
57
        header._position = position;
60✔
58
        file.seek(position);
60✔
59

60
        const data = file.readBlock(32);
60✔
61
        let offset = 0;
60✔
62

63
        if (data.length < 8 + offset) {
60!
64
            throw new Error("Not enough data in box header.");
×
65
        }
66

67
        header._headerSize = 8;
60✔
68
        header._boxSize = data.subarray(offset, 4).toUint();
60✔
69
        header._boxType = data.subarray(offset + 4, 4);
60✔
70

71
        // If the size is 1, that just tells us we have a massive ULONG size waiting for us in the next 8 bytes.
72
        if (header._boxSize === 1) {
60!
73
            if (data.length < 8 + offset) {
×
74
                throw new Error("Not enough data in box header.");
×
75
            }
76

77
            header._headerSize += 8;
×
78
            offset += 8;
×
79
            header._boxSize = Number(data.subarray(offset, 8).toUlong());
×
80
        }
81

82
        // UUID has a special header with 16 extra bytes.
83
        if (ByteVector.equals(header.boxType, Mpeg4BoxType.UUID)) {
60!
84
            if (data.length < 16 + offset) {
×
85
                throw new Error("Not enough data in box header.");
×
86
            }
87

88
            header._headerSize += 16;
×
89
            header._extendedType = data.subarray(offset, 16);
×
90
        } else {
91
            header._extendedType = undefined;
60✔
92

93
            if (header._boxSize > file.length - position) {
60!
94
                throw new Error(
×
95
                    `Box header specified a size of ${header._boxSize} bytes ` +
96
                    `but only ${file.length - position} bytes left in the file`
97
                );
98
            }
99
        }
100

101
        return header;
60✔
102
    }
103

104
    /**
105
     * Constructs and initializes a new instance of {@link Mpeg4BoxHeader} with a specified box type.
106
     * @param type A ByteVector object containing the four byte box type.
107
     * @returns A new instance of Mpeg4BoxHeader with a specified box type.
108
     */
109
    public static fromType(type: ByteVector): Mpeg4BoxHeader {
110
        return Mpeg4BoxHeader.fromTypeAndExtendedType(type, undefined);
1,166✔
111
    }
112

113
    /**
114
     * Constructs and initializes a new instance of {@link Mpeg4BoxHeader} with a specified box type
115
     * and optionally extended type.
116
     * @param type A {@link ByteVector} object containing the four byte box type.
117
     * @param extendedType A {@link ByteVector} object containing the four byte box type.
118
     * @returns A new instance of {@link Mpeg4BoxHeader} with a specified box type and optionally extended type.
119
     */
120
    public static fromTypeAndExtendedType(type: ByteVector, extendedType: ByteVector): Mpeg4BoxHeader {
121
        Guards.notNullOrUndefined(type, "type");
1,166✔
122
        Guards.equals(type.length, 4, "type.length");
1,166✔
123

124
        const header = new Mpeg4BoxHeader();
1,166✔
125
        header._position = -1;
1,166✔
126
        header._fromDisk = false;
1,166✔
127
        header._boxType = type;
1,166✔
128
        header._boxSize = 8;
1,166✔
129
        header._headerSize = 8;
1,166✔
130

131
        if (!ByteVector.equals(type, Mpeg4BoxType.UUID)) {
1,166!
132
            if (extendedType) {
1,166!
133
                throw new Error("Extended type only permitted for 'uuid'.");
×
134
            }
135

136
            header._extendedType = extendedType;
1,166✔
137
            return header;
1,166✔
138
        }
139

140
        Guards.notNullOrUndefined(extendedType, "extendedType");
×
141
        Guards.equals(extendedType.length, 16, "extendedType.length");
×
142

143
        header._boxSize = 24;
×
144
        header._headerSize = 24;
×
145
        header._extendedType = extendedType;
×
146

147
        return header;
×
148
    }
149

150
    // #endregion
151

152
    // #region Properties
153

154
    /**
155
     * Gets the type of box represented by the current instance.
156
     */
157
    public get boxType(): ByteVector { return this._boxType; }
3,756✔
158

159
    /**
160
     * Gets the extended type of the box represented by the current instance.
161
     */
162
    public get extendedType(): ByteVector { return this._extendedType; }
×
163

164
    /**
165
     * Gets the size of the header represented by the current instance.
166
     */
167
    public get headerSize(): number { return this._headerSize; }
1,191✔
168

169
    /**
170
     * Gets the size of the data in the box described by the current instance.
171
     */
172
    public get dataSize(): number { return this._boxSize - this._headerSize; }
×
173
    /**
174
     * Gets the size of the data in the box described by the current instance.
175
     */
176
    public set dataSize(v: number) { this._boxSize = v + this._headerSize; }
×
177

178
    /**
179
     * Gets the total size of the box described by the current instance.
180
     */
181
    public get totalBoxSize(): number { return this._boxSize; }
120✔
182

183
    /**
184
     * Gets the position box represented by the current instance in the file it comes from.
185
     */
186
    public get position(): number { return this._fromDisk ? this._position : -1; }
1,161!
187

188
    // #endregion
189

190
    /**
191
     *  Overwrites the header on disk, updating it to include a change in the size of the box.
192
     * @param file  A {@link File} object containing the file from which the box originates.
193
     * @param sizeChange A value indicating the change in the size of the box described by the
194
     *     current instance.
195
     * @returns  The size change encountered by the box that parents the box described the current
196
     *     instance, equal to the size change of the box plus any size change that should happen in
197
     *     the header.
198
     */
199
    public overwrite(file: File, sizeChange: number): number {
200
        Guards.notNullOrUndefined(file, "file");
×
201

202
        if (!this._fromDisk) {
×
203
            throw new Error("Cannot overwrite headers not on disk.");
×
204
        }
205

206
        const oldHeaderSize = this._headerSize;
×
207
        this.dataSize += sizeChange;
×
208
        file.insert(this.render(), this._position, oldHeaderSize);
×
209

210
        return sizeChange + this.headerSize - oldHeaderSize;
×
211
    }
212

213
    /**
214
     * Renders the header represented by the current instance.
215
     * @returns A {@link ByteVector} object containing the rendered version of the current instance.
216
     */
217
    public render(): ByteVector {
218
        // Enlarge for size if necessary.
219
        if ((this._headerSize === 8 || this._headerSize === 24) && this._boxSize > NumberUtils.MAX_UINT) {
×
220
            this._headerSize += 8;
×
221
            this._boxSize += 8;
×
222
        }
223

224
        // Calculate what needs to be rendered
225
        const boxSizeValue = (this._headerSize === 8 || this._headerSize === 24)
×
226
            ? this._boxSize
×
227
            : 1;
228
        const extendedSize = (this._headerSize === 16 || this._headerSize === 32)
×
229
            ? ByteVector.fromUlong(this._boxSize)
×
230
            : undefined;
231
        const extendedType = this.headerSize > 24
×
232
            ? this._extendedType
×
233
            : undefined;
234

235
        // Put it all together
236
        return ByteVector.concatenate(
×
237
            ByteVector.fromUint(boxSizeValue), // Box size of 1 if extended
238
            this._boxType,
239
            extendedSize,                      // Extended size or undefined if box is regular sized
240
            extendedType                       // Extended type or undefined if box is regular sized
241
        )
242
    }
243
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc