diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt
index 90385653f7..a9535a1799 100644
--- a/Source/Core/Common/CMakeLists.txt
+++ b/Source/Core/Common/CMakeLists.txt
@@ -14,6 +14,7 @@ set(SRCS BreakPoints.cpp
MsgHandler.cpp
NandPaths.cpp
Network.cpp
+ PcapFile.cpp
SettingsHandler.cpp
SDCardUtil.cpp
StringUtil.cpp
diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj
index 00bcb07c80..87c14c321c 100644
--- a/Source/Core/Common/Common.vcxproj
+++ b/Source/Core/Common/Common.vcxproj
@@ -78,6 +78,7 @@
+
@@ -114,6 +115,7 @@
+
diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters
index 5f9b211828..bca6b0c68e 100644
--- a/Source/Core/Common/Common.vcxproj.filters
+++ b/Source/Core/Common/Common.vcxproj.filters
@@ -39,6 +39,7 @@
+
@@ -86,6 +87,7 @@
+
diff --git a/Source/Core/Common/PcapFile.cpp b/Source/Core/Common/PcapFile.cpp
new file mode 100644
index 0000000000..9a28daca2d
--- /dev/null
+++ b/Source/Core/Common/PcapFile.cpp
@@ -0,0 +1,66 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include
+
+#include "Common/CommonTypes.h"
+#include "Common/FileUtil.h"
+#include "Common/PcapFile.h"
+
+namespace {
+
+const u32 PCAP_MAGIC = 0xa1b2c3d4;
+const u16 PCAP_VERSION_MAJOR = 2;
+const u16 PCAP_VERSION_MINOR = 4;
+const u32 PCAP_CAPTURE_LENGTH = 65535;
+
+// TODO(delroth): Make this configurable at PCAP creation time?
+const u32 PCAP_DATA_LINK_TYPE = 147; // Reserved for internal use.
+
+// Designed to be directly written into the PCAP file. The PCAP format is
+// endian independent, so this works just fine.
+#pragma pack(push, 1)
+struct PCAPHeader
+{
+ u32 magic_number;
+ u16 version_major;
+ u16 version_minor;
+ s32 tz_offset; // Offset in seconds from the GMT timezone.
+ u32 ts_accuracy; // In practice, 0.
+ u32 capture_length; // Size at which we truncate packets.
+ u32 data_link_type;
+};
+
+struct PCAPRecordHeader
+{
+ u32 ts_sec;
+ u32 ts_usec;
+ u32 size_in_file; // Size after eventual truncation.
+ u32 real_size; // Size before eventual truncation.
+};
+#pragma pack(pop)
+
+} // namespace
+
+void PCAP::AddHeader()
+{
+ PCAPHeader hdr = {
+ PCAP_MAGIC, PCAP_VERSION_MAJOR, PCAP_VERSION_MINOR,
+ 0, 0, PCAP_CAPTURE_LENGTH, PCAP_DATA_LINK_TYPE
+ };
+ m_fp->WriteBytes(&hdr, sizeof (hdr));
+}
+
+void PCAP::AddPacket(const u8* bytes, size_t size)
+{
+ std::chrono::system_clock::time_point now(std::chrono::system_clock::now());
+ auto ts = now.time_since_epoch();
+ PCAPRecordHeader rec_hdr = {
+ (u32)std::chrono::duration_cast(ts).count(),
+ (u32)(std::chrono::duration_cast(ts).count() % 1000000),
+ (u32)size, (u32)size
+ };
+ m_fp->WriteBytes(&rec_hdr, sizeof (rec_hdr));
+ m_fp->WriteBytes(bytes, size);
+}
diff --git a/Source/Core/Common/PcapFile.h b/Source/Core/Common/PcapFile.h
new file mode 100644
index 0000000000..f3bc98d23c
--- /dev/null
+++ b/Source/Core/Common/PcapFile.h
@@ -0,0 +1,44 @@
+// Copyright 2014 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+// PCAP is a standard file format for network capture files. This also extends
+// to any capture of packetized intercommunication data. This file provides a
+// class called PCAP which is a very light wrapper around the file format,
+// allowing only creating a new PCAP capture file and appending packets to it.
+//
+// Example use:
+// PCAP pcap(new IOFile("test.pcap", "wb"));
+// pcap.AddPacket(pkt); // pkt is automatically casted to u8*
+
+#pragma once
+
+#include
+#include
+
+#include "Common/CommonTypes.h"
+#include "Common/FileUtil.h"
+
+class PCAP final : public NonCopyable
+{
+public:
+ // Takes ownership of the file object. Assumes the file object is already
+ // opened in write mode.
+ explicit PCAP(File::IOFile* fp) : m_fp(fp)
+ {
+ AddHeader();
+ }
+
+ template
+ void AddPacket(const T& obj)
+ {
+ AddPacket(reinterpret_cast(&obj), sizeof (obj));
+ }
+
+ void AddPacket(const u8* bytes, size_t size);
+
+private:
+ void AddHeader();
+
+ std::unique_ptr m_fp;
+};