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

benrr101 / node-taglib-sharp / 48387633

28 Oct 2023 05:34AM UTC coverage: 92.442% (+0.5%) from 91.899%
48387633

push

appveyor

web-flow
Merge 6a78b5713 into f0c9477b7

3250 of 4147 branches covered (0.0%)

Branch coverage included in aggregate %.

1763 of 1763 new or added lines in 39 files covered. (100.0%)

26753 of 28309 relevant lines covered (94.5%)

422.49 hits per line

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

39.81
/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.truthy(file, "file");
2✔
54

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

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

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

67
        header._headerSize = 8;
2✔
68
        header._boxSize = data.subarray(offset, 4).toUint();
2✔
69
        header._boxType = data.subarray(offset + 4, 4);
2✔
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) {
2!
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)) {
2!
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;
2✔
92

93
            if (header._boxSize > file.length - position) {
2!
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;
2✔
102
    }
103

104
    /**
105
     * Constructs and initializes a new instance of {@link Mpeg4BoxHeader} with a specified box type
106
     * and optionally extended type.
107
     * @param type A {@link ByteVector} object containing the four byte box type.
108
     * @param extendedType A {@link ByteVector} object containing the four byte box type.
109
     * @returns A new instance of {@link Mpeg4BoxHeader} with a specified box type and optionally extended type.
110
     */
111
    public static fromType(type: ByteVector, extendedType?: ByteVector): Mpeg4BoxHeader {
112
        Guards.truthy(type, "type");
1,226✔
113
        Guards.equals(type.length, 4, "type.length");
1,226✔
114

115
        const header = new Mpeg4BoxHeader();
1,226✔
116
        header._position = -1;
1,226✔
117
        header._fromDisk = false;
1,226✔
118
        header._boxType = type;
1,226✔
119
        header._boxSize = 8;
1,226✔
120
        header._headerSize = 8;
1,226✔
121

122
        if (!ByteVector.equals(type, Mpeg4BoxType.UUID)) {
1,226!
123
            if (extendedType) {
1,226!
124
                throw new Error("Extended type only permitted for 'uuid'.");
×
125
            }
126

127
            header._extendedType = extendedType;
1,226✔
128
            return header;
1,226✔
129
        }
130

131
        Guards.truthy(extendedType, "extendedType");
×
132
        Guards.equals(extendedType.length, 16, "extendedType.length");
×
133

134
        header._boxSize = 24;
×
135
        header._headerSize = 24;
×
136
        header._extendedType = extendedType;
×
137

138
        return header;
×
139
    }
140

141
    // #endregion
142

143
    // #region Properties
144

145
    /**
146
     * Gets the type of box represented by the current instance.
147
     */
148
    public get boxType(): ByteVector { return this._boxType; }
3,917✔
149

150
    /**
151
     * Gets the extended type of the box represented by the current instance.
152
     */
153
    public get extendedType(): ByteVector { return this._extendedType; }
×
154

155
    /**
156
     * Gets the size of the header represented by the current instance.
157
     */
158
    public get headerSize(): number { return this._headerSize; }
1,222✔
159

160
    /**
161
     * Gets the size of the data in the box described by the current instance.
162
     */
163
    public get dataSize(): number { return this._boxSize - this._headerSize; }
×
164
    /**
165
     * Gets the size of the data in the box described by the current instance.
166
     * @internal
167
     */
168
    public set dataSize(v: number) {
169
        Guards.safeUint(v, "v");
×
170
        this._boxSize = v + this._headerSize;
×
171
    }
172

173
    /**
174
     * Gets the total size of the box described by the current instance.
175
     */
176
    public get totalBoxSize(): number { return this._boxSize; }
4✔
177

178
    /**
179
     * Gets the position box represented by the current instance in the file it comes from.
180
     */
181
    public get position(): number { return this._fromDisk ? this._position : -1; }
1,221!
182

183
    // #endregion
184

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

198
        if (!this._fromDisk) {
×
199
            throw new Error("Cannot overwrite headers not on disk.");
×
200
        }
201

202
        const oldHeaderSize = this._headerSize;
×
203
        this.dataSize += sizeChange;
×
204
        file.insert(this.render(), this._position, oldHeaderSize);
×
205

206
        return sizeChange + this.headerSize - oldHeaderSize;
×
207
    }
208

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

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

231
        // Put it all together
232
        return ByteVector.concatenate(
×
233
            ByteVector.fromUint(boxSizeValue), // Box size of 1 if extended
234
            this._boxType,
235
            extendedSize,                      // Extended size or undefined if box is regular sized
236
            extendedType                       // Extended type or undefined if box is regular sized
237
        )
238
    }
239
}
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