/*****************************************************
 * mp3tagger.c
 * Copyright January 6, 2001
 * Adam Woodworth
 * adam@mirkwood.com
 * www.mirkwood.com
 *
 * This program is freeware.
 * You may use this program as you wish,
 * but please e-mail me if you find this program
 * useful and/or if you borrow code from this
 * source file.
 *
 * Usage:
 *   For displaying a tag:
 *       mp3tagger <file>
 *
 *   For writing/rewriting a tag:
 *       mp3tagger <file> <title> <artist> <album> \
 *                 <year> <comment> <trackNum> <genre>
 *
 *
 * mp3tagger currently only reads and writes
 * ID3 version 1 format tags.
 *
 * My intention with mp3tagger was to make a simple
 * command line interface tagger so that one could
 * make a Perl or other script that would parse the
 * names of MP3 files and automatically run
 * this program with the appropriate arguments to
 * write a tag to each MP3 file.
 *****************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifdef WIN32  /* Windows doesn't have unistd.h, of course. */
#include <io.h>
#else
#include <unistd.h>
#endif


#define ID3_LENGTH 128
#define DEF_COMMENT "mp3tagger : www.mirkwood.com"

struct id3 {
  char tagID[3];     /* Tag ID.  Must be "TAG". */
  char title[30];    /* Title of the song. */
  char artist[30];   /* Artist name. */
  char album[30];    /* Album name. */
  char year[4];      /* Year released. */
  char comment[29];  /* Any comments. */
  char trackNum;     /* Track number on album. */
  char genre;        /* Genre ID. */
};


void printID3(struct id3 *tag) {
  printf("TAG ID: %.3s\n", tag->tagID);
  printf("Title: %.30s\n", tag->title);
  printf("Artist: %.30s\n", tag->artist);
  printf("Album: %.30s\n", tag->album);
  printf("Year: %.4s\n", tag->year);
  printf("Comment: %.29s\n", tag->comment);
  printf("Track Number: %d\n", tag->trackNum);
  printf("Genre: %d\n", tag->genre);
}


int main(int argc, char **argv) {
  struct id3 *tag;
  int file, result;

  if (argc != 2 && argc != 9) {
    printf("  mp3tagger\n"
	   "\n"
	   "  Copyright 2001, Adam Woodworth\n"
	   "  adam@mirkwood.com\n"
	   "  www.mirkwood.com\n"
	   "\n"
	   "  Usage:\n"
	   "  For displaying a tag:\n"
	   "    mp3tagger <file>\n"
	   "\n"
	   "  For writing/rewriting a tag:\n"
	   "    mp3tagger <file> <title> <artist> <album> <year> <comment> <trackNum> <genre>\n"
	   );
    return 0;
  }
	   

  tag = (struct id3 *)malloc(ID3_LENGTH);
  memset((void *)tag, 0, ID3_LENGTH);

  printf("Processing %s\n", argv[1]);

#ifdef WIN32
  /* MS Visual C has this stupid behaviour of opening files up in
   * text mode translation by default, so we have to explicitly
   * say that we want normal (binary, no translation) mode.
   */
  file = open(argv[1], O_RDWR | O_APPEND | O_BINARY);
#else
  file = open(argv[1], O_RDWR | O_APPEND);
#endif
  if (file == -1) {
    perror("could not open file");
    return 1;
  }

  /* Seek to the end of the file, minus 128 bytes to find the ID3 tag,
   * if one exists.
   */
  result = lseek(file, -1*ID3_LENGTH, SEEK_END);
  if (result == -1) {
    perror("could not seek to ID3 tag");
    return 1;
  }

  result = read(file, tag, ID3_LENGTH);
  if (result == -1) {
    perror("could not read ID3 tag");
    return 1;
  }

  if (strncmp(tag->tagID, "TAG", 3) == 0) {
    /* We found a valid ID3 tag in this MP3, so seek back to the
     * tag location so we can rewrite the tag.
     */
    printID3(tag);
    printf("Found a valid ID3 tag.\n");
    result = lseek(file, -1*ID3_LENGTH, SEEK_END);
    if (result == -1) {
      perror("could not seek to ID3 tag");
      return 1;
    }
    if (argc == 2) {  /* Only reading the tag. */
      close(file);
      return 0;
    }
    printf("Overwriting with new tag.\n");
  }
  else {
    printf("Found no valid ID3 tag.\n");
    if (argc == 2) {  /* Only reading the tag. */
      close(file);
      return 0;
    }
    printf("Appending new tag.\n");
  }

  memset((void *)tag, 0, ID3_LENGTH);

  strcpy(tag->tagID, "TAG");
  strcpy(tag->title, argv[2]);
  strcpy(tag->artist, argv[3]);
  strcpy(tag->album, argv[4]);
  strcpy(tag->year, argv[5]);
  if (strlen(argv[6]) > 0)
    strcpy(tag->comment, argv[6]);
  else
    strcpy(tag->comment, DEF_COMMENT);
  tag->trackNum = atoi(argv[7]);
  tag->genre = atoi(argv[8]);

  printID3(tag);

  result = write(file, tag, ID3_LENGTH);
  if (result == -1) {
    perror("could not write ID3 tag");
    return 1;
  }

  close(file);

  printf("\n");

  return 0;
}
