summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd/RIFF.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clangd/RIFF.cpp')
-rw-r--r--clang-tools-extra/clangd/RIFF.cpp88
1 files changed, 88 insertions, 0 deletions
diff --git a/clang-tools-extra/clangd/RIFF.cpp b/clang-tools-extra/clangd/RIFF.cpp
new file mode 100644
index 00000000000..cb832db87f9
--- /dev/null
+++ b/clang-tools-extra/clangd/RIFF.cpp
@@ -0,0 +1,88 @@
+//===--- RIFF.cpp - Binary container file format --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RIFF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+namespace clang {
+namespace clangd {
+namespace riff {
+
+static Error makeError(const char *Msg) {
+ return createStringError(inconvertibleErrorCode(), Msg);
+}
+
+Expected<Chunk> readChunk(StringRef &Stream) {
+ if (Stream.size() < 8)
+ return makeError("incomplete chunk header");
+ Chunk C;
+ std::copy(Stream.begin(), Stream.begin() + 4, C.ID.begin());
+ Stream = Stream.drop_front(4);
+ uint32_t Len = support::endian::read32le(Stream.take_front(4).begin());
+ Stream = Stream.drop_front(4);
+ if (Stream.size() < Len)
+ return makeError("truncated chunk");
+ C.Data = Stream.take_front(Len);
+ Stream = Stream.drop_front(Len);
+ if (Len % 2 & !Stream.empty()) { // Skip padding byte.
+ if (Stream.front())
+ return makeError("nonzero padding byte");
+ Stream = Stream.drop_front();
+ }
+ return C;
+};
+
+raw_ostream &operator<<(raw_ostream &OS, const Chunk &C) {
+ OS.write(C.ID.begin(), C.ID.size());
+ char Size[4];
+ llvm::support::endian::write32le(Size, C.Data.size());
+ OS.write(Size, sizeof(Size));
+ OS << C.Data;
+ if (C.Data.size() % 2)
+ OS.write(0);
+ return OS;
+}
+
+llvm::Expected<File> readFile(llvm::StringRef Stream) {
+ auto RIFF = readChunk(Stream);
+ if (!RIFF)
+ return RIFF.takeError();
+ if (RIFF->ID != fourCC("RIFF"))
+ return makeError("not a RIFF container");
+ if (RIFF->Data.size() < 4)
+ return makeError("RIFF chunk too short");
+ File F;
+ std::copy(RIFF->Data.begin(), RIFF->Data.begin() + 4, F.Type.begin());
+ for (llvm::StringRef Body = RIFF->Data.drop_front(4); !Body.empty();)
+ if (auto Chunk = readChunk(Body)) {
+ F.Chunks.push_back(*Chunk);
+ } else
+ return Chunk.takeError();
+ return F;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const File &F) {
+ // To avoid copies, we serialize the outer RIFF chunk "by hand".
+ size_t DataLen = 4; // Predict length of RIFF chunk data.
+ for (const auto &C : F.Chunks)
+ DataLen += 4 + 4 + C.Data.size() + (C.Data.size() % 2);
+ OS << "RIFF";
+ char Size[4];
+ llvm::support::endian::write32le(Size, DataLen);
+ OS.write(Size, sizeof(Size));
+ OS.write(F.Type.begin(), F.Type.size());
+ for (const auto &C : F.Chunks)
+ OS << C;
+ return OS;
+}
+
+} // namespace riff
+} // namespace clangd
+} // namespace clang
OpenPOWER on IntegriCloud