1
0
Fork 0
forked from len0rd/rockbox

(Tag) Database v2. this fixes all bugs in the old songdb.pl, should react like

v1, except this has albums with multiple artists support. *prays nothing breaks*
:X


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6347 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michiel Van Der Kolk 2005-04-25 18:19:59 +00:00
parent de4ef019b9
commit d41d44f073
2 changed files with 304 additions and 153 deletions

View file

@ -57,16 +57,21 @@
#define BE32(_x_) _x_
#endif
#define ID3DB_VERSION 1
#define SONGENTRY_SIZE (songlen+12+genrelen+4)
#define FILEENTRY_SIZE (filelen+12)
#define ALBUMENTRY_SIZE (albumlen+4+songarraylen*4)
#define ARTISTENTRY_SIZE (artistlen+albumarraylen*4)
#define ID3DB_VERSION 2
static int fd;
static int
songstart, albumstart, artiststart,
songcount, albumcount, artistcount,
songlen, songarraylen,
songstart, albumstart, artiststart, filestart,
songcount, albumcount, artistcount, filecount,
songlen, songarraylen, genrelen, filelen,
albumlen, albumarraylen,
artistlen, initialized = 0;
artistlen, rundbdirty,initialized = 0;
static int db_play_folder(struct tree_context* c);
static int db_search(struct tree_context* c, char* string);
@ -76,7 +81,7 @@ static char searchstring[32];
int db_init(void)
{
unsigned int version;
unsigned int buf[12];
unsigned int buf[17];
unsigned char* ptr = (char*)buf;
fd = open(ROCKBOX_DIR "/rockbox.id3db", O_RDONLY);
@ -84,7 +89,7 @@ int db_init(void)
DEBUGF("Failed opening database\n");
return -1;
}
read(fd, buf, 48);
read(fd, buf, 68);
if (ptr[0] != 'R' ||
ptr[1] != 'D' ||
@ -94,29 +99,35 @@ int db_init(void)
return -1;
}
version = BE32(buf[0]) & 0xff;
version = BE32(buf[0])&0xFF;
if (version != ID3DB_VERSION)
{
splash(HZ,true,"Unsupported database version %d!", version);
return -1;
}
songstart = BE32(buf[1]);
songcount = BE32(buf[2]);
songlen = BE32(buf[3]);
artiststart = BE32(buf[1]);
albumstart = BE32(buf[2]);
songstart = BE32(buf[3]);
filestart = BE32(buf[4]);
artistcount = BE32(buf[5]);
albumcount = BE32(buf[6]);
songcount = BE32(buf[7]);
filecount = BE32(buf[8]);
artistlen = BE32(buf[9]);
albumlen = BE32(buf[10]);
songlen = BE32(buf[11]);
genrelen = BE32(buf[12]);
filelen = BE32(buf[13]);
songarraylen = BE32(buf[14]);
albumarraylen = BE32(buf[15]);
rundbdirty = BE32(buf[16]);
albumstart = BE32(buf[4]);
albumcount = BE32(buf[5]);
albumlen = BE32(buf[6]);
songarraylen = BE32(buf[7]);
artiststart = BE32(buf[8]);
artistcount = BE32(buf[9]);
artistlen = BE32(buf[10]);
albumarraylen = BE32(buf[11]);
if (songstart > albumstart ||
albumstart > artiststart)
if (songstart > filestart ||
albumstart > songstart ||
artiststart > albumstart)
{
splash(HZ,true,"Corrupt ID3 database!");
return -1;
@ -150,7 +161,7 @@ int db_load(struct tree_context* c)
c->dentry_size = 2;
c->dirfull = false;
DEBUGF("db_load(%d, %x, %d)\n", table, extra, c->firstpos);
DEBUGF("db_load() table: %d extra: 0x%x firstpos: %d\n", table, extra, c->firstpos);
if (!table) {
table = root;
@ -166,7 +177,7 @@ int db_load(struct tree_context* c)
str(LANG_ID3DB_ALBUMS),
str(LANG_ID3DB_SONGS),
str(LANG_ID3DB_SEARCH)};
DEBUGF("dbload table root\n");
for (i=0; i < 4; i++) {
strcpy(nbuf, labels[i]);
dptr[0] = (unsigned long)nbuf;
@ -186,7 +197,7 @@ int db_load(struct tree_context* c)
char* labels[] = { str(LANG_ID3DB_SEARCH_ARTISTS),
str(LANG_ID3DB_SEARCH_ALBUMS),
str(LANG_ID3DB_SEARCH_SONGS)};
DEBUGF("dbload table search\n");
for (i=0; i < 3; i++) {
strcpy(nbuf, labels[i]);
dptr[0] = (unsigned long)nbuf;
@ -201,6 +212,7 @@ int db_load(struct tree_context* c)
case searchartists:
case searchalbums:
case searchsongs:
DEBUGF("dbload table searchsongs/searchartists/searchalbums\n");
i = db_search(c, searchstring);
c->dirlength = c->filesindir = i;
if (c->dirfull) {
@ -214,26 +226,28 @@ int db_load(struct tree_context* c)
return i;
case allsongs:
offset = songstart + c->firstpos * (songlen + 12);
DEBUGF("dbload table allsongs\n");
offset = songstart + c->firstpos * SONGENTRY_SIZE;
itemcount = songcount;
stringlen = songlen;
break;
case allalbums:
offset = albumstart +
c->firstpos * (albumlen + 4 + songarraylen * 4);
DEBUGF("dbload table allalbums\n");
offset = albumstart + c->firstpos * ALBUMENTRY_SIZE;
itemcount = albumcount;
stringlen = albumlen;
break;
case allartists:
offset = artiststart +
c->firstpos * (artistlen + albumarraylen * 4);
DEBUGF("dbload table allartists\n");
offset = artiststart + c->firstpos * ARTISTENTRY_SIZE;
itemcount = artistcount;
stringlen = artistlen;
break;
case albums4artist:
DEBUGF("dbload table albums4artist\n");
/* 'extra' is offset to the artist */
safeplacelen = albumarraylen * 4;
safeplace = (void*)(end_of_nbuf - safeplacelen);
@ -252,6 +266,7 @@ int db_load(struct tree_context* c)
break;
case songs4album:
DEBUGF("dbload table songs4album\n");
/* 'extra' is offset to the album */
safeplacelen = songarraylen * 4;
safeplace = (void*)(end_of_nbuf - safeplacelen);
@ -261,8 +276,10 @@ int db_load(struct tree_context* c)
return -1;
#ifdef LITTLE_ENDIAN
for (i=0; i<songarraylen; i++)
for (i=0; i<songarraylen; i++) {
safeplace[i] = BE32(safeplace[i]);
DEBUGF("db_load songs4album song %d: 0x%x\n",i,safeplace[i]);
}
#endif
offset = safeplace[0];
itemcount = songarraylen;
@ -270,8 +287,9 @@ int db_load(struct tree_context* c)
break;
case songs4artist:
DEBUGF("dbload table songs4artist\n");
/* 'extra' is offset to the artist, used as filter */
offset = songstart + c->firstpos * (songlen + 12);
offset = songstart + c->firstpos * SONGENTRY_SIZE;
itemcount = songcount;
stringlen = songlen;
break;
@ -318,13 +336,16 @@ int db_load(struct tree_context* c)
case songs4album:
case songs4artist:
rc = read(fd, intbuf, 12);
skip = SONGENTRY_SIZE-stringlen-12; /* skip the rest of the song info */
if (rc < 12) {
DEBUGF("%d read(%d) returned %d\n", i, 12, rc);
return -1;
}
/* continue to next song if wrong artist */
if (table == songs4artist && (int)BE32(intbuf[0]) != extra)
if (table == songs4artist && (int)BE32(intbuf[0]) != extra) {
lseek(fd, skip, SEEK_CUR);
continue;
}
/* save offset of filename */
dptr[1] = BE32(intbuf[2]);
@ -400,19 +421,19 @@ static int db_search(struct tree_context* c, char* string)
case searchartists:
start = artiststart;
count = artistcount;
size = artistlen + albumarraylen * 4;
size = ARTISTENTRY_SIZE;
break;
case searchalbums:
start = albumstart;
count = albumcount;
size = albumlen + 4 + songarraylen * 4;
size = ALBUMENTRY_SIZE;
break;
case searchsongs:
start = songstart;
count = songcount;
size = songlen + 12;
size = SONGENTRY_SIZE;
break;
default:
@ -497,7 +518,7 @@ int db_enter(struct tree_context* c)
case searchalbums:
/* virtual <all albums> entry points to the artist,
all normal entries point to the album */
if (newextra >= artiststart)
if (newextra < albumstart)
c->currtable = songs4artist;
else
c->currtable = songs4album;

View file

@ -12,6 +12,8 @@ my $dir;
my $strip;
my $verbose;
my $help;
my $dirisalbum;
my $dirisalbumname;
while($ARGV[0]) {
if($ARGV[0] eq "--db") {
@ -33,6 +35,14 @@ while($ARGV[0]) {
$verbose = 1;
shift @ARGV;
}
elsif($ARGV[0] eq "--dirisalbum") {
$dirisalbum = 1;
shift @ARGV;
}
elsif($ARGV[0] eq "--dirisalbumname") {
$dirisalbumname = 1;
shift @ARGV;
}
elsif($ARGV[0] eq "--help" or ($ARGV[0] eq "-h")) {
$help = 1;
shift @ARGV;
@ -50,11 +60,13 @@ my %filename;
my %lcartists;
my %lcalbums;
my $dbver = 1;
my %dir2albumname;
my $dbver = 2;
if(! -d $dir or $help) {
print "'$dir' is not a directory\n" if ($dir ne "" and ! -d $dir);
print "songdb --path <dir> [--db <file>] [--strip <path>] [--verbose] [--help]\n";
print "songdb --path <dir> [--dirisalbum] [--dirisalbumname] [--db <file>] [--strip <path>] [--verbose] [--help]\n";
exit;
}
@ -140,6 +152,7 @@ sub dodir {
# YEAR
# don't index songs without tags
# um. yes we do.
if (not defined $$id3{'ARTIST'} and
not defined $$id3{'ALBUM'} and
not defined $$id3{'TITLE'})
@ -178,29 +191,56 @@ sub dodir {
# fallback names
$$id3{'ARTIST'} = "<no artist tag>" if ($$id3{'ARTIST'} eq "");
# Fall back on the directory name (not full path dirname),
# if no album tag
$$id3{'ALBUM'} = (split m[/], $dir)[-1] if ($$id3{'ALBUM'} eq "");
#if that doesn't work, fall back.
# Fall back on the directory name (not full path dirname),
# if no album tag
if ($dirisalbum) {
if($dir2albumname{$dir} eq "") {
$dir2albumname{$dir} = $$id3{'ALBUM'};
}
elsif($dir2albumname{$dir} ne $$id3{'ALBUM'}) {
$dir2albumname{$dir} = (split m[/], $dir)[-1];
}
}
# if no directory
if ($dirisalbumname) {
$$id3{'ALBUM'} = (split m[/], $dir)[-1] if ($$id3{'ALBUM'} eq "");
}
$$id3{'ALBUM'} = "<no album tag>" if ($$id3{'ALBUM'} eq "");
# fall back on basename of the file if no title tag.
my $base;
($base = $f) =~ s/\.\w+$//;
# fall back on basename of the file if no title tag.
my $base;
($base = $f) =~ s/\.\w+$//;
$$id3{'TITLE'} = $base if ($$id3{'TITLE'} eq "");
# Append dirname, to handle multi-artist albums
$$id3{'DIR'} = $dir;
my $albumid = $id3->{'ALBUM'}."___".$$id3{'DIR'};
if($id3->{'ALBUM'}."___".$id3->{'DIR'} ne "<no album tag>___<no artist tag>") {
my $albumid;
if ($dirisalbum) {
$albumid=$$id3{'DIR'};
}
else {
$albumid= $id3->{'ALBUM'}."___".$$id3{'DIR'};
}
#printf "album id: %s\n", $albumid;
# if($id3->{'ALBUM'}."___".$id3->{'DIR'} ne "<no album tag>___<no artist tag>") {
my $num = ++$albums{$albumid};
if($num > $maxsongperalbum) {
$maxsongperalbum = $num;
$longestalbum = $albumid;
}
$album2songs{$albumid}{$$id3{TITLE}} = $id3;
$artist2albums{$$id3{ARTIST}}{$$id3{ALBUM}} = $id3;
}
if($dirisalbum) {
$artist2albums{$$id3{ARTIST}}{$$id3{DIR}} = $id3;
}
else {
$artist2albums{$$id3{ARTIST}}{$$id3{ALBUM}} = $id3;
}
# }
}
if($dirisalbum and $dir2albumname{$dir} eq "") {
$dir2albumname{$dir} = (split m[/], $dir)[-1];
printf "%s\n", $dir2albumname{$dir};
}
# extractdirs filters out only subdirectories from all given entries
@ -217,17 +257,24 @@ dodir($dir);
print "\n";
print "File name table\n" if ($verbose);
my $fc;
for(sort keys %entries) {
printf(" %s\n", $_) if ($verbose);
$fc += length($_)+1;
my $l = length($_);
if($l > $maxfilelen) {
$maxfilelen = $l;
$longestfilename = $_;
}
}
$maxfilelen++; # include zero termination byte
while($maxfilelen&3) {
$maxfilelen++;
}
my $maxsonglen = 0;
my $sc;
print "\nSong title table\n" if ($verbose);
for(sort {$entries{$a}->{'TITLE'} cmp $entries{$b}->{'TITLE'}} keys %entries) {
for(sort {uc($entries{$a}->{'TITLE'}) cmp uc($entries{$b}->{'TITLE'})} keys %entries) {
printf(" %s\n", $entries{$_}->{'TITLE'} ) if ($verbose);
my $l = length($entries{$_}->{'TITLE'});
if($l > $maxsonglen) {
@ -244,8 +291,8 @@ my $maxartistlen = 0;
print "\nArtist table\n" if ($verbose);
my $i=0;
my %artistcount;
for(sort keys %artists) {
printf(" %s\n", $_) if ($verbose);
for(sort {uc($a) cmp uc($b)} keys %artists) {
printf(" %s: %d\n", $_, $i) if ($verbose);
$artistcount{$_}=$i++;
my $l = length($_);
if($l > $maxartistlen) {
@ -256,6 +303,7 @@ for(sort keys %artists) {
$l = scalar keys %{$artist2albums{$_}};
if ($l > $maxalbumsperartist) {
$maxalbumsperartist = $l;
$longestartistalbum = $_;
}
}
$maxartistlen++; # include zero termination byte
@ -263,12 +311,22 @@ while($maxartistlen&3) {
$maxartistlen++;
}
if ($verbose) {
print "\nGenre table\n";
for(sort keys %genres) {
printf(" %s\n", $_);
}
print "\nGenre table\n" if ($verbose);
for(sort keys %genres) {
my $l = length($_);
if($l > $maxgenrelen) {
$maxgenrelen = $l;
$longestgenrename = $_;
}
}
$maxgenrelen++; #include zero termination byte
while($maxgenrelen&3) {
$maxgenrelen++;
}
if ($verbose) {
print "\nYear table\n";
for(sort keys %years) {
printf(" %s\n", $_);
@ -279,14 +337,32 @@ print "\nAlbum table\n" if ($verbose);
my $maxalbumlen = 0;
my %albumcount;
$i=0;
for(sort keys %albums) {
my @albumssort;
if($dirisalbum) {
@albumssort = sort {uc($dir2albumname{$a}) cmp uc($dir2albumname{$b})} keys %albums;
}
else {
@albumssort = sort {uc($a) cmp uc($b)} keys %albums;
}
for(@albumssort) {
my @moo=split(/___/, $_);
printf(" %s\n", $moo[0]) if ($verbose);
$albumcount{$_} = $i++;
my $l = length($moo[0]);
my $l;
if($dirisalbum) {
$l = length($dir2albumname{$_});
}
else {
$l = length($moo[0]);
}
if($l > $maxalbumlen) {
$maxalbumlen = $l;
$longestalbumname = $moo[0];
if($dirisalbum) {
$longestalbumname = $dir2albumname{$_};
}
else {
$longestalbumname = $moo[0];
}
}
}
$maxalbumlen++; # include zero termination byte
@ -296,6 +372,14 @@ while($maxalbumlen&3) {
sub dumpshort {
my ($num)=@_;
# print "int: $num\n";
print DB pack "n", $num;
}
sub dumpint {
my ($num)=@_;
@ -311,111 +395,124 @@ if (!scalar keys %entries) {
}
if ($db) {
my $songentrysize = $maxsonglen + 12;
my $songentrysize = $maxsonglen + 12 + $maxgenrelen+ 4;
my $albumentrysize = $maxalbumlen + 4 + $maxsongperalbum*4;
my $artistentrysize = $maxartistlen + $maxalbumsperartist*4;
my $fileentrysize = $maxfilelen + 12;
printf "Number of artists : %d\n", scalar keys %artists;
printf "Number of albums : %d\n", scalar keys %albums;
printf "Number of songs : %d\n", scalar keys %entries;
print "Max artist length : $maxartistlen ($longestartist)\n";
print "Max album length : $maxalbumlen ($longestalbumname)\n";
print "Max song length : $maxsonglen ($longestsong)\n";
print "Max songs per album: $maxsongperalbum ($longestalbum)\n";
printf "Number of artists : %d\n", scalar keys %artists;
printf "Number of albums : %d\n", scalar keys %albums;
printf "Number of songs / files : %d\n", scalar keys %entries;
print "Max artist length : $maxartistlen ($longestartist)\n";
print "Max album length : $maxalbumlen ($longestalbumname)\n";
print "Max song length : $maxsonglen ($longestsong)\n";
print "Max songs per album : $maxsongperalbum ($longestalbum)\n";
print "Max albums per artist: $maxalbumsperartist ($longestartistalbum)\n";
print "Max genre length : $maxgenrelen ($longestgenrename)\n";
print "Max file length : $maxfilelen ($longestfilename)\n";
print "Database version: $dbver\n" if ($verbose);
print "Song Entry Size : $songentrysize ($maxsonglen + 12 + $maxgenrelen + 4)\n" if ($verbose);
print "Album Entry Size: $albumentrysize ($maxalbumlen + 4 + $maxsongperalbum * 4)\n" if ($verbose);
print "Artist Entry Size: $artistentrysize ($maxartistlen + $maxalbumsperartist * 4)\n" if ($verbose);
print "File Entry Size: $fileentrysize ($maxfilelen + 12)\n" if ($verbose);
open(DB, ">$db") || die "couldn't make $db";
binmode(DB);
printf DB "RDB%c", $dbver;
$pathindex = 48; # paths always start at index 48
$pathindex = 68; # paths always start at index 68
$songindex = $pathindex + $fc; # fc is size of all paths
$songindex++ while ($songindex & 3); # align to 32 bits
dumpint($songindex); # file position index of song table
dumpint(scalar(keys %entries)); # number of songs
dumpint($maxsonglen); # length of song name field
$artistindex = $pathindex;
# set total size of song title table
$sc = scalar(keys %entries) * $songentrysize;
$albumindex = $songindex + $sc; # sc is size of all songs
dumpint($albumindex); # file position index of album table
dumpint(scalar(keys %albums)); # number of albums
dumpint($maxalbumlen); # length of album name field
dumpint($maxsongperalbum); # number of entries in songs-per-album array
my $ac = scalar(keys %albums) * $albumentrysize;
$artistindex = $albumindex + $ac; # ac is size of all albums
my $arc = scalar(keys %artists) * $artistentrysize;
$albumindex = $artistindex + $arc; # arc is size of all artists
$songindex = $albumindex + $ac; # ac is size of all albums
my $fileindex = $songindex + $sc; # sc is size of all songs
dumpint($artistindex); # file position index of artist table
dumpint($albumindex); # file position index of album table
dumpint($songindex); # file position index of song table
dumpint($fileindex); # file position index of file table
dumpint(scalar(keys %artists)); # number of artists
dumpint(scalar(keys %albums)); # number of albums
dumpint(scalar(keys %entries)); # number of songs
dumpint(scalar(keys %entries)); # number of files
dumpint($maxartistlen); # length of artist name field
dumpint($maxalbumlen); # length of album name field
dumpint($maxsonglen); # length of song name field
dumpint($maxgenrelen); #length of genre field
dumpint($maxfilelen); # length of file field
dumpint($maxsongperalbum); # number of entries in songs-per-album array
dumpint($maxalbumsperartist); # number of entries in albums-per-artist array
dumpint(-1); # rundb dirty
my $l=0;
#### TABLE of artists ###
# name of artist1
# pointers to albums of artist1
#### TABLE of file names ###
# path1
for (sort {uc($a) cmp uc($b)} keys %artists) {
my $artist = $_;
my $str = $_."\x00" x ($maxartistlen - length($_));
print DB $str;
for (sort keys %{$artist2albums{$artist}}) {
my $id3 = $artist2albums{$artist}{$_};
my $a;
if($dirisalbum) {
$a = $albumcount{"$$id3{'DIR'}"} * $albumentrysize;
}
else {
$a = $albumcount{"$$id3{'ALBUM'}___$$id3{'DIR'}"} * $albumentrysize;
}
dumpint($a + $albumindex);
}
for (scalar keys %{$artist2albums{$artist}} .. $maxalbumsperartist-1) {
print DB "\x00\x00\x00\x00";
}
my %filenamepos;
for $f (sort keys %entries) {
printf DB ("%s\x00", $f);
$filenamepos{$f}= $l;
$l += length($f)+1;
}
while ($l & 3) {
print DB "\x00";
$l++;
}
#### TABLE of songs ###
# title of song1
# pointer to artist of song1
# pointer to album of song1
# pointer to filename of song1
my $offset = $songindex;
for(sort {uc($entries{$a}->{'TITLE'}) cmp uc($entries{$b}->{'TITLE'})} keys %entries) {
my $f = $_;
my $id3 = $entries{$f};
my $t = $id3->{'TITLE'};
my $str = $t."\x00" x ($maxsonglen- length($t));
print DB $str; # title
my $a = $artistcount{$id3->{'ARTIST'}} * $artistentrysize;
dumpint($a + $artistindex); # pointer to artist of this song
$a = $albumcount{"$$id3{ALBUM}___$$id3{DIR}"} * $albumentrysize;
dumpint($a + $albumindex); # pointer to album of this song
# pointer to filename of this song
dumpint($filenamepos{$f} + $pathindex);
$$id3{'songoffset'} = $offset;
$offset += $songentrysize;
}
### Build song offset info.
my $offset = $songindex;
for(sort {uc($entries{$a}->{'TITLE'}) cmp uc($entries{$b}->{'TITLE'})} keys %entries) {
my $id3 = $entries{$_};
$$id3{'songoffset'} = $offset;
$offset += $songentrysize;
}
#### TABLE of albums ###
# name of album1
# pointers to artists of album1
# pointers to songs on album1
for(sort {uc($a) cmp uc($b)} keys %albums) {
for(@albumssort) {
my $albumid = $_;
my @moo=split(/___/, $_);
my $t = $moo[0];
my $str = $t."\x00" x ($maxalbumlen - length($t));
print DB $str;
my @moo=split(/___/, $_);
my $t;
my $str;
if($dirisalbum) {
$t = $dir2albumname{$albumid};
}
else {
$t = $moo[0];
}
$str = $t."\x00" x ($maxalbumlen - length($t));
print DB $str;
my @songlist = keys %{$album2songs{$albumid}};
my $id3 = $album2songs{$albumid}{$songlist[0]};
#printf "(d) albumid: %s artist: %s\n",$albumid, $id3->{'ARTIST'};
my $aoffset = $artistcount{$id3->{'ARTIST'}} * $artistentrysize;
dumpint($aoffset + $artistindex); # pointer to artist of this album
dumpint($aoffset + $artistindex); # pointer to artist of this album
if (defined $id3->{'TRACKNUM'}) {
@songlist = sort {
$album2songs{$albumid}{$a}->{'TRACKNUM'} <=>
@ -435,26 +532,59 @@ if ($db) {
print DB "\x00\x00\x00\x00";
}
}
#### TABLE of artists ###
# name of artist1
# pointers to albums of artist1
for (sort {uc($a) cmp uc($b)} keys %artists) {
my $artist = $_;
my $str = $_."\x00" x ($maxartistlen - length($_));
#### Build filename offset info
my $l=$fileindex;
my %filenamepos;
for $f (sort keys %entries) {
$filenamepos{$f}= $l;
$l += $fileentrysize;
}
#### TABLE of songs ###
# title of song1
# pointer to artist of song1
# pointer to album of song1
# pointer to filename of song1
for(sort {uc($entries{$a}->{'TITLE'}) cmp uc($entries{$b}->{'TITLE'})} keys %entries) {
my $f = $_;
my $id3 = $entries{$f};
my $t = $id3->{'TITLE'};
my $g = $id3->{'GENRE'};
my $str = $t."\x00" x ($maxsonglen- length($t));
print DB $str; # title
$str = $g."\x00" x ($maxgenrelen - length($g));
my $a = $artistcount{$id3->{'ARTIST'}} * $artistentrysize;
dumpint($a + $artistindex); # pointer to artist of this song
if($dirisalbum) {
$a = $albumcount{"$$id3{DIR}"} * $albumentrysize;
}
else {
$a = $albumcount{"$$id3{ALBUM}___$$id3{DIR}"} * $albumentrysize;
}
dumpint($a + $albumindex); # pointer to album of this song
# pointer to filename of this song
dumpint($filenamepos{$f});
print DB $str; #genre
dumpshort(-1);
dumpshort($id3->{'YEAR'});
}
#### TABLE of file names ###
# path1
for $f (sort keys %entries) {
my $str = $f."\x00" x ($maxfilelen- length($f));
my $id3 = $entries{$f};
print DB $str;
for (sort keys %{$artist2albums{$artist}}) {
my $id3 = $artist2albums{$artist}{$_};
my $a = $albumcount{"$$id3{'ALBUM'}___$$id3{'DIR'}"} * $albumentrysize;
dumpint($a + $albumindex);
}
for (scalar keys %{$artist2albums{$artist}} .. $maxalbumsperartist-1) {
print DB "\x00\x00\x00\x00";
}
dumpint(0);
dumpint($id3->{'songoffset'});
dumpint(-1);
}
close(DB);