예제 #1
0
파일: command.c 프로젝트: daaang/mpc
int
cmd_listall(int argc, char **argv, struct mpd_connection *conn)
{
	const char * listall = "";
	int i = 0;

	if (argc > 0)
		listall = charset_to_utf8(argv[i]);

	do {
		char *tmp = strdup(listall);
		strip_trailing_slash(tmp);

		if (options.custom_format) {
			if (!mpd_send_list_all_meta(conn, tmp))
				printErrorAndExit(conn);

			print_entity_list(conn, MPD_ENTITY_TYPE_UNKNOWN);
		} else {
			if (!mpd_send_list_all(conn, tmp))
				printErrorAndExit(conn);

			print_filenames(conn);
		}

		my_finishCommand(conn);
		free(tmp);
	} while (++i < argc && (listall = charset_to_utf8(argv[i])) != NULL);

	return 0;
}
예제 #2
0
int cmd_ls ( int argc, char ** argv, mpd_Connection * conn )
{
	mpd_InfoEntity * entity;
	const char *ls;
	int i = 0;

	if (argc > 0)
		ls = charset_to_utf8(argv[i]);
	else
		ls = strdup("");

	do {
		mpd_sendLsInfoCommand(conn,ls);
		printErrorAndExit(conn);

		while((entity = mpd_getNextInfoEntity(conn))) {
			if(entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY) {
				mpd_Directory * dir = entity->info.directory;
				printf("%s\n", charset_from_utf8(dir->path));
			}
			else if(entity->type==MPD_INFO_ENTITY_TYPE_SONG) {
				struct mpd_song *song = entity->info.song;
				printf("%s\n", charset_from_utf8(song->file));
			}
			mpd_freeInfoEntity(entity);
		}

		my_finishCommand(conn);

	} while (++i < argc && (ls = charset_to_utf8(argv[i])) != NULL);

	return 0;
}
예제 #3
0
int cmd_lsplaylists ( int argc, char ** argv, mpd_Connection * conn )
{
	mpd_InfoEntity * entity;
	const char * ls = "";
	int i = 0;

	if(argc>0) ls = charset_to_utf8(argv[i]);

	do {
		mpd_sendLsInfoCommand(conn,ls);
		printErrorAndExit(conn);

		while((entity = mpd_getNextInfoEntity(conn))) {
			if(entity->type==
					MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
				mpd_PlaylistFile * pl = entity->info.playlistFile;
				printf("%s\n", charset_from_utf8(pl->path));
			}
			mpd_freeInfoEntity(entity);
		}

		my_finishCommand(conn);

	} while (++i < argc && (ls = charset_to_utf8(argv[i])) != NULL);
	return 0;
}
예제 #4
0
void set_charset(Octstr *document, Octstr *charset)
{
    long gt = 0, enc = 0;
    Octstr *encoding = NULL, *text = NULL, *temp = NULL;

    if (octstr_len(charset) == 0)
        return;

    encoding = octstr_create(" encoding");
    enc = octstr_search(document, encoding, 0);
    gt = octstr_search_char(document, '>', 0);

    if (enc < 0 || enc > gt) {
        gt++;
        text = octstr_copy(document, gt, octstr_len(document) - gt);
        if (charset_to_utf8(text, &temp, charset) >= 0) {
            octstr_delete(document, gt, octstr_len(document) - gt);
            octstr_append_data(document, octstr_get_cstr(temp), 
                               octstr_len(temp));
        }

        octstr_destroy(temp);
        octstr_destroy(text);
    }

    octstr_destroy(encoding);
}
예제 #5
0
static int do_search ( int argc, char ** argv, mpd_Connection * conn, int exact )
{
	Constraint *constraints;
	int numconstraints;
	int i;

	if (argc % 2 != 0)
		DIE("arguments must be pairs of search types and queries\n");

	numconstraints = get_constraints(argc, argv, &constraints);
	if (numconstraints < 0)
		return -1;

	mpd_startSearch(conn, exact);

	for (i = 0; i < numconstraints; i++) {
		mpd_addConstraintSearch(conn, constraints[i].type,
		                        charset_to_utf8(constraints[i].query));
	}

	free(constraints);

	mpd_commitSearch(conn);
	printErrorAndExit(conn);

	print_filenames(conn);

	my_finishCommand(conn);

	return 0;
}
예제 #6
0
파일: command.c 프로젝트: daaang/mpc
static int
ls_entity(int argc, char **argv, struct mpd_connection *conn,
	  enum mpd_entity_type type)
{
	const char *ls = "";
	int i = 0;
	if (argc > 0)
		ls = charset_to_utf8(argv[i]);

	do {
		if (!mpd_send_list_meta(conn, ls))
			printErrorAndExit(conn);

		print_entity_list(conn, type);
		my_finishCommand(conn);
	} while (++i < argc && (ls = charset_to_utf8(argv[i])) != NULL);

	return 0;
}
예제 #7
0
int cmd_listall ( int argc, char ** argv, mpd_Connection * conn )
{
	const char * listall = "";
	int i=0;

	if (argc > 0)
		listall = charset_to_utf8(argv[i]);

	do {
		mpd_sendListallCommand(conn,listall);
		printErrorAndExit(conn);

		print_filenames(conn);

		my_finishCommand(conn);

	} while (++i < argc && (listall = charset_to_utf8(argv[i])) != NULL);

	return 0;
}
예제 #8
0
파일: search.c 프로젝트: prosbloom225/mmpc
static void
add_constraint(struct mpd_connection *conn,
               const struct constraint *constraint)
{
    if (constraint->type == (enum mpd_tag_type)SEARCH_TAG_ANY)
        mpd_search_add_any_tag_constraint(conn, MPD_OPERATOR_DEFAULT,
                                          charset_to_utf8(constraint->query));
    else if (constraint->type == (enum mpd_tag_type)SEARCH_TAG_URI)
        mpd_search_add_uri_constraint(conn, MPD_OPERATOR_DEFAULT,
                                      charset_to_utf8(constraint->query));
#if LIBMPDCLIENT_CHECK_VERSION(2,9,0)
    else if (constraint->type == (enum mpd_tag_type)SEARCH_TAG_BASE)
        mpd_search_add_base_constraint(conn, MPD_OPERATOR_DEFAULT,
                                       charset_to_utf8(constraint->query));
#endif
    else
        mpd_search_add_tag_constraint(conn, MPD_OPERATOR_DEFAULT,
                                      constraint->type,
                                      charset_to_utf8(constraint->query));
}
예제 #9
0
int cmd_update ( int argc, char ** argv, mpd_Connection * conn)
{
	const char * update = "";
	int i = 0;

	mpd_sendCommandListBegin(conn);
	printErrorAndExit(conn);

	if(argc > 0) update = charset_to_utf8(argv[i]);

	do {
		mpd_sendUpdateCommand(conn, update);
	} while (++i < argc && (update = charset_to_utf8(argv[i])) != NULL);

	mpd_sendCommandListEnd(conn);
	printErrorAndExit(conn);
	mpd_finishCommand(conn);
	printErrorAndExit(conn);

	return 1;
}
예제 #10
0
static void test_charset_iconv_utf7_state(void)
{
	struct charset_translation *trans;
	string_t *str = t_str_new(32);
	unsigned char nextbuf[5+CHARSET_MAX_PENDING_BUF_SIZE+1];
	size_t size;

	test_begin("charset iconv utf7 state");
	test_assert(charset_to_utf8_begin("UTF-7", NULL, &trans) == 0);
	size = 2;
	test_assert(charset_to_utf8(trans, (const void *)"a+", &size, str) == CHARSET_RET_INCOMPLETE_INPUT);
	test_assert(strcmp(str_c(str), "a") == 0);
	test_assert(size == 1);
	memset(nextbuf, '?', sizeof(nextbuf));
	memcpy(nextbuf, "+AOQ-", 5);
	size = sizeof(nextbuf);
	test_assert(charset_to_utf8(trans, nextbuf, &size, str) == CHARSET_RET_OK);
	test_assert(strcmp(str_c(str), "a\xC3\xA4???????????") == 0);
	charset_to_utf8_end(&trans);
	test_end();
}
예제 #11
0
파일: command.c 프로젝트: prosbloom225/mmpc
int cmd_load ( int argc, char ** argv, struct mpd_connection *conn )
{
	if (!mpd_command_list_begin(conn, false))
		printErrorAndExit(conn);

	for (int i = 0; i < argc; ++i) {
		printf("loading: %s\n",argv[i]);
		mpd_send_load(conn, charset_to_utf8(argv[i]));
	}
	mpd_command_list_end(conn);
	my_finishCommand(conn);

	return 0;
}
예제 #12
0
파일: command.c 프로젝트: somecommand/mpc
int cmd_add (int argc, char ** argv, struct mpd_connection *conn )
{
	if (contains_absolute_path(argc, argv) && !path_prepare(conn))
		printErrorAndExit(conn);

	int i;

	if (!mpd_command_list_begin(conn, false))
		printErrorAndExit(conn);

	for(i=0;i<argc;i++) {
		strip_trailing_slash(argv[i]);

		const char *path = argv[i];
		const char *relative_path = to_relative_path(path);
		if (relative_path != NULL)
			path = relative_path;

		if (options.verbosity >= V_VERBOSE)
			printf("adding: %s\n", path);
		mpd_send_add(conn, charset_to_utf8(path));
	}

	if (!mpd_command_list_end(conn))
		printErrorAndExit(conn);

	if (!mpd_response_finish(conn)) {
#if LIBMPDCLIENT_CHECK_VERSION(2,4,0)
		if (mpd_connection_get_error(conn) == MPD_ERROR_SERVER) {
			/* check which of the arguments has failed */
			unsigned location =
				mpd_connection_get_server_error_location(conn);
			if (location < (unsigned)argc) {
				/* we've got a valid location from the
				   server */
				const char *message =
					mpd_connection_get_error_message(conn);
				message = charset_from_utf8(message);
				fprintf(stderr, "error adding %s: %s\n",
					argv[location], message);
				exit(EXIT_FAILURE);
			}
		}
#endif

		printErrorAndExit(conn);
	}

	return 0;
}
예제 #13
0
int cmd_list ( int argc, char ** argv, mpd_Connection * conn )
{
	Constraint *constraints;
	int numconstraints = 0;
	int type;
	int i;
	char *tag;

	type = get_search_type(argv[0]);
	if (type < 0)
		return -1;

	argc -= 1;
	argv += 1;

	if (argc > 0) {
		if (argc % 2 != 0) {
			DIE("arguments must be a tag type and "
			    "optional pairs of search types and queries\n");
		}

		numconstraints = get_constraints(argc, argv, &constraints);
		if (numconstraints < 0)
			return -1;
	}

	mpd_startFieldSearch(conn, type);

	if (argc > 0) {
		for (i = 0; i < numconstraints; i++) {
			mpd_addConstraintSearch(conn, constraints[i].type,
						charset_to_utf8(constraints[i].query));
		}

		free(constraints);
	}

	mpd_commitSearch(conn);
	printErrorAndExit(conn);

	while ((tag = mpd_getNextTag(conn, type))) {
		printErrorAndExit(conn);
		printf("%s\n", charset_from_utf8(tag));
		free(tag);
	}

	my_finishCommand(conn);

	return 0;
}
예제 #14
0
static void test_charset_iconv(void)
{
	struct {
		const char *charset;
		const char *input;
		const char *output;
		enum charset_result result;
	} tests[] = {
		{ "ISO-8859-1", "p\xE4\xE4", "p\xC3\xA4\xC3\xA4", CHARSET_RET_OK },
		{ "UTF-7", "+AOQA5AD2AOQA9gDkAPYA5AD2AOQA9gDkAPYA5AD2AOQA9gDkAPYA5AD2AOQA9gDkAPYA5AD2AOQA9gDkAPYA5AD2AOQA9gDk",
		  "\xC3\xA4\xC3\xA4\xC3\xB6\xC3\xA4\xC3\xB6\xC3\xA4\xC3\xB6\xC3\xA4"
		  "\xC3\xB6\xC3\xA4\xC3\xB6\xC3\xA4\xC3\xB6\xC3\xA4\xC3\xB6\xC3\xA4"
		  "\xC3\xB6\xC3\xA4\xC3\xB6\xC3\xA4\xC3\xB6\xC3\xA4\xC3\xB6\xC3\xA4"
		  "\xC3\xB6\xC3\xA4\xC3\xB6\xC3\xA4\xC3\xB6\xC3\xA4\xC3\xB6\xC3\xA4"
		  "\xC3\xB6\xC3\xA4\xC3\xB6\xC3\xA4", CHARSET_RET_OK }
	};
	string_t *str = t_str_new(128);
	struct charset_translation *trans;
	enum charset_result result;
	size_t pos, left, limit, len;
	unsigned int i;

	test_begin("charset iconv");
	for (i = 0; i < N_ELEMENTS(tests); i++) {
		str_truncate(str, 0);
		test_assert_idx(charset_to_utf8_str(tests[i].charset, NULL,
						    tests[i].input, str, &result) == 0, i);
		test_assert_idx(strcmp(tests[i].output, str_c(str)) == 0, i);
		test_assert_idx(result == tests[i].result, i);

		str_truncate(str, 0);
		test_assert_idx(charset_to_utf8_begin(tests[i].charset, NULL, &trans) == 0, i);
		len = strlen(tests[i].input);
		for (pos = 0, limit = 1; limit <= len; pos += left, limit++) {
			left = limit - pos;
			result = charset_to_utf8(trans, (const void *)(tests[i].input + pos),
						 &left, str);
			if (result != CHARSET_RET_INCOMPLETE_INPUT &&
			    result != CHARSET_RET_OK)
				break;
		}
		test_assert_idx(strcmp(tests[i].output, str_c(str)) == 0, i);
		test_assert_idx(result == tests[i].result, i);
		charset_to_utf8_end(&trans);
	}
	/* Use //IGNORE just to force handling to be done by iconv
	   instead of our own UTF-8 routines. */
	test_charset_utf8_common("UTF-8//IGNORE");
	test_end();
}
예제 #15
0
int charset_to_utf8_str(const char *charset, normalizer_func_t *normalizer,
			const char *input, string_t *output,
			enum charset_result *result_r)
{
	struct charset_translation *t;
	size_t len = strlen(input);

	if (charset_to_utf8_begin(charset, normalizer, &t) < 0)
		return -1;

	*result_r = charset_to_utf8(t, (const unsigned char *)input,
				    &len, output);
	charset_to_utf8_end(&t);
	return 0;
}
예제 #16
0
int cmd_add (int argc, char ** argv, mpd_Connection * conn )
{
	int i;

	mpd_sendCommandListBegin(conn);
	printErrorAndExit(conn);

	for(i=0;i<argc;i++) {
		printf("adding: %s\n", argv[i]);
		mpd_sendAddCommand(conn, charset_to_utf8(argv[i]));
		printErrorAndExit(conn);
	}

	mpd_sendCommandListEnd(conn);
	my_finishCommand(conn);

	return 0;
}
예제 #17
0
int cmd_load ( int argc, char ** argv, mpd_Connection * conn )
{
	int i;
	char * sp;
	char * dp;
	mpd_InfoEntity * entity;
	mpd_PlaylistFile * pl;

	for(i=0;i<argc;i++) {
		sp = argv[i];
		while((sp = strchr(sp,' '))) *sp = '_';
	}

	mpd_sendLsInfoCommand(conn,"");
	printErrorAndExit(conn);
	while((entity = mpd_getNextInfoEntity(conn))) {
		if(entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
			pl = entity->info.playlistFile;
			dp = sp = strdup(charset_from_utf8(pl->path));
			while((sp = strchr(sp,' '))) *sp = '_';
			for(i=0;i<argc;i++) {
				if(strcmp(dp,argv[i])==0)
					strcpy(argv[i], charset_from_utf8(pl->path));
			}
			free(dp);
			mpd_freeInfoEntity(entity);
		}
	}
	my_finishCommand(conn);

	mpd_sendCommandListBegin(conn);
	printErrorAndExit(conn);
	for(i=0;i<argc;i++) {
		printf("loading: %s\n",argv[i]);
		mpd_sendLoadCommand(conn,charset_to_utf8(argv[i]));
		printErrorAndExit(conn);
	}
	mpd_sendCommandListEnd(conn);
	my_finishCommand(conn);

	return 0;
}
예제 #18
0
파일: command.c 프로젝트: daaang/mpc
static int
find_songname_id(struct mpd_connection *conn, const char *s)
{
	int res = -1;

	mpd_search_queue_songs(conn, false);

	const char *pattern = charset_to_utf8(s);
	mpd_search_add_any_tag_constraint(conn, MPD_OPERATOR_DEFAULT,
					       pattern);
	mpd_search_commit(conn);

	struct mpd_song *song = mpd_recv_song(conn);
	if (song != NULL) {
		res = mpd_song_get_id(song);

		mpd_song_free(song);
	}

	my_finishCommand(conn);

	return res;
}
예제 #19
0
static void translation_buf_decode(struct message_decoder_context *ctx,
				   const unsigned char **data, size_t *size)
{
	unsigned char trans_buf[CHARSET_MAX_PENDING_BUF_SIZE+1];
	unsigned int data_wanted, skip;
	size_t trans_size, orig_size;

	/* @UNSAFE: move the previously untranslated bytes to trans_buf
	   and see if we have now enough data to get the next character
	   translated */
	memcpy(trans_buf, ctx->translation_buf, ctx->translation_size);
	data_wanted = sizeof(trans_buf) - ctx->translation_size;
	if (data_wanted > *size)
		data_wanted = *size;
	memcpy(trans_buf + ctx->translation_size, *data, data_wanted);

	orig_size = trans_size = ctx->translation_size + data_wanted;
	(void)charset_to_utf8(ctx->charset_trans, trans_buf,
			      &trans_size, ctx->buf2);

	if (trans_size <= ctx->translation_size) {
		/* need more data to finish the translation. */
		i_assert(orig_size < CHARSET_MAX_PENDING_BUF_SIZE);
		memcpy(ctx->translation_buf, trans_buf, orig_size);
		ctx->translation_size = orig_size;
		*data += *size;
		*size = 0;
		return;
	}
	skip = trans_size - ctx->translation_size;

	i_assert(*size >= skip);
	*data += skip;
	*size -= skip;

	ctx->translation_size = 0;
}
예제 #20
0
static bool message_decode_body(struct message_decoder_context *ctx,
				struct message_block *input,
				struct message_block *output)
{
	const unsigned char *data = NULL;
	size_t pos = 0, size = 0;
	int ret;

	if (ctx->encoding_buf->used != 0) {
		/* @UNSAFE */
		buffer_append(ctx->encoding_buf, input->data, input->size);
	}

	switch (ctx->message_cte) {
	case MESSAGE_CTE_UNKNOWN:
		/* just skip this body */
		return FALSE;

	case MESSAGE_CTE_78BIT:
	case MESSAGE_CTE_BINARY:
		data = input->data;
		size = pos = input->size;
		break;
	case MESSAGE_CTE_QP:
		buffer_set_used_size(ctx->buf, 0);
		if (ctx->encoding_buf->used != 0) {
			(void)quoted_printable_decode(ctx->encoding_buf->data,
						      ctx->encoding_buf->used,
						      &pos, ctx->buf);
		} else {
			(void)quoted_printable_decode(input->data, input->size,
						      &pos, ctx->buf);
		}
		data = ctx->buf->data;
		size = ctx->buf->used;
		break;
	case MESSAGE_CTE_BASE64:
		buffer_set_used_size(ctx->buf, 0);
		if (ctx->encoding_buf->used != 0) {
			ret = base64_decode(ctx->encoding_buf->data,
					    ctx->encoding_buf->used,
					    &pos, ctx->buf);
		} else {
			ret = base64_decode(input->data, input->size,
					    &pos, ctx->buf);
		}
		if (ret < 0) {
			/* corrupted base64 data, don't bother with
			   the rest of it */
			return FALSE;
		}
		if (ret == 0) {
			/* end of base64 input */
			pos = input->size;
			buffer_set_used_size(ctx->encoding_buf, 0);
		}
		data = ctx->buf->data;
		size = ctx->buf->used;
		break;
	}

	if (ctx->encoding_buf->used != 0)
		buffer_delete(ctx->encoding_buf, 0, pos);
	else if (pos != input->size) {
		buffer_append(ctx->encoding_buf,
			      input->data + pos, input->size - pos);
	}

	if (ctx->binary_input) {
		output->data = data;
		output->size = size;
	} else if (ctx->charset_utf8 || ctx->charset_trans == NULL) {
		/* handle unknown charsets the same as UTF-8. it might find
		   usable ASCII text. */
		buffer_set_used_size(ctx->buf2, 0);
		if (ctx->normalizer != NULL) {
			(void)ctx->normalizer(data, size, ctx->buf2);
			output->data = ctx->buf2->data;
			output->size = ctx->buf2->used;
		} else if (uni_utf8_get_valid_data(data, size, ctx->buf2)) {
			output->data = data;
			output->size = size;
		} else {
			output->data = ctx->buf2->data;
			output->size = ctx->buf2->used;
		}
	} else {
		buffer_set_used_size(ctx->buf2, 0);
		if (ctx->translation_size != 0)
			translation_buf_decode(ctx, &data, &size);

		pos = size;
		(void)charset_to_utf8(ctx->charset_trans,
				      data, &pos, ctx->buf2);
		if (pos != size) {
			ctx->translation_size = size - pos;
			i_assert(ctx->translation_size <=
				 sizeof(ctx->translation_buf));
			memcpy(ctx->translation_buf, data + pos,
			       ctx->translation_size);
		}
		output->data = ctx->buf2->data;
		output->size = ctx->buf2->used;
	}

	output->hdr = NULL;
	return TRUE;
}
예제 #21
0
static bool message_decode_body(struct message_decoder_context *ctx,
				struct message_block *input,
				struct message_block *output)
{
	const unsigned char *data = NULL;
	size_t pos = 0, size = 0;
	const char *error;
	int ret;

	if (ctx->encoding_buf->used != 0)
		buffer_append(ctx->encoding_buf, input->data, input->size);

	switch (ctx->message_cte) {
	case MESSAGE_CTE_UNKNOWN:
		/* just skip this body */
		return FALSE;

	case MESSAGE_CTE_78BIT:
	case MESSAGE_CTE_BINARY:
		i_assert(ctx->encoding_buf->used == 0);
		data = input->data;
		size = pos = input->size;
		break;
	case MESSAGE_CTE_QP: {
		i_assert(ctx->encoding_buf->used == 0);
		buffer_set_used_size(ctx->buf, 0);
		if (ctx->qp == NULL)
			ctx->qp = qp_decoder_init(ctx->buf);
		(void)qp_decoder_more(ctx->qp, input->data, input->size,
				      &pos, &error);
		data = ctx->buf->data;
		size = ctx->buf->used;
		/* eat away all input. qp-decoder buffers it internally. */
		pos = input->size;
		break;
	}
	case MESSAGE_CTE_BASE64:
		buffer_set_used_size(ctx->buf, 0);
		if (ctx->encoding_buf->used != 0) {
			ret = base64_decode(ctx->encoding_buf->data,
					    ctx->encoding_buf->used,
					    &pos, ctx->buf);
		} else {
			ret = base64_decode(input->data, input->size,
					    &pos, ctx->buf);
		}
		if (ret < 0) {
			/* corrupted base64 data, don't bother with
			   the rest of it */
			return FALSE;
		}
		if (ret == 0) {
			/* end of base64 input */
			pos = input->size;
			buffer_set_used_size(ctx->encoding_buf, 0);
		}
		data = ctx->buf->data;
		size = ctx->buf->used;
		break;
	}

	if (ctx->encoding_buf->used != 0)
		buffer_delete(ctx->encoding_buf, 0, pos);
	else if (pos != input->size) {
		buffer_append(ctx->encoding_buf,
			      input->data + pos, input->size - pos);
	}

	if (ctx->binary_input) {
		output->data = data;
		output->size = size;
	} else {
		buffer_set_used_size(ctx->buf2, 0);
		if (ctx->translation_size != 0)
			translation_buf_decode(ctx, &data, &size);

		pos = size;
		(void)charset_to_utf8(ctx->charset_trans,
				      data, &pos, ctx->buf2);
		if (pos != size) {
			ctx->translation_size = size - pos;
			i_assert(ctx->translation_size <=
				 sizeof(ctx->translation_buf));
			memcpy(ctx->translation_buf, data + pos,
			       ctx->translation_size);
		}
		output->data = ctx->buf2->data;
		output->size = ctx->buf2->used;
	}

	output->hdr = NULL;
	return TRUE;
}
예제 #22
0
파일: id3read.c 프로젝트: cjd/mtpfs
static gchar *
getFrameText (struct id3_tag *tag, char *frame_name)
{
  const id3_ucs4_t *string;
  struct id3_frame *frame;
  union id3_field *field;
  gchar *utf8 = NULL;
  enum id3_field_textencoding encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;

  frame = id3_tag_findframe (tag, frame_name, 0);
  if (!frame)
    return NULL;

  /* Find the encoding used for the field */
  field = id3_frame_field (frame, 0);
  //printf ("field: %p\n", field);
  if (field && (id3_field_type (field) == ID3_FIELD_TYPE_TEXTENCODING))
    {
      encoding = field->number.value;
      //printf ("encoding: %d\n", encoding);
    }

  if (strcmp (frame_name, ID3_FRAME_COMMENT) == 0)
    field = id3_frame_field (frame, 3);
  else
    field = id3_frame_field (frame, 1);

  //printf ("field: %p\n", field);

  if (!field)
    return NULL;

  if (strcmp (frame_name, ID3_FRAME_COMMENT) == 0)
    string = id3_field_getfullstring (field);
  else
    string = id3_field_getstrings (field, 0);

  // g_debug("string: %s\n", string);

  if (!string)
    return NULL;

  if (strcmp (frame_name, ID3_FRAME_GENRE) == 0)
    string = id3_genre_name (string);

  if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
    {
      /* ISO_8859_1 is just a "marker" -- most people just drop
         whatever coding system they are using into it, so we use
         charset_to_utf8() to convert to utf8 */
      id3_latin1_t *raw = id3_ucs4_latin1duplicate (string);
      utf8 = (gchar *) charset_to_utf8 (raw);
      g_free (raw);
    }
  else
    {
      /* Standard unicode is being used -- we won't have to worry
         about charsets then. */
      // g_debug("This frame is a Unicode frame!\n");
      utf8 = (gchar *) id3_ucs4_utf8duplicate (string);
    }
  // g_debug("Found tag: %s, value: %s\n", frame_name, utf8);
  return utf8;
}
예제 #23
0
/**
 * Open and scan the metadata of the m4a/mp4/... file
 * and populate the given track.
 */
void AP_read_metadata(const char *filePath, Track *track) {
    FILE *mp4File;
    Trackage *trackage;
    uint8_t track_cur;
    uint8_t txttrack_cur;
    gboolean audio_or_video_found = FALSE;
    gboolean has_quicktime_chaps = FALSE;
    uint32_t timescale = 0;

    APar_ScanAtoms(filePath, true);
    mp4File = openSomeFile(filePath, true);

    trackage = APar_ExtractDetails(mp4File, SHOW_TRACK_INFO);

    for (track_cur = 0; track_cur < trackage->total_tracks; ++track_cur) {
        TrackInfo *info = trackage->infos[track_cur];

        if ((info->type_of_track & AUDIO_TRACK) || (info->type_of_track & VIDEO_TRACK)
                        || (info->type_of_track & DRM_PROTECTED_TRACK)) {

            /*
             * the info->duration is in the track's timescale units so must be divided by that
             * value to get seconds, while track->tracklen in gtkpod is in ms
             */
            float duration = ((float) info->duration / (float) info->parent->movie_info->timescale) * 1000;
            track->tracklen = (gint32) duration;

            track->bitrate = APar_calculate_bitrate(info);
            track->samplerate = info->media_sample_rate;
            audio_or_video_found = TRUE;
            break;
        }
    }
    for (txttrack_cur = 0; audio_or_video_found && txttrack_cur < trackage->total_tracks; ++txttrack_cur) {
        TrackInfo *txtinfo = trackage->infos[txttrack_cur];
        char buf[128];
        // search for chapter track
        if (!(txtinfo->type_of_track & TEXT_TRACK))
            continue;
        // see if the AV track's chap refers to this text track
        // chap: 0: atom size  4: 'chap'  8,12,...,8+(N-1)*4: (0: referenced track ID)
        snprintf(buf, sizeof(buf), "moov.trak[%u].tref.chap", track_cur + 1);
        AtomicInfo* chapAtom = APar_FindAtom(buf, false, SIMPLE_ATOM, 0);
        if (!chapAtom)
            continue;
        int entry_count = (chapAtom->AtomicLength - 8) / 4;
        for (int i = 0; i < entry_count; ++i) {
            if (APar_read32(buf, mp4File, chapAtom->AtomicStart + 8 + i * 4) == txtinfo->track_id) {
                has_quicktime_chaps = TRUE;
                timescale = txtinfo->media_sample_rate;
                break;
            }
        }
        if (has_quicktime_chaps)
            break;
    }
    if (has_quicktime_chaps) {
        // found a chapter... now get the chapter data from the text track
        char buf[128];

        // stts: 0: atom size  4: 'stts'  8: version  12: entry count  16,24,...,16+(N-1)*8: (0: frame count 4: duration)
        snprintf(buf, sizeof(buf), "moov.trak[%u].mdia.minf.stbl.stts", txttrack_cur + 1);
        AtomicInfo* sampleAtom = APar_FindAtom(buf, false, VERSIONED_ATOM, 0);

        // stsz: 0: atom size  4: 'stsz'  8: version  12: size of all (or 0)  16: entry count  20,24,...,20+(N-1)*4: (0: sample size)
        snprintf(buf, sizeof(buf), "moov.trak[%u].mdia.minf.stbl.stsz", txttrack_cur + 1);
        AtomicInfo* sampleSizeAtom = APar_FindAtom(buf, false, VERSIONED_ATOM, 0);

        // stco: 0: atom size  4: 'stco'  8: version  12: entry count  16,20,...,16+(N-1)*4: (0: sample byte offset)
        snprintf(buf, sizeof(buf), "moov.trak[%u].mdia.minf.stbl.stco", txttrack_cur + 1);
        AtomicInfo* sampleOffsetAtom = APar_FindAtom(buf, false, VERSIONED_ATOM, 0);

        // We must have a valid sampleAtom to know chapter times. If sampleSizeAtom or sampleOffsetAtom is invalid,
        // we can do without them (and instead create a default chapter name).
        if (sampleAtom && sampleAtom->AtomicLength >= 16) {
            Itdb_Chapterdata *chapterdata = itdb_chapterdata_new();
            uint32_t stts_entry_count = APar_read32(buf, mp4File, sampleAtom->AtomicStart + 12);
            uint32_t stsz_entry_count = !sampleSizeAtom || sampleSizeAtom->AtomicLength < 20 ? 0 :
                APar_read32(buf, mp4File, sampleSizeAtom->AtomicStart + 16);
            uint32_t stco_entry_count = !sampleOffsetAtom || sampleOffsetAtom->AtomicLength < 16 ? 0 :
                APar_read32(buf, mp4File, sampleOffsetAtom->AtomicStart + 12);
            uint32_t stsz_all_size = !sampleSizeAtom || sampleSizeAtom->AtomicLength < 16 ? 0 :
                APar_read32(buf, mp4File, sampleSizeAtom->AtomicStart + 12);

            uint32_t start_time = 0;

            u_int32_t max_frame_size = stsz_all_size; // if stsz_all_size specified, use only that size
            for (int i = 0; !stsz_all_size && i < stsz_entry_count; ++i) {
                uint32_t chap_name_len = APar_read32(buf, mp4File, sampleSizeAtom->AtomicStart + 20 + i * 4);
                if (chap_name_len > max_frame_size)
                    max_frame_size = chap_name_len;
            }
            max_frame_size += 1; // for trailing '\0' (unneeded?), and to make sure that malloc() gets passed at least 1
            char * namebuf = (char *)malloc(max_frame_size * sizeof(char));
            for (int i = 0; i < stts_entry_count; ++i) {
                gchar *title = NULL;
                uint32_t chap_name_len = stsz_all_size;
                uint32_t chap_offset = 0;
                if (stsz_all_size == 0 && i < stsz_entry_count)
                    chap_name_len = APar_read32(buf, mp4File, sampleSizeAtom->AtomicStart + 20 + i * 4);
                if (i < stco_entry_count)
                    chap_offset = APar_read32(buf, mp4File, sampleOffsetAtom->AtomicStart + 16 + i * 4);
                if (chap_offset != 0)
                    APar_readX(namebuf, mp4File, chap_offset, chap_name_len);
                else // If the location of the chapter name is unknown, trigger default chapter naming
                    chap_name_len = 0;
                if (chap_name_len > 2) {
                    int titlelength = (namebuf[0] << 8) + namebuf[1];
                    // if the stsz atom and the title value disagree, use the smaller one for safety
                    titlelength = (titlelength > chap_name_len) ? chap_name_len : titlelength;
                    // If a title begins with 0xFFFE, it's a UTF-16 title
                    if (titlelength >= 2 && namebuf[2] == 0xff && namebuf[3] == 0xfe)
                        title = g_utf16_to_utf8((const gunichar2 *) &namebuf[4], titlelength - 2, NULL, NULL, NULL);
                    else
                        title = g_strndup(&namebuf[2], titlelength);
                }
                else
                {
                    // chapter title couldn't be found; create our own titles (and some ipods don't display them anyway).
                    // Translators: this string is used to create a chapter title when no chapter title could be found
                    title = g_strdup_printf(_("Chapter %3d"), i);
                }

                if (!timescale) // assume 1000, also, don't divide by 0
                    timescale = 1000;
                double duration_ms = (double)start_time * 1000.0 / (double)timescale;

                itdb_chapterdata_add_chapter(chapterdata, duration_ms, title);
                g_free(title);

                if (i < (stts_entry_count - 1)) // skip this stage after the last chapter has been added
                {
                    uint32_t frame_count = APar_read32(buf, mp4File, sampleAtom->AtomicStart + 16 + i * 8);
                    uint32_t duration = APar_read32(buf, mp4File, sampleAtom->AtomicStart + 20 + i * 8);
                    start_time += frame_count * duration;
                }
            }
            if (namebuf)
                free(namebuf);
            if (track->chapterdata) // if there was already chapter data, don't leak it
                itdb_chapterdata_free(track->chapterdata);
            track->chapterdata = itdb_chapterdata_duplicate(chapterdata);
            itdb_chapterdata_free(chapterdata);
        }
    }
    // TODO: add support for Nero-style mp4 chapters

    if (prefs_get_int("readtags")) {
        char* value = NULL;

        // MP4 Title
        value = find_atom_value(TITLE);
        if (value) {
            track->title = g_strdup(value);
            free(value);
        }

        // MP4 Artist
        value = find_atom_value(ARTIST);
        if (value) {
            track->artist = g_strdup(value);
            free(value);
        }

        // MP4 Album Artist
        value = find_atom_value(ALBUM_ARTIST);
        if (value) {
            track->albumartist = g_strdup(value);
            free(value);
        }

        // MP4 Composer
        value = find_atom_value(COMPOSER);
        if (value) {
            track->composer = g_strdup(value);
            free(value);
        }

        // MP4 Comment
        value = find_atom_value(COMMENT);
        if (value) {
            track->comment = g_strdup(value);
            free(value);
        }

        // MP4 Description
        value = find_atom_value(DESCRIPTION);
        if (value) {
            track->description = g_strdup(value);
            free(value);
        }

        // MP4 Keywords
        value = find_atom_value(KEYWORD);
        if (value) {
            track->keywords = g_strdup(value);
            free(value);
        }

        // MP4 Year
        value = find_atom_value(YEAR);
        if (value) {
            track->year = atoi(value);
            free(value);
        }

        // MP4 Album
        value = find_atom_value(ALBUM);
        if (value) {
            track->album = g_strdup(value);
            free(value);
        }

        // MP4 Track No. and Total
        value = find_atom_value(TRACK_NUM_AND_TOTAL);
        if (value) {
            const char* delimiter = " of ";
            char *result = NULL;
            result = strtok(value, delimiter);
            if (result)
                track->track_nr = atoi(result);

            result = strtok(NULL, delimiter);
            if (result)
                track->tracks = atoi(result);

            free(value);
        }

        // MP4 Disk No. and Total
        value = find_atom_value(DISK_NUM_AND_TOTAL);
        if (value) {
            const char* delimiter = " of ";
            char *result = NULL;
            result = strtok(value, delimiter);
            if (result)
                track->cd_nr = atoi(result);

            result = strtok(NULL, delimiter);
            if (result)
                track->cds = atoi(result);

            free(value);
        }

        // MP4 Grouping
        value = find_atom_value(GROUPING);
        if (value) {
            track->grouping = g_strdup(value);
            free(value);
        }

        // MP4 Genre - note: can be either a standard or custom genre
        // standard genre
        value = find_atom_value(STANDARD_GENRE);
        if (value) {
            track->genre = charset_to_utf8(value);
            // Should not free standard genres
        }
        else {
            // custom genre
            value = find_atom_value(CUSTOM_GENRE);
            if (value) {
                track->genre = g_strdup(value);
                free(value);
            }
        }

        // MP4 Tempo / BPM
        value = find_atom_value(TEMPO);
        if (value) {
            track->BPM = atoi(value);
            free(value);
        }

        // MP4 Lyrics
        value = find_atom_value(LYRICS);
        if (value) {
            track->lyrics_flag = 0x01;
            free(value);
        }

        // MP4 TV Show
        value = find_atom_value(TV_SHOW);
        if (value) {
            track->tvshow = g_strdup(value);
            free(value);
        }

        // MP4 TV Episode
        value = find_atom_value(TV_EPISODE);
        if (value) {
            track->tvepisode = g_strdup(value);
            free(value);
        }

        // MP4 TV Episode No.
        value = find_atom_value(TV_EPISODE_NO);
        if (value) {
            track->episode_nr = atoi(value);
            free(value);
        }

        // MP4 TV Network
        value = find_atom_value(TV_NETWORK_NAME);
        if (value) {
            track->tvnetwork = g_strdup(value);
            free(value);
        }

        // MP4 TV Season No.
        value = find_atom_value(TV_SEASON_NO);
        if (value) {
            track->season_nr = atoi(value);
            free(value);
        }

        // MP4 Media Type
        value = find_atom_value(MEDIA_TYPE);
        if (value) {
            stiks * stik = MatchStikString(value);
            if (stik)
            {
                track->mediatype = mediaTypeTagToMediaType(stik->stik_number);
            }
            // Should not free standard media types
        }

        // MP4 Compilation flag
        value = find_atom_value(COMPILATION);
        if (value) {
            track->compilation = !g_strcmp0("true", value);
            free(value);
        }

        // MP4 Category
        value = find_atom_value(CATEGORY);
        if (value) {
            track->category = g_strdup(value);
            free(value);
        }

        // MP4 Podcast URL
        value = find_atom_value(PODCAST_URL);
        if (value) {
            track->podcasturl = g_strdup(value);
            free(value);
        }

        value = find_atom_value(GAPLESS_FLAG);
        if (value) {
            track->gapless_track_flag = atoi(value);
            free(value);
        }

        // MP4 Sort Title
        value = find_atom_value(SORT_TITLE);
        if (value) {
            track->sort_title = g_strdup(value);
            free(value);
        }

        // MP4 Sort Artist
        value = find_atom_value(SORT_ARTIST);
        if (value) {
            track->sort_artist = g_strdup(value);
            free(value);
        }

        // MP4 Sort Album Artist
        value = find_atom_value(SORT_ALBUM_ARTIST);
        if (value) {
            track->sort_albumartist = g_strdup(value);
            free(value);
        }

        // MP4 Sort Composer
        value = find_atom_value(SORT_COMPOSER);
        if (value) {
            track->sort_composer = g_strdup(value);
            free(value);
        }

        // MP4 Sort Album
        value = find_atom_value(SORT_ALBUM);
        if (value) {
            track->sort_album = g_strdup(value);
            free(value);
        }

        // MP4 Sort TV Show
        value = find_atom_value(SORT_TV_SHOW);
        if (value) {
            track->sort_tvshow = g_strdup(value);
            free(value);
        }

        if (prefs_get_int("coverart_apic")) {
            gchar *tmp_file_prefix = g_build_filename(g_get_tmp_dir(), "ttt", NULL);
            gchar *tmp_file;

            AtomicInfo *info = find_atom("covr");
            if (info) {

                // Extract the data to a temporary file
                tmp_file = APar_ExtractAAC_Artwork(info->AtomicNumber, tmp_file_prefix, 1);
                g_free(tmp_file_prefix);

                if (tmp_file && g_file_test(tmp_file, G_FILE_TEST_EXISTS)) {

                    // Set the thumbnail using the tmp file
                    GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(tmp_file, NULL);
                    if (pixbuf) {
                        itdb_track_set_thumbnails_from_pixbuf(track, pixbuf);
                        g_object_unref(pixbuf);
                    }

                    g_remove(tmp_file);
                }

                if (tmp_file)
                    g_free(tmp_file);
            }
        }
    }

    APar_FreeMemory();

}
예제 #24
0
파일: command.c 프로젝트: daaang/mpc
int
cmd_update(int argc, char **argv, struct mpd_connection *conn)
{
	if (contains_absolute_path(argc, argv) && !path_prepare(conn))
		printErrorAndExit(conn);

	if (!mpd_command_list_begin(conn, false))
		printErrorAndExit(conn);

	int i = 0;
	const char *update = "";
	if (argc > 0)
		update = charset_to_utf8(argv[i]);

	do {
		char *tmp = strdup(update);
		strip_trailing_slash(tmp);

		const char *path = tmp;
		const char *relative_path = to_relative_path(path);
		if (relative_path != NULL)
			path = relative_path;

		mpd_send_update(conn, path);
		free(tmp);
	} while (++i < argc && (update = charset_to_utf8(argv[i])) != NULL);

	if (!mpd_command_list_end(conn))
		printErrorAndExit(conn);

	/* obtain the last "update id" response */

	unsigned id = 0;
	while (true) {
		unsigned next_id = mpd_recv_update_id(conn);
		if (next_id == 0)
			break;
		id = next_id;
	}

	my_finishCommand(conn);

	while (options.wait) {
		/* idle until an update finishes */
		enum mpd_idle idle = mpd_run_idle_mask(conn, MPD_IDLE_UPDATE);
		struct mpd_status *status;
		unsigned current_id;

		if (idle == 0)
			printErrorAndExit(conn);

		/* determine the current "update id" */

		status = getStatus(conn);
		current_id = mpd_status_get_update_id(status);
		mpd_status_free(status);

		/* is our last queued update finished now? */

		if (current_id == 0 || current_id > id ||
		    (id > 1 << 30 && id < 1000)) /* wraparound */
			break;
	}

	return 1;
}
예제 #25
0
/**
 * Using the given track, set the metadata of the target
 * file
 */
void AP_write_metadata(Track *track, const char *filePath, GError **error) {
    ExtraTrackData *etr;
    gchar *atom;
    gchar *value;

    g_return_if_fail(track);

    APar_ScanAtoms(filePath);

    if (metadata_style != ITUNES_STYLE) {
        gchar *fbuf = charset_to_utf8(filePath);
        gtkpod_log_error(error, g_strdup_printf(_("ERROR %s is not itunes style."), fbuf));
        g_free(fbuf);
        return;
    }

    // Title
    set_limited_text_atom_value(TITLE, track->title);

    // Artist
    set_limited_text_atom_value(ARTIST, track->artist);

    // Album Artist
    set_limited_text_atom_value(ALBUM_ARTIST, track->albumartist);

    // Album
    set_limited_text_atom_value(ALBUM, track->album);

    // Genre
    APar_MetaData_atomGenre_Set(track->genre);

    // Track Number and Total
    atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, TRACK_NUM_AND_TOTAL, DATA);
    if (track->track_nr == 0) {
        APar_RemoveAtom(atom, VERSIONED_ATOM, 0);
    }
    else {
        gchar *track_info = g_strdup_printf("%d / %d", track->track_nr, track->tracks);
        short tracknumData_atom = APar_MetaData_atom_Init(atom, track_info, AtomFlags_Data_Binary);
        APar_Unified_atom_Put(tracknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16);
        APar_Unified_atom_Put(tracknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, track->track_nr, 16);
        APar_Unified_atom_Put(tracknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, track->tracks, 16);
        APar_Unified_atom_Put(tracknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16);
        g_free(track_info);
    }
    g_free(atom);

    // Disk Number and Total
    atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, DISK_NUM_AND_TOTAL, DATA);
    if (track->cd_nr == 0) {
        APar_RemoveAtom(atom, VERSIONED_ATOM, 0);
    }
    else {
        gchar *disk_info = g_strdup_printf("%d / %d", track->cd_nr, track->cds);
        short disknumData_atom = APar_MetaData_atom_Init(atom, disk_info, AtomFlags_Data_Binary);
        APar_Unified_atom_Put(disknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16);
        APar_Unified_atom_Put(disknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, track->cd_nr, 16);
        APar_Unified_atom_Put(disknumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, track->cds, 16);
        g_free(disk_info);
    }
    g_free(atom);

    // Comment
    set_limited_text_atom_value(COMMENT, track->comment);

    // Year
    gchar *yr = NULL;
    if (track->year > 0)
        yr = g_strdup_printf("%d", track->year);

    set_limited_text_atom_value(YEAR, yr);

    if (yr)
        g_free(yr);

    // Lyrics
    etr = (ExtraTrackData *) track->userdata;
    if (etr)
        write_lyrics_internal(etr->lyrics, filePath, error);

    // Composer
    set_limited_text_atom_value(COMPOSER, track->composer);

    // Grouping
    set_limited_text_atom_value(GROUPING, track->grouping);

    // Description
    set_limited_text_atom_value(DESCRIPTION, track->description);

    // TV Network
    set_limited_text_atom_value(TV_NETWORK_NAME, track->tvnetwork);

    // TV Show Name
    set_limited_text_atom_value(TV_SHOW, track->tvshow);

    // TV Episode
    set_limited_text_atom_value(TV_EPISODE, track->tvepisode);

    // Compilation
    atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, COMPILATION, DATA);
    if (!track->compilation) {
        APar_RemoveAtom(atom, VERSIONED_ATOM, 0);
    }
    else {
        //compilation: [0, 0, 0, 0,   boolean_value]; BUT that first uint32_t is already accounted for in APar_MetaData_atom_Init
        value = g_strdup_printf("%d", track->compilation);
        short compilationData_atom = APar_MetaData_atom_Init(atom, value, AtomFlags_Data_UInt);
        APar_Unified_atom_Put(compilationData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 1, 8); //a hard coded uint8_t of: 1 is compilation
        g_free(value);
    }
    g_free(atom);

    // Tempo / BPM
    atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, TEMPO, DATA);
    if (!track->BPM) {
        APar_RemoveAtom(atom, VERSIONED_ATOM, 0);
    }
    else {
        //bpm is [0, 0, 0, 0,   0, bpm_value]; BUT that first uint32_t is already accounted for in APar_MetaData_atom_Init
        value = g_strdup_printf("%d", track->BPM);
        short bpmData_atom = APar_MetaData_atom_Init(atom, value, AtomFlags_Data_UInt);
        APar_Unified_atom_Put(bpmData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, track->BPM, 16);
        g_free(value);
    }
    g_free(atom);

    // Media Type
    atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, MEDIA_TYPE, DATA);
    guint8 mediaTypeTag = mediaTypeToMediaTypeTag(track->mediatype);
    value = g_strdup_printf("%d", track->season_nr);
    short stikData_atom = APar_MetaData_atom_Init(atom, value, AtomFlags_Data_UInt);
    APar_Unified_atom_Put(stikData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, mediaTypeTag, 8);
    g_free(value);
    g_free(atom);

    // TV Season No.
    atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, TV_SEASON_NO, DATA);
    if (track->season_nr == 0) {
        APar_RemoveAtom(atom, VERSIONED_ATOM, 0);
    }
    else {
        value = g_strdup_printf("%d", track->season_nr);
        short tvseasonData_atom = APar_MetaData_atom_Init(atom, value, AtomFlags_Data_UInt);
        APar_Unified_atom_Put(tvseasonData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16);
        APar_Unified_atom_Put(tvseasonData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, track->season_nr, 16);
        g_free(value);
    }
    g_free(atom);

    // TV Episode No.
    atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, TV_EPISODE_NO, DATA);
    if (track->episode_nr == 0) {
        APar_RemoveAtom(atom, VERSIONED_ATOM, 0);
    }
    else {
        value = g_strdup_printf("%d", track->episode_nr);
        short tvepisodenumData_atom = APar_MetaData_atom_Init(atom, value, AtomFlags_Data_UInt);
        APar_Unified_atom_Put(tvepisodenumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 0, 16);
        APar_Unified_atom_Put(tvepisodenumData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, track->episode_nr, 16);
        g_free(value);
    }
    g_free(atom);

    // Keywords
    set_limited_text_atom_value(KEYWORD, track->keywords);

    // Podcast Category
    set_limited_text_atom_value(CATEGORY, track->category);

    // Podcast URL
    atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, PODCAST_URL, DATA);
    if (!track->podcasturl || strlen(track->podcasturl) == 0) {
        APar_RemoveAtom(atom, VERSIONED_ATOM, 0);
    }
    else {
        short podcasturlData_atom = APar_MetaData_atom_Init(atom, track->podcasturl, AtomFlags_Data_Binary);
        APar_Unified_atom_Put(podcasturlData_atom, track->podcasturl, UTF8_iTunesStyle_Binary, 0, 0);
    }
    g_free(atom);

    // Gapless Playback
    atom = g_strdup_printf("%s.%s.%s", ILST_FULL_ATOM, GAPLESS_FLAG, DATA);
    if (!track->gapless_track_flag) {
        APar_RemoveAtom(atom, VERSIONED_ATOM, 0);
    }
    else {
        value = g_strdup_printf("%d", track->gapless_track_flag);
        short gaplessData_atom = APar_MetaData_atom_Init(atom, value, AtomFlags_Data_UInt);
        APar_Unified_atom_Put(gaplessData_atom, NULL, UTF8_iTunesStyle_256glyphLimited, 1, 8); //a hard coded uint8_t of: 1 is gapl
        g_free(value);
    }
    g_free(atom);

    // Sort Title
    set_limited_text_atom_value(SORT_TITLE, track->sort_title);

    // Sort Artist
    set_limited_text_atom_value(SORT_ARTIST, track->sort_artist);

    // Sort Album Artist
    set_limited_text_atom_value(SORT_ALBUM_ARTIST, track->sort_albumartist);

    // Sort Composer
    set_limited_text_atom_value(SORT_COMPOSER, track->sort_composer);

    // Sort Album
    set_limited_text_atom_value(SORT_ALBUM, track->sort_album);

    // Sort TV Show
    set_limited_text_atom_value(SORT_TV_SHOW, track->sort_tvshow);

    if (prefs_get_int("coverart_apic")) {
        GdkPixbuf *pixbuf = (GdkPixbuf*) itdb_artwork_get_pixbuf(track->itdb->device, track->artwork, -1, -1);
        if (!pixbuf) {
            // Destroy any existing artwork if any
            APar_MetaData_atomArtwork_Set("REMOVE_ALL", NULL);
        }
        else {
            gchar *tmp_file = g_build_filename(g_get_tmp_dir(), "ttt.jpg", NULL);
            GError *pixbuf_err = NULL;

            gdk_pixbuf_save(pixbuf, tmp_file, "jpeg", &pixbuf_err, "quality", "100", NULL);

            if (!pixbuf_err) {
                APar_MetaData_atomArtwork_Set(tmp_file, NULL);
                g_remove(tmp_file);
            }
            else {
                gtkpod_log_error(error, g_strdup_printf(_("ERROR failed to change track file's artwork.") ));
                g_error_free(pixbuf_err);
                return;
            }

            g_free(tmp_file);
            g_object_unref(pixbuf);
        }
    }

    // after all the modifications are enacted on the tree in memory
    // then write out the changes
    APar_DetermineAtomLengths();
    openSomeFile(filePath, true);
    APar_WriteFile(filePath, NULL, true);

    APar_FreeMemory();
}
예제 #26
0
Track *wav_get_file_info(const gchar *filename, GError **error) {
    Track *track = NULL;
    gchar *fn;
    gchar magic[4];
    gulong len;
    WaveFile *wav_file;

    wav_file = g_malloc(sizeof(WaveFile));
    memset(wav_file, 0, sizeof(WaveFile));
    if (!(wav_file->file = fopen(filename, "rb"))) {
        gchar *fn = charset_to_utf8(filename);
        gtkpod_log_error(error, g_strdup_printf(_("Could not open '%s' for reading.\n"), fn));
        g_free(fn);
        g_free(wav_file);
        wav_file = NULL;
        return NULL;
    }

    fread(magic, 1, 4, wav_file->file);
    if (strncmp(magic, "RIFF", 4) != 0)
        goto file_error;
    read_le_long(wav_file->file, &len);
    fread(magic, 1, 4, wav_file->file);
    if (strncmp(magic, "WAVE", 4) != 0)
        goto file_error;
    for (;;) {
        fread(magic, 1, 4, wav_file->file);
        if (!read_le_long(wav_file->file, &len))
            goto file_error;
        if (!strncmp("fmt ", magic, 4))
            break;
        fseek(wav_file->file, len, SEEK_CUR);
    }
    if (len < 16)
        goto file_error;
    read_le_short(wav_file->file, &wav_file->format_tag);
    switch (wav_file->format_tag) {
    case WAVE_FORMAT_UNKNOWN:
    case WAVE_FORMAT_ALAW:
    case WAVE_FORMAT_MULAW:
    case WAVE_FORMAT_ADPCM:
    case WAVE_FORMAT_OKI_ADPCM:
    case WAVE_FORMAT_DIGISTD:
    case WAVE_FORMAT_DIGIFIX:
    case IBM_FORMAT_MULAW:
    case IBM_FORMAT_ALAW:
    case IBM_FORMAT_ADPCM:
        goto file_error;
    }
    read_le_short(wav_file->file, &wav_file->channels);
    read_le_long(wav_file->file, &wav_file->samples_per_sec);
    read_le_long(wav_file->file, &wav_file->avg_bytes_per_sec);
    read_le_short(wav_file->file, &wav_file->block_align);
    read_le_short(wav_file->file, &wav_file->bits_per_sample);
    /*    if (wav_file->bits_per_sample != 8 && wav_file->bits_per_sample != 16)
     goto file_error;*/
    len -= 16;
    if (len)
        fseek(wav_file->file, len, SEEK_CUR);

    for (;;) {
        fread(magic, 4, 1, wav_file->file);

        if (!read_le_long(wav_file->file, &len))
            goto file_error;
        if (!strncmp("data", magic, 4))
            break;
        fseek(wav_file->file, len, SEEK_CUR);
    }

    track = gp_track_new();
    track->mediatype = ITDB_MEDIATYPE_AUDIO;

    track->bitrate = wav_file->samples_per_sec * wav_file->channels * wav_file->bits_per_sample;
    track->samplerate = wav_file->samples_per_sec;
    track->tracklen = 1000 * ((double) 8 * len / track->bitrate);
    track->bitrate /= 1000; /* change to kbps */
    track->filetype = g_strdup(_("WAV audio file"));

    fclose(wav_file->file);
    g_free(wav_file);
    wav_file = NULL;
    return track;

    file_error: fclose(wav_file->file);
    g_free(wav_file);
    wav_file = NULL;
    fn = charset_to_utf8(filename);
    gtkpod_log_error(error, g_strdup_printf(_("%s does not appear to be a supported wav file.\n"), fn));
    g_free(fn);
    return NULL;
}