| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545 | 
							- #include "dmap_parser.h"
 
- #include <stdio.h>
 
- #include <stdlib.h>
 
- #include <string.h>
 
- #include <ctype.h>
 
- #define DMAP_STRINGIFY_(x) #x
 
- #define DMAP_STRINGIFY(x) DMAP_STRINGIFY_(x)
 
- typedef enum {
 
- 	DMAP_UNKNOWN,
 
- 	DMAP_UINT,
 
- 	DMAP_INT,
 
- 	DMAP_STR,
 
- 	DMAP_DATA,
 
- 	DMAP_DATE,
 
- 	DMAP_VERS,
 
- 	DMAP_DICT,
 
- 	DMAP_ITEM
 
- } DMAP_TYPE;
 
- typedef struct {
 
- 	/**
 
- 	 * The four-character code used in the encoded message.
 
- 	 */
 
- 	const char *code;
 
- 	/**
 
- 	 * The type of data associated with the content code.
 
- 	 */
 
- 	DMAP_TYPE type;
 
- 	/**
 
- 	 * For listings, the type of their listing item children.
 
- 	 *
 
- 	 * Listing items (mlit) can be of any type, and as with other content codes
 
- 	 * their type information is not encoded in the message. Parsers must
 
- 	 * determine the type of the listing items based on their parent context.
 
- 	 */
 
- 	DMAP_TYPE list_item_type;
 
- 	/**
 
- 	 * A human-readable name for the content code.
 
- 	 */
 
- 	const char *name;
 
- } dmap_field;
 
- static const dmap_field dmap_fields[] = {
 
- 	{ "abal",    DMAP_DICT, DMAP_STR,  "daap.browsealbumlisting" },
 
- 	{ "abar",    DMAP_DICT, DMAP_STR,  "daap.browseartistlisting" },
 
- 	{ "abcp",    DMAP_DICT, DMAP_STR,  "daap.browsecomposerlisting" },
 
- 	{ "abgn",    DMAP_DICT, DMAP_STR,  "daap.browsegenrelisting" },
 
- 	{ "abpl",    DMAP_UINT, 0,         "daap.baseplaylist" },
 
- 	{ "abro",    DMAP_DICT, 0,         "daap.databasebrowse" },
 
- 	{ "adbs",    DMAP_DICT, 0,         "daap.databasesongs" },
 
- 	{ "aeAD",    DMAP_DICT, 0,         "com.apple.itunes.adam-ids-array" },
 
- 	{ "aeAI",    DMAP_UINT, 0,         "com.apple.itunes.itms-artistid" },
 
- 	{ "aeCD",    DMAP_DATA, 0,         "com.apple.itunes.flat-chapter-data" },
 
- 	{ "aeCF",    DMAP_UINT, 0,         "com.apple.itunes.cloud-flavor-id" },
 
- 	{ "aeCI",    DMAP_UINT, 0,         "com.apple.itunes.itms-composerid" },
 
- 	{ "aeCK",    DMAP_UINT, 0,         "com.apple.itunes.cloud-library-kind" },
 
- 	{ "aeCM",    DMAP_UINT, 0,         "com.apple.itunes.cloud-match-type" },
 
- 	{ "aeCR",    DMAP_STR,  0,         "com.apple.itunes.content-rating" } ,
 
- 	{ "aeCS",    DMAP_UINT, 0,         "com.apple.itunes.artworkchecksum" },
 
- 	{ "aeCU",    DMAP_UINT, 0,         "com.apple.itunes.cloud-user-id" },
 
- 	{ "aeCd",    DMAP_UINT, 0,         "com.apple.itunes.cloud-id" },
 
- 	{ "aeDE",    DMAP_STR,  0,         "com.apple.itunes.longest-content-description" },
 
- 	{ "aeDL",    DMAP_UINT, 0,         "com.apple.itunes.drm-downloader-user-id" },
 
- 	{ "aeDP",    DMAP_UINT, 0,         "com.apple.itunes.drm-platform-id" },
 
- 	{ "aeDR",    DMAP_UINT, 0,         "com.apple.itunes.drm-user-id" },
 
- 	{ "aeDV",    DMAP_UINT, 0,         "com.apple.itunes.drm-versions" },
 
- 	{ "aeEN",    DMAP_STR,  0,         "com.apple.itunes.episode-num-str" },
 
- 	{ "aeES",    DMAP_UINT, 0,         "com.apple.itunes.episode-sort" },
 
- 	{ "aeFA",    DMAP_UINT, 0,         "com.apple.itunes.drm-family-id" },
 
- 	{ "aeGD",    DMAP_UINT, 0,         "com.apple.itunes.gapless-enc-dr" } ,
 
- 	{ "aeGE",    DMAP_UINT, 0,         "com.apple.itunes.gapless-enc-del" },
 
- 	{ "aeGH",    DMAP_UINT, 0,         "com.apple.itunes.gapless-heur" },
 
- 	{ "aeGI",    DMAP_UINT, 0,         "com.apple.itunes.itms-genreid" },
 
- 	{ "aeGR",    DMAP_UINT, 0,         "com.apple.itunes.gapless-resy" },
 
- 	{ "aeGU",    DMAP_UINT, 0,         "com.apple.itunes.gapless-dur" },
 
- 	{ "aeGs",    DMAP_UINT, 0,         "com.apple.itunes.can-be-genius-seed" },
 
- 	{ "aeHC",    DMAP_UINT, 0,         "com.apple.itunes.has-chapter-data" },
 
- 	{ "aeHD",    DMAP_UINT, 0,         "com.apple.itunes.is-hd-video" },
 
- 	{ "aeHV",    DMAP_UINT, 0,         "com.apple.itunes.has-video" },
 
- 	{ "aeK1",    DMAP_UINT, 0,         "com.apple.itunes.drm-key1-id" },
 
- 	{ "aeK2",    DMAP_UINT, 0,         "com.apple.itunes.drm-key2-id" },
 
- 	{ "aeMC",    DMAP_UINT, 0,         "com.apple.itunes.playlist-contains-media-type-count" },
 
- 	{ "aeMK",    DMAP_UINT, 0,         "com.apple.itunes.mediakind" },
 
- 	{ "aeMX",    DMAP_STR,  0,         "com.apple.itunes.movie-info-xml" },
 
- 	{ "aeMk",    DMAP_UINT, 0,         "com.apple.itunes.extended-media-kind" },
 
- 	{ "aeND",    DMAP_UINT, 0,         "com.apple.itunes.non-drm-user-id" },
 
- 	{ "aeNN",    DMAP_STR,  0,         "com.apple.itunes.network-name" },
 
- 	{ "aeNV",    DMAP_UINT, 0,         "com.apple.itunes.norm-volume" },
 
- 	{ "aePC",    DMAP_UINT, 0,         "com.apple.itunes.is-podcast" },
 
- 	{ "aePI",    DMAP_UINT, 0,         "com.apple.itunes.itms-playlistid" },
 
- 	{ "aePP",    DMAP_UINT, 0,         "com.apple.itunes.is-podcast-playlist" },
 
- 	{ "aePS",    DMAP_UINT, 0,         "com.apple.itunes.special-playlist" },
 
- 	{ "aeRD",    DMAP_UINT, 0,         "com.apple.itunes.rental-duration" },
 
- 	{ "aeRP",    DMAP_UINT, 0,         "com.apple.itunes.rental-pb-start" },
 
- 	{ "aeRS",    DMAP_UINT, 0,         "com.apple.itunes.rental-start" },
 
- 	{ "aeRU",    DMAP_UINT, 0,         "com.apple.itunes.rental-pb-duration" },
 
- 	{ "aeRf",    DMAP_UINT, 0,         "com.apple.itunes.is-featured" },
 
- 	{ "aeSE",    DMAP_UINT, 0,         "com.apple.itunes.store-pers-id" },
 
- 	{ "aeSF",    DMAP_UINT, 0,         "com.apple.itunes.itms-storefrontid" },
 
- 	{ "aeSG",    DMAP_UINT, 0,         "com.apple.itunes.saved-genius" },
 
- 	{ "aeSI",    DMAP_UINT, 0,         "com.apple.itunes.itms-songid" },
 
- 	{ "aeSN",    DMAP_STR,  0,         "com.apple.itunes.series-name" },
 
- 	{ "aeSP",    DMAP_UINT, 0,         "com.apple.itunes.smart-playlist" },
 
- 	{ "aeSU",    DMAP_UINT, 0,         "com.apple.itunes.season-num" },
 
- 	{ "aeSV",    DMAP_VERS, 0,         "com.apple.itunes.music-sharing-version" },
 
- 	{ "aeXD",    DMAP_STR,  0,         "com.apple.itunes.xid" },
 
- 	{ "aecp",    DMAP_STR,  0,         "com.apple.itunes.collection-description" },
 
- 	{ "aels",    DMAP_UINT, 0,         "com.apple.itunes.liked-state" },
 
- 	{ "aemi",    DMAP_DICT, 0,         "com.apple.itunes.media-kind-listing-item" },
 
- 	{ "aeml",    DMAP_DICT, 0,         "com.apple.itunes.media-kind-listing" },
 
- 	{ "agac",    DMAP_UINT, 0,         "daap.groupalbumcount" },
 
- 	{ "agma",    DMAP_UINT, 0,         "daap.groupmatchedqueryalbumcount" },
 
- 	{ "agmi",    DMAP_UINT, 0,         "daap.groupmatchedqueryitemcount" },
 
- 	{ "agrp",    DMAP_STR,  0,         "daap.songgrouping" },
 
- 	{ "ajAE",    DMAP_UINT, 0,         "com.apple.itunes.store.ams-episode-type" },
 
- 	{ "ajAS",    DMAP_UINT, 0,         "com.apple.itunes.store.ams-episode-sort-order" },
 
- 	{ "ajAT",    DMAP_UINT, 0,         "com.apple.itunes.store.ams-show-type" },
 
- 	{ "ajAV",    DMAP_UINT, 0,         "com.apple.itunes.store.is-ams-video" },
 
- 	{ "ajal",    DMAP_UINT, 0,         "com.apple.itunes.store.album-liked-state" },
 
- 	{ "ajcA",    DMAP_UINT, 0,         "com.apple.itunes.store.show-composer-as-artist" },
 
- 	{ "ajca",    DMAP_UINT, 0,         "com.apple.itunes.store.show-composer-as-artist" },
 
- 	{ "ajuw",    DMAP_UINT, 0,         "com.apple.itunes.store.use-work-name-as-display-name" },
 
- 	{ "amvc",    DMAP_UINT, 0,         "daap.songmovementcount" },
 
- 	{ "amvm",    DMAP_STR,  0,         "daap.songmovementname" },
 
- 	{ "amvn",    DMAP_UINT, 0,         "daap.songmovementnumber" },
 
- 	{ "aply",    DMAP_DICT, 0,         "daap.databaseplaylists" },
 
- 	{ "aprm",    DMAP_UINT, 0,         "daap.playlistrepeatmode" },
 
- 	{ "apro",    DMAP_VERS, 0,         "daap.protocolversion" },
 
- 	{ "apsm",    DMAP_UINT, 0,         "daap.playlistshufflemode" },
 
- 	{ "apso",    DMAP_DICT, 0,         "daap.playlistsongs" },
 
- 	{ "arif",    DMAP_DICT, 0,         "daap.resolveinfo" },
 
- 	{ "arsv",    DMAP_DICT, 0,         "daap.resolve" },
 
- 	{ "asaa",    DMAP_STR,  0,         "daap.songalbumartist" },
 
- 	{ "asac",    DMAP_UINT, 0,         "daap.songartworkcount" },
 
- 	{ "asai",    DMAP_UINT, 0,         "daap.songalbumid" },
 
- 	{ "asal",    DMAP_STR,  0,         "daap.songalbum" },
 
- 	{ "asar",    DMAP_STR,  0,         "daap.songartist" },
 
- 	{ "asas",    DMAP_UINT, 0,         "daap.songalbumuserratingstatus" },
 
- 	{ "asbk",    DMAP_UINT, 0,         "daap.bookmarkable" },
 
- 	{ "asbo",    DMAP_UINT, 0,         "daap.songbookmark" },
 
- 	{ "asbr",    DMAP_UINT, 0,         "daap.songbitrate" },
 
- 	{ "asbt",    DMAP_UINT, 0,         "daap.songbeatsperminute" },
 
- 	{ "ascd",    DMAP_UINT, 0,         "daap.songcodectype" },
 
- 	{ "ascm",    DMAP_STR,  0,         "daap.songcomment" },
 
- 	{ "ascn",    DMAP_STR,  0,         "daap.songcontentdescription" },
 
- 	{ "asco",    DMAP_UINT, 0,         "daap.songcompilation" },
 
- 	{ "ascp",    DMAP_STR,  0,         "daap.songcomposer" },
 
- 	{ "ascr",    DMAP_UINT, 0,         "daap.songcontentrating" },
 
- 	{ "ascs",    DMAP_UINT, 0,         "daap.songcodecsubtype" },
 
- 	{ "asct",    DMAP_STR,  0,         "daap.songcategory" },
 
- 	{ "asda",    DMAP_DATE, 0,         "daap.songdateadded" },
 
- 	{ "asdb",    DMAP_UINT, 0,         "daap.songdisabled" },
 
- 	{ "asdc",    DMAP_UINT, 0,         "daap.songdisccount" },
 
- 	{ "asdk",    DMAP_UINT, 0,         "daap.songdatakind" },
 
- 	{ "asdm",    DMAP_DATE, 0,         "daap.songdatemodified" },
 
- 	{ "asdn",    DMAP_UINT, 0,         "daap.songdiscnumber" },
 
- 	{ "asdp",    DMAP_DATE, 0,         "daap.songdatepurchased" },
 
- 	{ "asdr",    DMAP_DATE, 0,         "daap.songdatereleased" },
 
- 	{ "asdt",    DMAP_STR,  0,         "daap.songdescription" },
 
- 	{ "ased",    DMAP_UINT, 0,         "daap.songextradata" },
 
- 	{ "aseq",    DMAP_STR,  0,         "daap.songeqpreset" },
 
- 	{ "ases",    DMAP_UINT, 0,         "daap.songexcludefromshuffle" },
 
- 	{ "asfm",    DMAP_STR,  0,         "daap.songformat" },
 
- 	{ "asgn",    DMAP_STR,  0,         "daap.songgenre" },
 
- 	{ "asgp",    DMAP_UINT, 0,         "daap.songgapless" },
 
- 	{ "asgr",    DMAP_UINT, 0,         "daap.supportsgroups" },
 
- 	{ "ashp",    DMAP_UINT, 0,         "daap.songhasbeenplayed" },
 
- 	{ "askd",    DMAP_DATE, 0,         "daap.songlastskipdate" },
 
- 	{ "askp",    DMAP_UINT, 0,         "daap.songuserskipcount" },
 
- 	{ "asky",    DMAP_STR,  0,         "daap.songkeywords" },
 
- 	{ "aslc",    DMAP_STR,  0,         "daap.songlongcontentdescription" },
 
- 	{ "aslr",    DMAP_UINT, 0,         "daap.songalbumuserrating" },
 
- 	{ "asls",    DMAP_UINT, 0,         "daap.songlongsize" },
 
- 	{ "aspc",    DMAP_UINT, 0,         "daap.songuserplaycount" },
 
- 	{ "aspl",    DMAP_DATE, 0,         "daap.songdateplayed" },
 
- 	{ "aspu",    DMAP_STR,  0,         "daap.songpodcasturl" },
 
- 	{ "asri",    DMAP_UINT, 0,         "daap.songartistid" },
 
- 	{ "asrs",    DMAP_UINT, 0,         "daap.songuserratingstatus" },
 
- 	{ "asrv",    DMAP_INT,  0,         "daap.songrelativevolume" },
 
- 	{ "assa",    DMAP_STR,  0,         "daap.sortartist" },
 
- 	{ "assc",    DMAP_STR,  0,         "daap.sortcomposer" },
 
- 	{ "assl",    DMAP_STR,  0,         "daap.sortalbumartist" },
 
- 	{ "assn",    DMAP_STR,  0,         "daap.sortname" },
 
- 	{ "assp",    DMAP_UINT, 0,         "daap.songstoptime" },
 
- 	{ "assr",    DMAP_UINT, 0,         "daap.songsamplerate" },
 
- 	{ "asss",    DMAP_STR,  0,         "daap.sortseriesname" },
 
- 	{ "asst",    DMAP_UINT, 0,         "daap.songstarttime" },
 
- 	{ "assu",    DMAP_STR,  0,         "daap.sortalbum" },
 
- 	{ "assz",    DMAP_UINT, 0,         "daap.songsize" },
 
- 	{ "astc",    DMAP_UINT, 0,         "daap.songtrackcount" },
 
- 	{ "astm",    DMAP_UINT, 0,         "daap.songtime" },
 
- 	{ "astn",    DMAP_UINT, 0,         "daap.songtracknumber" },
 
- 	{ "asul",    DMAP_STR,  0,         "daap.songdataurl" },
 
- 	{ "asur",    DMAP_UINT, 0,         "daap.songuserrating" },
 
- 	{ "asvc",    DMAP_UINT, 0,         "daap.songprimaryvideocodec" },
 
- 	{ "asyr",    DMAP_UINT, 0,         "daap.songyear" },
 
- 	{ "ated",    DMAP_UINT, 0,         "daap.supportsextradata" },
 
- 	{ "avdb",    DMAP_DICT, 0,         "daap.serverdatabases" },
 
- 	{ "awrk",    DMAP_STR,  0,         "daap.songwork" },
 
- 	{ "caar",    DMAP_UINT, 0,         "dacp.availablerepeatstates" },
 
- 	{ "caas",    DMAP_UINT, 0,         "dacp.availableshufflestates" },
 
- 	{ "caci",    DMAP_DICT, 0,         "caci" },
 
- 	{ "cafe",    DMAP_UINT, 0,         "dacp.fullscreenenabled" },
 
- 	{ "cafs",    DMAP_UINT, 0,         "dacp.fullscreen" },
 
- 	{ "caia",    DMAP_UINT, 0,         "dacp.isactive" },
 
- 	{ "cana",    DMAP_STR,  0,         "dacp.nowplayingartist" },
 
- 	{ "cang",    DMAP_STR,  0,         "dacp.nowplayinggenre" },
 
- 	{ "canl",    DMAP_STR,  0,         "dacp.nowplayingalbum" },
 
- 	{ "cann",    DMAP_STR,  0,         "dacp.nowplayingname" },
 
- 	{ "canp",    DMAP_UINT, 0,         "dacp.nowplayingids" },
 
- 	{ "cant",    DMAP_UINT, 0,         "dacp.nowplayingtime" },
 
- 	{ "capr",    DMAP_VERS, 0,         "dacp.protocolversion" },
 
- 	{ "caps",    DMAP_UINT, 0,         "dacp.playerstate" },
 
- 	{ "carp",    DMAP_UINT, 0,         "dacp.repeatstate" },
 
- 	{ "cash",    DMAP_UINT, 0,         "dacp.shufflestate" },
 
- 	{ "casp",    DMAP_DICT, 0,         "dacp.speakers" },
 
- 	{ "cast",    DMAP_UINT, 0,         "dacp.songtime" },
 
- 	{ "cavc",    DMAP_UINT, 0,         "dacp.volumecontrollable" },
 
- 	{ "cave",    DMAP_UINT, 0,         "dacp.visualizerenabled" },
 
- 	{ "cavs",    DMAP_UINT, 0,         "dacp.visualizer" },
 
- 	{ "ceJC",    DMAP_UINT, 0,         "com.apple.itunes.jukebox-client-vote" },
 
- 	{ "ceJI",    DMAP_UINT, 0,         "com.apple.itunes.jukebox-current" },
 
- 	{ "ceJS",    DMAP_UINT, 0,         "com.apple.itunes.jukebox-score" },
 
- 	{ "ceJV",    DMAP_UINT, 0,         "com.apple.itunes.jukebox-vote" },
 
- 	{ "ceQR",    DMAP_DICT, 0,         "com.apple.itunes.playqueue-contents-response" },
 
- 	{ "ceQa",    DMAP_STR,  0,         "com.apple.itunes.playqueue-album" },
 
- 	{ "ceQg",    DMAP_STR,  0,         "com.apple.itunes.playqueue-genre" },
 
- 	{ "ceQn",    DMAP_STR,  0,         "com.apple.itunes.playqueue-name" },
 
- 	{ "ceQr",    DMAP_STR,  0,         "com.apple.itunes.playqueue-artist" },
 
- 	{ "cmgt",    DMAP_DICT, 0,         "dmcp.getpropertyresponse" },
 
- 	{ "cmmk",    DMAP_UINT, 0,         "dmcp.mediakind" },
 
- 	{ "cmpr",    DMAP_VERS, 0,         "dmcp.protocolversion" },
 
- 	{ "cmsr",    DMAP_UINT, 0,         "dmcp.serverrevision" },
 
- 	{ "cmst",    DMAP_DICT, 0,         "dmcp.playstatus" },
 
- 	{ "cmvo",    DMAP_UINT, 0,         "dmcp.volume" },
 
- 	{ "f\215ch", DMAP_UINT, 0,         "dmap.haschildcontainers" },
 
- 	{ "ipsa",    DMAP_DICT, 0,         "dpap.iphotoslideshowadvancedoptions" },
 
- 	{ "ipsl",    DMAP_DICT, 0,         "dpap.iphotoslideshowoptions" },
 
- 	{ "mbcl",    DMAP_DICT, 0,         "dmap.bag" },
 
- 	{ "mccr",    DMAP_DICT, 0,         "dmap.contentcodesresponse" },
 
- 	{ "mcna",    DMAP_STR,  0,         "dmap.contentcodesname" },
 
- 	{ "mcnm",    DMAP_UINT, 0,         "dmap.contentcodesnumber" },
 
- 	{ "mcon",    DMAP_DICT, 0,         "dmap.container" },
 
- 	{ "mctc",    DMAP_UINT, 0,         "dmap.containercount" },
 
- 	{ "mcti",    DMAP_UINT, 0,         "dmap.containeritemid" },
 
- 	{ "mcty",    DMAP_UINT, 0,         "dmap.contentcodestype" },
 
- 	{ "mdbk",    DMAP_UINT, 0,         "dmap.databasekind" },
 
- 	{ "mdcl",    DMAP_DICT, 0,         "dmap.dictionary" },
 
- 	{ "mdst",    DMAP_UINT, 0,         "dmap.downloadstatus" },
 
- 	{ "meds",    DMAP_UINT, 0,         "dmap.editcommandssupported" },
 
- 	{ "meia",    DMAP_UINT, 0,         "dmap.itemdateadded" },
 
- 	{ "meip",    DMAP_UINT, 0,         "dmap.itemdateplayed" },
 
- 	{ "mext",    DMAP_UINT, 0,         "dmap.objectextradata" },
 
- 	{ "miid",    DMAP_UINT, 0,         "dmap.itemid" },
 
- 	{ "mikd",    DMAP_UINT, 0,         "dmap.itemkind" },
 
- 	{ "mimc",    DMAP_UINT, 0,         "dmap.itemcount" },
 
- 	{ "minm",    DMAP_STR,  0,         "dmap.itemname" },
 
- 	{ "mlcl",    DMAP_DICT, DMAP_DICT, "dmap.listing" },
 
- 	{ "mlid",    DMAP_UINT, 0,         "dmap.sessionid" },
 
- 	{ "mlit",    DMAP_ITEM, 0,         "dmap.listingitem" },
 
- 	{ "mlog",    DMAP_DICT, 0,         "dmap.loginresponse" },
 
- 	{ "mpco",    DMAP_UINT, 0,         "dmap.parentcontainerid" },
 
- 	{ "mper",    DMAP_UINT, 0,         "dmap.persistentid" },
 
- 	{ "mpro",    DMAP_VERS, 0,         "dmap.protocolversion" },
 
- 	{ "mrco",    DMAP_UINT, 0,         "dmap.returnedcount" },
 
- 	{ "mrpr",    DMAP_UINT, 0,         "dmap.remotepersistentid" },
 
- 	{ "msal",    DMAP_UINT, 0,         "dmap.supportsautologout" },
 
- 	{ "msas",    DMAP_UINT, 0,         "dmap.authenticationschemes" },
 
- 	{ "msau",    DMAP_UINT, 0,         "dmap.authenticationmethod" },
 
- 	{ "msbr",    DMAP_UINT, 0,         "dmap.supportsbrowse" },
 
- 	{ "msdc",    DMAP_UINT, 0,         "dmap.databasescount" },
 
- 	{ "msex",    DMAP_UINT, 0,         "dmap.supportsextensions" },
 
- 	{ "msix",    DMAP_UINT, 0,         "dmap.supportsindex" },
 
- 	{ "mslr",    DMAP_UINT, 0,         "dmap.loginrequired" },
 
- 	{ "msma",    DMAP_UINT, 0,         "dmap.machineaddress" },
 
- 	{ "msml",    DMAP_DICT, 0,         "msml" },
 
- 	{ "mspi",    DMAP_UINT, 0,         "dmap.supportspersistentids" },
 
- 	{ "msqy",    DMAP_UINT, 0,         "dmap.supportsquery" },
 
- 	{ "msrs",    DMAP_UINT, 0,         "dmap.supportsresolve" },
 
- 	{ "msrv",    DMAP_DICT, 0,         "dmap.serverinforesponse" },
 
- 	{ "mstc",    DMAP_DATE, 0,         "dmap.utctime" },
 
- 	{ "mstm",    DMAP_UINT, 0,         "dmap.timeoutinterval" },
 
- 	{ "msto",    DMAP_INT,  0,         "dmap.utcoffset" },
 
- 	{ "msts",    DMAP_STR,  0,         "dmap.statusstring" },
 
- 	{ "mstt",    DMAP_UINT, 0,         "dmap.status" },
 
- 	{ "msup",    DMAP_UINT, 0,         "dmap.supportsupdate" },
 
- 	{ "mtco",    DMAP_UINT, 0,         "dmap.specifiedtotalcount" },
 
- 	{ "mudl",    DMAP_DICT, 0,         "dmap.deletedidlisting" },
 
- 	{ "mupd",    DMAP_DICT, 0,         "dmap.updateresponse" },
 
- 	{ "musr",    DMAP_UINT, 0,         "dmap.serverrevision" },
 
- 	{ "muty",    DMAP_UINT, 0,         "dmap.updatetype" },
 
- 	{ "pasp",    DMAP_STR,  0,         "dpap.aspectratio" },
 
- 	{ "pcmt",    DMAP_STR,  0,         "dpap.imagecomments" },
 
- 	{ "peak",    DMAP_UINT, 0,         "com.apple.itunes.photos.album-kind" },
 
- 	{ "peed",    DMAP_DATE, 0,         "com.apple.itunes.photos.exposure-date" },
 
- 	{ "pefc",    DMAP_DICT, 0,         "com.apple.itunes.photos.faces" },
 
- 	{ "peki",    DMAP_UINT, 0,         "com.apple.itunes.photos.key-image-id" },
 
- 	{ "pekm",    DMAP_DICT, 0,         "com.apple.itunes.photos.key-image" },
 
- 	{ "pemd",    DMAP_DATE, 0,         "com.apple.itunes.photos.modification-date" },
 
- 	{ "pfai",    DMAP_DICT, 0,         "dpap.failureids" },
 
- 	{ "pfdt",    DMAP_DICT, 0,         "dpap.filedata" },
 
- 	{ "pfmt",    DMAP_STR,  0,         "dpap.imageformat" },
 
- 	{ "phgt",    DMAP_UINT, 0,         "dpap.imagepixelheight" },
 
- 	{ "picd",    DMAP_DATE, 0,         "dpap.creationdate" },
 
- 	{ "pifs",    DMAP_UINT, 0,         "dpap.imagefilesize" },
 
- 	{ "pimf",    DMAP_STR,  0,         "dpap.imagefilename" },
 
- 	{ "plsz",    DMAP_UINT, 0,         "dpap.imagelargefilesize" },
 
- 	{ "ppro",    DMAP_VERS, 0,         "dpap.protocolversion" },
 
- 	{ "prat",    DMAP_UINT, 0,         "dpap.imagerating" },
 
- 	{ "pret",    DMAP_DICT, 0,         "dpap.retryids" },
 
- 	{ "pwth",    DMAP_UINT, 0,         "dpap.imagepixelwidth" }
 
- };
 
- static const size_t dmap_field_count = sizeof(dmap_fields) / sizeof(dmap_field);
 
- typedef int (*sort_func) (const void *, const void *);
 
- int dmap_version(void) {
 
- 	return DMAP_VERSION;
 
- }
 
- const char *dmap_version_string(void) {
 
- 	return DMAP_STRINGIFY(DMAP_VERSION_MAJOR) "."
 
- 	       DMAP_STRINGIFY(DMAP_VERSION_MINOR) "."
 
- 	       DMAP_STRINGIFY(DMAP_VERSION_PATCH);
 
- }
 
- static int dmap_field_sort(const dmap_field *a, const dmap_field *b) {
 
- 	return memcmp(a->code, b->code, 4);
 
- }
 
- static const dmap_field *dmap_field_from_code(const char *code) {
 
- 	dmap_field key;
 
- 	key.code = code;
 
- 	return bsearch(&key, dmap_fields, dmap_field_count, sizeof(dmap_field), (sort_func)dmap_field_sort);
 
- }
 
- const char *dmap_name_from_code(const char *code) {
 
- 	const dmap_field *field;
 
- 	if (!code)
 
- 		return NULL;
 
- 	field = dmap_field_from_code(code);
 
- 	return field ? field->name : NULL;
 
- }
 
- static uint16_t dmap_read_u16(const char *buf) {
 
- 	return (uint16_t)(((buf[0] & 0xff) << 8) | (buf[1] & 0xff));
 
- }
 
- static int16_t dmap_read_i16(const char *buf) {
 
- 	return (int16_t)dmap_read_u16(buf);
 
- }
 
- static uint32_t dmap_read_u32(const char *buf) {
 
- 	return ((uint32_t)(buf[0] & 0xff) << 24) |
 
- 	((uint32_t)(buf[1] & 0xff) << 16) |
 
- 	((uint32_t)(buf[2] & 0xff) <<  8) |
 
- 	((uint32_t)(buf[3] & 0xff));
 
- }
 
- static int32_t dmap_read_i32(const char *buf) {
 
- 	return (int32_t)dmap_read_u32(buf);
 
- }
 
- static uint64_t dmap_read_u64(const char *buf) {
 
- 	return ((uint64_t)(buf[0] & 0xff) << 56) |
 
- 	((uint64_t)(buf[1] & 0xff) << 48) |
 
- 	((uint64_t)(buf[2] & 0xff) << 40) |
 
- 	((uint64_t)(buf[3] & 0xff) << 32) |
 
- 	((uint64_t)(buf[4] & 0xff) << 24) |
 
- 	((uint64_t)(buf[5] & 0xff) << 16) |
 
- 	((uint64_t)(buf[6] & 0xff) <<  8) |
 
- 	((uint64_t)(buf[7] & 0xff));
 
- }
 
- static int64_t dmap_read_i64(const char *buf) {
 
- 	return (int64_t)dmap_read_u64(buf);
 
- }
 
- static int dmap_parse_internal(const dmap_settings *settings, const char *buf, size_t len, const dmap_field *parent) {
 
- 	const dmap_field *field;
 
- 	DMAP_TYPE field_type;
 
- 	size_t field_len;
 
- 	const char *field_name;
 
- 	const char *p = buf;
 
- 	const char *end = buf + len;
 
- 	char code[5] = {0};
 
- 	if (!settings || !buf)
 
- 		return -1;
 
- 	while (end - p >= 8) {
 
- 		memcpy(code, p, 4);
 
- 		field = dmap_field_from_code(code);
 
- 		p += 4;
 
- 		field_len = dmap_read_u32(p);
 
- 		p += 4;
 
- 		if (p + field_len > end)
 
- 			return -1;
 
- 		if (field) {
 
- 			field_type = field->type;
 
- 			field_name = field->name;
 
- 			if (field_type == DMAP_ITEM) {
 
- 				if (parent != NULL && parent->list_item_type) {
 
- 					field_type = parent->list_item_type;
 
- 				} else {
 
- 					field_type = DMAP_DICT;
 
- 				}
 
- 			}
 
- 		} else {
 
- 			/* Make a best guess of the type */
 
- 			field_type = DMAP_UNKNOWN;
 
- 			field_name = code;
 
- 			if (field_len >= 8) {
 
- 				/* Look for a four char code followed by a length within the current field */
 
- 				if (isalpha(p[0] & 0xff) &&
 
- 				    isalpha(p[1] & 0xff) &&
 
- 				    isalpha(p[2] & 0xff) &&
 
- 				    isalpha(p[3] & 0xff)) {
 
- 					if (dmap_read_u32(p + 4) < field_len)
 
- 						field_type = DMAP_DICT;
 
- 				}
 
- 			}
 
- 			if (field_type == DMAP_UNKNOWN) {
 
- 				size_t i;
 
- 				int is_string = 1;
 
- 				for (i=0; i < field_len; i++) {
 
- 					if (!isprint(p[i] & 0xff)) {
 
- 						is_string = 0;
 
- 						break;
 
- 					}
 
- 				}
 
- 				field_type = is_string ? DMAP_STR : DMAP_UINT;
 
- 			}
 
- 		}
 
- 		switch (field_type) {
 
- 			case DMAP_UINT:
 
- 				/* Determine the integer's type based on its size */
 
- 				switch (field_len) {
 
- 					case 1:
 
- 						if (settings->on_uint32)
 
- 							settings->on_uint32(settings->ctx, code, field_name, (unsigned char)*p);
 
- 						break;
 
- 					case 2:
 
- 						if (settings->on_uint32)
 
- 							settings->on_uint32(settings->ctx, code, field_name, dmap_read_u16(p));
 
- 						break;
 
- 					case 4:
 
- 						if (settings->on_uint32)
 
- 							settings->on_uint32(settings->ctx, code, field_name, dmap_read_u32(p));
 
- 						break;
 
- 					case 8:
 
- 						if (settings->on_uint64)
 
- 							settings->on_uint64(settings->ctx, code, field_name, dmap_read_u64(p));
 
- 						break;
 
- 					default:
 
- 						if (settings->on_data)
 
- 							settings->on_data(settings->ctx, code, field_name, p, field_len);
 
- 						break;
 
- 				}
 
- 				break;
 
- 			case DMAP_INT:
 
- 				switch (field_len) {
 
- 					case 1:
 
- 						if (settings->on_int32)
 
- 							settings->on_int32(settings->ctx, code, field_name, *p);
 
- 						break;
 
- 					case 2:
 
- 						if (settings->on_int32)
 
- 							settings->on_int32(settings->ctx, code, field_name, dmap_read_i16(p));
 
- 						break;
 
- 					case 4:
 
- 						if (settings->on_int32)
 
- 							settings->on_int32(settings->ctx, code, field_name, dmap_read_i32(p));
 
- 						break;
 
- 					case 8:
 
- 						if (settings->on_int64)
 
- 							settings->on_int64(settings->ctx, code, field_name, dmap_read_i64(p));
 
- 						break;
 
- 					default:
 
- 						if (settings->on_data)
 
- 							settings->on_data(settings->ctx, code, field_name, p, field_len);
 
- 						break;
 
- 				}
 
- 				break;
 
- 			case DMAP_STR:
 
- 				if (settings->on_string)
 
- 					settings->on_string(settings->ctx, code, field_name, p, field_len);
 
- 				break;
 
- 			case DMAP_DATA:
 
- 				if (settings->on_data)
 
- 					settings->on_data(settings->ctx, code, field_name, p, field_len);
 
- 				break;
 
- 			case DMAP_DATE:
 
- 				/* Seconds since epoch */
 
- 				if (settings->on_date)
 
- 					settings->on_date(settings->ctx, code, field_name, dmap_read_u32(p));
 
- 				break;
 
- 			case DMAP_VERS:
 
- 				if (settings->on_string && field_len >= 4) {
 
- 					char version[20];
 
- 					sprintf(version, "%u.%u", dmap_read_u16(p), dmap_read_u16(p+2));
 
- 					settings->on_string(settings->ctx, code, field_name, version, strlen(version));
 
- 				}
 
- 				break;
 
- 			case DMAP_DICT:
 
- 				if (settings->on_dict_start)
 
- 					settings->on_dict_start(settings->ctx, code, field_name);
 
- 				if (dmap_parse_internal(settings, p, field_len, field) != 0)
 
- 					return -1;
 
- 				if (settings->on_dict_end)
 
- 					settings->on_dict_end(settings->ctx, code, field_name);
 
- 				break;
 
- 			case DMAP_ITEM:
 
- 				/* Unreachable: listing item types are always mapped to another type */
 
- 				abort();
 
- 			case DMAP_UNKNOWN:
 
- 				break;
 
- 		}
 
- 		p += field_len;
 
- 	}
 
- 	if (p != end)
 
- 		return -1;
 
- 	return 0;
 
- }
 
- int dmap_parse(const dmap_settings *settings, const char *buf, size_t len) {
 
- 	return dmap_parse_internal(settings, buf, len, NULL);
 
- }
 
 
  |