Compresser ses sauvegardes smsbackuprestore (android) en c avec smscompress

Description

Bonjour à tous,
nombreuses sont les personnes qui utilisent un logiciel de sauvegarde de SMS avec android et l'un des plus populaire est SMSBackupRestore (source voir tout en bas).
Le souci de celui-ci c'est qu'il créé de multiples sauvegardes et qu'il ne propose pas des les compresser en une seule.
smscompress est un logiciel en cours de développement qui permettra de charger un ou plusieurs fichier de sauvegarde xml, de les ranger et de le faire un seul fichier.
Pour le moment il ne prend pas en compte les multiples erreurs pouvant venir des fichiers&utilisateurs, il est donc à utiliser avec prudence.
Hésitez pas à faire des commentaires ou corriger des choses qui vous choquent.

Source / Exemple :


/*************************

    • SMSCOMPRESS **
    • Version 1.0.0(b) **
    • By Thal-Lab **
    • Where is my mind ? **
                                                  • /
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "loadsms.h" /*
    • Ce programme est un complément à l'application SMSBACKUP.APK, logiciel pour Gphone sous android.
    • Principe :
    • Les sauvegardes se font sur des fichiers XML, qui se cumulent si elles sont faites régulièrement.
    • Entrée : un/des fichier(s) XML,
    • Sorti : Un fichier XML sans doublon rangé par date et d'ordre croissant,
    • Variable : Seront précisés au cours du code source,
    • Le programme se devra d'être le plus simple possible et faire le travail sans trop de complexité,
    • Il pourra accepter de nombreux arguments correspondant aux nombreux fichiers d'entrées.
    • Aucun commentaire sur mon anglais S.V.P. (lol)
  • /
int main(int argc, char *argv[]) { /*
    • Vérification des erreurs d'arguments
    • Le logiciel se fermera si les conditions d'utilisations ne sont pas respéctées, c'est-à-dire :
    • Deux arguments minimum dont :
    • -Le premier la destination de sauvergarde,
    • -Le second la source de sauvegarde
    • Il affichera éventuellement un mini manuelle.
  • /
if(argv[1]== NULL || argv[2] == NULL) { printf("Missing argument error, the program will close.\n"); printf("The application is used as follows:\n" "smscompress destination source1 source2 ... SourceN.\n" "example : smscompress /home/name/jhon-doe.xml /media/gphone/smsbackup/*\n"); return 0; } /*
    • Création de deux variables à allocation dynamique :
    • oldbackup : enregistrement de toutes les sauvegardes de tous les fichiers, sans en-tête,
    • Sans la balise smses.
    • newbackup : Sauvegarde prête à être utilisé et enregistré sur le fichier elle contient :
    • de nouvelles en-têtes et une balise smses contenant le nouveau nombre de sms
    • le tout rangé par ordre chronologique croissant.
    • Les deux variables pèsent au début SIZE_ALLOC octets chacune.
  • /
char *oldbackup = NULL; memmalloc(oldbackup, SIZE_ALLOC);//alloué if (oldbackup == NULL)//Si l'allocation a raté, fin. { printf("Memory allocation problem, the program needs to close.\n"); exit(0); } char *newbackup = NULL; memmalloc(newbackup, SIZE_ALLOC);//alloué if (newbackup == NULL)//Si l'allocation a raté, fin. { printf("Memory allocation problem, the program needs to close.\n"); exit(0); } char select = 0;//Cette variable à pour but de proposer à l'utilisateur des choix /*
    • Vérification de l'existence du fichier de destination
    • Si le fichier existe déjà, le programme demandera alors s'il peut l'écraser
    • Le cas contraire le programme se fermera pour laisser entrer de nouveaux arguments
  • /
FILE *destination = NULL; destination = fopen(argv[1], "rb"); if (destination != NULL) { while(select != 'o') { printf("Do you want to overwrite the file \"%s\"? ", argv[1]); scanf("%c", &select); if(select == 'n') { printf("You do not want to overwrite the file, the program will close.\n"); return 0; } else if(select == 'o') { destination = fopen(argv[1], "wb+"); if(destination == NULL) { printf("Error writing file, the program will close."); return 0; } else { printf("Writing the file was successful.\n"); } } else { select = 0; } } } else { destination = fopen(argv[1], "wb+"); if(destination == NULL) { printf("Error writing file, the program will close."); return 0; } } /*
    • Boucle de vérification d'existence des arguments
    • Ici le programme ne s'arrêtera pas si les sources sont mauvaises, il passera simplement à une autre
    • Si toutes les sources sont mauvaises, que la sauvegarde n'a pas lieu, le programme fera simplement une sauvegarde vide.
    • Dans la boucle i est initialisé à 2, car :
    • -Argument 0 : nom du programme,
    • -Argument 1 : nom de destination,
    • -Argument 2 : nom de la première source.
  • /
int i,//Variable de boucle for i, non initialisée j,//Variable de boucle non définie k,//Variable de boucle non définie gchar,//lecteur de caractère pour la fonction fgetc sizebackup = 0;//Evite des débordements mémoire /*
    • Ce buffer contient une balise sms entière, estimé par ce calcul à :
    • size_buffer = ( 160 * 50 ) + ( 160 * 10 ), large
  • /
char buffer[SIZE_BUFFER * sizeof(char)]; /*
    • Déclaration de la structure IntElementSMS
    • Elle servira à de multiple tache de manipulation
    • Déclaration de la structure d'allocation de mémoire
    • Initialisation de la variable memtest à 1 car 1 fois SIZE_ALLOC ont été alloué
  • /
ElementSMS sms; int memtest = 1; sms.countsms = 0; for(i = 2; i<= argc-1; i++) { /*
    • Prépraration du fichier source suivi de la vérification de son existence
    • En cas d'erreur le programme continue la boucle en attendant qu'il n'y ai plus d'argument(s)
    • Si aucune erreur se fait, lancement de la compression des fichiers.
  • /
FILE *source = NULL; printf("Opening of \"%s\", ",argv[i]);//Affichage à l'utilisateur de l'avancement source = fopen(argv[i], "rb+"); if(source == NULL || extension(argv[i]) != 1) { /*
    • Le programme donnera seulement l'argument erroné et la ligne lui correspondant
    • En fin de boucle le programme relancera soit un autre argument,
    • Soit il finira l'enregistrement.
  • /
printf("The file does not exist and/or extend is bad, argument \"%s\" number %d is not valide \n", argv[i], i); } else { printf("Current reading, ");//Affichage à l'utilisateur de l'avancement j = 0,//Boucle non défini, on met j à 0 k = 0,//Boucle non défini, on met k à 0 initElementSMS(&sms); initab(buffer, SIZE_BUFFER); /*
    • Cette boucle va permettre de supprimer les balise d'en-tête
    • Et ranger de manière compressé la sauvegarde
  • /
do { gchar = fgetc(source);//Lecture du caractère if(gchar == '<' || sms.openbalise == TRUE)//Si la balise s'ouvre ou si la balise est déjà ouverte { sms.openbalise =TRUE; buffer[j++] = gchar;//mise dans le buffer if(cmp_b(buffer,"<?xml",5) == 0 && sms.headxml == FALSE && sms.balisesmses == FALSE)//Détection de la balise <? ?> { /*
    • Suppression de cette balise qui peut-être handicapant pour la suite
    • Elle n'est plus utile le temps de la compression
  • /
while(gchar != '>') { gchar = fgetc(source); } sms.headxml = TRUE; j -= 5; } if(cmp_b(buffer,"<smses",6) == 0 && sms.balisesmses == FALSE && sms.headxml == TRUE) { /*
    • Suppression de la balise <smses>
    • Elle n'est plus utile le temps de la compression
  • /
while(gchar != '>') { gchar = fgetc(source); } sms.balisesmses = TRUE; j -= 6; } if(cmp_b(buffer,"<sms ",5) == 0 && sms.headxml == TRUE && sms.balisesmses == TRUE) { while(gchar != '>') { gchar = fgetc(source); buffer[j++] = gchar; } } if(cmp_b(buffer,"</smses>",8) == 0 && sms.balisesmses == TRUE && sms.headxml == TRUE) { /*
    • Suppression de la balise </smses>
    • Elle n'est plus utile le temps de la compression
  • /
j -= 8; } } if(gchar == '>' && sms.openbalise == TRUE) { /*
    • Le programme ferme le buffer par \0
    • Il augmente la taille de oldbackup
    • Il réallou autant que nécessaire la mémoire
  • /
buffer[j*sizeof(char*)]='\0';//ça parrait bête mais parfois ça sauve un bug ! sms.bufferint = readargdate(buffer); if(sms.bufferint != ERROR_F && sms.headxml == TRUE && sms.balisesmses == TRUE) { if((single(sms.dateorder, sms.countsms, sms.bufferint)) == TRUE) { sms.dateorder[sms.countsms++] = sms.bufferint; sizebackup += j; while(((memtest)*(SIZE_ALLOC))>=(sizebackup)) { memrealloc(oldbackup, memtest++);//Réalouer (SIZE_ALLOC * 4) Octet } sprintf(oldbackup, "%s%s",oldbackup, buffer); } } j = 0, sms.openbalise = FALSE; } }while(gchar != EOF); printf("0k.\n"); } close(source); } printf("Storing date in ascending order during...\n"); ascendingdate(sms.dateorder, sms.countsms); /*
    • Le tri des sms ne peut se faire en une fois, ça rendrait le programme trop lourd à écrire x)
    • La boucle rangera les sms gràce dateorder dans newbackup
    • Un allocation dynamique sera faite sur newbackup en début de programme
    • il ne sera plus question ensuite de la remodifier, realloc étant trop gourmand
    • La taille de realloc est de la taille de oldbackup + le nombre de sms x 3 c'est attire, deux espace et un \n
    • Et de MAX_BALISE une estimation de la taille des balises restantent
    • La fonction est un peu désorganisée mais elle fonctionne, c'est important !
  • /
printf("loading ...\n"); memnewrealloc(newbackup, ((strlen(oldbackup) + MAX_BALISE + (sms.countsms * 3)))); initElementSMS(&sms); sms.bufferint = 0, newbackup[0] = '\0'; printf("Text Analysis in progress ...\n"); for(k = 0; k <= sms.countsms; k++) { i = 0, j = 0; while(sms.dateorder[k] != sms.bufferint) { if(oldbackup[i] == '<' || sms.openbalise == TRUE) { sms.openbalise = TRUE; buffer[j++] = oldbackup[i]; } if(oldbackup[i] == '>' && sms.openbalise == TRUE) { sms.openbalise = FALSE; buffer[j] = '\0'; sms.bufferint = readargdate(buffer); if(sms.dateorder[k] == sms.bufferint) { sprintf(newbackup, "%s %s\n", newbackup, buffer);//on note bien la préparation au nouveau fichier XML } j = 0; } i++; } } free(oldbackup);//Libèration de la mémoire oldbackup = NULL;//Forcer /*
    • Fermeture du programme
    • Libération de la mémoire
  • /
printf("Writing the new xml file ...\n"); fprintf(destination,"%s%s%d%s%s%s", HEAD, BODY_SMSES, sms.countsms, BODY_SMSES_CLOSE, newbackup, BODY_END_SMSES);//on remarque l'ajout des balises close(destination); free(newbackup); newbackup = NULL; printf("Finish, you have analyzed %d SMS. The program will close, bye.\n", sms.countsms); return 0; } /***************************************************************************************************************************************/ //loadsms.c /***************************************************************************************************************************************/ #include <string.h> #include "loadsms.h" //Initialiser un tableau char à 0 sur n caractère. void initab(char tab[], int n) { int i; for(i = 0 ;i <= n; i++) { tab[i] = 0; } } /*
    • La fonction va changer un char en int
    • Cette fonction à pour but de lire un attribut "date" écrit dans le buffer
    • Elle revoit un int et avec la formule : n = (n * 10) + chartoint
    • On convertira un string en int facilement.
  • /
int chartoint(int charint) { if(charint=='0') return 0; if(charint=='1') return 1; if(charint=='2') return 2; if(charint=='3') return 3; if(charint=='4') return 4; if(charint=='5') return 5; if(charint=='6') return 6; if(charint=='7') return 7; if(charint=='8') return 8; if(charint=='9') return 9; return -1; } //Cette fonction range par ordre croissant les dates void ascendingdate(double tab[], int max) { int i,j; for(i = 0; i <= (max - 1); i++) { for(j = 0 + 1; j <= (max - 1); j++) if(tab[i] < tab[j]) { exchange(tab, i, j); } if(tab[i] > tab[j]) { exchange(tab, j, i); } } } /*
    • Cette fonction va vérifier si dans un table une valeur est unique
    • La fonction renverra TRUE si c'est vérifié ou FALSE si cela n'est pas
  • /
int single(double tab[], int max, double singlevaleur) { int i; for(i = 0; i <= max; i++) { if(singlevaleur == tab[i]) { return FALSE; } } return TRUE; } /*
    • Ce tableau permet de lire et analyser l'attribut "date" dans le buffer
    • La fonction peut prendre énormement de temps
    • Elle renvoie -1 si il y a une erreur ou la valeur de la date si ça se passe bien
  • /
double readargdate(char tab[]) { int i, j; double n = 0; for(i = 0; (strncmp((tab + i), "date=\"", 6)) != 0; i++) { if(tab[i] == '\0') { return ERROR_F; } } for(j = i + 6; tab[j] != '"'; j++) { if(chartoint(tab[j]) == ERROR_F) { return ERROR_F; } n = (n * 10) + chartoint(tab[j]); } return n; } //Echanger la valeur b/a et a/b dans le tableau void exchange(double tab[], int a, int b) { double n; n = tab[a]; tab[a] = tab[b]; tab[b] = n; } /*
    • Fonction pour initialiser la structure ElementSMS, pointeur utile ici.
    • openbalise : Ouverture(TRUE) de balise (<) et fermeture(FALSE) de balise (>).
    • openvar : Ouverture(TRUE) de valeur d'attrivut (<) et fermeture(FALSE) de valeur d'attribut (>).
    • headxml : Balise d'en-tête <?xml version='1.0' encoding='UTF-8' standalone='yes' ?> croisé ou non.
  • balisesmses : Balise <smses/> croisé ou non.
  • /
void initElementSMS(ElementSMS *tmp) { tmp->openbalise = FALSE, tmp->openvar = FALSE, tmp->headxml = FALSE, tmp->balisesmses = FALSE; } //Fonction pour la lecture des extensions et éliminer les fichiers non XML, peut-on faire plus simple ? int extension(char *ext) { int i = strlen(ext); if(strcmp((ext + i - 4), ".xml") == 0 || strcmp((ext + i - 4), ".XML") == 0) { return TRUE; } return FALSE; } /*
    • Fonction pour la lecture des balises moins performante que strncmp mais évite un bug de la fonction
    • c'est moche de faire strncmp à sa "sauce".
  • /
int cmp_b(const char *s1, const char *s2, int sizechar) { int i; for(i = 0;((*s1++) == (*s2++)); ++i) { if(i == sizechar) { for(;((*s1--) == (*s2--));--i) { if(i <= 0) { return TRUE; } } } } return FALSE; } /***************************************************************************************************************************************/ //loadsms.h /***************************************************************************************************************************************/ #ifndef EXPORTSMS_H #define EXPORTSMS_H #include <stdlib.h> //Booléens très utile #define FALSE 0 #define TRUE 1 /*
    • Ces variables vont définir la taille du buffer
    • On prend 160 la taille maximum d'un SMS
    • On suppose que les messages de 50 sont le maximum qu'un utilisateur va envoyé
    • On suppose aussi que les balises et leur contenu seront de la taille de :
    • 10 SMS au maximum. Le tout est large.
  • /
#define SIZE_SMS 160 #define SEND_SMS 50 #define SIZE_BALISE (SIZE_SMS * 10) #define SIZE_BUFFER ((SIZE_SMS * SEND_SMS) + SIZE_BALISE) /*
    • Définition des mémoires utilisées
    • Diverses macros pour l'allocation et la réallocation
  • /
#define MAX_BALISE 1024 #define SIZE_ALLOC 16384 #define DATE_ORDER 200000 //ça represente quand même 200k SMS, c'est énorme #define memmalloc(var, n)((var) = malloc((n) * (sizeof(*var)))) #define memrealloc(var, n)((var) = realloc((var), ((n) * (SIZE_ALLOC)) * (sizeof(*var)))) #define memnewrealloc(var, n)((var) = realloc((var), ((n) * (sizeof(*var))))) /*
    • Définition de constante pour la création de la nouvelle sauvegarde
    • Pour le moment elles sont peu nombreuse
  • /
#define HEAD "<?xml version=\'1.0\' encoding=\'UTF-8\' standalone=\'yes' ?>\n" #define BODY_SMSES "<smses count=\"" #define BODY_END_SMSES "</smses>" #define BODY_SMSES_CLOSE "\">\n" //les erreurs possibles #define ERROR_F -1 /*
    • Structure pour la gestion des SMS :
    • openbalise, Variable permettant de savoir si une balise est ouverte ou non
    • openvar, Variable permettant de savoir si un attribut est cours de lecture ou non
    • headxml, Variable d'en-tête de balise, si elle a été vu ou non (<? ?>)
    • countsms, Variable pour compter le nombre de SMS traité et prêt à être enregistrée
    • balisesmses, Balise <smses/> lu ou non.
  • /
typedef struct ElementSMS{ int openbalise, openvar, headxml, countsms, balisesmses; double dateorder[DATE_ORDER], bufferint; }ElementSMS; //Header de fonction void initab(char tab[], int n); int chartoint(int charint); void ascendingdate(double tab[], int max); int single(double tab[], int max, double singlevaleur); double readargdate(char tab[]); void exchange(double tab[], int a, int b); void initElementSMS(ElementSMS *tmp); int extension(char *ext); int cmp_b(const char *s1, const char *s2, int sizechar); #endif

Conclusion :


J'ai vu beaucoup de genre chercher à savoir comment lire une balise XML en C, ici il y a une réponse.
Si des améliorations sont possibles (et il y en a !), vous gênez pas :).

Logiciel smsbackup&restore:
http://android.riteshsahu.com/apps/sms-backup-restore

Thal-Lab.

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.