Cette article présente 2 fonctions qui permette de géré les chemin relative a un fichier ou absolue depuis un fichier.

Ces fonctions sont particulièrement utiles lorsque il s’agit d’interpréter un fichier qui contiens des chemin qu’il lui sont relative (un peu a l’image des fichier CSS dont les chemin sont relative au fichier et non a la page HTML).

On présentera tout d’abord 2 autres fonction qui seront utiles par la suite.

Note : les fonction présenté ici ne sont compatible avec les systèmes Linux et Windows

isAbsoloutPath

Cette fonction très simple qui ne fait que vérifier si le chemin est absolue ou relative.

Dans le cas Windows: vérifier si il ya le caractère ‘:’ qui vien just apres la lettre des disques racine

Le cas Linux: très simple si le chemin commence par un slache ‘/’

inline bool isAbsoloutPath(std::string path)
{
    #ifdef __WIN32__
    return (path.size() > 2 ? path[1] == ':' : false);
    #else
    return (path.size() > 0 ? path[0] == '/' : false);
    #endif
}

toSlashSeprator

Convertie les séparateurs utiliser par Windows (anti-slache \) à des formes plus supporté.
Noté que le anti-slache ‘\’ n’est supporté que sur Windows, a contrario du slache ‘/’ que lui est supporté par les système.

inline std::string toSlashSeprator(std::string path)
{
    unsigned reppos;
    while((reppos = path.find('\\')) != std::string::npos)
        path.replace(reppos, 1, 1, '/');

    if(*(--path.end()) == '/') path.erase(--path.end());

    return path;
}

pathCompnenets

Ici on s’en sert pour découper les différente parties des chemin avec les slaches comme séparateur

inline std::vector pathCompnenets(std::string path)
{
    std::vector comp;

    unsigned sc = 0;

    for(unsigned i = 0; i < path.size(); i++)
    {
        if(path[i] == '/')
        {
            comp.push_back(path.substr(sc, i - sc));
            sc = i + 1;
        }
    }

    comp.push_back(path.substr(sc));

    return comp;
}

resolvePath

Enfin une fonction intéressant qui va nous permetre de résoudre les chemin relative à un fichier

Prenons un exemple: on le chemin d’un fichier « images\photo.jpg », qui se trouve à l’intérieur d’un fichier qui est « C:\projet\document.txt »

En utilisant cette fonction on a voir comme sorite C:\projet\images\photo.jpg

std::string absolute_path = relativizePath("images\\photo.jpg", "C:\\projet\\document.txt");

Mais cette fonction est beacoup plus utiles dans le cas des dossiers parrent « ..\images\photo.jpg »

inline std::string resolvePath(std::string path, std::string base)
{
    using namespace std;

    if(isAbsoloutPath(path))
        return path;

    vector abscomp = pathCompnenets(toSlashSeprator(base));
    vector relcomp = pathCompnenets(toSlashSeprator(path));

    abscomp.pop_back();

    string out;

    while(!relcomp.empty())
        if(relcomp.front() == "..")
        {
            abscomp.pop_back();
            relcomp.erase(relcomp.begin());
        }
        else
            break;

    out = joinstr(abscomp, '/') + '/' + joinstr(relcomp, '/');

    return out;
}

 

relativizePath

Notre deuxièmement fonction intéressant permet quand à elle de relativiser un chemin par rapport a une base

Immaginon que nous vellon écrire un fichier image dans le dossier « images\ » et enregistrer son chemin relative dans le dossier courant.

On enregistre l’image qui a comme chemin « C:\projet\images\photo.jpg », ensuit on écrit notre fichier « C:\projet\document.txt » et l’aide de la fonction on pourras relativiser le chemin en « images\photo.jpg »

Comme la précédente fonction celle-ci gère aussi le cas des dossier parent.

std::string path = relativizePath("C:\\projet\\images\\photo.jpg", "C:\\projet\\fichiers\\document.txt");
path // == ../images/photo.jpg
inline std::string relativizePath(std::string path, std::string base)
{
    using namespace std;

    if(!isAbsoloutPath(path))
        return path;

    vector abscomp = pathCompnenets(toSlashSeprator(base));
    vector relcomp = pathCompnenets(toSlashSeprator(path));

    abscomp.pop_back();

    string out;

    bool done = false;

    for(unsigned i = 0; i < abscomp.size(); i++)
    {
        if(abscomp[i] != relcomp[i])
        {
            relcomp.erase(relcomp.begin(), relcomp.begin() + i);
            if(isAbsoloutPath(path))
                relcomp.insert(relcomp.begin(), abscomp.size() - i, "..");
            done = true;
            break;
        }
    }

    if(!done)
        relcomp.erase(relcomp.begin(), relcomp.begin() + abscomp.size());

    out = joinstr(relcomp, '/');

    return out;
}