<commit_before>/**
 * \file playlist-spl.c
 *
 * Playlist_t to Samsung (.spl) and back conversion functions.
 *
 * Copyright (C) 2008 <NAME> <<EMAIL>>
 *
 * This library 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 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY 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 library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <stdio.h>
#include <stdlib.h> // mkstmp()
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <fcntl.h>

#include <string.h>

#include "libmtp.h"
#include "libusb-glue.h"
#include "ptp.h"
#include "unicode.h"

#include "playlist-spl.h"

// set this to 1 to add lots of messy debug output to the playlist code
#define DEBUG_ENABLED 0

// debug macro
// d = indenting depth
#define IF_DEBUG() if(DEBUG_ENABLED) {\
                     printf("%s:%u:%s(): ", __FILE__, __LINE__, __func__); \
                   } \
                   if(DEBUG_ENABLED)

// Internal singly linked list of strings
// used to hold .spl playlist in memory
typedef struct text_struct {
  char* text; // String
  struct text_struct *next; // Link to next line, NULL if end of list
} text_t;


/**
 * Forward declarations of local (static) functions.
 */
static text_t* read_into_spl_text_t(LIBMTP_mtpdevice_t *device, const int fd);
static void write_from_spl_text_t(LIBMTP_mtpdevice_t *device, const int fd, text_t* p);
static void free_spl_text_t(text_t* p);
static void print_spl_text_t(text_t* p);
static uint32_t trackno_spl_text_t(text_t* p);
static void tracks_from_spl_text_t(text_t* p, uint32_t* tracks, LIBMTP_folder_t* folders, LIBMTP_file_t* files);
static void spl_text_t_from_tracks(text_t** p, uint32_t* tracks, const uint32_t trackno, const uint32_t ver_major, const uint32_t ver_minor, char* dnse, LIBMTP_folder_t* folders, LIBMTP_file_t* files);

static uint32_t discover_id_from_filepath(const char* s, LIBMTP_folder_t* folders, LIBMTP_file_t* files); // TODO add file/dir cached args
static void discover_filepath_from_id(char** p, uint32_t track, LIBMTP_folder_t* folders, LIBMTP_file_t* files);
static void find_folder_name(LIBMTP_folder_t* folders, uint32_t* id, char** name);
static uint32_t find_folder_id(LIBMTP_folder_t* folders, uint32_t parent, char* name);

static void append_text_t(text_t** t, char* s);




/**
 * Decides if the indicated object index is an .spl playlist.
 *
 * @param oi object we are deciding on
 * @return 1 if this is a Samsung .spl object, 0 otherwise
 */
int is_spl_playlist(PTPObjectInfo *oi)
{
  return (oi->ObjectFormat == PTP_OFC_Undefined) &&
         (strlen(oi->Filename) > 4) &&
         (strcmp((oi->Filename + strlen(oi->Filename) -4), ".spl") == 0);
}

/**
 * Take an object ID, a .spl playlist on the MTP device,
 * and convert it to a playlist_t object.
 *
 * @param device mtp device pointer
 * @param oi object we are reading
 * @param id .spl playlist id on MTP device
 * @param pl the LIBMTP_playlist_t pointer to be filled with info from id
 */

void spl_to_playlist_t(LIBMTP_mtpdevice_t* device, PTPObjectInfo *oi,
                       const uint32_t id, LIBMTP_playlist_t * const pl)
{
  // Fill in playlist metadata
  // Use the Filename as the playlist name, dropping the ".spl" extension
  pl->name = malloc(sizeof(char)*(strlen(oi->Filename) -4 +1));
  memcpy(pl->name, oi->Filename, strlen(oi->Filename) -4);
  pl->playlist_id = id;
  pl->parent_id = oi->ParentObject;
  pl->storage_id = oi->StorageID;
  pl->tracks = NULL;
  pl->no_tracks = 0;

  IF_DEBUG() printf("pl->name='%s'\n",pl->name);

  // open a temporary file
  char tmpname[] = "/tmp/mtp-spl2pl-XXXXXX";
  int fd = mkstemp(tmpname);
  if(fd < 0) {
    printf("failed to make temp file for %s.spl -> %s, errno=%s\n", pl->name, tmpname, strerror(errno));
    return;
  }
  // make sure the file will be deleted afterwards<commit_msg>Set terminating character for playlist name string<commit_after>/**
 * \file playlist-spl.c
 *
 * Playlist_t to Samsung (.spl) and back conversion functions.
 *
 * Copyright (C) 2008 <NAME> <<EMAIL>>
 *
 * This library 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 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY 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 library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <stdio.h>
#include <stdlib.h> // mkstmp()
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <fcntl.h>

#include <string.h>

#include "libmtp.h"
#include "libusb-glue.h"
#include "ptp.h"
#include "unicode.h"

#include "playlist-spl.h"

// set this to 1 to add lots of messy debug output to the playlist code
#define DEBUG_ENABLED 0

// debug macro
// d = indenting depth
#define IF_DEBUG() if(DEBUG_ENABLED) {\
                     printf("%s:%u:%s(): ", __FILE__, __LINE__, __func__); \
                   } \
                   if(DEBUG_ENABLED)

// Internal singly linked list of strings
// used to hold .spl playlist in memory
typedef struct text_struct {
  char* text; // String
  struct text_struct *next; // Link to next line, NULL if end of list
} text_t;


/**
 * Forward declarations of local (static) functions.
 */
static text_t* read_into_spl_text_t(LIBMTP_mtpdevice_t *device, const int fd);
static void write_from_spl_text_t(LIBMTP_mtpdevice_t *device, const int fd, text_t* p);
static void free_spl_text_t(text_t* p);
static void print_spl_text_t(text_t* p);
static uint32_t trackno_spl_text_t(text_t* p);
static void tracks_from_spl_text_t(text_t* p, uint32_t* tracks, LIBMTP_folder_t* folders, LIBMTP_file_t* files);
static void spl_text_t_from_tracks(text_t** p, uint32_t* tracks, const uint32_t trackno, const uint32_t ver_major, const uint32_t ver_minor, char* dnse, LIBMTP_folder_t* folders, LIBMTP_file_t* files);

static uint32_t discover_id_from_filepath(const char* s, LIBMTP_folder_t* folders, LIBMTP_file_t* files); // TODO add file/dir cached args
static void discover_filepath_from_id(char** p, uint32_t track, LIBMTP_folder_t* folders, LIBMTP_file_t* files);
static void find_folder_name(LIBMTP_folder_t* folders, uint32_t* id, char** name);
static uint32_t find_folder_id(LIBMTP_folder_t* folders, uint32_t parent, char* name);

static void append_text_t(text_t** t, char* s);




/**
 * Decides if the indicated object index is an .spl playlist.
 *
 * @param oi object we are deciding on
 * @return 1 if this is a Samsung .spl object, 0 otherwise
 */
int is_spl_playlist(PTPObjectInfo *oi)
{
  return (oi->ObjectFormat == PTP_OFC_Undefined) &&
         (strlen(oi->Filename) > 4) &&
         (strcmp((oi->Filename + strlen(oi->Filename) -4), ".spl") == 0);
}

/**
 * Take an object ID, a .spl playlist on the MTP device,
 * and convert it to a playlist_t object.
 *
 * @param device mtp device pointer
 * @param oi object we are reading
 * @param id .spl playlist id on MTP device
 * @param pl the LIBMTP_playlist_t pointer to be filled with info from id
 */

void spl_to_playlist_t(LIBMTP_mtpdevice_t* device, PTPObjectInfo *oi,
                       const uint32_t id, LIBMTP_playlist_t * const pl)
{
  // Fill in playlist metadata
  // Use the Filename as the playlist name, dropping the ".spl" extension
  pl->name = malloc(sizeof(char)*(strlen(oi->Filename) -4 +1));
  memcpy(pl->name, oi->Filename, strlen(oi->Filename) -4);
  // Set terminating character
  pl->name[strlen(oi->Filename) - 4] = 0;
  pl->playlist_id = id;
  pl->parent_id = oi->ParentObject;
  pl->storage_id = oi->StorageID;
  pl->tracks = NULL;
  pl->no_tracks = 0;

  IF_DEBUG() printf("pl->name='%s'\n",pl->name);

  // open a temporary file
  char tmpname[] = "/tmp/mtp-spl2pl-XXXXXX";
  int fd = mkstemp(tmpname);
  if(fd < 0) {
    printf("failed to make temp file for %s.spl -> %s, errno=%s\n", pl->name, tmpname, strerror(errno));
    return;
  }
  // make sure the file will be deleted afterwards
{'fraction_non_alphanumeric': 0.11318435754189944, 'fraction_numerical': 0.012737430167597765, 'mean_word_length': 3.915431081823174, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 71, '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': '1732686', 'n_tokens_mistral': 3144, 'n_tokens_neox': 2974, 'n_words': 1019}