use v5.26;
use warnings;
package Mac::Finder::Tags::Impl::mdls;
# ABSTRACT: Provides get_tags based on the mdls tool
$Mac::Finder::Tags::Impl::mdls::VERSION = '0.01';
use Object::Pad 0.57;
use Mac::Finder::Tags::Tag;
class Mac::Finder::Tags::Impl::mdls
:does(Mac::Finder::Tags::Impl)
:strict(params)
{
method get_tags ($path) {
return my @empty if not stat $path; # dangling symlinks etc.
$path =~ s/([\\"])/\\$1/g;
my $md = `mdls -name kMDItemFSLabel -name kMDItemUserTags -raw "$path"`;
my @md = split m/,?\n\s*/, decode_cesu8($md);
my $label = substr shift(@md), 0, 1;
pop @md;
my @tags;
if (@md == 1) {
@tags = ( Mac::Finder::Tags::Tag->new( name => trim($md[0]), color => $label ) );
}
else {
@tags = map { Mac::Finder::Tags::Tag->new( name => trim($_), color_guessed => !!1 ) } @md;
}
if (! @tags && $label) {
@tags = Mac::Finder::Tags::Tag->new( name => undef, color => $label, legacy_label => !!1 );
}
return @tags;
}
my $SURROGATE_OFFSET = 0x10000 - (0xD800 << 10) - 0xDC00; # for decoding CESU-8 surrogate pairs
sub decode_cesu8 ($data) {
# decode escaped Unicode sequences (CESU-8 encoded)
# https://unicode.org/faq/utf_bom.html#utf16-4
$data =~ s{
\\U([dD][89abAB][0-9a-fA-F]{2})
\\U([dD][c-fC-F][0-9a-fA-F]{2})
}{
my ($hi, $lo) = (hex $1, hex $2);
my $codepoint = ($hi << 10) + $lo + $SURROGATE_OFFSET;
chr $codepoint;
}exg;
$data =~ s{\\U([0-9a-fA-F]{4})}{chr hex $1}eg;
return $data;
}
# trim whitespace and remove any quotes
sub trim ($s) {
$s =~ s/\A\s+//;
$s =~ s/,?\s+\z//;
$s =~ s/\A"(.*)"\Z/$1/;
$s =~ s{\\"}{"}g;
$s;
}
}
1;