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

benrr101 / node-taglib-sharp / 48393127

29 Oct 2023 04:39AM UTC coverage: 92.535% (-1.4%) from 93.934%
48393127

push

appveyor

benrr101
Merge branch 'release/v5.2.0'

3244 of 4129 branches covered (0.0%)

Branch coverage included in aggregate %.

2177 of 2177 new or added lines in 61 files covered. (100.0%)

26728 of 28261 relevant lines covered (94.58%)

423.2 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
     */
50
    public static fromFileAndPosition(file: File, position: number): Mpeg4BoxHeader {
51
        Guards.truthy(file, "file");
2✔
52

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

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

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

65
        header._headerSize = 8;
2✔
66
        header._boxSize = data.subarray(offset, 4).toUint();
2✔
67
        header._boxType = data.subarray(offset + 4, 4);
2✔
68

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

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

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

86
            header._headerSize += 16;
×
87
            header._extendedType = data.subarray(offset, 16);
×
88
        } else {
89
            header._extendedType = undefined;
2✔
90

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

99
        return header;
2✔
100
    }
101

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

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

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

124
            header._extendedType = extendedType;
1,226✔
125
            return header;
1,226✔
126
        }
127

128
        Guards.truthy(extendedType, "extendedType");
×
129
        Guards.equals(extendedType.length, 16, "extendedType.length");
×
130

131
        header._boxSize = 24;
×
132
        header._headerSize = 24;
×
133
        header._extendedType = extendedType;
×
134

135
        return header;
×
136
    }
137

138
    // #endregion
139

140
    // #region Properties
141

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

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

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

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

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

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

180
    // #endregion
181

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

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

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

204
        return sizeChange + this.headerSize - oldHeaderSize;
×
205
    }
206

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

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

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