<?php
//----------------------------------------
// bfuv :   1.0 : 2022/03/11
//   SHA1 LIMIT2 0 MESSAGE DE 2^64 bit soit 2^56 octets https://fr.wikipedia.org/wiki/SHA-1
//          2.0 : 2022/03/25
//          2.1 : 2022/03/25    envoit un seul bloc !
//          2.1 : 2022/03/26    déplace texte vers le bas pour envoit_bloc
//          2.2 : 2022/03/27    ok pour les procédures avec fichier complet
//----------------------------------------  

/* Création des tables TabInd, metroMNT et corseMNT de la base de données SQLITE
BEGIN TRANSACTION;
DROP TABLE IF EXISTS TabInd;
CREATE TABLE "TabInd" (
    "Xl"    INTEGER,
    "Yl"    INTEGER,
    "Dp"    TEXT,
    "datT"  TEXT,
    "X_Y"   TEXT NOT NULL
);
DROP TABLE IF EXISTS metroMNT;
CREATE TABLE "metroMNT" (
    "Lg"    BLOB,
    "Ylamb" INTEGER NOT NULL UNIQUE,
    PRIMARY KEY("Ylamb")
) WITHOUT ROWID;
DROP TABLE IF EXISTS corseMNT;
CREATE TABLE "corseMNT" (
    "Lg"    BLOB,
    "Ylamb" INTEGER NOT NULL UNIQUE,
    PRIMARY KEY("Ylamb")
) WITHOUT ROWID;
WITH RECURSIVE
   f (n)
AS (
    SELECT 6135005
    UNION ALL
    SELECT n+5 FROM f WHERE n < 7115000
)
INSERT INTO metroMNT SELECT X'80c6', n FROM f;
WITH RECURSIVE
   g (n)
AS (
    SELECT 6045005
    UNION ALL
    SELECT n+5 FROM g WHERE n < 6240000
)
INSERT INTO corseMNT SELECT X'80e6', n FROM g;
COMMIT;
*/

/**************************
 * upload_max_filesize = 2M en général
 * post_max_size = 8M
 */

function file_ecrit($filename,$data)
  {                                  // pour gestion des erreurs ET sauvegarde de compte.txt (ceinture ET bretelles)
    if($fp = fopen($filename,'a'))   // mode ajout !!
    {
      $ok = fwrite($fp,$data);
      fclose($fp);
      return $ok;
    }
    else return false;
  }      
  date_default_timezone_set('Europe/Paris');
  ini_set("always_populate_raw_post_data", "-1");
  $name_sqlite = 'bfuv.sqlite';
  $db = new PDO('sqlite:bfuv.sqlite');
  // ATTENTION à ne pas oublier de CASTER le blob / "hex(hashT)" sous peine de détraquer le fichier HTML
  $pdo_result = $db->query('SELECT rowid, nom, taille, cluster, date, hex(hashT) FROM files');
  $vin = [];
  if (!$pdo_result){
      $sqlreq = 'CREATE TABLE "files" ( "nom" TEXT NOT NULL UNIQUE, "taille" TEXT NOT NULL, "cluster" INTEGER NOT NULL, "date" TEXT NOT NULL, "hashT" BLOB)';   
      $db->exec($sqlreq); 
      $db->exec($sqlreq);
  } else {
      $pdo_result->setFetchMode(PDO::FETCH_OBJ);
      $vin = $pdo_result->fetchAll();      
      $pdo_result->closeCursor(); 
  } 
  $db = Null;
  /* dans tous les cas, on part avec une base de données prête à être exploitée okazou !. */
?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">

    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
        <meta http-equiv="cache-control" content="no-cache, must-revalidate" />
        <meta http-equiv="Pragma" content="no-cache" />
        <meta http-equiv="Expires" content="0" />
        <meta name="DC.Language" content="fr" />
        <meta name="description" content="Reparetrace" />
        <meta name="author" content="ArouG" />
        <meta name="keywords" content="constitution et entretien MNT 5*5" />
        <meta name="date" content="2022/01/29" />
        <meta name="robots" content="nofollow" />
        <title>Upload de gros fichiers</title>
        <style>
        html {
            font: 1.1em sans-serif;
        }
        
        body {
            display: block;
            background-color: black;
            margin: 8px;
        }
        
        .top-box {
            width: 1400px;
            height: 18px;
            margin-bottom: -18px;
            position: relative;
        }
        
        #bidon {
            width: 1400px;
            height: 20px;
            background-color: #000000;
            float: left;
        }
        
        #entete {
            width: 1400px;
            margin-top: 0;
            margin-bottom: 0;
            margin-left: 0;
            margin-right: 0;
            line-height: 5px;
            background-color: #600c0c;
            padding-top: 0;
            z-index: 50;
        }
        
        #entete p {
            color: #f0e39e;
            font-family: Georgia, "Bitstream Vera Serif", Norasi, serif;
            font-size: 0.8em;
            font-style: italic;
            line-height: 0.2em;
        }
        
        #cornleft {
            float: left;
            width: 150px;
            height: 75px;
            position: relative;
            background-color: #600c0c;
        }
        
        #titre {
            float: left;
            width: 1100px;
            position: relative;
            margin-top: 0;
            height: 75px;
            background-color: #600c0c;
        }
        
        #titre h2 {
            color: #f0e39e;
            font-family: Georgia, "Bitstream Vera Serif", Norasi, serif;
            font-style: italic;
            font-size: 1.1em;
            font-style: italic;
            text-align: center;
        }
        
        #cornright {
            float: left;
            width: 150px;
            height: 75px;
            position: relative;
            background-color: #600c0c;
        }
        
        #menu {
            text-align: center;
            background-color: #FFDEAD;
            width: 1400px;
            margin: auto;
            padding: 0;
        }
        
        #basdepage {
            margin: 0;
            padding: 0;
            font-size: 0.55em;
            background-color: #600c0c;
            width: 1400px;
            float: left;
        }
        
        #gauche {
            text-align: left;
            float: left;
        }
        
        #droite {
            text-align: right;
            float: left;
        }
        
        #centrebas {
            float: left;
            width: 1224px;
            text-align: center;
            margin: auto;
            padding: 0;
            color: white;
            font-family: Georgia, "Bitstream Vera Serif", Norasi, serif;
            font-style: italic;
            font-size: 18px;
            font-style: italic;
        }
        
        #progressDesc {
            visibility: hidden;
        }
        
        #pgrbar {
            visibility: hidden;
        }
        </style>
        <script type="text/javascript">
        <?php echo 'var rep=' . json_encode($vin) . ";\n" ?>
        let main = {};
        let intervalId;
        let currentBar = 0;
        const nohash = 'Oooops!_no_data_hash';
        let RowId;

        function fichier_en_table_files(nom, taille, date) {
            let find = false;
            for(var i = 0; i < rep.length; i++) {
                if((rep[i]['nom'] == nom) && (rep[i]['taille'] == taille) && (rep[i]['date'] == date)) {
                    find = true;
                }
            }
            return find;
        }

        function indof(nom, taille, date) {
            for(var i = 0; i < rep.length; i++) {
                if((rep[i]['nom'] == nom) && (rep[i]['taille'] == taille) && (rep[i]['date'] == date)) {
                    //ok = i;
                    //break;
                    return i;
                }
            }
        }
        async function init_row(nom, taille, date, cluster) { // lancé que si le fichier n'est pas déjà en table
            let url = './receive.php?N=' + encodeURIComponent(nom) + "&S=" + taille + "&D=" + encodeURIComponent(date) + "&C=" + cluster;
            let reponse = await fetch(url, {
                method: 'GET'
            });
            if(reponse.status == 200) {
                let rep = await reponse.json();
                rowid = parseInt(rep['RId']);
                if(rowid > 0) {
                    document.querySelector('#outt').textContent += " : line number " + rowid + " \n";
                    return rowid;
                    // on continue
                } else {
                    // pas normal !!
                    document.querySelector('#outt').textContent += " : problem, retour = " + rowid + "\n";
                    return rowid;
                }
            } else {
                document.querySelector('#outt').textContent += " : problem, status = " + reponse.status + "\n";
                return reponse.status;
            }
        }
        /***************************************************
         * Concaténation de Blob   var myBlobBuilder = new MyBlobBuilder();
         **************************************************/
        var MyBlobBuilder = function() {
            this.parts = [];
        }
        MyBlobBuilder.prototype.append = function(part) {
            this.parts.push(part);
            this.blob = undefined; // Invalidate the blob
        };
        MyBlobBuilder.prototype.getBlob = function() {
            if(!this.blob) {
                //this.blob = new Blob(this.parts, { type: "text/plain" });
                this.blob = new Blob(this.parts, {
                    type: "binary"
                });
            }
            return this.blob;
        };
        async function part_envoi_data(str, buff) {
            var myBlobBuilder = new MyBlobBuilder();
            // concaténation pour avoir un blob formé de 2
            myBlobBuilder.append(str);
            myBlobBuilder.append(buff);
            var newdata = myBlobBuilder.getBlob();
            const settings = {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                body: newdata
            };
            var url = './receive.php';
            try {
                let response = await fetch(url, settings); // se résout avec des en-têtes de réponse
                let result = await response.text();
                return result;
            } catch(e) {
                return e;
            }
        }

        async function AsyncReadBytes(offset, nbB) {
            if((offset + nbB <= main.file.size) && (offset >= 0) && (nbB >= 0)) {
                try {
                    var partie = main.file.slice(offset, offset + nbB);
                    var tmpblob = new Response(partie);
                    var buffer = await tmpblob.arrayBuffer();
                    return new DataView(buffer);
                } catch {
                    console.log('error AsyncReadBytes');
                    return false;
                }
            } else {
                console.log('Buffer impossible');
                return false;
            }
        }

        async function tailleFSv(fname) {
            let url = './receive.php?N=' + encodeURIComponent(fname) + "&I";
            let reponse = await fetch(url, {
                method: 'GET'
            });
            if(reponse.status == 200) {
                let rep = await reponse.json();
                return rep;
            } else {
                document.querySelector('#outt').textContent += " : problem during tailleFSv, status = " + reponse.status + "\n";
                return reponse.status;
            }
        }

        function buf2hex(buffer) { // buffer is an ArrayBuffer
            return [...new Uint8Array(buffer)].map(x => x.toString(16).padStart(2, '0')).join('');
        }

        function buf2str(arrays) {
            var tab = new Uint8Array(arrays);
            result = '';
            for(var i = 0; i < tab.length; i++) result += String.fromCharCode(tab[i]);
            return result;
        }

        function human_date(fdate) {
            var d = new Date(fdate);
            var dattext = d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate() + '=' + d.getHours() + ':' + d.getMinutes();
            return dattext;
        }

        function Cluster(taille) {
            if(taille <= Math.pow(2, 26)) { // 64 Mo
                return 1;
            }
            if(taille <= Math.pow(2, 30)) { // 256 Mo
                return 2;
            }
            if(taille <= Math.pow(2, 34)) { // 1 Go
                return 4;
            }
            if(taille <= Math.pow(2, 38)) { // 4 Go
                return 8;
            }
            if(taille <= Math.pow(2, 42)) { // 16 Go
                return 16;
            }
            if(taille <= Math.pow(2, 46)) { // 64 Go
                return 32;
            }
            if(taille <= Math.pow(2, 50)) { // 256 Go
                return 64;
            }
            if(taille <= Math.pow(2, 54)) { // 1024 Go
                return 128;
            }
            return 256;
        }
        async function fetchPostB(str) {
            const settings = {
                method: 'POST',
                headers: {
                    //'Content-Type': 'application/octet-stream'
                    'Content-Type': 'text/plain'
                },
                body: str
            };
            var url = './receive.php';
            try {
                let response = await fetch(url, settings); // se résout avec des en-têtes de réponse
                let result = await response.text(); // en chaine hexa
                return result;
            } catch(e) {
                return e;
            }
        }
        async function envoit_bloc(i, hashBlock) {
            // Penser à déterminer taille totale du bloc d'abord (normalement Cluster sauf dernier)
            var ind;
            var ret_nb_octs;
            var offset;
            var lastbuffSize;
            var total = 100;
            var sizecluster = Math.pow(2, 20) * main.clust;
            var offsetbase = i * sizecluster;
            if((main.file.size - offsetbase) <= sizecluster) {
                sizecluster = main.file.size - offsetbase;
            }
            // sizecluster prend la taille du dernier cluster éventuellement !
            if(sizecluster < 1048576) {
                // reste moins d'un Mo à envoyer =>  d'un seul bloc
                document.querySelector('#outt').textContent += 'Un seul petit bloc de taille = ' + sizecluster + "\n";
                //considère que num partie = 99
                offset = offsetbase;
                lastbuffSize = sizecluster;
                var buff = await AsyncReadBytes(offset, lastbuffSize);
                var DataToSend = main.RowId.toString(10) + '-' + "cremod_" + i + "_100_"+ hashBlock +'_' + buff.byteLength + "*";
                ret_nb_octs = await part_envoi_data(DataToSend, buff);
                document.querySelector('#outt').textContent += 'Partie 100/100 : clef hash = ' + ret_nb_octs + "\n";
                document.querySelector('#outt').scrollTo(0, document.querySelector('#outt').scrollHeight);
                return ret_nb_octs;
            } else {
                var buffSize = Math.floor(sizecluster / 100);
                lastbuffSize = 0;
                if(sizecluster != 100 * buffSize) {
                    buffSize += 1;
                    lastbuffSize = sizecluster - (99 * buffSize);
                }
                document.querySelector('#outt').textContent += 'Nouveau bloc offset <' + offsetbase + '> prêt. Il devrait avoir ' + sizecluster + " octets\n";
                for(ind = 0; ind < 99; ind++) {
                    offset = offsetbase + (ind * buffSize);
                    var buff = await AsyncReadBytes(offset, buffSize);
                    var DataToSend = main.RowId.toString(10) + '-' + "cremod_" + i + "_" + ind + "_" + hashBlock +'_' + buff.byteLength + "*";
                    //var firstpart = DataToSend + buf2str(buff);
                    ret_nb_octs = await part_envoi_data(DataToSend, buff);
                    document.querySelector('#outt').textContent += 'Partie ' + (ind + 1) + '/100 : comporte ' + ret_nb_octs + " octets\n";
                    document.querySelector('#outt').scrollTo(0, document.querySelector('#outt').scrollHeight);
                }
                // ind == 99 (100ième envoi)
                offset = offsetbase + (ind * buffSize);
                var buff = await AsyncReadBytes(offset, lastbuffSize);
                var DataToSend = main.RowId.toString(10) + '-' + "cremod_" + i + "_" + ind + "_" +  hashBlock +'_' + buff.byteLength + "*";
                ret_nb_octs = await part_envoi_data(DataToSend, buff);
                document.querySelector('#outt').textContent += 'Partie ' + (ind + 1) + '/100 : clef hash = ' + ret_nb_octs + "\n";
                document.querySelector('#outt').scrollTo(0, document.querySelector('#outt').scrollHeight);
                return ret_nb_octs;
            }
        }
        async function return_hash_table(file, idx) {
            let fname = file.name;
            let fsize = file.size;
            let fdate = file.lastModified;
            var clust = Cluster(file.size);
            main.clust = clust;
            main.fsizeSv = await tailleFSv(fname);
            main.diff = 0;
            // enregistre dans BdD et récupère le rowId correspondant
            if(idx == 0) {
                var RowId = await init_row(fname, fsize, human_date(fdate), clust);
                if(RowId < 0) {
                    RowId = -RowId; // la création de fichier ne s'est pas passé comme il faut !? OU il n'existait pas !
                }
            } else {
                RowId = idx;
                document.querySelector('#outt').textContent += " : line number " + RowId + " \n";
            }
            // création hash Table
            main.HexHash = [];
            main.RowId = RowId;
            var tabHash = '';
            var buff;
            var nbB = clust * Math.pow(2, 20);
            var nbloop = Math.floor(file.size / nbB);
            var rest = file.size % nbB;
            var adeq = 0;
            if(rest > 0) adeq = 1;
            var offset = 0;
            main.HexHashS = [];
            document.querySelector('#progressDesc').textContent = "we build the hash table";
            intervalId = setInterval(displayBar, 100); // dysplayBar est appelée toutes les 100 millisecondes
            init_progress(0, nbloop + adeq);
            document.querySelector('#progressDesc').style.visibility = "visible";
            document.querySelector('#pgrbar').style.visibility = "visible";
            for(var i = 0; i < nbloop; i++) {
                buff = await AsyncReadBytes(offset, nbB);
                tmp = await crypto.subtle.digest('SHA-1', buff); //
                main.HexHash.push(buf2hex(tmp));
                tabHash += buf2str(tmp); //console.log('longueur hash = '+tabHash.length);
                document.querySelector('#outt').textContent += "Client : " + buf2hex(tmp) + "\n";
                document.querySelector('#outt').scrollTo(0, document.querySelector('#outt').scrollHeight);
                offset += nbB;
                // old
                var DataToSend = RowId.toString(10) + '-' + "hashSv_" + i + "_" + nbB + "_" + buf2hex(tmp) + "_O*"; // ou GET ?
                var firstpart = DataToSend + main.HexHash.join('');
                var ret = await fetchPostB(firstpart);
                main.HexHashS.push(ret);
                document.querySelector('#outt').textContent += "Server : " + ret + "\n";
                if(ret != buf2hex(tmp)) {
                    main.diff += 1;
                    document.querySelector('#outt').textContent += '---------error---------' + "\n";
                }
                document.querySelector('#outt').scrollTo(0, document.querySelector('#outt').scrollHeight);
                //barre de progression
                currentBar = i;
                displayBar();
            }
            if(rest > 0) {
                buff = await AsyncReadBytes(offset, rest);
                tmp = await crypto.subtle.digest('SHA-1', buff); //
                //tabHash += buf2str(tmp)+nohash;
                tabHash += buf2str(tmp); //console.log('longueur hash = '+tabHash.length);
                document.querySelector('#outt').textContent += "Client : " + buf2hex(tmp) + "\n";
                document.querySelector('#outt').scrollTo(0, document.querySelector('#outt').scrollHeight);
                main.HexHash.push(buf2hex(tmp));
                //document.getElementById("progressBar").value += adeq; 
                // old
                var DataToSend = RowId.toString(10) + '-' + "hashSv_" + i + "_" + rest + "_" + buf2hex(tmp) + "_O*"; // ou GET ?
                var firstpart = DataToSend + main.HexHash.join('');
                var ret = await fetchPostB(firstpart);
                main.HexHashS.push(ret);
                document.querySelector('#outt').textContent += "Server : " + ret + "\n";
                if(ret != buf2hex(tmp)) {
                    main.diff += 1;
                    document.querySelector('#outt').textContent += '---------error---------' + "\n";
                }
                document.querySelector('#outt').scrollTo(0, document.querySelector('#outt').scrollHeight);
            }
            document.querySelector('#outt').textContent += "\n\n" + "l'analyse a révélé : " + main.diff + " 'blocs' différents\n";
            document.querySelector('#outt').scrollTo(0, document.querySelector('#outt').scrollHeight);
            main.tabHash = tabHash;
            //barre de progression
            currentBar = 100;
            displayBar();
            clearInterval(intervalId);
            document.querySelector('#progressDesc').style.visibility = "hidden";
            document.querySelector('#pgrbar').style.visibility = "hidden";
            main.tabHash = tabHash; // 30940 octets !?
            i = 0;
            while(i < main.HexHash.length) {
                if(main.HexHash[i] != main.HexHashS[i]) {
                    document.querySelector('#outt').textContent += "Envoit bloc " + i + '/' + main.HexHash.length + "\n";
                    main.HexHashS[i] = await envoit_bloc(i, main.HexHash[i]);  // format hex
                }
                i += 1;
            }
            var tabinSv = [];
            for (i=0; i<main.HexHash.length; i++){
                tabinSv.push([main.HexHash[i], main.HexHashS[i]]);    
            }
            asyncFunc(tabinSv);
            var truc = 3;
        }

        function init_progress(currentBarv, currentBarmax) {
            progressBar = document.getElementById("progressBar");
            progressBar.value = currentBarv;
            progressBar.max = currentBarmax;
        }
        let displayBar = function() {
            progressBar.value = currentBar;
        }
        async function asyncFunc(tabinSv){
            var buff;
            var nbB = main.clust * Math.pow(2, 20);
            var nbloop = Math.floor(main.file.size / nbB);
            var rest = main.file.size % nbB;
            var adeq = 0;
            if(rest > 0) adeq = 1;
            var Clhash, Svhash;
            main.fsizeSv = await tailleFSv(main.fname);

                        i = 0;
                        while((i < tabinSv.length)) {
                            if(tabinSv[i][0] != tabinSv[i][1]) {
                                document.querySelector('#outt').textContent += "Envoit bloc " + i + '/' + tabinSv.length + "\n";
                                var tmp = await envoit_bloc(i, tabinSv[i][0]);   // format hex puisque 40 octets
                            }
                            i += 1;
                        }
            document.querySelector('#outt').textContent += "\n\nTous les blocs différents ont été mis à jour au niveau de la table de correspondance des blocs.\nDernière vérification entre la table et les deux fichiers avant de clore le sujet :\n\n";
            i=0;
            var offset = 0;
            var badSvCluster = [];
            var badClCluster = [];
            while (i<nbloop) {
                buff = await AsyncReadBytes(offset, nbB);
                tmp = await crypto.subtle.digest('SHA-1', buff); 

                var DataToSend = main.RowId.toString(10) + '-' + "hashSv_" + i + "_" + nbB + "_" + buf2hex(tmp) + "_N*"; // ou GET ?
                Svhash = await fetchPostB(DataToSend);

                if (tabinSv[i][0].toLowerCase() == buf2hex(tmp)){
                    document.querySelector('#outt').textContent += "Fichier Client, le bloc n°"+(i+1)+" correspond bien\n";
                } else {
                    badClCluster.push(i);   
                    document.querySelector('#outt').textContent += "Fichier Client, le bloc n°"+(i+1)+" ne correspond pas\n"; 
                }
                if (tabinSv[i][1].toLowerCase() == Svhash){
                    document.querySelector('#outt').textContent += "Fichier Serveur, le bloc n°"+(i+1)+" correspond bien\n";
                } else {
                    badSvCluster.push(i);   
                    document.querySelector('#outt').textContent += "Fichier Serveur, le bloc n°"+(i+1)+" ne correspond pas\n"; 
                }
                document.querySelector('#outt').scrollTo(0, document.querySelector('#outt').scrollHeight);
                offset += nbB;
                i += 1;
            }     
            if (rest > 0) {
                buff = await AsyncReadBytes(offset, rest);
                tmp = await crypto.subtle.digest('SHA-1', buff); //
                var DataToSend = main.RowId.toString(10) + '-' + "hashSv_" + nbloop + "_" + rest + "_" + buf2hex(tmp) + "_N*"; // ou GET ?
                Svhash = await fetchPostB(DataToSend);
                if (tabinSv[i][0].toLowerCase() == buf2hex(tmp)){
                    document.querySelector('#outt').textContent += "Fichier Client, le bloc n°"+(i+1)+" correspond bien\n";
                } else {
                    badClCluster.push(i);   
                    document.querySelector('#outt').textContent += "Fichier Client, le bloc n°"+(i+1)+" ne correspond pas\n"; 
                }
                if (tabinSv[i][1].toLowerCase() == Svhash){
                    document.querySelector('#outt').textContent += "Fichier Serveur, le bloc n°"+(i+1)+" correspond bien\n";
                } else {
                    badSvCluster.push(i);   
                    document.querySelector('#outt').textContent += "Fichier Serveur, le bloc n°"+(i+1)+" ne correspond pas\n"; 
                }
                document.querySelector('#outt').scrollTo(0, document.querySelector('#outt').scrollHeight);
            }        
            if (badClCluster.length + badSvCluster.length == 0){
                document.querySelector('#outt').textContent += "\n\nLes fichiers sont bien identiques. La table va être effacée. La voici avant effacement :\n";
                for (i=0; i<tabinSv.length; i++){
                    document.querySelector('#outt').textContent += "Bloc n°"+(i+1)+", clef SHA1 = " + tabinSv[i][0].toLowerCase()+ "\n";    
                }
                document.querySelector('#outt').scrollTo(0, document.querySelector('#outt').scrollHeight);
                // effacement de la ligne en table
                var DataToSend = main.RowId.toString(10) + '-' + "delete_" + i + "*";
                var nbLinesDeleted = await part_envoi_data(DataToSend, buff);
                if (nbLinesDeleted == 1){
                    document.querySelector('#outt').textContent += "\n\nLa ligne de ce fichier a bien été effacée de la table ! \n"; 
                } else {
                    document.querySelector('#outt').textContent += "\n\nProblème d'effacement en table (opérez en manuel SVP). \n";
                }
                document.querySelector('#outt').scrollTo(0, document.querySelector('#outt').scrollHeight);
            } else {
                document.querySelector('#outt').textContent += "Il reste des blocs différents ... Relancez SVP !\n"; 
            }

        }                

        async function init() {
            document.querySelector('#inp').onchange = function(e) {
                let fichiersInput = document.querySelector("#inp");
                let fichier = fichiersInput.files[0];
                main.file = fichier;
                main.clust = 1; // par défaut
                let fname = fichier.name;
                let fsize = fichier.size;
                let fdate = fichier.lastModified;
                var dattext = human_date(fdate);
                if(!fichier_en_table_files(fname, fsize, dattext)) {
                    // Considère que c'est la toute première fois
                    // initialise nouveau process
                    document.querySelector('#outt').textContent += "Begin a new process with " + fname;
                    document.querySelector('#textinp').textContent = 'file choosed = ' + fname;
                    return_hash_table(fichier, 0);   // on continue
                } else {
                    var indRep = indof(fname, fsize, dattext);
                    main.RowId = rep[indRep].rowid;
                    if ((rep[indRep]['hex(hashT)'] === undefined) || (rep[indRep]['hex(hashT)'] === '')){
                        // poursuit ... ou valide !
                        document.querySelector('#outt').textContent += "Continue the process with " + fname;
                        return_hash_table(fichier, rep[indRep]['rowid']);
                    } else {                                   // fichier en BdD et avec hashT
                        clust = rep[indRep]['cluster'];
                        main.clust = clust;
                        nbB = clust * Math.pow(2, 20);
                        nbloop = Math.floor(fsize / nbB);
                        rest = fsize % nbB;
                        adeq = 0;
                        if(rest > 0) adeq = 1;
                        hashSv = rep[indRep]['hex(hashT)'];
                        nbclust = hashSv.length / 40;
                        tabinSv = [];
                        for(i = 0; i < nbloop; i++) {
                            tabinSv.push([hashSv.substring(80 * i, (80 * i) + 40), hashSv.substring((80 * i) + 40, 80 * (i + 1))]);
                        }
                        if(adeq == 1) {
                            tabinSv.push([hashSv.substring(80 * nbloop, (80 * nbloop) + 40), hashSv.substring((80 * nbloop) + 40, 80 * (nbloop + 1))]);
                        }
                        //main.tabinSv = tabinSv;
                        asyncFunc(tabinSv);
                    }
                }
            }
        }
        </script>
    </head>

    <body onload="init();">
        <div id="menu">
            <div id="top_of_box" class="top-box"> </div>
            <div id="bidon"></div>
            <div id="entete"> <img id="cornleft" src="data:image/gif;base64, " alt="coingauche" />
                <div id="titre">
                    <h2><a>Big File Update & Verify</a></h2>
                    <p style="text-align:center;">--------------------------------</p>
                <p style="text-align:center;">V2.2 du 27/03/2022 - Contact : ArouG at turbosudoku dot fr</p>
                    <hr /> </div> <img id="cornright" src="data:image/gif;base64, " alt="coindroit" />
                <div><span class="bidon0">&nbsp;</span></div>
            </div>
            <div>
                <div id="choix">
                    <p id="textinp">Choose (again ?) your file to be uploaded :
                        <input id="inp" type="file"> </p>
                </div>
                <br />
                <p id="progressDesc"></p>
                <p id="pgrbar">
                    <progress id='progressBar'></progress>
                </p>
                <textarea id="outt" rows="20" cols="100"></textarea>
            </div>
            <div id="basdepage">
                <hr />
                <div id="gauche">
                    <a href="https://validator.w3.org/check?uri=https://aroug.eu/reparetrace/gere_mnt.php"> <img src="https://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0 Transitional" height="31" width="88" /> </a>
                </div>
                <div id="centrebas">Document soumis à licence <a href="https://creativecommons.org/licenses/by/2.0/fr/">Creative Commons "by"</a></div>
                <div id="droite">
                    <a href="https://jigsaw.w3.org/css-validator/validator?uri=https://aroug.eu/reparetrace/gere_mnt.php"> <img style="border:0;width:88px;height:31px" src="https://jigsaw.w3.org/css-validator/images/vcss" alt="CSS Valide !" /> </a>
                </div>
            </div>
            <form style="display:none;" name="log_out" id="logout" action="bfuv.php" method="post">
                <input type="hidden" name="username" value="toto" />
                <input type="submit" value="log out" /> </form>
        </div>
    </body>

    </html>