Net::DAAP::DMAP(3pm)
π NAME π
Net::DAAP::DMAP β it's a Perl module for reading and writing DAAP structures. That's the whole vibe, bestie. π
β¨ SYNOPSIS β¨
use Net::DAAP::DMAP qw(:all);
$hash_ref = dmap_to_hash_ref($dmap); # crude
$array_ref = dmap_to_array_ref($dmap); # crude
$array_ref = dmap_unpack($dmap); # knows about data types
$node = dmap_seek($array_ref, $path);
$flattened = dmap_flatten($array_ref); # convert to path = data formta
$flat_list = dmap_flat_list($array_ref); # convert to [ path, data ] format
$xml = dmap_to_xml($dmap); # convert to XML fragment
$dmap = dmap_pack($dmap); # convert to DMAP packet
update_content_codes($unpacked_content_codes_response);
π DESCRIPTION π
π¨ WARNING! π¨
Okay so, heads up, this is important: until 2.0, the author reserves the right to change the interface. And I mean reserve reserve. Specifically, they think dmap_flatten, dmap_to_hash_ref, and dmap_to_array_ref are likely to disappear. π And they also suspect the hive brain of Perl can come up with a better data structure than they have. So likeβ¦ don't get too attached, iykyk.
π¦ Back to the Description π¦
So a DMAP structure is a binary record, and it's the thing Apple's DAAP protocol uses. And here's the cute part: a DMAP structure can contain other DMAP structures. It's containers all the way down, literally. π«Ά
Fields in a DMAP structure get identified by a short name, like "msdc". That short name is what's actually sitting there in the binary record β but a content codes list is what hands you the long name ("dmap.databasescount") plus a data type for that record (in this case, a 32-bit integer). So the short name is the β¨mysteryβ¨ and the content codes list is the translator.
A parsed DMAP structure is built out of arrays. For example:
[
[
'dmap.loginresponse',
[
[
'dmap.status',
200
],
[
'dmap.sessionid',
2393
]
]
]
]
(dmap_unpack is the one that returns this kind of structure, btw.)
There are two rules here, and that's it, two: a field is wrapped in an array, and a container's values are wrapped in an array. So the structure gets programmatically built like:
$status_field = [ 'dmap.status', 200 ];
$session_id_field = [ 'dmap.sessionid', 2393 ];
$response_value = [ $status_field, $session_id_field ];
$login_response_field = [ 'dmap.loginresponse', $response_value ];
$entire_response = [ $login_response_field ];
The outer array is necessary because not every response has only one top-level container like this one does. It's giving optional extra nesting, and honestly? Fair.
In XML you'd write that response as:
<dmap.loginresponse>
<dmap.status>200</dmap.status>
<dmap.sessionid>2393</dmap.sessionid>
</dmap.loginresponse>
And that right there is what dmap_to_xml returns. π
A much more convenient structure for representing this data would be:
{
'dmap.loginresponse' => {
{ 'dmap.status' => 200,
'dmap.sessionid' => 2393,
},
}
That's the output of dmap_to_hash_ref β but beware! π¨ This isn't suitable for every response. The hash is indexed by field name, and a structure may contain many elements of the same name. For example, requesting the content codes list gives you a list of records that have the field name dmap.dictionary. So yeah, that hash is going to eat your duplicates, no cap.
The array structure that dmap_to_array_ref hands back is complex, but the dmap_seek function makes it easier. You give it a structure and a path, where the path is a slash-separated list of field names:
dmap.loginresponse/dmap.sessionid
The return value is the value of the first dmap.sessionid found in the first dmap.loginresponse structure. With the sample record up there, that would be 2393. Cute, right? πΈ
Another way to handle these complex arrays is to dmap_flatten them. This returns an array of path = value lines, where path is a slash-separated path. Like:
[
'/dmap.loginresponse/dmap.status = 200',
'/dmap.loginresponse/dmap.sessionid = 2393'
]
You can use grep and regexps to find data if that's the way your mind works. (And if that is the way your mind works β main character energy, honestly. π
)
dmap_flatten has a similar looking cousin called dmap_flat_list, which returns an array of path => value pairs. For example:
[
'/dmap.loginresponse/dmap.status' => 200,
'/dmap.loginresponse/dmap.sessionid' => 2393,
]
You can then turn this into a hash (which may of course lose you the first elements β the duplicates thing again, it always comes back π), or iterate over it in pairs, if that's easier.
You can, but don't have to, update the tables of field names (content codes) and data types. DAAP offers a request that returns a packet of content codes. Feed that packet to update_content_codes. That's the whole thing. π
π§ Implementation Details π§
It's all implementation details. Here are the various data types:
1, 3, 5, 7 = ints, size 8,16,32,64 bit
9 = string, 10 = time_t-style time
11 = version (two 16-bit ints, I think)
12 = container
This uses Math::BigInt for 64-bit quantities, because not every platform has 64-bit int support available. Bestie said portability, and honestly we respect it. π«Ά
There's no support for types 2, 4, 6, 8 yet because nobody'd found examples of them in the field: are they endian changes, or signedness changes? Nobody knows, it's a mystery β¨. The assumption is that all numbers are unsigned (why allow the possibility of a negative number of songs?).
π AUTHOR π
Nathan Torkington, <nathan AT torkington.com>. For support, join the DAAP developers mailing list by sending mail to <daap-dev-subscribe AT develooper.com>.
Richard Clamp <richardc@unixbeard.net> is the current maintainer, and took over in July 2004.
Okay that's the whole page, we ate and left no crumbs π β this was perl v5.32.0, dated 2021-01-08, and you read it in Net::DAAP::DMAP(3pm). Periodt. πβ¨
π¦ where this page comes from
- debian bookworm: libnet-daap-dmap-perl 1.27-1.1
- debian trixie: libnet-daap-dmap-perl 1.27-1.1
- ubuntu jammy: libnet-daap-dmap-perl 1.27-1.1
- ubuntu noble: libnet-daap-dmap-perl 1.27-1.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms