+package epg::flac::archive::tags;
+
+use v5.12;
+use warnings;
+
+use Exporter 'import';
+
+our @EXPORT_OK = qw[
+ read_tags
+ mangle_for_file_name
+ quote
+];
+
+sub read_tags {
+ my $fh = shift;
+ my %album;
+ my @tracks;
+ my $tracknum = 0;
+ while (<$fh>) {
+ chomp;
+ s/^([^=[\]]+)(\[(\d+)])?=// || die("no field name in $_");
+ my $name = $1;
+ # TODO validate $name
+ # TODO album tags should be illegal after track tags
+ if (defined($3)) {
+ if ($3 == $tracknum + 2) {
+ $tracknum++;
+ } elsif ($3 != $tracknum + 1) {
+ $tracknum++; # increment from 0 to 1 for error message
+ die("illegal track number jump from $tracknum to $3")
+ }
+ push(@{$tracks[$tracknum]->{$name}}, $_);
+ } else {
+ push(@{$album{$name}}, $_);
+ }
+ }
+
+ \%album, \@tracks
+}
+
+sub mangle_for_file_name {
+ my $fn = shift;
+ $fn =~ s/[!,.?]//g; # discard these punctuation marks
+ $fn =~ s/\s+/_/g; # replace all whitespace with _
+ $fn =~ s/[^A-Za-z0-9_]/-/g; # everything else with -
+ $fn =~ s/_[_-]/_/g; # collapse repeated _ or - to _
+ $fn =~ s/-[_-]/_/g; # more
+ $fn =~ s/^[_-]+//; # discard any _ or - at beginning
+ $fn =~ s/[_-]+$//; # at end too
+ $fn
+}
+
+sub quote {
+ my $s = shift;
+ $s =~ s/'/'\\''/g;
+ "'$s'"
+}
+
+1;