Skip to content

Commit 3bb035d

Browse files
authored
Use file content heuristics to decide file reader. (#1962)
* Added heuristics file content detector that determines the content based on the magic number. * Moved stream checkpoint outside format detector as it is not directly tied to it. * Added a new factory function `createReader` that uses the new heuristics detection method. * Add <algorithm> include. * Added unit tests. * Deprecated old factory function. * Add byte-swapped zstd magic number. * Lint * Move enum closer to first usage. * Added unit tests for file reader device factory. * Revert indentation. * Fixed StreamCheckpoint to restore original stream state. * Moved isStreamSeekable helper to inside `CaptureFileFormatDetector`. Move it out if it needs to be reused somewhere. * Added pcap magic number for Alexey Kuznetzov's modified pcap format. Libpcap supports reading this format since 0.9.1. The heuristics detection will identify such magic number as pcap and leave final support decision to the pcap backend infrastructure. * Split the unit test into multiple smaller tests. * Added helper to indicate if ZstSupport is enabled for PcapNg devices. * Split pcap microsecond and nanosecond file heuristics tests. Nanoseconds are skipped if they aren't supported. * Skipping Zst test case if zst is not supported. * Due to file heuristics returning PcapNG format on Zstd archive, if Zstd compression is unsupported, the format detector will return Unknown. * Lint * Added invalid device factory to pcap tag. * Updated static zst archives to be actual archives. * Centralized PTF test name width under a macro. * Add Pcap++Test header files to test sources for IDE tooling. * Fixed test output formatting. * Lint * Typo fix. * Shortened test names. * Simplified invalid file test. * Simplified ZST tests. * Added snoop test. * Expanded granularity of file format detection. Updated pcap file detection to return the precice format of Pcap instead of just `true` / `false`. Updated detect format to always retuirn the detected format. Previous responsibility for unsupported zstd archive files has been passed up the call stack to the factory function `createReader`. * Marked `checkSupport` functions as constexpr to enable compile time optimizations and branch pruning. * Exclude json from pre-commit cppcheck as it is slow due to many define branches. * Lint * Fix runtime side effects inside constexpr function. * Added a secondary factory function to separate mixed error handling methods. * Revert deprecation message, as doxygen is unhappy. * Update tests. * Update deprecation warning to point to the function closer to the signature. * Catch general exception instead of runtime error. * Shortened deprecation message due to pre-commit warnings when its is on 1 line and doxygen errors when its in 2 lines. * Fix braces. * Simplfy test. * Added tests for createReader failures. * Simplified pcap detection to not require to read the entire pcap header. * Added const qualifiers to detector methods. * Added dedicated unit tests for CaptureFileFormatDetector. * Added more tests for `createReader`. * Add static assert for array indice checks. * Updated detectPcap selection. * Extracted capture format detector to remove it from publicly available headers. * Fix includes. * Removed duplicate files from tracking. * Lint * Trimmed pcapng sample. * Change PcapNGZst to ZstArchive. Zst to PcapNG branch folding is done in `createReader` instead of having the Format detector assume that is what is intended. * Added separate format value for "modified" pcap to separate the format detector from libpcap behaviour. * Docs fix. * Add automatic open functionality to `createReader` factory to mimic RAII initialization. * Update docstring. * Fix exception message assert. * Refactored format tests to utilize the createReader factory. * Fix nanoprecision test issues. * Remove openDevice flag. Update create procedure to avoid exceptions on tryCreateDevice. * Docs update + Lint * Docs fix. * Lint. * Remove nano support checks as it should always be supported by the internal parser. * Extend format detector to capture byte order from magic number. * Add initial merge logic. * Add methods to check magic numbers directly. * Comment out unused variables. * Add helper to convert format to pcap precision. * Simplify code. * Fixed errors. * Disable pcap "modified" file format detection tests. * Lint * Fixed doxygen. * Change Kuznetzov pcap magic number to constexpr. * Change all temporary files to have `.tmp` extension. Remove `/temp/` subdirectory. * Lint * Revert `tryCreateReader` to use `createReader` * Remove conditional branch that always evaluates to true. * Lint
1 parent 0f64e8f commit 3bb035d

17 files changed

Lines changed: 862 additions & 214 deletions

.pre-commit-config.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
exclude: '.*\.(pcap|pcapng|dat)|(PacketExamples|PcapExamples|expected_output|pcap_examples).*\.txt'
1+
exclude: '.*\.(pcap|pcapng|dat)|(PacketExamples|PcapExamples|expected_output|pcap_examples).*\.(txt|zst|zstd)'
22
fail_fast: false
33
repos:
44
- repo: local
@@ -37,6 +37,7 @@ repos:
3737
files: ^(Common\+\+|Packet\+\+|Pcap\+\+|Tests|Examples)/.*\.(cpp|h)$
3838
- id: cppcheck
3939
args: ["--std=c++14", "--language=c++", "--suppressions-list=cppcheckSuppressions.txt", "--inline-suppr", "--force"]
40+
exclude: ^3rdParty/json
4041
- repo: https://github.com/BlankSpruce/gersemi
4142
rev: 0.26.1
4243
hooks:

Pcap++/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ target_link_libraries(
108108
)
109109

110110
if(LIGHT_PCAPNG_ZSTD)
111+
target_compile_definitions(Pcap++ PRIVATE -DPCPP_PCAPNG_ZSTD_SUPPORT)
111112
target_link_libraries(Pcap++ PRIVATE light_pcapng)
112113
endif()
113114

Pcap++/header/PcapFileDevice.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,32 @@ namespace pcpp
114114
/// it returns an instance of PcapFileReaderDevice
115115
/// @param[in] fileName The file name to open
116116
/// @return An instance of the reader to read the file. Notice you should free this instance when done using it
117+
/// @deprecated Prefer `createReader` or `tryCreateReader` due to selection of reader based on file content
118+
/// instead of extension.
119+
PCPP_DEPRECATED("Prefer `tryCreateReader` due to selection of reader based on file content.")
117120
static IFileReaderDevice* getReader(const std::string& fileName);
121+
122+
/// @brief Creates an instance of the reader best fit to read the file.
123+
///
124+
/// The factory function uses heuristics based on the file content to decide the reader.
125+
/// If the file type is known at compile time, it is better to construct a concrete reader instance directly.
126+
///
127+
/// @param[in] fileName The path to the file to open.
128+
/// @return A unique pointer to a reader instance
129+
/// @throws std::runtime_error If the file could not be opened or is of unsupported format.
130+
/// @remarks The device is not opened automatically. Call `open()` on the returned device before using it.
131+
static std::unique_ptr<IFileReaderDevice> createReader(const std::string& fileName);
132+
133+
/// @brief Tries to create an instance of the reader best fit to read the file.
134+
///
135+
/// The factory function uses heuristics based on the file content to decide the reader.
136+
/// If the file type is known at compile time, it is better to construct a concrete reader instance directly.
137+
///
138+
/// @param fileName The path to the file to open.
139+
/// @return A unique pointer to a reader instance, or nullptr if the file could not be opened or is of
140+
/// unsupported format.
141+
/// @remarks The device is not opened automatically. Call `open()` on the returned device before using it.
142+
static std::unique_ptr<IFileReaderDevice> tryCreateReader(const std::string& fileName);
118143
};
119144

120145
/// @class IFileWriterDevice

0 commit comments

Comments
 (0)