<commit_before>/*  =========================================================================
    fmq_patch - work with directory patches
    A patch is a change to the directory (create/delete/resize/retime).

    -------------------------------------------------------------------------
    Copyright (c) 1991-2012 iMatix Corporation -- http://www.imatix.com
    Copyright other contributors as noted in the AUTHORS file.

    This file is part of FILEMQ, see http://filemq.org.

    This is free software; you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License as published by the
    Free Software Foundation; either version 3 of the License, or (at your
    option) any later version.

    This software is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTA-
    BILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
    Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program. If not, see http://www.gnu.org/licenses/.
    =========================================================================
*/

/*
@header
    The fmq_patch class works with one patch, which really just says "create
    this file" or "delete this file" (referring to a zfile item each time).
@discuss
@end
*/

#include <czmq.h>
#include "../include/fmq.h"

//  Structure of our class
//  If you modify this beware to also change _dup

struct _fmq_patch_t {
    char *path;                 //  Directory path
    char *virtual;              //  Virtual file name
    zfile_t *file;           //  File we refer to
    fmq_patch_op_t op;          //  Operation
    char *digest;               //  File SHA-1 digest
};


//  --------------------------------------------------------------------------
//  Constructor
//  Create new patch, create virtual path from alias

fmq_patch_t *
fmq_patch_new (char *path, zfile_t *file, fmq_patch_op_t op, char *alias)
{
    fmq_patch_t *self = (fmq_patch_t *) zmalloc (sizeof (fmq_patch_t));
    self->path = strdup (path);
    self->file = zfile_dup (file);
    self->op = op;
    
    //  Calculate virtual filename for patch (remove path, prefix alias)
    char *filename = zfile_filename (file, path);
    assert (*filename != '/');
    self->virtual = malloc (strlen (alias) + strlen (filename) + 2);
    if (alias [strlen (alias) - 1] == '/')
        sprintf (self->virtual, "%s%s", alias, filename);
    else
        sprintf (self->virtual, "%s/%s", alias, filename);
    
    return self;
}


//  --------------------------------------------------------------------------
//  Destroy a patch

void
fmq_patch_destroy (fmq_patch_t **self_p)
{
    assert (self_p);
    if (*self_p) {
        fmq_patch_t *self = *self_p;
        free (self->path);
        free (self->virtual);
        free (self->digest);
        zfile_destroy (&self->file);
        free (self);
        *self_p = NULL;
    }
}


//  --------------------------------------------------------------------------
//  Create copy of a patch

fmq_patch_t *
fmq_patch_dup (fmq_patch_t *self)
{
    fmq_patch_t *copy = (fmq_patch_t *) zmalloc (sizeof (fmq_patch_t));
    copy->path = strdup (self->path);
    copy->file = zfile_dup (self->file);
    copy->op = self->op;
    copy->virtual = strdup (self->virtual);
    //  Don't recalculate hash when we duplicate patch
    copy->digest = self->digest? strdup (self->digest): NULL;
    return copy;
}


//  --------------------------------------------------------------------------
//  Return patch file directory path

char *
fmq_patch_path (fmq_patch_t *self)
{
    assert (self);
    return self->path;
}


//  --------------------------------------------------------------------------
//  Return patch file item

zfile_t *
fmq_patch_file (fmq_patch_t *self)
{
    assert (self);
    return self->file;
}


//  --------------------------------------------------------------------------
//  Return operation

fmq_patch_op_t
fmq_patch_op (fmq_patch_t *self)
{
    assert (self);
    return self->op;
}


//  --------------------------------------------------------------------------
//  Return patch virtual file name

char *
fmq_patch_virtual (fmq_patch_t *self)
{
    assert (self);
    return self->virtual;
}


//  Return file SHA-1 hash as string; caller has to free it
//  TODO: this has to be moved into CZMQ along with SHA1 and hash class

static char *
s_file_hash (zfile_t *file)
{
    if (zfile_input (file) == -1)
        return NULL;            //  Problem reading directory

    //  Now calculate hash for file data, chunk by chunk
    size_t blocksz = 65535;
    off_t offset = 0;
    fmq_hash_t *hash = fmq_hash_new ();
    zchunk_t *chunk = zfile_read (file, blocksz, offset);
    while (zchunk_size (chunk)) {
        fmq_hash_update (hash, zchunk_data (chunk), zchunk_size (chunk));
        zchunk_destroy (&chunk);
        offset += blocksz;
        chunk = zfile_read (file, blocksz, offset);
    }
    zchunk_destroy (&chunk);
    zfile_close (file);

    //  Convert to printable string
    char hex_char [] = "0123456789ABCDEF";
    char *hashstr = zmalloc (fmq_hash_size (hash) * 2 + 1);
    int byte_nbr;
    for (byte_nbr = 0; byte_nbr < fmq_hash_size (hash); byte_nbr++) {
        hashstr [byte_nbr * 2 + 0] = hex_char [fmq_hash_data (hash) [byte_nbr] >> 4];
        hashstr [byte_nbr * 2 + 1] = hex_char [fmq_hash_data (hash) [byte_nbr] & 15];<commit_msg>Rename member variable virtual to virtualf for MSVC, explicit type casting<commit_after>/*  =========================================================================
    fmq_patch - work with directory patches
    A patch is a change to the directory (create/delete/resize/retime).

    -------------------------------------------------------------------------
    Copyright (c) 1991-2012 iMatix Corporation -- http://www.imatix.com
    Copyright other contributors as noted in the AUTHORS file.

    This file is part of FILEMQ, see http://filemq.org.

    This is free software; you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License as published by the
    Free Software Foundation; either version 3 of the License, or (at your
    option) any later version.

    This software is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTA-
    BILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
    Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program. If not, see http://www.gnu.org/licenses/.
    =========================================================================
*/

/*
@header
    The fmq_patch class works with one patch, which really just says "create
    this file" or "delete this file" (referring to a zfile item each time).
@discuss
@end
*/

#include <czmq.h>
#include "../include/fmq.h"

//  Structure of our class
//  If you modify this beware to also change _dup

struct _fmq_patch_t {
    char *path;                 //  Directory path
    char *virtualf;              //  Virtual file name
    zfile_t *file;           //  File we refer to
    fmq_patch_op_t op;          //  Operation
    char *digest;               //  File SHA-1 digest
};


//  --------------------------------------------------------------------------
//  Constructor
//  Create new patch, create virtual path from alias

fmq_patch_t *
fmq_patch_new (char *path, zfile_t *file, fmq_patch_op_t op, char *alias)
{
    fmq_patch_t *self = (fmq_patch_t *) zmalloc (sizeof (fmq_patch_t));
    self->path = strdup (path);
    self->file = zfile_dup (file);
    self->op = op;
    
    //  Calculate virtual filename for patch (remove path, prefix alias)
    char *filename = zfile_filename (file, path);
    assert (*filename != '/');
    self->virtualf = (char*)malloc (strlen (alias) + strlen (filename) + 2);
    if (alias [strlen (alias) - 1] == '/')
        sprintf (self->virtualf, "%s%s", alias, filename);
    else
        sprintf (self->virtualf, "%s/%s", alias, filename);
    
    return self;
}


//  --------------------------------------------------------------------------
//  Destroy a patch

void
fmq_patch_destroy (fmq_patch_t **self_p)
{
    assert (self_p);
    if (*self_p) {
        fmq_patch_t *self = *self_p;
        free (self->path);
        free (self->virtualf);
        free (self->digest);
        zfile_destroy (&self->file);
        free (self);
        *self_p = NULL;
    }
}


//  --------------------------------------------------------------------------
//  Create copy of a patch

fmq_patch_t *
fmq_patch_dup (fmq_patch_t *self)
{
    fmq_patch_t *copy = (fmq_patch_t *) zmalloc (sizeof (fmq_patch_t));
    copy->path = strdup (self->path);
    copy->file = zfile_dup (self->file);
    copy->op = self->op;
    copy->virtualf = strdup (self->virtualf);
    //  Don't recalculate hash when we duplicate patch
    copy->digest = self->digest? strdup (self->digest): NULL;
    return copy;
}


//  --------------------------------------------------------------------------
//  Return patch file directory path

char *
fmq_patch_path (fmq_patch_t *self)
{
    assert (self);
    return self->path;
}


//  --------------------------------------------------------------------------
//  Return patch file item

zfile_t *
fmq_patch_file (fmq_patch_t *self)
{
    assert (self);
    return self->file;
}


//  --------------------------------------------------------------------------
//  Return operation

fmq_patch_op_t
fmq_patch_op (fmq_patch_t *self)
{
    assert (self);
    return self->op;
}


//  --------------------------------------------------------------------------
//  Return patch virtual file name

char *
fmq_patch_virtual (fmq_patch_t *self)
{
    assert (self);
    return self->virtualf;
}


//  Return file SHA-1 hash as string; caller has to free it
//  TODO: this has to be moved into CZMQ along with SHA1 and hash class

static char *
s_file_hash (zfile_t *file)
{
    if (zfile_input (file) == -1)
        return NULL;            //  Problem reading directory

    //  Now calculate hash for file data, chunk by chunk
    size_t blocksz = 65535;
    off_t offset = 0;
    fmq_hash_t *hash = fmq_hash_new ();
    zchunk_t *chunk = zfile_read (file, blocksz, offset);
    while (zchunk_size (chunk)) {
        fmq_hash_update (hash, zchunk_data (chunk), zchunk_size (chunk));
        zchunk_destroy (&chunk);
        offset += blocksz;
        chunk = zfile_read (file, blocksz, offset);
    }
    zchunk_destroy (&chunk);
    zfile_close (file);

    //  Convert to printable string
    char hex_char [] = "0123456789ABCDEF";
    char *hashstr = (char*)zmalloc (fmq_hash_size (hash) * 2 + 1);
    int byte_nbr;
    for (byte_nbr = 0; byte_nbr < fmq_hash_size (hash); byte_nbr++) {
        hashstr [byte_nbr * 2 + 0] = hex_char [fmq_hash_data (hash) [byte_nbr] >> 4];
        hashstr [byte_nbr * 2 + 1] = hex_char [fmq_hash_data (hash) [byte_nbr] & 15];
{'fraction_non_alphanumeric': 0.22796952039444196, 'fraction_numerical': 0.007350963693411027, 'mean_word_length': 1.9044519656339496, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 59, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3987223', 'n_tokens_mistral': 3352, 'n_tokens_neox': 3220, 'n_words': 1057}