1 //===--- RIFF.cpp - Binary container file format --------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 #include "support/Logger.h"
11 #include "llvm/Support/Endian.h"
17 llvm::Expected
<Chunk
> readChunk(llvm::StringRef
&Stream
) {
18 if (Stream
.size() < 8)
19 return error("incomplete chunk header: {0} bytes available", Stream
.size());
21 std::copy(Stream
.begin(), Stream
.begin() + 4, C
.ID
.begin());
22 Stream
= Stream
.drop_front(4);
23 uint32_t Len
= llvm::support::endian::read32le(Stream
.take_front(4).begin());
24 Stream
= Stream
.drop_front(4);
25 if (Stream
.size() < Len
)
26 return error("truncated chunk: want {0}, got {1}", Len
, Stream
.size());
27 C
.Data
= Stream
.take_front(Len
);
28 Stream
= Stream
.drop_front(Len
);
29 if ((Len
% 2) && !Stream
.empty()) { // Skip padding byte.
31 return error("nonzero padding byte");
32 Stream
= Stream
.drop_front();
37 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&OS
, const Chunk
&C
) {
38 OS
.write(C
.ID
.data(), C
.ID
.size());
40 llvm::support::endian::write32le(Size
, C
.Data
.size());
41 OS
.write(Size
, sizeof(Size
));
43 if (C
.Data
.size() % 2)
48 llvm::Expected
<File
> readFile(llvm::StringRef Stream
) {
49 auto RIFF
= readChunk(Stream
);
51 return RIFF
.takeError();
52 if (RIFF
->ID
!= fourCC("RIFF"))
53 return error("not a RIFF container: root is {0}", fourCCStr(RIFF
->ID
));
54 if (RIFF
->Data
.size() < 4)
55 return error("RIFF chunk too short");
57 std::copy(RIFF
->Data
.begin(), RIFF
->Data
.begin() + 4, F
.Type
.begin());
58 for (llvm::StringRef Body
= RIFF
->Data
.drop_front(4); !Body
.empty();)
59 if (auto Chunk
= readChunk(Body
)) {
60 F
.Chunks
.push_back(*Chunk
);
62 return Chunk
.takeError();
66 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&OS
, const File
&F
) {
67 // To avoid copies, we serialize the outer RIFF chunk "by hand".
68 size_t DataLen
= 4; // Predict length of RIFF chunk data.
69 for (const auto &C
: F
.Chunks
)
70 DataLen
+= 4 + 4 + C
.Data
.size() + (C
.Data
.size() % 2);
73 llvm::support::endian::write32le(Size
, DataLen
);
74 OS
.write(Size
, sizeof(Size
));
75 OS
.write(F
.Type
.data(), F
.Type
.size());
76 for (const auto &C
: F
.Chunks
)