Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
Language: Cpp
# BasedOnStyle: LLVM
Standard: c++17
BasedOnStyle: Google
Standard: C++17

# Indentation
# Indentation settings
IndentWidth: 4
UseTab: Never
TabWidth: 4
Expand All @@ -13,9 +13,11 @@ IndentGotoLabels: true
IndentPPDirectives: BeforeHash
NamespaceIndentation: None

# Line length and wrapping
ColumnLimit: 100
# Limit line length to 80 characters and reflow comments
ColumnLimit: 80
ReflowComments: true

# Line breaking options
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
Expand All @@ -24,7 +26,7 @@ BreakStringLiterals: true
AlwaysBreakTemplateDeclarations: Yes
AlwaysBreakBeforeMultilineStrings: false

# Braces and blocks
# Braces and one-liners
BreakBeforeBraces: Attach
AllowShortBlocksOnASingleLine: Empty
AllowShortFunctionsOnASingleLine: Inline
Expand All @@ -34,7 +36,7 @@ AllowShortLoopsOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: false

# Spacing and alignment
# Spacing and punctuation
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
Expand Down Expand Up @@ -64,11 +66,11 @@ AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true

# Pointer alignment
# Pointer and reference alignment
PointerAlignment: Left
ReferenceAlignment: Left

# Function declarations/definitions
# Function parameters formatting
BinPackArguments: false
BinPackParameters: false
AllowAllArgumentsOnNextLine: true
Expand All @@ -81,14 +83,14 @@ EmptyLineBeforeAccessModifier: LogicalBlock
ConstructorInitializerAllOnOneLineOrOnePerLine: true

# Include sorting
SortIncludes: CaseSensitive
SortIncludes: true
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"[[:alnum:]_]+\.h"'
- Regex: '^"[^/]*\.h"'
Priority: 1
- Regex: '^<[[:alnum:]_]+\.h>'
- Regex: '^<[^/]*\.h>'
Priority: 2
- Regex: '^<[[:alnum:]_]+>'
- Regex: '^<'
Priority: 3
- Regex: '.*'
Priority: 4
Expand All @@ -98,4 +100,5 @@ KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
SortUsingDeclarations: true
FixNamespaceComments: true

InsertTrailingNewline: true
...
6 changes: 6 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# editorconfig.org
root = true

[*]
indent_style = space
indent_size = 4
18 changes: 16 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ jobs:

- name: Check formatting
run: |
find include src test examples -name '*.hpp' -o -name '*.cpp' | xargs clang-format --dry-run --Werror
find include src test example -name '*.hpp' -o -name '*.cpp' | xargs clang-format --dry-run --Werror --style=Google

static-analysis:
name: Static Analysis
name: Static Analysis (cppcheck)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand Down Expand Up @@ -139,3 +139,17 @@ jobs:
- name: Validate CMake files
run: |
find . -name CMakeLists.txt -o -name "*.cmake" | xargs cmakelint

cpplint:
name: Code Style Lint (cpplint)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Install cpplint
run: pip install cpplint

- name: Run cpplint
run: |
# Lint all C++ source and header files in the project
find include src test examples -type f \( -name "*.cpp" -o -name "*.hpp" \) | xargs cpplint --filter=-whitespace/indent_namespace --recursive
12 changes: 12 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
repos:
- repo: https://github.com/cpplint/cpplint
rev: 2.0.0
hooks:
- id: cpplint
args:
- --filter=-whitespace/line_length,-whitespace/parens,-whitespace/indent_namespace
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v16.0.6
hooks:
- id: clang-format
args: [--style=Google]
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,23 @@ To build the example within the repository, ensure that you have successfully in
g++ -std=c++17 example/file_detect.cpp -o file_detect -lfiletype
```

## Development

### Prerequisites for Development

Install pre-commit:

```bash
pip install pre-commit
```

Install and run pre-commit hooks:

```bash
pre-commit install
pre-commit run --all
```


## License

Expand Down
121 changes: 61 additions & 60 deletions example/file_detect.cpp
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
// Copyright 2025 Prince Roshan <princekrroshan01@gmail.com>

/**
* @file file_detect.cpp
* @brief Example program to detect file types using magic numbers
*
* This program takes a file path as a command-line argument,
*
* This program takes a file path as a command-line argument,
* reads the file, and detects its type using the filetype library.
* It then prints the detected MIME type and extension.
*/

#include "filetype/filetype.hpp"
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <vector>
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>

#include "filetype/filetype.hpp"

/**
* @brief Print usage information for the program
* @param program_name The name of the executable
*/
void print_usage(const char* program_name) {
std::cerr << "Usage: " << program_name << " <file_path>\n"
<< "Detects the file type of the given file based on its magic number.\n";
std::cerr
<< "Usage: " << program_name << " <file_path>\n"
<< "Detects the file type of the given file based on its magic number.\n";
}

/**
Expand All @@ -30,61 +34,58 @@ void print_usage(const char* program_name) {
* @throws std::runtime_error if the file cannot be opened
*/
std::vector<uint8_t> read_file(const std::string& filepath) {
std::ifstream file(filepath, std::ios::binary);
if (!file) {
throw std::runtime_error("Could not open file: " + filepath);
}

// Read file into buffer
return std::vector<uint8_t>(
std::istreambuf_iterator<char>(file),
std::istreambuf_iterator<char>()
);
std::ifstream file(filepath, std::ios::binary);
if (!file) {
throw std::runtime_error("Could not open file: " + filepath);
}

// Read file into buffer
return std::vector<uint8_t>(std::istreambuf_iterator<char>(file),
std::istreambuf_iterator<char>());
}

int main(int argc, char* argv[]) {
// Check command line arguments
if (argc != 2) {
print_usage(argv[0]);
return EXIT_FAILURE;
}
// Check command line arguments
if (argc != 2) {
print_usage(argv[0]);
return EXIT_FAILURE;
}

const std::string filepath = argv[1];

try {
// Read file content
std::vector<uint8_t> buffer = read_file(filepath);

const std::string filepath = argv[1];

try {
// Read file content
std::vector<uint8_t> buffer = read_file(filepath);

// Detect file type
auto type = filetype::match(buffer);

if (type) {
std::cout << "File: " << filepath << "\n"
<< "MIME type: " << type->mime << "\n"
<< "Extension: ." << type->extension << "\n";

// Determine file category
if (filetype::is_image(buffer)) {
std::cout << "Category: Image\n";
} else if (filetype::is_document(buffer)) {
std::cout << "Category: Document\n";
} else if (filetype::is_archive(buffer)) {
std::cout << "Category: Archive\n";
} else if (filetype::is_audio(buffer)) {
std::cout << "Category: Audio\n";
} else if (filetype::is_video(buffer)) {
std::cout << "Category: Video\n";
} else {
std::cout << "Category: Other\n";
}
} else {
std::cout << "Unknown file type for: " << filepath << "\n";
}
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << "\n";
return EXIT_FAILURE;
// Detect file type
auto type = filetype::match(buffer);

if (type) {
std::cout << "File: " << filepath << "\n"
<< "MIME type: " << type->mime << "\n"
<< "Extension: ." << type->extension << "\n";

// Determine file category
if (filetype::is_image(buffer)) {
std::cout << "Category: Image\n";
} else if (filetype::is_document(buffer)) {
std::cout << "Category: Document\n";
} else if (filetype::is_archive(buffer)) {
std::cout << "Category: Archive\n";
} else if (filetype::is_audio(buffer)) {
std::cout << "Category: Audio\n";
} else if (filetype::is_video(buffer)) {
std::cout << "Category: Video\n";
} else {
std::cout << "Category: Other\n";
}
} else {
std::cout << "Unknown file type for: " << filepath << "\n";
}

return EXIT_SUCCESS;
}
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << "\n";
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}
Loading
Loading