| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549 | #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" },#ifdef DMAP_FULL        	{ "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" },#endif    	{ "miid",    DMAP_UINT, 0,         "dmap.itemid" },	{ "mikd",    DMAP_UINT, 0,         "dmap.itemkind" },	{ "mimc",    DMAP_UINT, 0,         "dmap.itemcount" },	{ "minm",    DMAP_STR,  0,         "dmap.itemname" },#ifdef DMAP_FULL    	{ "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" }#endif    };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);}
 |