# DL File System Operations Library
## Overview
The `dl_fs.h` header provides a comprehensive set of file system operations for the Bella Engine SDK. This library abstracts platform-specific file operations and provides UTF-8 filename support across Windows, macOS, and Linux. It's designed to be more convenient and safer than standard C file operations.
## Key Concepts for C++ Beginners
- **`DL_API`**: A macro that handles proper function export/import across different platforms
- **`constexpr`**: Declares constants that are evaluated at compile time
- **Namespaces**: `dl::fs` organizes functions to avoid naming conflicts
- **Default Parameters**: Functions can have optional parameters with default values (e.g., `bool create = true`)
- **Reference Parameters**: `String& out` means the function will modify the passed string
## Platform Constants
### Path Separators and Quote Characters
```cpp
#if DL_IS_WIN32
constexpr const char* sep = "\\"; // Windows uses backslash
constexpr const char* quot = "\""; // Windows uses double quotes
#else
constexpr const char* sep = "/"; // Unix/Linux/macOS use forward slash
constexpr const char* quot = "'"; // Unix systems use single quotes
#endif
```
**Usage Example:**
```cpp
#include "dl_fs.h"
using namespace dl::fs;
// Build a path that works on any platform
String configPath = homeDir() + sep + "config" + sep + "settings.txt";
```
## File Operations (Enhanced stdio wrappers)
These functions provide UTF-8 filename support and are safer alternatives to standard C file functions.
### Fopen - Open a File
```cpp
FILE* Fopen(String path, String mode);
```
**What it does:** Opens a file with UTF-8 filename support
**Parameters:**
- `path`: File path to open
- `mode`: File mode ("r", "w", "rb", "wb", etc.)
**Returns:** FILE pointer or nullptr on failure
**Example:**
```cpp
// Open a text file for reading
FILE* file = Fopen("config.txt", "r");
if (file) {
// File opened successfully
// ... read operations ...
Fclose(file);
} else {
// Failed to open file
std::cout << "Could not open config.txt" << std::endl;
}
// Open a binary file for writing
FILE* binFile = Fopen("data.bin", "wb");
if (binFile) {
// Write binary data
Fclose(binFile);
}
```
### Complete File Operations API
*********************************
*
* File Operations Flow:
*
* Fopen() ──→ File Handle ──→ Fread()/Fwrite()
* │ │
* │ ↓
* │ Fseek()/Ftell()
* │ │
* └────────────────────────→ Fclose()
*
*********************************
[Figure [diagram]: File operations workflow showing the typical sequence of file handling functions.]
### Directory Operations
#### Creating and Removing Directories
```cpp
bool mkDir(String dir); // Create a directory
bool rmDir(String dir); // Remove an empty directory
```
**Example:**
```cpp
// Create a directory structure
if (mkDir("projects")) {
std::cout << "Created projects directory" << std::endl;
if (mkDir("projects/my_game")) {
std::cout << "Created game project directory" << std::endl;
}
}
// Remove directory (must be empty)
if (rmDir("projects/old_project")) {
std::cout << "Removed old project directory" << std::endl;
}
```
### File Browser Dialogs
These functions provide native file browser dialogs for user interaction.
```cpp
String browseFile(
String title = "Open File",
String initialFile = "",
String description = "All Files",
StringVector extensions = StringVector()
);
StringVector browseFiles( // Multiple file selection
String title = "Open Files",
String initialDir = "",
String description = "All Files",
StringVector extensions = StringVector()
);
```
**Example - Open file dialog:**
```cpp
// Let user select an image file
StringVector imageExtensions = {"png", "jpg", "jpeg", "bmp", "gif"};
String selectedImage = browseFile(
"Select Image File", // Dialog title
"", // No initial file
"Image Files", // File type description
imageExtensions // Allowed extensions
);
if (!selectedImage.empty()) {
std::cout << "User selected: " << selectedImage << std::endl;
// Process the selected image
} else {
std::cout << "User cancelled file selection" << std::endl;
}
```
## Archive Operations
### ZIP File Operations
```cpp
struct ZipProgress {
String info; // Information about current operation
Real progress; // Progress from 0.0 to 1.0
};
StringVector readZip(String zipPath, String outDir, std::function callback);
bool writeZip(String zipPath, StringVector inputFiles, std::function callback);
```
**Example - Extract ZIP with progress:**
```cpp
void zipProgressCallback(ZipProgress progress) {
std::cout << progress.info << " (" << (progress.progress * 100) << "%)" << std::endl;
}
// Extract a ZIP file
String zipFile = "archive.zip";
String extractDir = "extracted";
if (exists(zipFile)) {
mkDir(extractDir); // Create extraction directory
StringVector extractedFiles = readZip(zipFile, extractDir, zipProgressCallback);
std::cout << "Extracted " << extractedFiles.size() << " files:" << std::endl;
for (const auto& file : extractedFiles) {
std::cout << " " << file << std::endl;
}
}
```
## Path Resolution and Asset Management
### Advanced Path Finding
```cpp
String resolvePath(
String path,
StringVector searchDirs = {},
StringVector allowedExtensions = {}
);
```
**What it does:** Finds files using search directories and extension resolution
**Parameters:**
- `path`: The file to find (can end with ".*" for extension matching)
- `searchDirs`: Directories to search in
- `allowedExtensions`: Valid file extensions for ".*" matching
**Example - Asset loading system:**
```cpp
// Set up search directories for game assets
StringVector assetDirs = {
currentDir() + sep + "assets",
currentDir() + sep + "assets" + sep + "textures",
currentDir() + sep + "assets" + sep + "models",
homeDir() + sep + "shared_assets"
};
// Find a texture file (try multiple formats)
StringVector imageExtensions = {"png", "jpg", "tga", "bmp"};
String texturePath = resolvePath("wood.*", assetDirs, imageExtensions);
if (!texturePath.empty()) {
std::cout << "Found texture: " << texturePath << std::endl;
// Load the texture file
} else {
std::cout << "Could not find wood texture in any format" << std::endl;
}
```
## System and Application Paths
### Executable Path Information
```cpp
String exePath(); // Full path to executable
String exeDir(); // Directory containing executable
String appDir(); // Application directory (different on macOS)
String resDir(); // Resources directory
```
### System Directories
There are two versions of each function:
- **get* functions**: Return `bool` for success/failure, result in reference parameter
- **Direct functions**: Return the path string, or `currentDir()` on failure
```cpp
// Reference parameter versions (safer)
bool getCurrentDir(String& out);
bool getHomeDir(String& out);
bool getTempDir(String& out);
// Direct return versions (more convenient)
String currentDir();
String homeDir();
String tempDir();
```
### Bella-Specific Directories
```cpp
// Reference parameter versions
bool getBellaUserDir(String& out, bool create = true);
bool getBellaConfigDir(String& out, bool create = true);
bool getBellaOutputDir(String& out, bool create = true);
bool getBellaPreviewDir(String& out, bool create = true);
// Direct return versions
String bellaUserDir(bool create = true);
String bellaConfigDir(bool create = true);
String bellaOutputDir(bool create = true);
String bellaPreviewDir(bool create = true);
String bellaNodeHelpPath(bool asUrl);
```
## Complete Usage Examples
### File Management Utility
```cpp
#include "dl_fs.h"
using namespace dl::fs;
class FileManager {
public:
void organizePhotos() {
String photosDir = homeDir() + sep + "Photos";
String organizedDir = photosDir + sep + "Organized";
// Create organized directory
mkDir(organizedDir);
// Get all image files
StringVector imageTypes = {"jpg", "jpeg", "png", "tiff", "bmp"};
StringVector photos = listFiles(photosDir, imageTypes);
for (const auto& photo : photos) {
String fullPath = photosDir + sep + photo;
String destPath = organizedDir + sep + photo;
if (copyFile(fullPath, destPath)) {
std::cout << "Organized: " << photo << std::endl;
}
}
}
void cleanTempFiles() {
String temp = tempDir();
StringVector tempFiles = listFiles(temp);
for (const auto& file : tempFiles) {
if (file.find("temp_") == 0) { // Files starting with "temp_"
String fullPath = temp + sep + file;
if (rmFile(fullPath)) {
std::cout << "Deleted temp file: " << file << std::endl;
}
}
}
}
};
```
### Configuration Manager
```cpp
class ConfigManager {
private:
String configDir;
String configFile;
public:
ConfigManager() {
// Set up configuration directory
if (!getBellaConfigDir(configDir, true)) {
configDir = currentDir(); // Fallback
}
configFile = configDir + sep + "app_config.json";
}
bool loadConfig() {
if (!exists(configFile)) {
createDefaultConfig();
return false;
}
FILE* file = Fopen(configFile, "r");
if (!file) return false;
// Read configuration data
char buffer[4096];
size_t bytesRead = Fread(buffer, 1, sizeof(buffer) - 1, file);
buffer[bytesRead] = '\0';
Fclose(file);
std::cout << "Loaded config: " << buffer << std::endl;
return true;
}
void createDefaultConfig() {
const char* defaultConfig = R"({
"window_width": 1920,
"window_height": 1080,
"fullscreen": false,
"auto_save": true
})";
FILE* file = Fopen(configFile, "w");
if (file) {
Fwrite(defaultConfig, 1, strlen(defaultConfig), file);
Fclose(file);
std::cout << "Created default config at: " << configFile << std::endl;
}
}
};
```
## Best Practices
1. **Always check return values** for file operations and existence before proceeding
2. **Use the safer reference parameter versions** of path functions when error handling is important
3. **Create directories before writing files** to them
4. **Close files promptly** after use to free resources
5. **Use platform-agnostic path construction** with the `sep` constant
6. **Leverage path resolution** for flexible asset loading
7. **Provide progress callbacks** for long-running archive operations
This documentation should give you a solid foundation for using the dl_fs library in your C++ projects!