<commit_before>#include <config.h>

#include <string.h>

#include "gfileinfo.h"
#include <glib/gi18n-lib.h>

typedef struct  {
  guint32 attribute;
  GFileAttributeType type;
  union {
    gint32 int32;
    guint32 uint32;
    gint64 int64;
    guint64 uint64;
    char *string;
    GQuark quark;
  } value;
} GFileAttributeValue;

struct _GFileInfo
{
  GObject parent_instance;

  GArray *attributes;
};

G_DEFINE_TYPE (GFileInfo, g_file_info, G_TYPE_OBJECT);

typedef struct {
  guint32 id;
  guint32 attribute_id_counter;
} NSInfo;

G_LOCK_DEFINE_STATIC (attribute_hash);
static int namespace_id_counter = 0;
static GHashTable *ns_hash = NULL;
static GHashTable *attribute_hash = NULL;
static char ***attributes = NULL;

/* Attribute ids are 32bit, we split it up like this:
 * |------------|--------------------|
 *   12 bit          20 bit       
 *   namespace      attribute id    
 *
 * This way the attributes gets sorted in namespace order
 */

#define NS_POS 20
#define NS_MASK ((guint32)((1<<12) - 1))
#define ID_POS 0
#define ID_MASK ((guint32)((1<<20) - 1))

#define GET_NS(_attr_id) \
    (((guint32) (_attr_id) >> NS_POS) & NS_MASK)
#define GET_ID(_attr_id) \
    (((guint32)(_attr_id) >> ID_POS) & ID_MASK)

#define MAKE_ATTR_ID(_ns, _id)				\
    ( ((((guint32) _ns) & NS_MASK) << NS_POS) |		\
      ((((guint32) _id) & ID_MASK) << ID_POS) )

static NSInfo *
_lookup_namespace (const char *namespace)
{
  NSInfo *ns_info;
  
  ns_info = g_hash_table_lookup (ns_hash, namespace);
  if (ns_info == NULL)
    {
      ns_info = g_new0 (NSInfo, 1);
      ns_info->id = ++namespace_id_counter;
      g_hash_table_insert (ns_hash, g_strdup (namespace), ns_info);
      attributes = g_realloc (attributes, (ns_info->id + 1) * sizeof (char **));
      attributes[ns_info->id] = NULL;
    }
  return ns_info;
}

static guint32
lookup_namespace (const char *namespace)
{
  NSInfo *ns_info;
  guint32 id;
  
  G_LOCK (attribute_hash);
  
  if (attribute_hash == NULL)
    {
      ns_hash = g_hash_table_new (g_str_hash, g_str_equal);
      attribute_hash = g_hash_table_new (g_str_hash, g_str_equal);
    }

  ns_info = _lookup_namespace (namespace);
  id = 0;
  if (ns_info)
    id = ns_info->id;
  
  G_UNLOCK (attribute_hash);

  return id;
}


static char *
get_attribute_for_id (int attribute)
{
  char *s;
  G_LOCK (attribute_hash);
  s = attributes[GET_NS(attribute)][GET_ID(attribute)];
  G_UNLOCK (attribute_hash);
  return s;
}

static guint32
lookup_attribute (const char *attribute)
{
  guint32 attr_id, id;
  char *ns;
  const char *colon;
  NSInfo *ns_info;
  
  G_LOCK (attribute_hash);
  if (attribute_hash == NULL)
    {
      ns_hash = g_hash_table_new (g_str_hash, g_str_equal);
      attribute_hash = g_hash_table_new (g_str_hash, g_str_equal);
    }

  attr_id = GPOINTER_TO_UINT (g_hash_table_lookup (attribute_hash, attribute));

  if (attr_id != 0)
    {
      G_UNLOCK (attribute_hash);
      return attr_id;
    }

  colon = strchr (attribute, ':');
  if (colon)
    ns = g_strndup (attribute, colon - attribute);
  else
    ns = g_strdup ("");

  ns_info = _lookup_namespace (ns);
  g_free (ns);

  id = ++ns_info->attribute_id_counter;
  attributes[ns_info->id] = g_realloc (attributes[ns_info->id], (id + 1) * sizeof (char *));
  attributes[ns_info->id][id] = g_strdup (attribute);
  
  attr_id = MAKE_ATTR_ID (ns_info->id, id);

  g_hash_table_insert (attribute_hash, attributes[ns_info->id][id], GUINT_TO_POINTER (attr_id));
  
  G_UNLOCK (attribute_hash);
  
  return attr_id;
}

static void
free_attribute_value (GFileAttributeValue *value)
{
      if (value->type == G_FILE_ATTRIBUTE_TYPE_STRING)
	g_free (value->value.string);
}

static void
g_file_info_finalize (GObject *object)
{
  GFileInfo *info;
  int i;
  GFileAttributeValue *values;

  info = G_FILE_INFO (object);

  values = (GFileAttributeValue *)info->attributes->data;
  for (i = 0; i < info->attributes->len; i++)
    free_attribute_value (&values[i]);
  g_array_free (info->attributes, TRUE);  
  
  if (G_OBJECT_CLASS (g_file_info_parent_class)->finalize)
    (*G_OBJECT_CLASS (g_file_info_parent_class)->finalize) (object);
}

static void
g_file_info_class_init (GFileInfoClass *klass)
{<commit_msg>Fix leak of byte strings.<commit_after>#include <config.h>

#include <string.h>

#include "gfileinfo.h"
#include <glib/gi18n-lib.h>

typedef struct  {
  guint32 attribute;
  GFileAttributeType type;
  union {
    gint32 int32;
    guint32 uint32;
    gint64 int64;
    guint64 uint64;
    char *string;
    GQuark quark;
  } value;
} GFileAttributeValue;

struct _GFileInfo
{
  GObject parent_instance;

  GArray *attributes;
};

G_DEFINE_TYPE (GFileInfo, g_file_info, G_TYPE_OBJECT);

typedef struct {
  guint32 id;
  guint32 attribute_id_counter;
} NSInfo;

G_LOCK_DEFINE_STATIC (attribute_hash);
static int namespace_id_counter = 0;
static GHashTable *ns_hash = NULL;
static GHashTable *attribute_hash = NULL;
static char ***attributes = NULL;

/* Attribute ids are 32bit, we split it up like this:
 * |------------|--------------------|
 *   12 bit          20 bit       
 *   namespace      attribute id    
 *
 * This way the attributes gets sorted in namespace order
 */

#define NS_POS 20
#define NS_MASK ((guint32)((1<<12) - 1))
#define ID_POS 0
#define ID_MASK ((guint32)((1<<20) - 1))

#define GET_NS(_attr_id) \
    (((guint32) (_attr_id) >> NS_POS) & NS_MASK)
#define GET_ID(_attr_id) \
    (((guint32)(_attr_id) >> ID_POS) & ID_MASK)

#define MAKE_ATTR_ID(_ns, _id)				\
    ( ((((guint32) _ns) & NS_MASK) << NS_POS) |		\
      ((((guint32) _id) & ID_MASK) << ID_POS) )

static NSInfo *
_lookup_namespace (const char *namespace)
{
  NSInfo *ns_info;
  
  ns_info = g_hash_table_lookup (ns_hash, namespace);
  if (ns_info == NULL)
    {
      ns_info = g_new0 (NSInfo, 1);
      ns_info->id = ++namespace_id_counter;
      g_hash_table_insert (ns_hash, g_strdup (namespace), ns_info);
      attributes = g_realloc (attributes, (ns_info->id + 1) * sizeof (char **));
      attributes[ns_info->id] = NULL;
    }
  return ns_info;
}

static guint32
lookup_namespace (const char *namespace)
{
  NSInfo *ns_info;
  guint32 id;
  
  G_LOCK (attribute_hash);
  
  if (attribute_hash == NULL)
    {
      ns_hash = g_hash_table_new (g_str_hash, g_str_equal);
      attribute_hash = g_hash_table_new (g_str_hash, g_str_equal);
    }

  ns_info = _lookup_namespace (namespace);
  id = 0;
  if (ns_info)
    id = ns_info->id;
  
  G_UNLOCK (attribute_hash);

  return id;
}


static char *
get_attribute_for_id (int attribute)
{
  char *s;
  G_LOCK (attribute_hash);
  s = attributes[GET_NS(attribute)][GET_ID(attribute)];
  G_UNLOCK (attribute_hash);
  return s;
}

static guint32
lookup_attribute (const char *attribute)
{
  guint32 attr_id, id;
  char *ns;
  const char *colon;
  NSInfo *ns_info;
  
  G_LOCK (attribute_hash);
  if (attribute_hash == NULL)
    {
      ns_hash = g_hash_table_new (g_str_hash, g_str_equal);
      attribute_hash = g_hash_table_new (g_str_hash, g_str_equal);
    }

  attr_id = GPOINTER_TO_UINT (g_hash_table_lookup (attribute_hash, attribute));

  if (attr_id != 0)
    {
      G_UNLOCK (attribute_hash);
      return attr_id;
    }

  colon = strchr (attribute, ':');
  if (colon)
    ns = g_strndup (attribute, colon - attribute);
  else
    ns = g_strdup ("");

  ns_info = _lookup_namespace (ns);
  g_free (ns);

  id = ++ns_info->attribute_id_counter;
  attributes[ns_info->id] = g_realloc (attributes[ns_info->id], (id + 1) * sizeof (char *));
  attributes[ns_info->id][id] = g_strdup (attribute);
  
  attr_id = MAKE_ATTR_ID (ns_info->id, id);

  g_hash_table_insert (attribute_hash, attributes[ns_info->id][id], GUINT_TO_POINTER (attr_id));
  
  G_UNLOCK (attribute_hash);
  
  return attr_id;
}

static void
free_attribute_value (GFileAttributeValue *value)
{
      if (value->type == G_FILE_ATTRIBUTE_TYPE_STRING ||
          value->type == G_FILE_ATTRIBUTE_TYPE_BYTE_STRING)
	g_free (value->value.string);
}

static void
g_file_info_finalize (GObject *object)
{
  GFileInfo *info;
  int i;
  GFileAttributeValue *values;

  info = G_FILE_INFO (object);

  values = (GFileAttributeValue *)info->attributes->data;
  for (i = 0; i < info->attributes->len; i++)
    free_attribute_value (&values[i]);
  g_array_free (info->attributes, TRUE);  
  
  if (G_OBJECT_CLASS (g_file_info_parent_class)->finalize)
    (*G_OBJECT_CLASS (g_file_info_parent_class)->finalize) (object);
}

static void
g_file_info_class_init (GFileInfoClass *klass)
{
{'fraction_non_alphanumeric': 0.13015312131919907, 'fraction_numerical': 0.01625441696113074, 'mean_word_length': 3.7303621169916434, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 56, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '3573182', 'n_tokens_mistral': 3316, 'n_tokens_neox': 3190, 'n_words': 700}