Reading in an ID3 tag in C

xplicitmastajs
xplicitmastajs used Ask the Experts™
on
Hi, I'm writing a program that will read (binary mode) in a music file through the command line, grab the id3 tag at the end of it, and then print it out. However, in C, I cannot get my fread() to work correctly; when I try to copy the id3 tag contents into a struct, I get jumbles of the id3 tag in places I don't  want them in (e.g. half the title in the author variable, part of the author in the comments variable).

Also, I don't think I'm using the strncpy() function correctly, but I think that I need to use it in order to keep the character length of each field constant. Any help would be greatly appreciated. My code so far is included.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int param_count;
char *file_name;
char title[30];
char artist[30];
char album[30];
char year[4];
char comment[28];
char track_num;
char genre;

int main(int argc, char *argv[])
{
	//save file name and paramater count
	param_count = argc;
	file_name = argv[1];
	
	struct id3tag
	{
		char TAG[3];
		char title[30];
		char artist[30];
		char album[30];
		char year[4];
		char comment[28];
		char seperator;
		char track_num;
		char genre;
	} tag;
	
	FILE *song_file;
	song_file = fopen(file_name, "r+b");
	if (song_file == NULL)
	{
		printf("File could not be opened.");
		return (0);
	}   
	
	fseek(song_file, -128, SEEK_END);
	fread(&tag.TAG, 1, sizeof(&tag.TAG), song_file);
	fread(&tag.title, 1, sizeof(&tag.title), song_file);
	fread(&tag.artist, 1, sizeof(&tag.artist), song_file);
	fread(&tag.album, 1, sizeof(&tag.album), song_file);
	fread(&tag.year, 1, sizeof(&tag.year), song_file);
	fread(&tag.comment, 1, sizeof(&tag.comment), song_file);
	fread(&tag.seperator, 1, sizeof(&tag.seperator), song_file);
	fread(&tag.track_num, 1, sizeof(&tag.track_num), song_file);
	fread(&tag.genre, 1, sizeof(&tag.genre), song_file);
	
	strncpy(title, tag.title, 30);
	strncpy(artist, tag.artist, 30);
	strncpy(album, tag.album, 30);
	strncpy(year, tag.year, 4);
	strncpy(comment, tag.comment, 28);
	strncpy(genre, tag.genre, 1);
	strncpy(track_num, tag.track_num, 1);
	
	//printf("%s\n", tag.TAG);
	printf("%s\n", title);
	printf("%s\n", artist);
	printf("%s\n", album);
	printf("%s\n", year);
	printf("%s\n", comment);
	printf("%d\n", track_num);
	printf("%d\n", genre);
}

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Commented:
code works... i've tested it

#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#pragma pack(push, 1)      // set 1 byte aligned
typedef struct id3tag{
      char TAG[3];
      char title[30];
      char artist[30];
      char album[30];
      char year[4];
      char comment[28];
      char seperator;
      char track_num;
      char genre;
} id3tag;
#pragma pack(pop)

int _tmain(int argc, _TCHAR* argv[])
{
      if(argv[1] == NULL || strlen(argv[1]) == 0) return 0;

      int param_count;
      char *file_name;
      id3tag tag;

      memset(&tag, 0x00, sizeof(tag));

      //save file name and paramater count
      param_count = argc;
      file_name = argv[1];      

      FILE *song_file = NULL;
      song_file = fopen(file_name, "r+b");
      if(song_file == NULL){
            printf("File could not be opened.");
            return(0);
      }

      fseek(song_file, -128, SEEK_END);
      fread(&tag, sizeof(tag), 1, song_file);
      fclose(song_file);
      
      printf("%.3s\n", tag.TAG);
      printf("%.30s\n", tag.title);
      printf("%.30s\n", tag.artist);
      printf("%.30s\n", tag.album);
      printf("%.4s\n", tag.year);
      printf("%.28s\n", tag.comment);
      printf("%d\n", tag.track_num);
      printf("%d\n", tag.genre);

      return 1;
}
re: sizeof(&tag.track_num)

The expression, &tag.track_num, is the address of tag.track_num, which is a pointer. The size of a pointer is 4 bytes. But track_num is a char, which is 1 byte.
Top Expert 2009
Commented:
1) Reading the entire data to the struct in one fread is not recommended. The original approach with the multiple freads is just fine.

2) Note that what phoffric said is true for all sizeof calls in your code - just remove the & for all of them.

3) You can't use strncpy for a single char either. strncpy is used to copy strings.
You don't need to though. You can simply do :

        genre = tag.genre;
        track_num = tag.track_num;

But just a question : why are you copying the data ? You already have it in the struct.

4) If you want to print the strings, you'll have to make sure that they are null terminated.
Announcing the Winners!

The results are in for the 15th Annual Expert Awards! Congratulations to the winners, and thank you to everyone who participated in the nominations. We are so grateful for the valuable contributions experts make on a daily basis. Click to read more about this year’s recipients!


4) If you want to print the strings, you'll have to make sure that they are null terminated.


how is this done???
Top Expert 2009

Commented:
You make sure that there's a '\0' character at the end of the string.
You make sure that there's a '\0' character at the end of the string.

Yes But how is it done?
Top Expert 2009

Commented:
However you want :) If there isn't one there, then you place one where you want the string to end. If there is already one there, nothing needs to be done.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial