Use errno to indicate error in parsing file.
[cascardo/libreceita.git] / decfile.c
index 196f591..98501b1 100644 (file)
--- a/decfile.c
+++ b/decfile.c
 #include <stdlib.h>
 #include <errno.h>
 #include <unistd.h>
+#include <gcrypt.h>
 #include "pmhash.h"
+#include "rnet_message.h"
+
+#ifndef MAX
+#define MAX(a,b) (a >= b) ? a : b
+#endif
 
 struct rnet_decfile {
        char *filename;
@@ -31,6 +37,7 @@ struct rnet_decfile {
        char **lines;
        int lines_len;
        struct pmhash *header;
+       struct rnet_message *message;
 };
 
 /*
@@ -53,7 +60,7 @@ static int append_line(struct rnet_decfile *decfile, char *line)
        return 0;
 out:
        decfile->lines_len -= 1;
-       return -1;
+       return -ENOMEM;
 }
 
 static void decfile_release_lines(struct rnet_decfile *decfile)
@@ -67,12 +74,13 @@ static void decfile_release_lines(struct rnet_decfile *decfile)
 
 static char * get_header(struct rnet_decfile *decfile);
 static int parse_header(struct pmhash *hash, char *buffer);
+static int decfile_parse_file(struct rnet_decfile *decfile);
 
 static int decfile_parse_header(struct rnet_decfile *decfile)
 {
        char *buffer = get_header(decfile);
        if (!buffer || strlen(buffer) != 765)
-               return 1;
+               return -EINVAL;
        return parse_header(decfile->header, buffer);
 }
 
@@ -90,22 +98,26 @@ static int decfile_parse(struct rnet_decfile *decfile)
                buffer = NULL;
                len = 0;
        }
-       if (!decfile_parse_header(decfile))
+       if (!(r = decfile_parse_header(decfile)) && !(r = decfile_parse_file(decfile)))
                return 0;
 out:
        decfile_release_lines(decfile);
-       return -1;
+       return r;
 }
 
 struct rnet_decfile * rnet_decfile_open(char *filename)
 {
        struct rnet_decfile *decfile;
+       int r = -ENOMEM;
        decfile = malloc(sizeof(*decfile));
        if (!decfile)
                return NULL;
        decfile->header = pmhash_new();
        if (!decfile->header)
                goto out_header;
+       decfile->message = rnet_message_new();
+       if (!decfile->message)
+               goto out_message;
        decfile->filename = strdup(filename);
        if (!decfile->filename)
                goto out_filename;
@@ -114,7 +126,7 @@ struct rnet_decfile * rnet_decfile_open(char *filename)
                goto out_file;
        decfile->lines_len = 0;
        decfile->lines = NULL;
-       if (decfile_parse(decfile))
+       if ((r = decfile_parse(decfile)))
                goto out_parse;
        return decfile;
 out_parse:
@@ -122,9 +134,12 @@ out_parse:
 out_file:
        free(decfile->filename);
 out_filename:
+       rnet_message_del(decfile->message);
+out_message:
        pmhash_del(decfile->header);
 out_header:
        free(decfile);
+       errno = -r;
        return NULL;
 }
 
@@ -261,3 +276,76 @@ char *rnet_decfile_get_header_field(struct rnet_decfile *decfile, char *field)
 {
        return pmhash_get(decfile->header, field);
 }
+
+/* returns true if register is declaration and not a receipt */
+static int decfile_reg_is_dec(char *line)
+{
+       if (line[0] >= '0' && line[0] <= '9' &&
+           line[1] >= '0' && line[1] <= '9')
+               return 1;
+       if (!strncmp(line, "IRPF    ", 8))
+               return 1;
+       if (!strncmp(line, "T9", 2))
+               return 1;
+       return 0;
+}
+
+/* strip a register from its control number and append it to message */
+static int append_stripped_reg_ctrl(struct rnet_message **message, char *line)
+{
+       size_t len;
+       struct rnet_message *msg = *message;
+       if (!decfile_reg_is_dec(line))
+               return 0;
+       len = strlen(line);
+       if (len < 12)
+               return -EINVAL;
+       if (msg->alen - msg->len < len) {
+               if (rnet_message_expand(message, MAX(msg->len, len)))
+                       return -ENOMEM;
+               msg = *message;
+       }
+       memcpy(&msg->buffer[msg->len], line, len - 12);
+       msg->buffer[msg->len + len - 12] = '\r';
+       msg->buffer[msg->len + len - 11] = '\n';
+       msg->len += len - 10;
+       return 0;
+}
+
+static int decfile_parse_file(struct rnet_decfile *decfile)
+{
+       int i;
+       int r;
+       for (i = 0; i < decfile->lines_len; i++) {
+               r = append_stripped_reg_ctrl(&decfile->message,
+                                               decfile->lines[i]);
+               if (r)
+                       return r;
+       }
+       return 0;
+}
+
+struct rnet_message * rnet_decfile_get_file(struct rnet_decfile *decfile)
+{
+       return decfile->message;
+}
+
+char * rnet_decfile_get_file_hash(struct rnet_decfile *decfile)
+{
+       char *hash;
+       size_t len;
+       if (gcry_md_test_algo(GCRY_MD_MD5))
+               return NULL;
+       len = gcry_md_get_algo_dlen(GCRY_MD_MD5);
+       hash = malloc(len);
+       if (!hash)
+               return NULL;
+       gcry_md_hash_buffer(GCRY_MD_MD5, hash, decfile->message->buffer,
+                                       decfile->message->len);
+       return hash;
+}
+
+char * rnet_decfile_get_header(struct rnet_decfile *decfile)
+{
+       return get_header(decfile);
+}