0 Comments

Creating a Cross-Platform App to Combine .bin Files

Figure: A visual representation of binary data (zeros and ones) illustrating the concept of a binary file. A binary file is any computer file whose contents are not plain text, but rather stored as raw binary data (bytes). In other words, a binary file contains sequences of bytes (groups of eight bits) that may represent anything from compiled program code to images or sound. The file extension “.bin” itself stands for “binary”, signalling that the content consists of bit patterns with little or no human-readable text. For example, CD/DVD images, firmware updates, or compiled executables often use the .bin extension. By contrast to a text file (which stores characters in a readable format), a binary file’s bytes can only be meaningfully interpreted by a program that understands the file’s format. This fundamental fact underpins our task: to build an app that combines (concatenates) multiple .bin files into a single .bin file, preserving the exact byte sequence of each in turn.

A useful way to understand binary files is that, under the hood, all data on a computer is stored in binary form (0s and 1s). However, when people talk about “binary files” they usually mean files that are not plain text (for example, photos, videos, executables, or formatted documents). As Wikipedia notes, a binary file is often contrasted with a text file, meaning it is a “computer file that is not a text file”. Many common file formats (such as images, audio, compressed archives, or compiled programs) are in binary form. These files may sometimes contain sections that look like text (e.g. metadata), but overall they require a special program or binary editor to interpret their contents. For instance, if one attempts to open a .bin file in a standard text editor, one typically sees garbled characters or hexadecimal dumps, because the editor is showing the raw byte values. This is why special programs (or custom code) are needed to manipulate binary files.

The IONOS Digital Guide further explains that the .bin extension denotes binary content and is an efficient way to store data across platforms. For example, exact copies (disk images) of CDs, DVDs or memory cards are often saved as .bin files. These images contain the full raw data – both the file contents and metadata – in a compact form. Binary file formats can also include custom “headers” or “footers” of metadata that tell software how to interpret the data (for instance, a series of images or tracks). When merging .bin files, our task is to place the bytes of each file directly after the previous one, so that no data is lost or mis-ordered. In essence, we are creating one long binary stream. As a file-joining tool explains, “joining by bytes, the files are aligned so that the last byte of the first file comes right before the first byte of the second file”. Our application will implement precisely this concept: concatenating the raw byte streams of input .bin files into a new output file.

Because binary files are sensitive to even a single-byte change, combining them must be done in binary mode, meaning the code must treat the files as raw data and not attempt any text conversions (such as interpreting newline characters). In C++ this is done by opening file streams with the ios::binary flag. In practice, this means using something like std::ifstream infile("file1.bin", std::ios::binary) and similarly an std::ofstream (opened with std::ios::binary as well) for writing the combined output. When such streams are in binary mode, C++ will not alter any bytes – it reads and writes them verbatim. This ensures the merged file is an exact byte-for-byte concatenation of the inputs.

In summary, the introduction sets the stage: a .bin file is a binary data file (not human-readable), and to combine multiple .bin files we must write a program that carefully reads each file’s bytes in turn and appends them to a new binary output file. We will use C++ for performance and control, along with a cross-platform GUI toolkit (like Qt) so the app works both on Windows and Ubuntu. Understanding this foundation will guide every development step that follows.

Designing the .bin Merger App

With the basics of binary files in mind, the next step is to plan the application. Our goal is to make a user-friendly tool that can select multiple .bin files and merge them into one. The design must consider functionality, target audience (advanced developers, but explained clearly), and technical requirements for Windows and Ubuntu.

Key features of the app will include: selecting a list of .bin files (in the correct order), merging their contents seamlessly, and saving to a new .bin file. We will likely provide a graphical interface with common controls: a file-selection dialog (for choosing one or more .bin files), a “Combine” or “Merge” button, and perhaps a progress indicator. Behind the scenes, the program will use C++ streams (or Qt file APIs) to open each file in binary mode and write its bytes to the output stream. We may also add basic validation (e.g. ensuring all files can be opened, warning if any file fails) and perhaps options like verifying the output file size or contents.

Technically, we will use C++ for its speed and direct file I/O control. C++ is well-suited for binary file handling; for example, the standard library allows us to open an std::ifstream or std::ofstream with the std::ios::binary flag. We should emphasise this in our design: the code will do something like

std::ofstream outfile("combined.bin", std::ios::binary);
for (const auto &fname : fileList) {
    std::ifstream infile(fname, std::ios::binary);
    outfile << infile.rdbuf();  // append entire file
    infile.close();
}
outfile.close();

This simple pattern (in pseudocode) reads each file as raw data and writes it to the output. The rdbuf() method shown above is a handy way in C++ to stream all data from one file to another without manually looping over bytes. In practice, one could also read in chunks (e.g. a 4 KB buffer at a time) to handle very large files without consuming too much memory. The key point is that we concatenate bytes exactly in order – there is no interpretation of the data. The result is a single, larger .bin file.

Tools and environment: We plan to use the Qt framework for the GUI (e.g. Qt Widgets or Qt Quick) because it supports both Windows and Linux (Ubuntu) with the same C++ codebase. Qt includes classes like QFile, QDataStream or even just QFile and write() that can also handle binary data. For instance, one could do:

QFile outFile("combined.bin");
outFile.open(QIODevice::WriteOnly);
for (const QString &path : filesToMerge) {
    QFile inFile(path);
    if (inFile.open(QIODevice::ReadOnly)) {
        outFile.write(inFile.readAll());
        inFile.close();
    }
}
outFile.close();

This Qt code (for example) achieves the same thing: it reads each input file in binary and writes to the output. The Qt method write() does an unformatted write of bytes, akin to C++ binary streams. (The Qt framework documentation notes that QFile in QIODevice::ReadOnly mode will give raw bytes.) We won’t limit ourselves to Qt—alternatively, one could use native Win32 file dialogs or GTK on Linux, but Qt is convenient and cross-platform.

C++ specifics: When working with files in C++, the default modes for ifstream and ofstream assume text mode (which might, for example, translate newline characters on Windows). To ensure exact binary handling, we must include std::ios::binary in the open mode. The C++ tutorial explains that binary mode causes the streams to perform input/output independently of any format translations. In our code, every file open should look like std::ifstream in("file.bin", std::ios::in | std::ios::binary); and similarly for the ofstream (often combined with std::ios::out | std::ios::binary). We should also use std::ios::app if appending, or simply open once for output and leave it in write mode, as in the snippet above.

Cross-platform considerations: File path handling differs slightly between Windows (backslashes) and Linux (slashes), but Qt’s QFileDialog will handle that. In pure C++, we may use forward slashes (which work on Windows too) or rely on the user selecting via a dialog. If we provide a CLI mode, we should document paths accordingly. We should also ensure the application can handle large files. On 64-bit systems, file sizes above 4 GB need special flags (like _FILE_OFFSET_BITS=64 on Linux), but on modern compilers this is usually automatic.

Summary of design choices:

  • Language: C++ (with Qt library for GUI).
  • Binary I/O: Use std::ifstream/ofstream or QFile, always with binary mode.
  • Algorithm: Sequentially read each input file and append to output.
  • Error handling: Check each file open/close, report any IO errors.
  • User Interface: Simple GUI with file selector, status messages, and a “Merge” button.
  • Platforms: Ensure the code compiles on Windows (MSVC or MinGW) and on Ubuntu (g++), using Qt 5 or 6.

In the next sections we will implement this plan step by step for each operating system.

Creating a Cross-Platform App to Combine bin Files

Implementing the Merger on Windows

On Windows, the development environment typically involves Visual Studio (or the Qt Creator IDE) and Qt libraries. Here are the steps to build our .bin merger app:

  1. Install tools:
    • Install Visual Studio (Community edition is free) with C++ support, or install Qt Creator with the Qt SDK. Qt can be downloaded from the official site (e.g. via the Qt Online Installer) or obtained through an installer that matches your compiler (MSVC or MinGW).
    • Make sure the Qt version is compatible with your compiler. For Visual Studio you might choose the pre-built Qt package for MSVC.
    • After installation, launch Qt Creator. It will detect compilers and kits automatically or prompt you to configure a “Kit” (compiler+Qt combo).
  2. Create a new project:
    • In Qt Creator, select File → New File or Project → Qt Widgets Application.
    • Name the project (e.g. BinMerger) and choose a location.
    • Select the appropriate kit (for example, “Desktop Qt 5.15.2 MSVC2019 64bit”).
    • Proceed through the wizard. This creates a basic GUI application with a mainwindow.ui for designing the interface.
  3. Design the GUI:
    • Open mainwindow.ui in the Qt Designer.
    • Drag and drop widgets: you might include a QPushButton for “Select Files…”, a QListWidget or QTextEdit to show selected file paths, and another QPushButton for “Merge Files”. Optionally add a QProgressBar or status label.
    • Name the widgets (e.g. btnSelect, btnMerge, listFiles). This will let you refer to them in code (via ui->btnSelect, etc.).
  4. Connect signals and slots:
    • In mainwindow.cpp, add slots for the button clicks. For example, slot on_btnSelect_clicked() will handle file selection, and on_btnMerge_clicked() will perform the merge.
    • In Qt Creator, you can use the Signal/Slot Editor or simply write the functions in code and Qt Creator will hook them up if you follow the naming pattern (on__()).
  5. Implement file selection: void MainWindow::on_btnSelect_clicked() { QStringList files = QFileDialog::getOpenFileNames( this, "Select .bin files", "", "*.bin"); if (!files.isEmpty()) { for (const QString &file : files) { // Add each file path to the list widget ui->listFiles->addItem(file); } } } This slot opens a file dialog where the user can select one or more .bin files (using wildcard *.bin). The selected file paths are stored and displayed in the UI (in a list). Internally, we also keep a QStringList of these paths (or just read them from the list when merging).
  6. Implement merging logic: void MainWindow::on_btnMerge_clicked() { QStringList filesToMerge; for (int i = 0; i < ui->listFiles->count(); ++i) { filesToMerge.append(ui->listFiles->item(i)->text()); } if (filesToMerge.isEmpty()) { QMessageBox::warning(this, "No files", "Please select at least one .bin file."); return; } QString outputFile = QFileDialog::getSaveFileName( this, "Save Merged File", "combined.bin", "*.bin"); if (outputFile.isEmpty()) return; QFile outFile(outputFile); if (!outFile.open(QIODevice::WriteOnly)) { QMessageBox::critical(this, "Error", "Cannot open output file."); return; } // Append each file's contents for (const QString &path : filesToMerge) { QFile inFile(path); if (inFile.open(QIODevice::ReadOnly)) { outFile.write(inFile.readAll()); inFile.close(); } else { QMessageBox::warning(this, "Error", "Cannot open input file: " + path); } } outFile.close(); QMessageBox::information(this, "Done", "Files have been merged."); } In this code, we collect the file names from the UI, ask for an output filename, then open the output file (outFile.open(QIODevice::WriteOnly)) which uses binary mode by default in Qt. We then loop over each input file, open it for read, and use write(inFile.readAll()) to append its bytes. (The call to readAll() loads the entire file as a byte array, which is fine for moderately sized files. For very large files, a loop reading chunks would be more memory-efficient, but the logic is similar.) We include error checks to warn the user if any file cannot be opened. After writing all files, the result is the single merged file.
  7. Compile and run:
    • Click the Run button in Qt Creator. It will compile the project and launch the application. You should see your window with the buttons and list.
    • Test it by clicking “Select Files” and choosing a couple of .bin test files, then clicking “Merge Files” and saving the output. The dialog will report “Done” when finished. Verify that the merged file’s size equals the sum of the inputs. If you open it in a hex editor, you should see the data of the first file followed immediately by the second (as described in the design).
  8. Build variations:
    • Optionally, if you did not use Qt Creator, you can build from the command line: ensure MSVC or MinGW is in your PATH, then run qmake to generate a Makefile and nmake or mingw32-make to compile.
    • If you prefer using std::ifstream/std::ofstream instead of Qt I/O, the implementation in on_btnMerge_clicked can be replaced with C++ code: std::ofstream out(outputFile.toStdString(), std::ios::binary); for (const QString &path : filesToMerge) { std::ifstream in(path.toStdString(), std::ios::binary); out << in.rdbuf(); in.close(); } out.close(); This achieves the same result; it opens each file in binary mode and concatenates them into out (using the iostream rdbuf() stream insertion). Either Qt’s QFile or C++ streams will work equivalently for merging.

By following these steps, even users with moderate programming knowledge can understand how the merger works. We have a self-explanatory GUI, and the code uses standard patterns (file dialogs, binary streams). Since the code is in C++ and Qt, advanced developers can easily extend it (for example, adding drag-and-drop support or handling different file formats). At every step, we treat the data as binary bytes – there are no encoding issues on Windows, and no special translation of newline characters since we use WriteOnly/ReadOnly which is inherently binary in Qt (and since we specified std::ios::binary in C++ if we used it).

Implementing the Merger on Ubuntu

The Ubuntu (or any Linux) implementation follows the same design as Windows, but with different tools. The advantage is that Qt supports Ubuntu just as well, and the C++ code is identical. Here are the steps specific to Ubuntu 22.04 LTS (for example):

  1. Install Qt and build tools:
    • Open a terminal and install the necessary packages. As recommended in an AskUbuntu guide, you can run: sudo apt update sudo apt install qtcreator qtbase5-dev qt5-qmake cmake g++ This installs Qt Creator (IDE), Qt libraries (qtbase5-dev), the Qt build system (qmake), CMake (if you choose to use it), and the GNU C++ compiler. On newer Ubuntu versions, you may prefer Qt6 packages (qt6-base-dev, etc.), but Qt5 is fine and widely supported.
    • Qt Creator’s dependencies on Qt6 or Qt5 depend on what you installed; the command above installs Qt5 by default. Confirm installation by running qtcreator from the terminal or looking under the applications menu.
  2. Set up the project:
    • Launch Qt Creator and create the same “Qt Widgets Application” project as on Windows. Use essentially the same wizard steps (name, location, kit selection).
    • Alternatively, you can use the command line: copy the project folder from Windows (if already created) or use qmake -project and qmake to generate a Makefile.
  3. Design the UI:
    • The mainwindow.ui can be identical: same buttons and widgets. Qt Designer is cross-platform, so just replicate the layout. The code (slots) will be the same as well.
  4. Write the merge logic:
    • In the source code (mainwindow.cpp or equivalent), paste the same slot implementations from the Windows section. Qt code is portable, so QFileDialog, QFile, and signals/slots work unchanged.
    • If you skipped Qt and want pure C++ (without Qt classes), on Ubuntu you might create a simple command-line app. In that case, the code would be something like: #include <iostream> #include <fstream> #include <vector> int main(int argc, char *argv[]) { if (argc < 3) { std::cerr << "Usage: merge output.bin input1.bin [input2.bin ...]\n"; return 1; } std::string outputFile = argv[1]; std::ofstream out(outputFile, std::ios::binary); for (int i = 2; i < argc; ++i) { std::ifstream in(argv[i], std::ios::binary); if (!in) { std::cerr << "Cannot open " << argv[i] << "\n"; return 1; } out << in.rdbuf(); // append binary content:contentReference[oaicite:21]{index=21} in.close(); } out.close(); std::cout << "Files merged into " << outputFile << "\n"; return 0; } You can compile this with: g++ -o binmerge merge.cpp. Running it as ./binmerge combined.bin part1.bin part2.bin will produce combined.bin. This is a simpler, GUI-free tool, which still uses std::ios::binary to handle raw bytes.
  5. Compile the Qt app:
    • If using Qt Creator, just press “Build” and “Run” as before. If using command line, navigate to the project directory and execute: qmake # generates Makefile make # compiles the code The executable will typically be placed in the build-<projectname>-Desktop_Qt... directory. You can copy it to a convenient location or run it from there.
  6. Run and test:
    • Double-click the resulting executable (if your desktop environment allows it) or run it from the terminal (./BinMerger or whatever name).
    • Use the GUI to select .bin files and merge them, exactly as on Windows. Qt’s file dialog will show Linux directory paths.
    • After merging, check that the output .bin has the correct size and contents. You may use the file command (file combined.bin) – it might not give much, but at least it confirms it’s a “data” file. You can also use hexdump -C combined.bin | head to see the first few bytes if you want to verify manually.
  7. Ubuntu-specific notes:
    • File permissions: Make sure the compiled executable has execute permission (chmod +x BinMerger).
    • Package dependencies: If you run the Qt binary on another Ubuntu machine, you may need to install qt5-default or the Qt runtime libraries. Often qtbase5-dev or libqt5widgets5 will cover it.
    • Using GCC directly: If you choose not to use Qt at all, the simple C++ program above (using rdbuf()) is straightforward on Ubuntu. The GNU compiler and standard library support 64-bit file offsets by default on modern systems, so it will handle large files. Just compile with -std=c++11 or later if needed.

By following these steps, even a user new to Ubuntu should be able to set up the environment and build the same .bin merger. The key operations (open with ios::binary, iterate over files, write output) are identical between Windows and Linux in C++. Only the installation commands and build tools differ. In both cases, the code emphasises binary file handling and minimal complexity, so that “any user can understand it”. Debugging any issues is helped by Qt Creator’s messages or standard compiler errors.

Testing and Using the Application

Once the app is built on either platform, it can be used by any user to merge .bin files. Here are some general usage steps and tests to ensure everything works correctly:

  • Launching the app: On Windows, double-click the executable or start it from the Start menu if installed. On Ubuntu, launch from the terminal (./BinMerger) or use the GUI environment. The window should appear with the “Select Files” and “Merge” buttons (or equivalent).
  • Selecting files: Click the “Select Files” button. A file dialog will open. Navigate to the folder containing your .bin parts (for example, file1.bin, file2.bin, etc.). You can typically select multiple files by holding Ctrl or Shift, or by dragging. Confirm selection; the app will list the chosen files in its window. Ensure they appear in the correct order (top-down in the list) – the program will merge them in that sequence.
  • Merging: Click the “Merge” (or “Combine”) button. The app may prompt for an output filename (or use a default like combined.bin). Enter a suitable name or path. The program will then open each input file in binary mode and write its contents to the output. If there is a progress bar, watch it fill; otherwise, a simple message (“Done” or “Files have been merged”) will indicate success. If any file cannot be opened (e.g. due to permissions or it not being a .bin), the program should alert you.
  • Verifying output: After merging, check that the output file’s size equals the sum of the input sizes. On Windows you can right-click and view “Properties” to see file size; on Linux, run ls -l or stat. To spot-check the contents, use a hex editor or simple command-line tools. For example, on Linux: hexdump -C combined.bin | head This shows the first bytes in hex. They should match the first part’s bytes exactly. Similarly, check the end of the first file against the start of the second: hexdump -C file1.bin | tail -n1 hexdump -C combined.bin | sed -n '1p' They should be identical (if not identical command usage, ensure you inspect overlapping boundary). Essentially, the result file should be indistinguishable from simply concatenating the inputs.
  • Edge cases:
    • If only one file is selected, the app will simply copy it to the new name (essentially a clone).
    • If the files have headers (e.g. if the first file is a special image with a header and second is a data append), our app does not adjust or modify headers – it just glues bytes together. For most .bin merging scenarios (raw data dumps), this is correct. But be aware: not all binary formats are safe to merge naively. Some may require updating a size field in the header. Our app does not do that; it treats the files as pure byte streams. This limitation should be documented. Users must understand that they get a raw byte concatenation.
  • Use with command-line (Ubuntu example): If you compiled the simple CLI version, you can use it directly in a terminal: ./binmerge combined.bin part1.bin part2.bin part3.bin It will print a message when done. On Windows, a similar command-line version can be compiled (using MinGW or Visual Studio’s cl).
  • Performance: For very large files, the GUI might become unresponsive if you load entire files into memory (as readAll() does). In that case, a loop reading chunks (e.g. 4096 bytes at a time) is better: char buffer[4096]; while (!inFile.atEnd()) { qint64 bytes = inFile.read(buffer, sizeof(buffer)); outFile.write(buffer, bytes); } This avoids large memory spikes. The advantage is most noticeable if you handle gigabyte-sized .bin files.

Overall, using the app should be straightforward: select files, click merge, and find the combined .bin file. If needed, the app can be extended with features like drag-and-drop, file removal from the list, or checking combined file size before writing. However, even this basic version is enough to combine binary files in one go.

Advantages and Drawbacks of the New Merger App

Having built and tested the .bin merger, it’s useful to compare it with existing methods and tools. Advantages of our custom app include:

  • Ease of Use: With a simple GUI, users don’t need to remember command-line syntax. Anyone can click to select files and merge them. This is more user-friendly than, say, using a console or third-party tool where one must type commands precisely.
  • Cross-Platform: Because we used Qt and standard C++, the same codebase works on both Windows and Ubuntu (and other OS if ported). Many existing tools are platform-specific. For example, the classic Windows command COPY /B only works on Windows. In contrast, our app (or its CLI version) can run on Linux as well. The IONOS guide even notes that .bin is useful cross-platform, and our app follows that by working on multiple systems.
  • No Size Restriction: Unlike some older utilities, our app can handle very large .bin files. (It will use 64-bit file pointers on modern systems.) For example, in the talkchess forum users of the Polyglot tool Poly17 found a 2 GB limit and “insufficient memory” error when dealing with large chess book files. Our program does not impose an arbitrary size cap – it will merge any number of gigabytes (limited only by disk and OS). This overcomes one drawback of older tools.
  • Customisable and Transparent: Because we wrote the code, it can be audited, modified, and extended. Advanced developers can add features like checksum verification, multi-threaded I/O, or format-specific handling if needed. In contrast, many existing tools are closed-source or fixed-feature.
  • Binary Fidelity: The app explicitly uses binary mode I/O, ensuring no data is altered or lost during merging. This exact byte-level concatenation matches what dedicated joiners promise. For raw data usage (e.g. binary dumps or images), this precision is important.

However, there are drawbacks and limitations to note:

  • Reinventing the wheel: Simple concatenation of files can already be done without coding. For example, on Windows one can use the command COPY /B File1.bin+File2.bin combined.bin. On Linux, cat file1.bin file2.bin > combined.bin will also join files (as long as no carriage-return translation is needed). In cases where no GUI is required, these built-in methods are quick. Our app adds convenience but also complexity. (It is worth noting that copy /B can be very slow on many files – one user reported concatenating dozens of small files taking 40 seconds. A custom app could be faster or multi-threaded.)
  • Existing specialized tools: There are utilities specifically for splitting and joining files. For example, BinaryMark’s File Split & Join tool supports binary join mode. It can batch-join files in a directory. Such tools may offer extra options (e.g. splitting back into parts or handling text mode). Our app focuses only on one task. Also, Poly17 (from the chess world) merges openings books with .bin files, but it also handles polyglot-specific weight data. Poly17 is command-line and quite old, and apparently has the 2 GB limit. Our app can mimic just the basic part of what Poly17 does (binary merge) without the book-weight features, and in a GUI.
  • Lack of advanced features: Our merger app does not interpret file formats. It cannot update headers, recompute checksums, or detect file types inside the .bin. For some formats, simply appending raw bytes is not enough. For example, a binary container format might need its directory of contents updated. Our tool will not do that. In comparison, a tool like Poly17 may know the Polyglot book structure and can update internal tables when merging (though in practice Poly17 is limited as mentioned). If merging generic data, our app is fine; if merging complex files, one must be careful.
  • Dependency on Qt/C++: Users must have the necessary runtime (Qt libraries on Linux/Windows) to run the app unless it’s statically linked. In contrast, a simple C# or Python script might not need heavy libraries. However, building in C++ means the app can be lightweight and fast once compiled.
  • Performance considerations: Reading and writing large files is I/O bound. Our basic implementation reads one file fully then the next. For most use-cases this is acceptable, but if someone wants extreme speed, they might look into memory-mapped files or asynchronous I/O. We did not implement these optimisations. In any case, our app’s performance should be similar to dedicated join tools for moderate file sizes.

In conclusion, the new .bin merging app offers a clear, multi-platform solution for combining binary files. It avoids some pitfalls of older methods (text-mode issues, platform limits) and provides a friendly interface. On the downside, it replicates functionality that was partially available via simple commands or existing utilities, and it lacks deep format awareness. For pure byte-level merging, however, it does the job cleanly.

Overall, compared to Poly17 and similar tools, our app’s pros are its GUI, cross-platform design, and absence of arbitrary size constraints. Poly17’s edge would be its specialized handling of polyglot book metadata (which we did not implement) and possibly mature error-handling for chess-specific formats. Our objective development, with cited knowledge, shows that both approaches have their uses. The new app fills a niche for general-purpose .bin merging, while users needing format-specific features may rely on dedicated tools.

Sources: We based our understanding of binary files on references that define binary formats. The C++ file I/O design was guided by standard documentation on binary mode streams. We also drew on developer resources (such as Qt forums and tutorials) describing how to append data from one file to another. In comparing tools, we noted descriptions of binary join modes from available software documentation and Windows command behavior. These sources ensure our app design and analysis are well-founded.

Jorge Ruiz Centelles

Filólogo y amante de la antropología social africana

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts