1
0

iPodDB.cpp 105 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807
  1. /*
  2. *
  3. *
  4. * Copyright (c) 2004 Samuel Wood ([email protected])
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. The name of the author may not be used to endorse or promote products
  16. * derived from this software without specific prior permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  19. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  20. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  23. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *
  29. *
  30. *
  31. */
  32. // For more information on how all this stuff works, see:
  33. // http://www.ipodlinux.org/ITunesDB
  34. // iPodDB.cpp: implementation of the iPod classes.
  35. //
  36. //////////////////////////////////////////////////////////////////////
  37. #pragma warning( disable : 4786)
  38. #include "iPodDB.h"
  39. #include <bfc/platform/types.h>
  40. #include <assert.h>
  41. #include <time.h>
  42. #include <windows.h>
  43. #include <tchar.h>
  44. #include <math.h>
  45. #include <vector>
  46. /*
  47. #ifdef ASSERT
  48. #undef ASSERT
  49. #define ASSERT(x) {}
  50. #endif
  51. */
  52. //#define IPODDB_PROFILER // Uncomment to enable profiler measurments
  53. #ifdef IPODDB_PROFILER
  54. /* profiler code from Foobar2000's PFC library:
  55. *
  56. * Copyright (c) 2001-2003, Peter Pawlowski
  57. * All rights reserved.
  58. *
  59. * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
  60. *
  61. * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  62. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  63. * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
  64. *
  65. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  66. */
  67. class profiler_static
  68. {
  69. private:
  70. const char * name;
  71. __int64 total_time,num_called;
  72. public:
  73. profiler_static(const char * p_name)
  74. {
  75. name = p_name;
  76. total_time = 0;
  77. num_called = 0;
  78. }
  79. ~profiler_static()
  80. {
  81. char blah[512] = {0};
  82. char total_time_text[128] = {0};
  83. char num_text[128] = {0};
  84. _i64toa(total_time,total_time_text,10);
  85. _i64toa(num_called,num_text,10);
  86. _snprintf(blah, sizeof(blah), "profiler: %s - %s cycles (executed %s times)\n",name,total_time_text,num_text);
  87. OutputDebugStringA(blah);
  88. }
  89. void add_time(__int64 delta) {total_time+=delta;num_called++;}
  90. };
  91. class profiler_local
  92. {
  93. private:
  94. static __int64 get_timestamp();
  95. __int64 start;
  96. profiler_static * owner;
  97. public:
  98. profiler_local(profiler_static * p_owner)
  99. {
  100. owner = p_owner;
  101. start = get_timestamp();
  102. }
  103. ~profiler_local()
  104. {
  105. __int64 end = get_timestamp();
  106. owner->add_time(end-start);
  107. }
  108. };
  109. __declspec(naked) __int64 profiler_local::get_timestamp()
  110. {
  111. __asm
  112. {
  113. rdtsc
  114. ret
  115. }
  116. }
  117. #define profiler(name) \
  118. static profiler_static profiler_static_##name(#name); \
  119. profiler_local profiler_local_##name(&profiler_static_##name);
  120. #endif
  121. #ifdef _DEBUG
  122. #define MYDEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__)
  123. // Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
  124. //allocations to be of _CLIENT_BLOCK type
  125. #define _CRTDBG_MAP_ALLOC
  126. #include <stdlib.h>
  127. #include <crtdbg.h>
  128. #undef THIS_FILE
  129. static char THIS_FILE[] = __FILE__;
  130. #define new MYDEBUG_NEW
  131. #endif
  132. //
  133. // useful functions
  134. //////////////////////////////////////////////////////////////////////
  135. inline BOOL WINAPI IsCharSpaceW(wchar_t c) { return (c == L' ' || c == L'\t'); }
  136. inline bool IsTheW(const wchar_t *str) { if (str && (str[0] == L't' || str[0] == L'T') && (str[1] == L'h' || str[1] == L'H') && (str[2] == L'e' || str[2] == L'E') && (str[3] == L' ')) return true; else return false; }
  137. #define SKIP_THE_AND_WHITESPACE(x) { wchar_t *save##x=(wchar_t*)x; while (IsCharSpaceW(*x) && *x) x++; if (IsTheW(x)) x+=4; while (IsCharSpaceW(*x)) x++; if (!*x) x=save##x; }
  138. ///#define SKIP_THE_AND_WHITESPACE(x) { while (!iswalnum(*x) && *x) x++; if (!_wcsnicmp(x,L"the ",4)) x+=4; while (*x == L' ') x++; }
  139. int STRCMP_NULLOK(const wchar_t *pa, const wchar_t *pb) {
  140. if (!pa) pa=L"";
  141. else SKIP_THE_AND_WHITESPACE(pa)
  142. if (!pb) pb=L"";
  143. else SKIP_THE_AND_WHITESPACE(pb)
  144. return lstrcmpi(pa,pb);
  145. }
  146. #undef SKIP_THE_AND_WHITESPACE
  147. // convert Macintosh timestamp to windows timestamp
  148. time_t mactime_to_wintime (const unsigned long mactime)
  149. {
  150. if (mactime != 0) return (time_t)(mactime - 2082844800);
  151. else return (time_t)mactime;
  152. }
  153. // convert windows timestamp to Macintosh timestamp
  154. unsigned long wintime_to_mactime (const __time64_t time)
  155. {
  156. return (unsigned long)(time + 2082844800);
  157. }
  158. char * UTF16_to_UTF8(wchar_t * str)
  159. {
  160. const unsigned int tempstrLen = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
  161. char * tempstr=(char *)malloc(tempstrLen + 1);
  162. int ret=WideCharToMultiByte( CP_UTF8, 0, str, -1, tempstr, tempstrLen, NULL, NULL );
  163. tempstr[tempstrLen]='\0';
  164. if (!ret) DWORD bob=GetLastError();
  165. return tempstr;
  166. }
  167. wchar_t* UTF8_to_UTF16(char *str)
  168. {
  169. const unsigned int tempstrLen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
  170. wchar_t *tempstr = (wchar_t*)malloc((tempstrLen * 2) + 2);
  171. MultiByteToWideChar(CP_UTF8, 0, str, -1, tempstr, tempstrLen);
  172. tempstr[tempstrLen] = '\0';
  173. return tempstr;
  174. }
  175. // get 2 bytes from data, reversed
  176. static __forceinline uint16_t rev2(const uint8_t * data)
  177. {
  178. uint16_t ret;
  179. ret = ((uint16_t) data[1]) << 8;
  180. ret += ((uint16_t) data[0]);
  181. return ret;
  182. }
  183. static __forceinline void rev2(const unsigned short number, unsigned char * data)
  184. {
  185. data[1] = (unsigned char)(number >> 8) & 0xff;
  186. data[0] = (unsigned char)number & 0xff;
  187. }
  188. // get 4 bytes from data, reversed
  189. static __forceinline uint32_t rev4(const uint8_t * data)
  190. {
  191. unsigned long ret;
  192. ret = ((unsigned long) data[3]) << 24;
  193. ret += ((unsigned long) data[2]) << 16;
  194. ret += ((unsigned long) data[1]) << 8;
  195. ret += ((unsigned long) data[0]);
  196. return ret;
  197. }
  198. // get 4 bytes from data
  199. static __forceinline uint32_t get4(const uint8_t * data)
  200. {
  201. unsigned long ret;
  202. ret = ((unsigned long) data[0]) << 24;
  203. ret += ((unsigned long) data[1]) << 16;
  204. ret += ((unsigned long) data[2]) << 8;
  205. ret += ((unsigned long) data[3]);
  206. return ret;
  207. }
  208. // get 8 bytes from data
  209. static __forceinline unsigned __int64 get8(const uint8_t * data)
  210. {
  211. unsigned __int64 ret;
  212. ret = get4(data);
  213. ret = ret << 32;
  214. ret += get4(&data[4]);
  215. return ret;
  216. }
  217. // reverse 8 bytes in place
  218. static __forceinline unsigned __int64 rev8(uint64_t number)
  219. {
  220. unsigned __int64 ret;
  221. ret = (number&0x00000000000000FF) << 56;
  222. ret+= (number&0x000000000000FF00) << 40;
  223. ret+= (number&0x0000000000FF0000) << 24;
  224. ret+= (number&0x00000000FF000000) << 8;
  225. ret+= (number&0x000000FF00000000) >> 8;
  226. ret+= (number&0x0000FF0000000000) >> 24;
  227. ret+= (number&0x00FF000000000000) >> 40;
  228. ret+= (number&0xFF00000000000000) >> 56;
  229. return ret;
  230. }
  231. //write 4 bytes reversed
  232. static __forceinline void rev4(const unsigned long number, uint8_t * data)
  233. {
  234. data[3] = (uint8_t)(number >> 24) & 0xff;
  235. data[2] = (uint8_t)(number >> 16) & 0xff;
  236. data[1] = (uint8_t)(number >> 8) & 0xff;
  237. data[0] = (uint8_t)number & 0xff;
  238. }
  239. //write 4 bytes normal
  240. static __forceinline void put4(const unsigned long number, uint8_t * data)
  241. {
  242. data[0] = (uint8_t)(number >> 24) & 0xff;
  243. data[1] = (uint8_t)(number >> 16) & 0xff;
  244. data[2] = (uint8_t)(number >> 8) & 0xff;
  245. data[3] = (uint8_t)number & 0xff;
  246. }
  247. // write 8 bytes normal
  248. static __forceinline void put8(const unsigned __int64 number, uint8_t * data)
  249. {
  250. data[0] = (uint8_t)(number >> 56) & 0xff;
  251. data[1] = (uint8_t)(number >> 48) & 0xff;
  252. data[2] = (uint8_t)(number >> 40) & 0xff;
  253. data[3] = (uint8_t)(number >> 32) & 0xff;
  254. data[4] = (uint8_t)(number >> 24) & 0xff;
  255. data[5] = (uint8_t)(number >> 16) & 0xff;
  256. data[6] = (uint8_t)(number >> 8) & 0xff;
  257. data[7] = (uint8_t)number & 0xff;
  258. }
  259. // get 3 bytes from data, reversed
  260. static __forceinline unsigned long rev3(const uint8_t * data)
  261. {
  262. unsigned long ret = 0;
  263. ret += ((unsigned long) data[2]) << 16;
  264. ret += ((unsigned long) data[1]) << 8;
  265. ret += ((unsigned long) data[0]);
  266. return ret;
  267. }
  268. //write 3 bytes normal (used in iTunesSD)
  269. static __forceinline void put3(const unsigned long number, uint8_t * data)
  270. {
  271. data[0] = (uint8_t)(number >> 16) & 0xff;
  272. data[1] = (uint8_t)(number >> 8) & 0xff;
  273. data[2] = (uint8_t)number & 0xff;
  274. }
  275. //write 3 bytes reversed
  276. static __forceinline void rev3(const unsigned long number, uint8_t * data)
  277. {
  278. data[2] = (uint8_t)(number >> 16) & 0xff;
  279. data[1] = (uint8_t)(number >> 8) & 0xff;
  280. data[0] = (uint8_t)number & 0xff;
  281. }
  282. // pass data and ptr, updates ptr automatically (by reference)
  283. static __forceinline void write_uint32_t(uint8_t *data, size_t &offset, uint32_t value)
  284. {
  285. rev4(value, &data[offset]);
  286. offset+=4;
  287. }
  288. static __forceinline uint32_t read_uint32_t(const uint8_t *data, size_t &offset)
  289. {
  290. const uint8_t *ptr = &data[offset];
  291. offset+=4;
  292. return rev4(ptr);
  293. }
  294. static __forceinline uint32_t read_uint16_t(const uint8_t *data, size_t &offset)
  295. {
  296. const uint8_t *ptr = &data[offset];
  297. offset+=2;
  298. return rev2(ptr);
  299. }
  300. static unsigned __int64 Generate64BitID()
  301. {
  302. GUID tmp;
  303. CoCreateGuid(&tmp);
  304. unsigned __int64 one = tmp.Data1;
  305. unsigned __int64 two = tmp.Data2;
  306. unsigned __int64 three = tmp.Data3;
  307. unsigned __int64 four = rand();
  308. return(one << 32 | two << 16 | three | four);
  309. }
  310. // useful function to convert from UTF16 to chars
  311. char * UTF16_to_char(wchar_t * str, int length)
  312. {
  313. char * tempstr=(char *)malloc(length/2+1);
  314. int ret=WideCharToMultiByte( CP_MACCP, 0, str, length/2, tempstr, length/2, "x", NULL );
  315. tempstr[length/2]='\0';
  316. if (!ret) DWORD bob=GetLastError();
  317. return tempstr;
  318. }
  319. // Case insensitive version of wcsstr
  320. wchar_t *wcsistr (const wchar_t *s1, const wchar_t *s2)
  321. {
  322. wchar_t *cp = (wchar_t*) s1;
  323. wchar_t *s, *t, *endp;
  324. wchar_t l, r;
  325. endp = (wchar_t*)s1 + ( lstrlen(s1) - lstrlen(s2)) ;
  326. while (cp && *cp && (cp <= endp))
  327. {
  328. s = cp;
  329. t = (wchar_t*)s2;
  330. while (s && *s && t && *t)
  331. {
  332. l = towupper(*s);
  333. r = towupper(*t);
  334. if (l != r)
  335. break;
  336. s++, t++;
  337. }
  338. if (*t == 0)
  339. return cp;
  340. cp = CharNext(cp);
  341. }
  342. return NULL;
  343. }
  344. //////////////////////////////////////////////////////////////////////
  345. // iPodObj - Base for all iPod classes
  346. //////////////////////////////////////////////////////////////////////
  347. iPodObj::iPodObj() :
  348. size_head(0),
  349. size_total(0)
  350. {
  351. }
  352. iPodObj::~iPodObj()
  353. {
  354. }
  355. //////////////////////////////////////////////////////////////////////
  356. // iPod_mhbd - iTunes database class
  357. //////////////////////////////////////////////////////////////////////
  358. iPod_mhbd::iPod_mhbd() :
  359. unk1(1),
  360. dbversion(0x0c), // iTunes 4.2 = 0x09, 4.5 = 0x0a, 4.7 = 0x0b, 4.7.1 = 0x0c, 0x0d, 0x13
  361. children(2),
  362. id(0),
  363. platform(2),
  364. language('ne'), // byte-swapped 'en'
  365. library_id(0),
  366. timezone(0),
  367. audio_language(0),
  368. unk80(1),
  369. unk84(15),
  370. subtitle_language(0),
  371. unk164(0),
  372. unk166(0),
  373. unk168(0)
  374. {
  375. // get timezone info
  376. _tzset(); // this function call ensures that _timezone global var is valid
  377. timezone = -_timezone;
  378. id = Generate64BitID();
  379. mhsdsongs = new iPod_mhsd(1);
  380. mhsdplaylists = new iPod_mhsd(3);
  381. mhsdsmartplaylists = new iPod_mhsd(5);
  382. }
  383. iPod_mhbd::~iPod_mhbd()
  384. {
  385. delete mhsdsongs;
  386. delete mhsdplaylists;
  387. }
  388. long iPod_mhbd::parse(const uint8_t *data)
  389. {
  390. size_t ptr=0;
  391. //check mhbd header
  392. if (_strnicmp((char *)&data[ptr],"mhbd",4)) return -1;
  393. ptr+=4;
  394. // get sizes
  395. size_head=read_uint32_t(data, ptr);
  396. size_total=read_uint32_t(data, ptr);
  397. //ASSERT(size_head == 0xbc);
  398. // get unk's and numchildren
  399. unk1=read_uint32_t(data, ptr);
  400. dbversion=read_uint32_t(data, ptr);
  401. children=read_uint32_t(data, ptr);
  402. id=rev8(get8(&data[ptr]));
  403. ptr+=8;
  404. if(id == 0)
  405. {
  406. // Force the id to be a valid value.
  407. // This may not always be the right thing to do, but I can't think of any reason why it wouldn't be ok...
  408. id = Generate64BitID();
  409. }
  410. platform=read_uint16_t(data, ptr);
  411. ptr = 0x46;
  412. language = read_uint16_t(data, ptr);
  413. library_id = rev8(get8(&data[ptr]));
  414. ptr+=8;
  415. unk80 = read_uint32_t(data, ptr);
  416. unk84 = read_uint32_t(data, ptr);
  417. ptr = 0xA0;
  418. audio_language = read_uint16_t(data, ptr);
  419. subtitle_language =read_uint16_t(data, ptr);
  420. unk164 = read_uint16_t(data, ptr);
  421. unk166 = read_uint16_t(data, ptr);
  422. unk168 = read_uint16_t(data, ptr);
  423. // timezone is at 0x6c, but we want to calculate this based on the computer timezone
  424. // TODO: 4 byte field at 0xA0 that contains FFFFFFFF for the ipod shuffle I'm playing with
  425. //if (children != 2) return -1;
  426. //skip over nulls
  427. ptr=size_head;
  428. // get the mhsd's
  429. bool parsedPlaylists = false;
  430. for(unsigned int i=0; i<children; i++)
  431. {
  432. iPod_mhsd * mhsd = new iPod_mhsd(0);
  433. long ret = mhsd->parse(&data[ptr]);
  434. if(ret<0) return ret;
  435. else ptr+=ret;
  436. if(mhsd->index == 1)
  437. {
  438. delete mhsdsongs;
  439. mhsdsongs = mhsd;
  440. }
  441. else if(mhsd->index == 3 && !parsedPlaylists)
  442. {
  443. delete mhsdplaylists;
  444. mhsdplaylists = mhsd;
  445. parsedPlaylists = true;
  446. }
  447. else if(mhsd->index == 2 && !parsedPlaylists)
  448. {
  449. delete mhsdplaylists;
  450. mhsdplaylists = mhsd;
  451. }
  452. else if(mhsd->index == 5)
  453. {
  454. delete mhsdsmartplaylists;
  455. mhsdsmartplaylists = mhsd;
  456. }
  457. else
  458. {
  459. delete mhsd;
  460. }
  461. }
  462. return size_total;
  463. }
  464. long iPod_mhbd::write(unsigned char * data, const unsigned long datasize)
  465. {
  466. return write(data,datasize,NULL);
  467. }
  468. extern void GenerateHash(unsigned char *pFWID, unsigned char *pDataBase, long lSize, unsigned char *pHash);
  469. long iPod_mhbd::write(unsigned char * data, const unsigned long datasize, unsigned char *fwid)
  470. {
  471. //const unsigned int headsize=0xbc; // for db version 0x19
  472. const unsigned int headsize=188; // for db version 0x2A
  473. // check for header size
  474. if (headsize>datasize) return -1;
  475. long ptr=0;
  476. //write mhbd header
  477. data[0]='m';data[1]='h';data[2]='b';data[3]='d';
  478. ptr+=4;
  479. // write sizes
  480. rev4(headsize,&data[ptr]); // header size
  481. ptr+=4;
  482. rev4(0x00,&data[ptr]); // placeholder for total size (fill in later)
  483. ptr+=4;
  484. //write unks
  485. rev4(unk1,&data[ptr]);
  486. ptr+=4;
  487. rev4(0x2a/*dbversion*/,&data[ptr]);
  488. ptr+=4;
  489. //write numchildren
  490. //ASSERT (children == 2); // seen no other case in an iTunesDB yet
  491. children = 4;
  492. rev4(children,&data[ptr]);
  493. ptr+=4;
  494. // fill this in later (it's the db id, it has to be 0 for the hash generation)
  495. put8(0,&data[ptr]);
  496. ptr+=8;
  497. rev2(2, &data[ptr]); // platform (2 == Windows)
  498. ptr+=2;
  499. // fill up the rest of the header with nulls
  500. for (unsigned int i=ptr;i<headsize;i++)
  501. data[i]=0;
  502. ptr=headsize;
  503. rev2(1, &data[0x30]);
  504. rev2(language, &data[0x46]);
  505. put8(library_id, &data[0x48]);
  506. rev4(unk80, &data[0x50]);
  507. rev4(unk84, &data[0x54]);
  508. rev4(timezone, &data[0x6c]);
  509. rev2(2, &data[0x70]);
  510. rev2(audio_language, &data[0xA0]);
  511. rev2(subtitle_language, &data[0xA2]);
  512. rev2(unk164, &data[0xA4]);
  513. rev2(unk166, &data[0xA6]);
  514. rev2(unk168, &data[0xA8]);
  515. long ret;
  516. // write the mhla (album list)
  517. iPod_mhsd mhsd_mhla(4);
  518. iPod_mhla *album_list = mhsd_mhla.mhla;
  519. iPod_mhlt::mhit_map_t::const_iterator begin = mhsdsongs->mhlt->mhit.begin();
  520. iPod_mhlt::mhit_map_t::const_iterator end = mhsdsongs->mhlt->mhit.end();
  521. for(iPod_mhlt::mhit_map_t::const_iterator it = begin; it != end; it++)
  522. {
  523. wchar_t * artist = L"";
  524. wchar_t * album = L"";
  525. iPod_mhit *m = static_cast<iPod_mhit*>((*it).second);
  526. iPod_mhod *mhartist = m->FindString(MHOD_ARTIST);
  527. iPod_mhod *mhalbum = m->FindString(MHOD_ALBUM);
  528. if(mhartist && mhartist->str)
  529. artist = mhartist->str;
  530. if(mhalbum && mhalbum->str)
  531. album = mhalbum->str;
  532. m->album_id = mhsd_mhla.mhla->GetAlbumId(artist, album);
  533. }
  534. ret=mhsd_mhla.write(&data[ptr], datasize-ptr, 4);
  535. ASSERT(ret >= 0);
  536. if (ret<0) return ret;
  537. else ptr+=ret;
  538. // write the mhsd's
  539. ret=mhsdsongs->write(&data[ptr], datasize-ptr);
  540. ASSERT(ret >= 0);
  541. if (ret<0) return ret;
  542. else ptr+=ret;
  543. ret=mhsdplaylists->write(&data[ptr], datasize-ptr, 3);
  544. ASSERT(ret >= 0);
  545. if (ret<0) return ret;
  546. else ptr+=ret;
  547. ret=mhsdplaylists->write(&data[ptr], datasize-ptr, 2);
  548. ASSERT(ret >= 0);
  549. if (ret<0) return ret;
  550. else ptr+=ret;
  551. if(mhsdsmartplaylists->mhlp_smart) {
  552. ret=mhsdsmartplaylists->write(&data[ptr], datasize-ptr, 5);
  553. ASSERT(ret >= 0);
  554. if (ret<0) return ret;
  555. else ptr+=ret;
  556. } else children--;
  557. // fix the total size
  558. rev4(ptr,&data[8]);
  559. rev4(children,&data[20]);
  560. if(fwid)
  561. GenerateHash(fwid,data,ptr,data+0x58); // fuck you, gaydickian
  562. put8(rev8(id),&data[0x18]); // put this back in -- it has to be 0 for the hash generation.
  563. return ptr;
  564. }
  565. //////////////////////////////////////////////////////////////////////
  566. // iPod_mhsd - Holds tracklists and playlists
  567. //////////////////////////////////////////////////////////////////////
  568. iPod_mhsd::iPod_mhsd() :
  569. index(0),
  570. mhlt(NULL),
  571. mhlp(NULL),
  572. mhlp_smart(NULL),
  573. mhla(NULL)
  574. {
  575. }
  576. iPod_mhsd::iPod_mhsd(int newindex) :
  577. index(newindex),
  578. mhlt(NULL),
  579. mhlp(NULL),
  580. mhlp_smart(NULL),
  581. mhla(NULL)
  582. {
  583. switch(newindex)
  584. {
  585. case 1: mhlt=new iPod_mhlt(); break;
  586. case 2:
  587. case 3:
  588. case 5: mhlp=new iPod_mhlp(); break;
  589. case 4: mhla=new iPod_mhla(); break;
  590. default: index=0;
  591. }
  592. }
  593. iPod_mhsd::~iPod_mhsd()
  594. {
  595. delete mhlt;
  596. delete mhlp;
  597. delete mhla;
  598. }
  599. long iPod_mhsd::parse(const uint8_t *data)
  600. {
  601. unsigned long ptr=0;
  602. //check mhsd header
  603. if (_strnicmp((char *)&data[ptr],"mhsd",4)) return -1;
  604. ptr+=4;
  605. // get sizes
  606. size_head=rev4(&data[ptr]);
  607. ptr+=4;
  608. size_total=rev4(&data[ptr]);
  609. ptr+=4;
  610. ASSERT(size_head == 0x60);
  611. // get index number
  612. index=rev4(&data[ptr]);
  613. ptr+=4;
  614. // skip null padding
  615. ptr=size_head;
  616. long ret;
  617. // check to see if this is a holder for an mhlt or an mhlp
  618. if (!_strnicmp((char *)&data[ptr],"mhlt",4))
  619. {
  620. if (mhlt==NULL)
  621. {
  622. mhlt=new iPod_mhlt();
  623. //index=1;
  624. }
  625. ret=mhlt->parse(&data[ptr]);
  626. ASSERT(ret >= 0);
  627. if (ret<0) return ret;
  628. else ptr+=ret;
  629. }
  630. else if (!_strnicmp((char *)&data[ptr],"mhlp",4) && (index == 2 || index == 3))
  631. {
  632. if (mhlp==NULL)
  633. {
  634. mhlp=new iPod_mhlp();
  635. if(index != 2) index=3;
  636. }
  637. ret=mhlp->parse(&data[ptr]);
  638. ASSERT(ret >= 0);
  639. if (ret<0) return ret;
  640. else ptr+=ret;
  641. }
  642. else if (!_strnicmp((char *)&data[ptr],"mhlp",4) && index == 5) // smart playlists
  643. {
  644. if (mhlp_smart==NULL)
  645. mhlp_smart=new iPod_mhlp();
  646. ret=mhlp_smart->parse(&data[ptr]);
  647. ASSERT(ret >= 0);
  648. if (ret<0) return ret;
  649. else ptr+=ret;
  650. }
  651. else {
  652. }
  653. //return -1;
  654. //if (ptr != size_total) return -1;
  655. return size_total;
  656. }
  657. long iPod_mhsd::write(unsigned char * data, const unsigned long datasize, int index)
  658. {
  659. const unsigned int headsize=0x60;
  660. // check for header size
  661. if (headsize>datasize) return -1;
  662. long ptr=0;
  663. //write mhsd header
  664. data[0]='m';data[1]='h';data[2]='s';data[3]='d';
  665. ptr+=4;
  666. // write sizes
  667. rev4(headsize,&data[ptr]); // header size
  668. ptr+=4;
  669. rev4(0x00,&data[ptr]); // placeholder for total size (fill in later)
  670. ptr+=4;
  671. // write index number
  672. rev4(index,&data[ptr]);
  673. ptr+=4;
  674. // fill up the rest of the header with nulls
  675. for (unsigned int i=ptr;i<headsize;i++)
  676. data[i]=0;
  677. ptr=headsize;
  678. // write out the songs or the playlists, depending on index
  679. long ret;
  680. if (index==1) // mhlt
  681. ret=mhlt->write(&data[ptr],datasize-ptr);
  682. else if (index==2 || index==3) // mhlp
  683. ret=mhlp->write(&data[ptr],datasize-ptr,index);
  684. else if (index == 4) // mhla
  685. ret=mhla->write(&data[ptr],datasize-ptr);
  686. else if (index==5) // mhlp_smart
  687. ret=mhlp_smart->write(&data[ptr],datasize-ptr,3);
  688. else return -1;
  689. ASSERT(ret>=0);
  690. if (ret<0) return ret;
  691. else ptr+=ret;
  692. // fix the total size
  693. rev4(ptr,&data[8]);
  694. return ptr;
  695. }
  696. //////////////////////////////////////////////////////////////////////
  697. // iPod_mhlt - TrackList class
  698. //////////////////////////////////////////////////////////////////////
  699. iPod_mhlt::iPod_mhlt() :
  700. mhit(),
  701. next_mhit_id(100)
  702. {
  703. }
  704. iPod_mhlt::~iPod_mhlt()
  705. {
  706. // It is unnecessary (and slow) to clear the map, since the object is being destroyed anyway
  707. ClearTracks(false);
  708. }
  709. long iPod_mhlt::parse(const uint8_t *data)
  710. {
  711. long ptr=0;
  712. //check mhlt header
  713. if (_strnicmp((char *)&data[ptr],"mhlt",4)) return -1;
  714. ptr+=4;
  715. // get size
  716. size_head=rev4(&data[ptr]);
  717. ptr+=4;
  718. ASSERT(size_head == 0x5c);
  719. // get num children (num songs on iPod)
  720. const unsigned long children=rev4(&data[ptr]); // Only used locally - child count is obtained from the mhit list
  721. ptr+=4;
  722. //skip nulls
  723. ptr=size_head;
  724. long ret;
  725. // get children one by one
  726. for (unsigned long i=0;i<children;i++)
  727. {
  728. iPod_mhit *m = new iPod_mhit;
  729. ret=m->parse(&data[ptr]);
  730. ASSERT(ret >= 0);
  731. if (ret<0)
  732. {
  733. delete m;
  734. return ret;
  735. }
  736. ptr+=ret;
  737. mhit.insert(mhit_value_t(m->id, m));
  738. mhit_indexer.push_back(m->id);
  739. }
  740. if (!mhit.empty())
  741. {
  742. //InterlockedExchange(&next_mhit_id, mhit.back().first);
  743. uint32_t id = mhit_indexer[mhit_indexer.size() - 1];
  744. InterlockedExchange(&next_mhit_id, id);
  745. }
  746. return ptr;
  747. }
  748. uint32_t iPod_mhlt::GetNextID()
  749. {
  750. return (uint32_t)InterlockedIncrement(&next_mhit_id);
  751. }
  752. long iPod_mhlt::write(unsigned char * data, const unsigned long datasize)
  753. {
  754. const unsigned int headsize=0x5c;
  755. // check for header size
  756. if (headsize>datasize) return -1;
  757. long ptr=0;
  758. //write mhlt header
  759. data[0]='m';data[1]='h';data[2]='l';data[3]='t';
  760. ptr+=4;
  761. // write size
  762. rev4(headsize,&data[ptr]); // header size
  763. ptr+=4;
  764. // write numchildren (numsongs)
  765. const unsigned long children = GetChildrenCount();
  766. rev4(children,&data[ptr]);
  767. ptr+=4;
  768. // fill up the rest of the header with nulls
  769. for (unsigned long i=ptr;i<headsize;i++)
  770. data[i]=0;
  771. ptr=headsize;
  772. long ret;
  773. // write children one by one
  774. mhit_map_t::const_iterator begin = mhit.begin();
  775. mhit_map_t::const_iterator end = mhit.end();
  776. for(mhit_map_t::const_iterator it = begin; it != end; it++)
  777. {
  778. iPod_mhit *m = static_cast<iPod_mhit*>(it->second);
  779. #ifdef _DEBUG
  780. const unsigned int mapID = (*it).first;
  781. ASSERT(mapID == m->id);
  782. #endif
  783. ret=m->write(&data[ptr],datasize-ptr);
  784. ASSERT(ret >= 0);
  785. if (ret<0) return ret;
  786. else ptr+=ret;
  787. }
  788. return ptr;
  789. }
  790. iPod_mhit * iPod_mhlt::NewTrack()
  791. {
  792. iPod_mhit *track = new iPod_mhit;
  793. if (track != NULL)
  794. {
  795. track->addedtime = wintime_to_mactime(time(0));
  796. track->id = GetNextID();
  797. }
  798. return track;
  799. }
  800. void iPod_mhlt::AddTrack(iPod_mhit *new_track)
  801. {
  802. mhit_indexer.push_back(new_track->id);
  803. mhit.insert(mhit_value_t(new_track->id, new_track));
  804. }
  805. bool iPod_mhlt::DeleteTrack(const unsigned long index)
  806. {
  807. //unsigned int i=0;
  808. //for(mhit_map_t::const_iterator it = mhit.begin(); it != mhit.end(); it++, i++)
  809. //{
  810. // if(i == index)
  811. // {
  812. // iPod_mhit *m = static_cast<iPod_mhit*>(it->second);
  813. // return(DeleteTrackByID(m->id));
  814. // }
  815. //}
  816. //return false;
  817. if (index > mhit_indexer.size())
  818. {
  819. return false;
  820. }
  821. auto key = mhit_indexer[index];
  822. auto it = mhit.find(key);
  823. if (mhit.end() == it)
  824. {
  825. return false;
  826. }
  827. return DeleteTrackByID(it->first);
  828. }
  829. bool iPod_mhlt::DeleteTrackByID(const unsigned long id)
  830. {
  831. mhit_map_t::iterator it = mhit.find(id);
  832. if(it != mhit.end())
  833. {
  834. iPod_mhit *m = static_cast<iPod_mhit*>(it->second);
  835. mhit.erase(it);
  836. // remove also from indexer!!
  837. for (size_t n = 0; n < mhit_indexer.size(); ++n)
  838. {
  839. if (id == mhit_indexer[n])
  840. {
  841. mhit_indexer.erase(mhit_indexer.begin() + n);
  842. break;
  843. }
  844. }
  845. delete m;
  846. return true;
  847. }
  848. return false;
  849. }
  850. iPod_mhit * iPod_mhlt::GetTrack(uint32_t index) const
  851. {
  852. //mhit_map_t::value_type value = mhit.at(index);
  853. //return value.second;
  854. if (index > mhit_indexer.size())
  855. {
  856. return nullptr;
  857. }
  858. uint32_t key = mhit_indexer[index];
  859. auto it = mhit.find(key);
  860. if (mhit.end() == it)
  861. {
  862. return nullptr;
  863. }
  864. return it->second;
  865. }
  866. iPod_mhit * iPod_mhlt::GetTrackByID(const unsigned long id)
  867. {
  868. mhit_map_t::const_iterator it = mhit.find(id);
  869. if(it == mhit.end())
  870. return NULL;
  871. return static_cast<iPod_mhit*>(it->second);
  872. }
  873. bool iPod_mhlt::ClearTracks(const bool clearMap)
  874. {
  875. #ifdef IPODDB_PROFILER
  876. profiler(iPodDB__iPod_mhlt_ClearTracks);
  877. #endif
  878. mhit_map_t::const_iterator begin = mhit.begin();
  879. mhit_map_t::const_iterator end = mhit.end();
  880. for(mhit_map_t::const_iterator it = begin; it != end; it++)
  881. {
  882. delete static_cast<iPod_mhit*>(it->second);
  883. }
  884. if (clearMap)
  885. {
  886. mhit.clear();
  887. mhit_indexer.clear();
  888. }
  889. return true;
  890. }
  891. //////////////////////////////////////////////////////////////////////
  892. // iPod_mhit - Holds info about a song
  893. //////////////////////////////////////////////////////////////////////
  894. iPod_mhit::iPod_mhit() :
  895. id(0),
  896. visible(1),
  897. filetype(0),
  898. vbr(0),
  899. type(0),
  900. compilation(0),
  901. stars(0),
  902. lastmodifiedtime(0),
  903. size(0),
  904. length(0),
  905. tracknum(0),
  906. totaltracks(0),
  907. year(0),
  908. bitrate(0),
  909. samplerate(0),
  910. samplerate_fixedpoint(0),
  911. volume(0),
  912. starttime(0),
  913. stoptime(0),
  914. soundcheck(0),
  915. playcount(0),
  916. playcount2(0),
  917. lastplayedtime(0),
  918. cdnum(0),
  919. totalcds(0),
  920. userID(0),
  921. addedtime(0),
  922. bookmarktime(0),
  923. dbid(0),
  924. BPM(0),
  925. app_rating(0),
  926. checked(0),
  927. unk9(0),
  928. artworkcount(0),
  929. artworksize(0),
  930. unk11(0),
  931. samplerate2(0),
  932. releasedtime(0),
  933. unk14(0),
  934. unk15(0),
  935. unk16(0),
  936. skipcount(0),
  937. skippedtime(0),
  938. hasArtwork(2), // iTunes 4.7.1 always seems to write 2 for unk19
  939. skipShuffle(0),
  940. rememberPosition(0),
  941. unk19(0),
  942. dbid2(0),
  943. lyrics_flag(0),
  944. movie_flag(0),
  945. mark_unplayed(0),
  946. unk20(0),
  947. unk21(0),
  948. pregap(0),
  949. samplecount(0),
  950. unk25(0),
  951. postgap(0),
  952. unk27(0),
  953. mediatype(0),
  954. seasonNumber(0),
  955. episodeNumber(0),
  956. unk31(0),
  957. unk32(0),
  958. unk33(0),
  959. unk34(0),
  960. unk35(0),
  961. unk36(0),
  962. unk37(0),
  963. gaplessData(0),
  964. unk39(0),
  965. albumgapless(0),
  966. trackgapless(0),
  967. unk40(0),
  968. unk41(0),
  969. unk42(0),
  970. unk43(0),
  971. unk44(0),
  972. unk45(0),
  973. unk46(0),
  974. album_id(0),
  975. unk48(0),
  976. unk49(0),
  977. unk50(0),
  978. unk51(0),
  979. unk52(0),
  980. unk53(0),
  981. unk54(0),
  982. unk55(0),
  983. unk56(0),
  984. mhii_link(0),
  985. mhod()
  986. {
  987. // Create a highly randomized 64 bit value for the dbID
  988. dbid = Generate64BitID();
  989. dbid2 = dbid;
  990. for(int i=0; i<25; i++) mhodcache[i]=NULL;
  991. mhod.reserve(8);
  992. }
  993. iPod_mhit::~iPod_mhit()
  994. {
  995. #ifdef IPODDB_PROFILER
  996. profiler(iPodDB__iPod_mhit_destructor);
  997. #endif
  998. const unsigned long count = GetChildrenCount();
  999. for (unsigned long i=0;i<count;i++)
  1000. delete mhod[i];
  1001. }
  1002. long iPod_mhit::parse(const uint8_t *data)
  1003. {
  1004. size_t ptr=0;
  1005. unsigned long temp=0;
  1006. //check mhit header
  1007. if (_strnicmp((char *)&data[ptr],"mhit",4)) return -1;
  1008. ptr+=4;
  1009. // get sizes
  1010. size_head=read_uint32_t(data, ptr);
  1011. size_total=read_uint32_t(data, ptr);
  1012. ASSERT(size_head == 0x9c || size_head == 0xf4 || size_head == 0x148 || size_head == 0x184 || size_head == 0x248); // if this is false, this is a new mhit format
  1013. // get rest of data
  1014. unsigned long mhodnum=read_uint32_t(data, ptr); // Only used locally
  1015. id=read_uint32_t(data, ptr);
  1016. visible=read_uint32_t(data, ptr);
  1017. filetype=read_uint32_t(data, ptr);
  1018. vbr = data[ptr++];
  1019. type = data[ptr++];
  1020. compilation = data[ptr++];
  1021. stars = data[ptr++];
  1022. lastmodifiedtime=read_uint32_t(data, ptr);
  1023. size=read_uint32_t(data, ptr);
  1024. length=read_uint32_t(data, ptr);
  1025. tracknum=read_uint32_t(data, ptr);
  1026. totaltracks=read_uint32_t(data, ptr);
  1027. year=read_uint32_t(data, ptr);
  1028. bitrate=read_uint32_t(data, ptr);
  1029. temp=rev4(&data[ptr]);
  1030. ptr+=4;
  1031. samplerate = (uint16_t)(temp >> 16);
  1032. samplerate_fixedpoint = (uint16_t)(temp & 0x0000ffff);
  1033. volume=read_uint32_t(data, ptr);
  1034. starttime=read_uint32_t(data, ptr);
  1035. stoptime=read_uint32_t(data, ptr);
  1036. soundcheck=read_uint32_t(data, ptr);
  1037. playcount=read_uint32_t(data, ptr);
  1038. playcount2=read_uint32_t(data, ptr);
  1039. lastplayedtime=read_uint32_t(data, ptr);
  1040. cdnum=read_uint32_t(data, ptr);;
  1041. totalcds=read_uint32_t(data, ptr);
  1042. userID=read_uint32_t(data, ptr);
  1043. addedtime=read_uint32_t(data, ptr);
  1044. bookmarktime=read_uint32_t(data, ptr);
  1045. dbid=rev8(get8(&data[ptr]));
  1046. ptr+=8;
  1047. if(dbid == 0)
  1048. {
  1049. // Force the dbid to be a valid value.
  1050. // This may not always be the right thing to do, but I can't think of any reason why it wouldn't be ok...
  1051. dbid = Generate64BitID();
  1052. }
  1053. temp=rev4(&data[ptr]);
  1054. BPM=temp>>16;
  1055. app_rating=(temp&0xff00) >> 8;
  1056. checked = (uint8_t)(temp&0xff);
  1057. ptr+=4;
  1058. artworkcount=rev2(&data[ptr]);
  1059. ptr+=2;
  1060. unk9=rev2(&data[ptr]);
  1061. ptr+=2;
  1062. artworksize=read_uint32_t(data, ptr);
  1063. unk11=read_uint32_t(data, ptr);
  1064. memcpy(&samplerate2, &data[ptr], sizeof(float));
  1065. ptr+=4;
  1066. releasedtime=read_uint32_t(data, ptr);
  1067. unk14=read_uint32_t(data, ptr);
  1068. unk15=read_uint32_t(data, ptr);
  1069. unk16=read_uint32_t(data, ptr);
  1070. // Newly added as of dbversion 0x0c
  1071. if(size_head >= 0xf4)
  1072. {
  1073. skipcount=read_uint32_t(data, ptr);
  1074. skippedtime=read_uint32_t(data, ptr);
  1075. hasArtwork=data[ptr++];
  1076. skipShuffle=data[ptr++];
  1077. rememberPosition=data[ptr++];
  1078. unk19=data[ptr++];
  1079. dbid2=rev8(get8(&data[ptr]));
  1080. ptr+=8;
  1081. if(dbid2 == 0)
  1082. dbid2 = dbid;
  1083. lyrics_flag=data[ptr++];
  1084. movie_flag=data[ptr++];
  1085. mark_unplayed=data[ptr++];
  1086. unk20=data[ptr++];
  1087. unk21=read_uint32_t(data, ptr); // 180
  1088. pregap=read_uint32_t(data, ptr);
  1089. samplecount=rev8(get8(&data[ptr])); //sample count
  1090. ptr+=8;
  1091. unk25=read_uint32_t(data, ptr); // 196
  1092. postgap=read_uint32_t(data, ptr);
  1093. unk27=read_uint32_t(data, ptr);
  1094. mediatype=read_uint32_t(data, ptr);
  1095. seasonNumber=read_uint32_t(data, ptr);
  1096. episodeNumber=read_uint32_t(data, ptr);
  1097. unk31=read_uint32_t(data, ptr);
  1098. unk32=read_uint32_t(data, ptr);
  1099. unk33=read_uint32_t(data, ptr);
  1100. unk34=read_uint32_t(data, ptr);
  1101. unk35=read_uint32_t(data, ptr);
  1102. unk36=read_uint32_t(data, ptr);
  1103. }
  1104. if(size_head >= 0x148)
  1105. { // dbversion 0x13
  1106. unk37=read_uint32_t(data, ptr);
  1107. gaplessData=read_uint32_t(data, ptr);
  1108. unk39=read_uint32_t(data, ptr);
  1109. trackgapless = read_uint16_t(data, ptr);
  1110. albumgapless = read_uint16_t(data, ptr);
  1111. unk40=read_uint32_t(data, ptr); // 260
  1112. unk41=read_uint32_t(data, ptr); // 264
  1113. unk42=read_uint32_t(data, ptr); // 268
  1114. unk43=read_uint32_t(data, ptr); // 272
  1115. unk44=read_uint32_t(data, ptr); // 276
  1116. unk45=read_uint32_t(data, ptr); // 280
  1117. unk46=read_uint32_t(data, ptr); // 284
  1118. album_id=read_uint32_t(data, ptr); // 288 - libgpod lists "album_id"
  1119. unk48=read_uint32_t(data, ptr); // 292 - libgpod lists first half of an id
  1120. unk49=read_uint32_t(data, ptr); // 296 - libgpod lists second half of an id
  1121. unk50=read_uint32_t(data, ptr); // 300 - libgpod lists file size
  1122. unk51=read_uint32_t(data, ptr); // 304
  1123. unk52=read_uint32_t(data, ptr); // 308 - libgpod mentions 8 bytes of 0x80
  1124. unk53=read_uint32_t(data, ptr); // 312 - libgpod mentions 8 bytes of 0x80
  1125. unk54=read_uint32_t(data, ptr); // 316
  1126. unk55=read_uint32_t(data, ptr); // 320
  1127. unk56=read_uint32_t(data, ptr); // 324
  1128. }
  1129. if(size_head >= 0x184)
  1130. {
  1131. ptr = 0x148; // line it up, just in case
  1132. ptr += 22; // dunno what the first 22 bytes are
  1133. album_id = read_uint16_t(data, ptr);
  1134. mhii_link = read_uint32_t(data, ptr);
  1135. }
  1136. #ifdef _DEBUG
  1137. // If these trigger an assertion, something in the database format has changed/been added
  1138. ASSERT(visible == 1);
  1139. ASSERT(unk11 == 0);
  1140. ASSERT(unk16 == 0);
  1141. // ASSERT(unk19 == 0);
  1142. // ASSERT(hasArtwork == 2); // iTunes always sets unk19 to 2, but older programs won't have set it
  1143. ASSERT(unk20 == 0);
  1144. ASSERT(unk21 == 0);
  1145. ASSERT(unk25 == 0);
  1146. // ASSERT(unk27 == 0);
  1147. //ASSERT(unk31 == 0);
  1148. ASSERT(unk32 == 0);
  1149. ASSERT(unk33 == 0);
  1150. ASSERT(unk34 == 0);
  1151. ASSERT(unk35 == 0);
  1152. ASSERT(unk36 == 0);
  1153. ASSERT(unk37 == 0);
  1154. ASSERT(unk39 == 0);
  1155. ASSERT(unk40 == 0);
  1156. ASSERT(unk41 == 0);
  1157. ASSERT(unk42 == 0);
  1158. ASSERT(unk43 == 0);
  1159. ASSERT(unk44 == 0);
  1160. ASSERT(unk45 == 0);
  1161. ASSERT(unk46 == 0);
  1162. // ASSERT(unk47 == 0);
  1163. //ASSERT(unk48 == 0);
  1164. // ASSERT(unk49 == 0);
  1165. ASSERT(unk50 == 0 || unk50 == size);
  1166. ASSERT(unk51 == 0);
  1167. // ASSERT(unk52 == 0);
  1168. ASSERT(unk53 == 0 || unk53 == 0x8080 || unk53 == 0x8081);
  1169. ASSERT(unk54 == 0);
  1170. ASSERT(unk55 == 0);
  1171. ASSERT(unk56 == 0);
  1172. #endif
  1173. // skip nulls
  1174. ptr=size_head;
  1175. long ret;
  1176. for (unsigned long i=0;i<mhodnum;i++)
  1177. {
  1178. iPod_mhod *m = new iPod_mhod;
  1179. ret=m->parse(&data[ptr]);
  1180. ASSERT(ret >= 0);
  1181. if (ret<0)
  1182. {
  1183. delete m;
  1184. return ret;
  1185. }
  1186. ptr+=ret;
  1187. mhod.push_back(m);
  1188. if(m->type <= 25 && m->type >= 1) mhodcache[m->type-1] = m;
  1189. }
  1190. return size_total;
  1191. }
  1192. long iPod_mhit::write(unsigned char * data, const unsigned long datasize)
  1193. {
  1194. #ifdef IPODDB_PROFILER
  1195. profiler(iPodDB__iPod_mhit_write);
  1196. #endif
  1197. //const unsigned int headsize=0x148; // was 0x9c in db version <= 0x0b
  1198. const unsigned int headsize=0x184; // db version 0x19
  1199. // check for header size
  1200. if (headsize>datasize) return -1;
  1201. size_t ptr=0;
  1202. //write mhlt header
  1203. data[0]='m';data[1]='h';data[2]='i';data[3]='t';
  1204. ptr+=4;
  1205. // write sizes
  1206. write_uint32_t(data, ptr, headsize); // header size
  1207. write_uint32_t(data, ptr, 0); // placeholder for total size (fill in later)
  1208. unsigned long temp, i;
  1209. // Remove all empty MHOD strings before continuing
  1210. for(i=0;i<GetChildrenCount();i++)
  1211. {
  1212. iPod_mhod *m = mhod[i];
  1213. ASSERT(m != NULL);
  1214. if(m == NULL)
  1215. continue;
  1216. if(m->type < 50 && m->length == 0)
  1217. {
  1218. //DeleteString(m->type);
  1219. //i = 0;
  1220. }
  1221. }
  1222. // write stuff out
  1223. unsigned long mhodnum = GetChildrenCount();
  1224. write_uint32_t(data, ptr, mhodnum);
  1225. write_uint32_t(data, ptr, id);
  1226. write_uint32_t(data, ptr, visible);
  1227. if(filetype == 0)
  1228. {
  1229. iPod_mhod *mhod = FindString(MHOD_LOCATION);
  1230. if(mhod)
  1231. {
  1232. filetype = GetFileTypeID(mhod->str);
  1233. }
  1234. }
  1235. write_uint32_t(data, ptr, filetype);
  1236. vbr = data[ptr++] = vbr;
  1237. type = data[ptr++] = type;
  1238. compilation = data[ptr++] = compilation;
  1239. stars = data[ptr++] = stars;
  1240. write_uint32_t(data, ptr, lastmodifiedtime);
  1241. write_uint32_t(data, ptr, size);
  1242. write_uint32_t(data, ptr, length);
  1243. write_uint32_t(data, ptr, tracknum);
  1244. write_uint32_t(data, ptr, totaltracks);
  1245. write_uint32_t(data, ptr, year);
  1246. write_uint32_t(data, ptr, bitrate);
  1247. temp = samplerate << 16 | samplerate_fixedpoint & 0x0000ffff;
  1248. rev4(temp,&data[ptr]);
  1249. ptr+=4;
  1250. write_uint32_t(data, ptr, volume);
  1251. write_uint32_t(data, ptr, starttime);
  1252. write_uint32_t(data, ptr, stoptime);
  1253. write_uint32_t(data, ptr, soundcheck);
  1254. write_uint32_t(data, ptr, playcount);
  1255. write_uint32_t(data, ptr, playcount2);
  1256. write_uint32_t(data, ptr, lastplayedtime);
  1257. write_uint32_t(data, ptr, cdnum);
  1258. write_uint32_t(data, ptr, totalcds);
  1259. write_uint32_t(data, ptr, userID);
  1260. write_uint32_t(data, ptr, addedtime);
  1261. write_uint32_t(data, ptr, bookmarktime);
  1262. put8(rev8(dbid),&data[ptr]);
  1263. ptr+=8;
  1264. temp = BPM << 16 | (app_rating & 0xff) << 8 | (checked & 0xff);
  1265. write_uint32_t(data, ptr, temp);
  1266. rev2(artworkcount, &data[ptr]);
  1267. ptr+=2;
  1268. rev2(unk9, &data[ptr]);
  1269. ptr+=2;
  1270. write_uint32_t(data, ptr, artworksize);
  1271. write_uint32_t(data, ptr, unk11);
  1272. // If samplerate2 is not set, base it off of samplerate
  1273. if(samplerate2 == 0)
  1274. {
  1275. // samplerate2 is the binary representation of the samplerate, as a 32 bit float
  1276. const float foo = (float)samplerate;
  1277. memcpy(&data[ptr], &foo, 4);
  1278. }
  1279. else
  1280. {
  1281. memcpy(&data[ptr], &samplerate2, 4);
  1282. }
  1283. ptr+=4;
  1284. rev4(releasedtime,&data[ptr]);
  1285. ptr+=4;
  1286. rev4(unk14,&data[ptr]);
  1287. ptr+=4;
  1288. rev4(unk15,&data[ptr]);
  1289. ptr+=4;
  1290. rev4(unk16,&data[ptr]);
  1291. ptr+=4;
  1292. // New data as of dbversion 0x0c
  1293. if(headsize >= 0xf4)
  1294. {
  1295. rev4(skipcount,&data[ptr]);
  1296. ptr+=4;
  1297. rev4(skippedtime,&data[ptr]);
  1298. ptr+=4;
  1299. data[ptr++]=hasArtwork;
  1300. data[ptr++]=skipShuffle;
  1301. data[ptr++]=rememberPosition;
  1302. data[ptr++]=unk19;
  1303. put8(rev8(dbid2),&data[ptr]);
  1304. ptr+=8;
  1305. data[ptr++]=lyrics_flag;
  1306. data[ptr++]=movie_flag;
  1307. data[ptr++]=mark_unplayed;
  1308. data[ptr++]=unk20;
  1309. rev4(unk21,&data[ptr]);
  1310. ptr+=4;
  1311. rev4(pregap,&data[ptr]);
  1312. ptr+=4;
  1313. put8(rev8(samplecount),&data[ptr]);
  1314. ptr+=8;
  1315. rev4(unk25,&data[ptr]);
  1316. ptr+=4;
  1317. rev4(postgap,&data[ptr]);
  1318. ptr+=4;
  1319. rev4(unk27,&data[ptr]);
  1320. ptr+=4;
  1321. rev4(mediatype,&data[ptr]);
  1322. ptr+=4;
  1323. rev4(seasonNumber,&data[ptr]);
  1324. ptr+=4;
  1325. rev4(episodeNumber,&data[ptr]);
  1326. ptr+=4;
  1327. rev4(unk31,&data[ptr]);
  1328. ptr+=4;
  1329. rev4(unk32,&data[ptr]);
  1330. ptr+=4;
  1331. rev4(unk33,&data[ptr]);
  1332. ptr+=4;
  1333. rev4(unk34,&data[ptr]);
  1334. ptr+=4;
  1335. rev4(unk35,&data[ptr]);
  1336. ptr+=4;
  1337. rev4(unk36,&data[ptr]);
  1338. ptr+=4;
  1339. }
  1340. if(headsize >= 0x148)
  1341. {
  1342. rev4(unk37,&data[ptr]); ptr+=4;
  1343. rev4(gaplessData,&data[ptr]); ptr+=4;
  1344. rev4(unk39,&data[ptr]); ptr+=4;
  1345. temp = albumgapless << 16 | (trackgapless & 0xffff);
  1346. rev4(temp, &data[ptr]); ptr+=4;
  1347. rev4(unk40,&data[ptr]); ptr+=4;
  1348. rev4(unk41,&data[ptr]); ptr+=4;
  1349. rev4(unk42,&data[ptr]); ptr+=4;
  1350. rev4(unk43,&data[ptr]); ptr+=4;
  1351. rev4(unk44,&data[ptr]); ptr+=4;
  1352. rev4(unk45,&data[ptr]); ptr+=4;
  1353. rev4(unk46,&data[ptr]); ptr+=4;
  1354. rev4(album_id,&data[ptr]); ptr+=4;
  1355. rev4(unk48,&data[ptr]); ptr+=4;
  1356. rev4(unk49,&data[ptr]); ptr+=4;
  1357. rev4(size,&data[ptr]); ptr+=4;
  1358. rev4(unk51,&data[ptr]); ptr+=4;
  1359. rev4(unk52,&data[ptr]); ptr+=4;
  1360. rev4(unk53,&data[ptr]); ptr+=4;
  1361. rev4(unk54,&data[ptr]); ptr+=4;
  1362. rev4(unk55,&data[ptr]); ptr+=4;
  1363. rev4(unk56,&data[ptr]); ptr+=4;
  1364. }
  1365. if (headsize >= 0x184)
  1366. {
  1367. ptr = 0x148; // line it up, just in case
  1368. memset(&data[ptr], 0, 22); // write a bunch of zeroes
  1369. ptr+=22;
  1370. rev2(album_id, &data[ptr]); ptr+=2;
  1371. rev4(mhii_link,&data[ptr]); ptr+=4;
  1372. memset(&data[ptr], 0, 32); // write a bunch of zeroes
  1373. ptr+=32;
  1374. }
  1375. ASSERT(ptr==headsize); // if this ain't true, I screwed up badly somewhere above
  1376. long ret;
  1377. for (i=0;i<mhodnum;i++)
  1378. {
  1379. ret=mhod[i]->write(&data[ptr],datasize-ptr);
  1380. ASSERT(ret >= 0);
  1381. if (ret<0) return ret;
  1382. else ptr+=ret;
  1383. }
  1384. // fix the total size
  1385. rev4(ptr,&data[8]);
  1386. return ptr;
  1387. }
  1388. iPod_mhod * iPod_mhit::AddString(const int type)
  1389. {
  1390. #ifdef IPODDB_PROFILER
  1391. profiler(iPodDB__iPod_mhit_AddString);
  1392. #endif
  1393. iPod_mhod * m;
  1394. if (type)
  1395. {
  1396. m = FindString(type);
  1397. if (m != NULL)
  1398. {
  1399. return m;
  1400. }
  1401. }
  1402. m=new iPod_mhod;
  1403. if (m!=NULL && type) m->type=type;
  1404. mhod.push_back(m);
  1405. if(m->type <= 25 && m->type >= 1) mhodcache[m->type-1] = m;
  1406. return m;
  1407. }
  1408. iPod_mhod * iPod_mhit::FindString(const unsigned long type) const
  1409. {
  1410. #ifdef IPODDB_PROFILER
  1411. profiler(iPodDB__iPod_mhit_FindString);
  1412. #endif
  1413. if(type <= 25 && type >= 1) return mhodcache[type-1];
  1414. const unsigned long children = GetChildrenCount();
  1415. for (unsigned long i=0;i<children;i++)
  1416. {
  1417. if (mhod[i]->type == type) return mhod[i];
  1418. }
  1419. return NULL;
  1420. }
  1421. unsigned long iPod_mhit::DeleteString(const unsigned long type)
  1422. {
  1423. #ifdef IPODDB_PROFILER
  1424. profiler(iPodDB__iPod_mhit_DeleteString);
  1425. #endif
  1426. if(type <= 25 && type >= 1) mhodcache[type-1] = NULL;
  1427. unsigned long count=0;
  1428. for (unsigned long i=0; i != GetChildrenCount(); i++)
  1429. {
  1430. if (mhod[i]->type == type)
  1431. {
  1432. iPod_mhod * m = mhod.at(i);
  1433. mhod.erase(mhod.begin() + i);
  1434. delete m;
  1435. i = i > 0 ? i - 1 : 0; // do this to ensure that it checks the new entry in position i next
  1436. count++;
  1437. }
  1438. }
  1439. return count;
  1440. }
  1441. unsigned int iPod_mhit::GetFileTypeID(const wchar_t *filename)
  1442. {
  1443. ASSERT(filename);
  1444. if(filename == NULL)
  1445. return(0);
  1446. // Incredibly, this is really the file extension as ASCII characters
  1447. // e.g. 0x4d = 'M', 0x50 = 'P', 0x33 = '3', 0x20 = '<space>'
  1448. if(wcsistr(filename, L".mp3") != NULL)
  1449. return FILETYPE_MP3;
  1450. else if(wcsistr(filename, L".m4a") != NULL)
  1451. return FILETYPE_M4A;
  1452. else if(wcsistr(filename, L".m4b") != NULL)
  1453. return(0x4d344220);
  1454. else if(wcsistr(filename, L".m4p") != NULL)
  1455. return(0x4d345020);
  1456. else if(wcsistr(filename, L".wav") != NULL)
  1457. return FILETYPE_WAV;
  1458. return(0);
  1459. }
  1460. iPod_mhit& iPod_mhit::operator=(const iPod_mhit& src)
  1461. {
  1462. Duplicate(&src,this);
  1463. return *this;
  1464. }
  1465. void iPod_mhit::Duplicate(const iPod_mhit *src, iPod_mhit *dst)
  1466. {
  1467. #ifdef IPODDB_PROFILER
  1468. profiler(iPodDB__iPod_mhit_Duplicate);
  1469. #endif
  1470. if(src == NULL || dst == NULL)
  1471. return;
  1472. dst->id = src->id;
  1473. dst->visible = src->visible;
  1474. dst->filetype = src->filetype;
  1475. dst->vbr = src->vbr;
  1476. dst->type = src->type;
  1477. dst->compilation = src->compilation;
  1478. dst->stars = src->stars;
  1479. dst->lastmodifiedtime = src->lastmodifiedtime;
  1480. dst->size = src->size;
  1481. dst->length = src->length;
  1482. dst->tracknum = src->tracknum;
  1483. dst->totaltracks = src->totaltracks;
  1484. dst->year = src->year;
  1485. dst->bitrate = src->bitrate;
  1486. dst->samplerate = src->samplerate;
  1487. dst->samplerate_fixedpoint = src->samplerate_fixedpoint;
  1488. dst->volume = src->volume;
  1489. dst->starttime = src->starttime;
  1490. dst->stoptime = src->stoptime;
  1491. dst->soundcheck = src->soundcheck;
  1492. dst->playcount = src->playcount;
  1493. dst->playcount2 = src->playcount2;
  1494. dst->lastplayedtime = src->lastplayedtime;
  1495. dst->cdnum = src->cdnum;
  1496. dst->totalcds = src->totalcds;
  1497. dst->userID = src->userID;
  1498. dst->addedtime = src->addedtime;
  1499. dst->bookmarktime = src->bookmarktime;
  1500. dst->dbid = src->dbid;
  1501. dst->BPM = src->BPM;
  1502. dst->app_rating = src->app_rating;
  1503. dst->checked = src->checked;
  1504. dst->unk9 = src->unk9;
  1505. dst->artworksize = src->artworksize;
  1506. dst->unk11 = src->unk11;
  1507. dst->samplerate2 = src->samplerate2;
  1508. dst->releasedtime = src->releasedtime;
  1509. dst->unk14 = src->unk14;
  1510. dst->unk15 = src->unk15;
  1511. dst->unk16 = src->unk16;
  1512. dst->skipcount = src->skipcount;
  1513. dst->skippedtime = src->skippedtime;
  1514. dst->hasArtwork = src->hasArtwork;
  1515. dst->skipShuffle = src->skipShuffle;
  1516. dst->rememberPosition = src->rememberPosition;
  1517. dst->unk19 = src->unk19;
  1518. dst->dbid2 = src->dbid2;
  1519. dst->lyrics_flag = src->lyrics_flag;
  1520. dst->movie_flag = src->movie_flag;
  1521. dst->mark_unplayed = src->mark_unplayed;
  1522. dst->unk20 = src->unk20;
  1523. dst->unk21 = src->unk21;
  1524. dst->pregap = src->pregap;
  1525. dst->samplecount = src->samplecount;
  1526. dst->unk25 = src->unk25;
  1527. dst->postgap = src->postgap;
  1528. dst->unk27 = src->unk27;
  1529. dst->mediatype = src->mediatype;
  1530. dst->seasonNumber = src->seasonNumber;
  1531. dst->episodeNumber = src->episodeNumber;
  1532. dst->unk31 = src->unk31;
  1533. dst->unk32 = src->unk32;
  1534. dst->unk33 = src->unk33;
  1535. dst->unk34 = src->unk34;
  1536. dst->unk35 = src->unk35;
  1537. dst->unk36 = src->unk36;
  1538. dst->unk37 = src->unk37;
  1539. dst->gaplessData = src->gaplessData;
  1540. dst->unk39 = src->unk39;
  1541. dst->albumgapless = src->albumgapless;
  1542. dst->trackgapless = src->trackgapless;
  1543. dst->unk40 = src->unk40;
  1544. dst->unk41 = src->unk41;
  1545. dst->unk42 = src->unk42;
  1546. dst->unk43 = src->unk43;
  1547. dst->unk44 = src->unk44;
  1548. dst->unk45 = src->unk45;
  1549. dst->unk46 = src->unk46;
  1550. dst->album_id = src->album_id;
  1551. dst->unk48 = src->unk48;
  1552. dst->unk49 = src->unk49;
  1553. dst->unk50 = src->unk50;
  1554. dst->unk51 = src->unk51;
  1555. dst->unk52 = src->unk52;
  1556. dst->unk53 = src->unk53;
  1557. dst->unk54 = src->unk54;
  1558. dst->unk55 = src->unk55;
  1559. dst->unk56 = src->unk56;
  1560. dst->mhii_link = src->mhii_link;
  1561. const unsigned int mhodSize = src->mhod.size();
  1562. for(unsigned int i=0; i<mhodSize; i++)
  1563. {
  1564. iPod_mhod *src_mhod = src->mhod[i];
  1565. if(src_mhod == NULL)
  1566. continue;
  1567. iPod_mhod *dst_mhod = dst->AddString(src_mhod->type);
  1568. if(dst_mhod)
  1569. dst_mhod->Duplicate(src_mhod, dst_mhod);
  1570. }
  1571. }
  1572. int iPod_mhit::GetEQSetting()
  1573. {
  1574. iPod_mhod *mhod = FindString(MHOD_EQSETTING);
  1575. if(mhod == NULL)
  1576. return(EQ_NONE);
  1577. ASSERT(lstrlen(mhod->str) == 9);
  1578. if(lstrlen(mhod->str) != 9)
  1579. return(EQ_NONE);
  1580. wchar_t strval[4] = {0};
  1581. lstrcpyn(strval, mhod->str + 3, 3);
  1582. int val = _wtoi(strval);
  1583. ASSERT(val >= EQ_ACOUSTIC && val <= EQ_VOCALBOOSTER);
  1584. return(val);
  1585. }
  1586. void iPod_mhit::SetEQSetting(int value)
  1587. {
  1588. DeleteString(MHOD_EQSETTING);
  1589. if(value < 0)
  1590. return;
  1591. ASSERT(value >= EQ_ACOUSTIC && value <= EQ_VOCALBOOSTER);
  1592. wchar_t strval[10] = {0};
  1593. _snwprintf(strval, 9, L"#!#%d#!#", value);
  1594. strval[9] = '\0';
  1595. iPod_mhod *mhod = AddString(MHOD_EQSETTING);
  1596. ASSERT(mhod);
  1597. if(mhod == NULL)
  1598. return;
  1599. mhod->SetString(strval);
  1600. }
  1601. //////////////////////////////////////////////////////////////////////
  1602. // iPod_mhod - Holds strings for a song or playlist, among other things
  1603. //////////////////////////////////////////////////////////////////////
  1604. iPod_mhod::iPod_mhod() :
  1605. type(0),
  1606. unk1(0),
  1607. unk2(0),
  1608. position(1),
  1609. length(0),
  1610. unk3(1),
  1611. unk4(0),
  1612. str(NULL),
  1613. binary(NULL),
  1614. liveupdate(1),
  1615. checkrules(0),
  1616. matchcheckedonly(0),
  1617. limitsort_opposite(0),
  1618. limittype(0),
  1619. limitsort(0),
  1620. limitvalue(0),
  1621. unk5(0),
  1622. rules_operator(SPLMATCH_AND),
  1623. parseSmartPlaylists(true)
  1624. {
  1625. }
  1626. iPod_mhod::~iPod_mhod()
  1627. {
  1628. #ifdef IPODDB_PROFILER
  1629. profiler(iPodDB__iPod_mhod_destructor);
  1630. #endif
  1631. if (str) delete [] str;
  1632. if (binary) delete [] binary;
  1633. const unsigned int size = rule.size();
  1634. for (unsigned int i=0;i<size;i++)
  1635. delete rule[i];
  1636. }
  1637. long iPod_mhod::parse(const uint8_t *data)
  1638. {
  1639. size_t ptr=0;
  1640. unsigned long i = 0;
  1641. //check mhod header
  1642. if (_strnicmp((char *)&data[ptr],"mhod",4)) return -1;
  1643. ptr+=4;
  1644. // get sizes
  1645. size_head=read_uint32_t(data, ptr);
  1646. size_total=read_uint32_t(data, ptr);
  1647. ASSERT(size_head == 0x18);
  1648. // get type
  1649. type=read_uint32_t(data, ptr);
  1650. // dunno what these are, but they are definitely common among all the types of mhods
  1651. // smartlist types prove that.
  1652. // they're usually zero though.. null padding for the MHOD header?
  1653. unk1=read_uint32_t(data, ptr);
  1654. unk2=read_uint32_t(data, ptr);
  1655. if (iPod_mhod::IsSimpleStringType(type))
  1656. {
  1657. // string types get parsed
  1658. // 1 == UTF-16, 2 == UTF-8
  1659. // TODO: handle UTF-8
  1660. encoding_type=read_uint32_t(data, ptr);
  1661. length=read_uint32_t(data, ptr);
  1662. unk3=read_uint32_t(data, ptr);
  1663. unk4=read_uint32_t(data, ptr);
  1664. str=new wchar_t[length + 1];
  1665. memcpy(str,&data[ptr],length);
  1666. str[length / 2] = '\0';
  1667. ptr+=length;
  1668. }
  1669. else if (type == MHOD_ENCLOSUREURL || type == MHOD_RSSFEEDURL)
  1670. {
  1671. // Apple makes life hard again! These are almost like regular/simple MHOD string types,
  1672. // except the string is UTF-8 encoded and there is no length or position fields
  1673. length = size_total - size_head;
  1674. ASSERT(length > 0);
  1675. if(length > 0)
  1676. {
  1677. char *tmp = new char[length + 1];
  1678. ASSERT(tmp);
  1679. if(tmp != NULL)
  1680. {
  1681. memcpy(tmp, &data[ptr], length);
  1682. tmp[length] = '\0';
  1683. wchar_t *tmpUTF = UTF8_to_UTF16(tmp);
  1684. unsigned int len = wcslen(tmpUTF);
  1685. str=new wchar_t[len + 1];
  1686. wcsncpy(str, tmpUTF, len);
  1687. str[len] = '\0';
  1688. free(tmpUTF);
  1689. }
  1690. ptr+=length;
  1691. }
  1692. }
  1693. else if (type==MHOD_SPLPREF)
  1694. {
  1695. if(parseSmartPlaylists)
  1696. {
  1697. liveupdate=data[ptr]; ptr++;
  1698. checkrules=data[ptr]; ptr++;
  1699. checklimits=data[ptr]; ptr++;
  1700. limittype=data[ptr]; ptr++;
  1701. limitsort=data[ptr]; ptr++;
  1702. ptr+=3;
  1703. limitvalue=read_uint32_t(data, ptr);
  1704. matchcheckedonly=data[ptr]; ptr++;
  1705. // if the opposite flag is on, set limitsort's high bit
  1706. limitsort_opposite=data[ptr]; ptr++;
  1707. if(limitsort_opposite)
  1708. limitsort += 0x80000000;
  1709. }
  1710. }
  1711. else if (type==MHOD_SPLDATA)
  1712. {
  1713. if(parseSmartPlaylists)
  1714. {
  1715. // strangely, SPL Data is the only thing in the file that *isn't* byte reversed.
  1716. // check for SLst header
  1717. if (_strnicmp((char *)&data[ptr],"SLst",4)) return -1;
  1718. ptr+=4;
  1719. unk5=get4(&data[ptr]); ptr+=4;
  1720. const unsigned int numrules=get4(&data[ptr]); ptr+=4;
  1721. rules_operator=get4(&data[ptr]); ptr+=4;
  1722. ptr+=120;
  1723. rule.reserve(numrules);
  1724. for (i=0;i<numrules;i++)
  1725. {
  1726. SPLRule * r = new SPLRule;
  1727. ASSERT(r);
  1728. if(r == NULL)
  1729. continue;
  1730. r->field=get4(&data[ptr]); ptr+=4;
  1731. r->action=get4(&data[ptr]); ptr+=4;
  1732. ptr+=44;
  1733. r->length=get4(&data[ptr]); ptr+=4;
  1734. #ifdef _DEBUG
  1735. switch(r->action)
  1736. {
  1737. case SPLACTION_IS_INT:
  1738. case SPLACTION_IS_GREATER_THAN:
  1739. case SPLACTION_IS_NOT_GREATER_THAN:
  1740. case SPLACTION_IS_LESS_THAN:
  1741. case SPLACTION_IS_NOT_LESS_THAN:
  1742. case SPLACTION_IS_IN_THE_RANGE:
  1743. case SPLACTION_IS_NOT_IN_THE_RANGE:
  1744. case SPLACTION_IS_IN_THE_LAST:
  1745. case SPLACTION_IS_STRING:
  1746. case SPLACTION_CONTAINS:
  1747. case SPLACTION_STARTS_WITH:
  1748. case SPLACTION_DOES_NOT_START_WITH:
  1749. case SPLACTION_ENDS_WITH:
  1750. case SPLACTION_DOES_NOT_END_WITH:
  1751. case SPLACTION_IS_NOT_INT:
  1752. case SPLACTION_IS_NOT_IN_THE_LAST:
  1753. case SPLACTION_IS_NOT:
  1754. case SPLACTION_DOES_NOT_CONTAIN:
  1755. case SPLACTION_BINARY_AND:
  1756. case SPLACTION_UNKNOWN2:
  1757. break;
  1758. default:
  1759. // New action!
  1760. //printf("New Action Discovered = %x\n",r->action);
  1761. ASSERT(0);
  1762. break;
  1763. }
  1764. #endif
  1765. const bool hasString = iPod_slst::GetFieldType(r->field) == iPod_slst::ftString;
  1766. if(hasString)
  1767. {
  1768. // For some unknown reason, smart playlist strings have UTF-16 characters that are byte swapped
  1769. unsigned char *c = (unsigned char*)r->string;
  1770. const unsigned len = min(r->length, SPL_MAXSTRINGLENGTH);
  1771. for(unsigned int i=0; i<len; i+=2)
  1772. {
  1773. *(c + i) = data[ptr + i + 1];
  1774. *(c + i + 1) = data[ptr + i];
  1775. }
  1776. ptr += r->length;
  1777. }
  1778. else
  1779. {
  1780. // from/to combos always seem to be 0x44 in length in all cases...
  1781. // fix this to be smarter if it turns out not to be the case
  1782. ASSERT(r->length == 0x44);
  1783. r->fromvalue=get8(&data[ptr]); ptr+=8;
  1784. r->fromdate=get8(&data[ptr]); ptr+=8;
  1785. r->fromunits=get8(&data[ptr]); ptr+=8;
  1786. r->tovalue=get8(&data[ptr]); ptr+=8;
  1787. r->todate=get8(&data[ptr]); ptr+=8;
  1788. r->tounits=get8(&data[ptr]); ptr+=8;
  1789. // SPLFIELD_PLAYLIST seems to use the unks here...
  1790. r->unk1=get4(&data[ptr]); ptr+=4;
  1791. r->unk2=get4(&data[ptr]); ptr+=4;
  1792. r->unk3=get4(&data[ptr]); ptr+=4;
  1793. r->unk4=get4(&data[ptr]); ptr+=4;
  1794. r->unk5=get4(&data[ptr]); ptr+=4;
  1795. }
  1796. rule.push_back(r);
  1797. }
  1798. }
  1799. }
  1800. else if(type == MHOD_PLAYLIST)
  1801. {
  1802. position=read_uint32_t(data, ptr);
  1803. // Skip to the end
  1804. ptr+=16;
  1805. }
  1806. else
  1807. {
  1808. // non string/smart playlist types get copied in.. with the header and such being ignored
  1809. binary=new unsigned char[size_total-size_head];
  1810. memcpy(binary,&data[ptr],size_total-size_head);
  1811. // in this case, we'll use the length field to store the length of the binary stuffs,
  1812. // since it's not being used for anything else in these entries.
  1813. // this helps in the writing phase of the process.
  1814. // note that if, for some reason, you decide to create a mhod for type 50+ from scratch,
  1815. // you need to set the length = the size of your binary space
  1816. length=size_total-size_head;
  1817. }
  1818. return size_total;
  1819. }
  1820. long iPod_mhod::write(unsigned char * data, const unsigned long datasize)
  1821. {
  1822. const unsigned long headsize=0x18;
  1823. // check for header size
  1824. if (headsize>datasize) return -1;
  1825. long ptr=0;
  1826. //write mhod header
  1827. data[0]='m';data[1]='h';data[2]='o';data[3]='d';
  1828. ptr+=4;
  1829. // write sizes
  1830. rev4(headsize,&data[ptr]); // header size
  1831. ptr+=4;
  1832. rev4(0x00,&data[ptr]); // placeholder for total size (fill in later)
  1833. ptr+=4;
  1834. // write stuff out
  1835. rev4(type,&data[ptr]);
  1836. ptr+=4;
  1837. rev4(unk1,&data[ptr]);
  1838. ptr+=4;
  1839. rev4(unk2,&data[ptr]);
  1840. ptr+=4;
  1841. if (iPod_mhod::IsSimpleStringType(type))
  1842. {
  1843. // check for string size
  1844. if (16+length+headsize>datasize) return -1;
  1845. rev4(position,&data[ptr]);
  1846. ptr+=4;
  1847. rev4(length,&data[ptr]);
  1848. ptr+=4;
  1849. rev4(unk3,&data[ptr]);
  1850. ptr+=4;
  1851. rev4(unk4,&data[ptr]);
  1852. ptr+=4;
  1853. const unsigned int len = length / 2;
  1854. for (unsigned int i=0;i<len;i++)
  1855. {
  1856. data[ptr]=str[i] & 0xff;
  1857. ptr++;
  1858. data[ptr]=(str[i] >> 8) & 0xff;
  1859. ptr++;
  1860. }
  1861. }
  1862. else if (type == MHOD_ENCLOSUREURL || type == MHOD_RSSFEEDURL)
  1863. {
  1864. // Convert the UTF-16 string back to UTF-8
  1865. char *utf8Str = UTF16_to_UTF8(str);
  1866. const unsigned int len = strlen(utf8Str);
  1867. if (16+len+headsize>datasize) { free(utf8Str); return -1; }
  1868. memcpy(data + ptr, utf8Str, len);
  1869. free(utf8Str);
  1870. ptr += len;
  1871. }
  1872. else if (type==MHOD_SPLPREF)
  1873. {
  1874. if (16+74 > datasize) return -1;
  1875. // write the type 50 mhod
  1876. data[ptr]=liveupdate; ptr++;
  1877. data[ptr]=checkrules; ptr++;
  1878. data[ptr]=checklimits; ptr++;
  1879. data[ptr]=(unsigned char)(limittype); ptr++;
  1880. data[ptr]=(unsigned char)((limitsort & 0x000000ff)); ptr++;
  1881. data[ptr]=0; ptr++;
  1882. data[ptr]=0; ptr++;
  1883. data[ptr]=0; ptr++;
  1884. rev4(limitvalue,&data[ptr]); ptr+=4;
  1885. data[ptr]=matchcheckedonly; ptr++;
  1886. // set the limitsort_opposite flag by checking the high bit of limitsort
  1887. data[ptr] = limitsort & 0x80000000 ? 1 : 0; ptr++;
  1888. // insert 58 nulls
  1889. memset(data + ptr, 0, 58); ptr += 58;
  1890. }
  1891. else if (type==MHOD_SPLDATA)
  1892. {
  1893. const unsigned int ruleCount = rule.size();
  1894. if (16+136+ (ruleCount*(124+515)) > datasize) return -1;
  1895. // put "SLst" header
  1896. data[ptr]='S';data[ptr+1]='L';data[ptr+2]='s';data[ptr+3]='t';
  1897. ptr+=4;
  1898. put4(unk5,&data[ptr]); ptr+=4;
  1899. put4(ruleCount,&data[ptr]); ptr+=4;
  1900. put4(rules_operator,&data[ptr]); ptr+=4;
  1901. memset(data + ptr, 0, 120); ptr+=120;
  1902. for (unsigned int i=0;i<ruleCount;i++)
  1903. {
  1904. SPLRule *r = rule[i];
  1905. ASSERT(r);
  1906. if(r == NULL)
  1907. continue;
  1908. put4(r->field,&data[ptr]); ptr+=4;
  1909. put4(r->action,&data[ptr]); ptr+=4;
  1910. memset(data + ptr, 0, 44); ptr+=44;
  1911. put4(r->length,&data[ptr]); ptr+=4;
  1912. const bool hasString = iPod_slst::GetFieldType(r->field) == iPod_slst::ftString;
  1913. if(hasString)
  1914. {
  1915. // Byte swap the characters
  1916. unsigned char *c = (unsigned char*)r->string;
  1917. for(unsigned int i=0; i<r->length; i+=2)
  1918. {
  1919. data[ptr + i] = *(c + i + 1);
  1920. data[ptr + i + 1] = *(c + i);
  1921. }
  1922. ptr += r->length;
  1923. }
  1924. else
  1925. {
  1926. put8(r->fromvalue,&data[ptr]); ptr+=8;
  1927. put8(r->fromdate,&data[ptr]); ptr+=8;
  1928. put8(r->fromunits,&data[ptr]); ptr+=8;
  1929. put8(r->tovalue,&data[ptr]); ptr+=8;
  1930. put8(r->todate,&data[ptr]); ptr+=8;
  1931. put8(r->tounits,&data[ptr]); ptr+=8;
  1932. put4(r->unk1,&data[ptr]); ptr+=4;
  1933. put4(r->unk2,&data[ptr]); ptr+=4;
  1934. put4(r->unk3,&data[ptr]); ptr+=4;
  1935. put4(r->unk4,&data[ptr]); ptr+=4;
  1936. put4(r->unk5,&data[ptr]); ptr+=4;
  1937. }
  1938. } // end for
  1939. }
  1940. else if(type == MHOD_PLAYLIST)
  1941. {
  1942. if (16+20 > datasize) return -1;
  1943. rev4(position,&data[ptr]); // position in playlist
  1944. ptr+=4;
  1945. rev4(0,&data[ptr]); // four nulls
  1946. ptr+=4;
  1947. rev4(0,&data[ptr]);
  1948. ptr+=4;
  1949. rev4(0,&data[ptr]);
  1950. ptr+=4;
  1951. rev4(0,&data[ptr]);
  1952. ptr+=4;
  1953. }
  1954. else // not a known type, use the binary
  1955. {
  1956. // check for binary size
  1957. if (length+headsize>datasize) return -1;
  1958. for (unsigned int i=0;i<length;i++)
  1959. {
  1960. data[ptr]=binary[i];
  1961. ptr++;
  1962. }
  1963. }
  1964. // fix the total size
  1965. rev4(ptr,&data[8]);
  1966. return ptr;
  1967. }
  1968. void iPod_mhod::SetString(const wchar_t *string)
  1969. {
  1970. #ifdef IPODDB_PROFILER
  1971. profiler(iPodDB__iPod_mhod_SetString);
  1972. #endif
  1973. if(!string)
  1974. return;
  1975. delete [] str;
  1976. length = 0;
  1977. unsigned int stringLen = min(wcslen(string), 512);
  1978. str = new wchar_t[stringLen + 1];
  1979. memset(str, 0, sizeof(wchar_t) * (stringLen + 1));
  1980. if(str)
  1981. {
  1982. wcsncpy(str, string, stringLen);
  1983. length = stringLen * 2;
  1984. }
  1985. }
  1986. bool iPod_mhod::IsSimpleStringType(const unsigned int type)
  1987. {
  1988. switch(type)
  1989. {
  1990. case MHOD_TITLE:
  1991. case MHOD_LOCATION:
  1992. case MHOD_ALBUM:
  1993. case MHOD_ARTIST:
  1994. case MHOD_GENRE:
  1995. case MHOD_FILETYPE:
  1996. case MHOD_EQSETTING:
  1997. case MHOD_COMMENT:
  1998. case MHOD_CATEGORY:
  1999. case MHOD_COMPOSER:
  2000. case MHOD_GROUPING:
  2001. case MHOD_DESCRIPTION:
  2002. case MHOD_SUBTITLE:
  2003. case MHOD_ALBUMARTIST:
  2004. case MHOD_ARTIST_SORT:
  2005. case MHOD_TITLE_SORT:
  2006. case MHOD_ALBUM_SORT:
  2007. case MHOD_ALBUMARTIST_SORT:
  2008. case MHOD_COMPOSER_SORT:
  2009. case MHOD_SHOW_SORT:
  2010. case MHOD_ALBUMLIST_ALBUM:
  2011. case MHOD_ALBUMLIST_ARTIST:
  2012. return(true);
  2013. }
  2014. return(false);
  2015. }
  2016. void iPod_mhod::Duplicate(iPod_mhod *src, iPod_mhod *dst)
  2017. {
  2018. #ifdef IPODDB_PROFILER
  2019. profiler(iPodDB__iPod_mhod_Duplicate);
  2020. #endif
  2021. if(src == NULL || dst == NULL)
  2022. return;
  2023. dst->type = src->type;
  2024. dst->unk1 = src->unk1;
  2025. dst->unk2 = src->unk2;
  2026. dst->position = src->position;
  2027. dst->length = src->length;
  2028. dst->unk3 = src->unk3;
  2029. dst->unk4 = src->unk4;
  2030. dst->liveupdate = src->liveupdate;
  2031. dst->checkrules = src->checkrules;
  2032. dst->checklimits = src->checklimits;
  2033. dst->limittype = src->limittype;
  2034. dst->limitsort = src->limitsort;
  2035. dst->limitvalue = src->limitvalue;
  2036. dst->matchcheckedonly = src->matchcheckedonly;
  2037. dst->limitsort_opposite = src->limitsort_opposite;
  2038. dst->unk5 = src->unk5;
  2039. dst->rules_operator = src->rules_operator;
  2040. if(src->str)
  2041. {
  2042. dst->SetString(src->str);
  2043. }
  2044. else if(src->binary)
  2045. {
  2046. dst->binary = new unsigned char[src->length];
  2047. if(dst->binary)
  2048. memcpy(dst->binary, src->binary, src->length);
  2049. }
  2050. const unsigned int ruleLen = src->rule.size();
  2051. for(unsigned int i=0; i<ruleLen; i++)
  2052. {
  2053. SPLRule *srcRule = src->rule[i];
  2054. if(srcRule)
  2055. {
  2056. SPLRule *dstRule = new SPLRule;
  2057. if(dstRule)
  2058. memcpy(dstRule, srcRule, sizeof(SPLRule));
  2059. dst->rule.push_back(dstRule);
  2060. }
  2061. }
  2062. }
  2063. //////////////////////////////////////////////////////////////////////
  2064. // iPod_mhlp - Holds playlists
  2065. //////////////////////////////////////////////////////////////////////
  2066. iPod_mhlp::iPod_mhlp() :
  2067. mhyp(),
  2068. beingDeleted(false)
  2069. {
  2070. // Always start off with an empty, hidden, default playlist
  2071. ASSERT(GetChildrenCount() == 0);
  2072. GetDefaultPlaylist();
  2073. }
  2074. iPod_mhlp::~iPod_mhlp()
  2075. {
  2076. // This is unnecessary (and slow) to clear the vector list,
  2077. // since the object is being destroyed anyway...
  2078. beingDeleted = true;
  2079. ClearPlaylists();
  2080. }
  2081. long iPod_mhlp::parse(const uint8_t *data)
  2082. {
  2083. long ptr=0;
  2084. //check mhlp header
  2085. if (_strnicmp((char *)&data[ptr],"mhlp",4)) return -1;
  2086. ptr+=4;
  2087. // get sizes
  2088. size_head=rev4(&data[ptr]);
  2089. ptr+=4;
  2090. const unsigned long children=rev4(&data[ptr]); // Only used locally - child count is obtained from the mhyp vector list
  2091. ptr+=4;
  2092. ASSERT(size_head == 0x5c);
  2093. // skip nulls
  2094. ptr=size_head;
  2095. mhyp.reserve(children); // pre allocate the space, for speed
  2096. ClearPlaylists();
  2097. long ret;
  2098. for (unsigned long i=0;i<children; i++)
  2099. {
  2100. iPod_mhyp *m = new iPod_mhyp;
  2101. ret=m->parse(&data[ptr]);
  2102. ASSERT(ret >= 0);
  2103. if (ret<0)
  2104. {
  2105. delete m;
  2106. return ret;
  2107. }
  2108. // If this is really a smart playlist, we need to parse it again as a smart playlist
  2109. if(m->FindString(MHOD_SPLPREF) != NULL)
  2110. {
  2111. delete m;
  2112. ptr+=ret;
  2113. continue;
  2114. m = new iPod_slst;
  2115. ASSERT(m);
  2116. ret = m->parse(&data[ptr]);
  2117. ASSERT(ret >= 0);
  2118. if(ret < 0)
  2119. {
  2120. delete m;
  2121. return ret;
  2122. }
  2123. }
  2124. ptr+=ret;
  2125. mhyp.push_back(m);
  2126. }
  2127. return ptr;
  2128. }
  2129. long iPod_mhlp::write(unsigned char * data, const unsigned long datasize, int index)
  2130. {
  2131. #ifdef IPODDB_PROFILER
  2132. profiler(iPodDB__iPod_mhlp_write);
  2133. #endif
  2134. const unsigned int headsize=0x5c;
  2135. // check for header size
  2136. if (headsize>datasize) return -1;
  2137. long ptr=0;
  2138. //write mhlp header
  2139. data[0]='m';data[1]='h';data[2]='l';data[3]='p';
  2140. ptr+=4;
  2141. // write sizes
  2142. rev4(headsize,&data[ptr]); // header size
  2143. ptr+=4;
  2144. // write num of children
  2145. const unsigned long children = GetChildrenCount();
  2146. rev4(children,&data[ptr]);
  2147. ptr+=4;
  2148. // fill up the rest of the header with nulls
  2149. unsigned int i;
  2150. for (i=ptr;i<headsize;i++)
  2151. data[i]=0;
  2152. ptr=headsize;
  2153. long ret;
  2154. for (i=0;i<children; i++)
  2155. {
  2156. ret=mhyp[i]->write(&data[ptr],datasize-ptr,index);
  2157. ASSERT(ret >= 0);
  2158. if (ret<0) return ret;
  2159. ptr+=ret;
  2160. }
  2161. return ptr;
  2162. }
  2163. iPod_mhyp * iPod_mhlp::AddPlaylist()
  2164. {
  2165. #ifdef IPODDB_PROFILER
  2166. profiler(iPodDB__iPod_mhlp_AddPlaylist);
  2167. #endif
  2168. iPod_mhyp * m = new iPod_mhyp;
  2169. ASSERT(m);
  2170. if (m != NULL)
  2171. {
  2172. mhyp.push_back(m);
  2173. return m;
  2174. }
  2175. else return NULL;
  2176. }
  2177. iPod_mhyp * iPod_mhlp::FindPlaylist(const unsigned __int64 playlistID)
  2178. {
  2179. const unsigned long count = GetChildrenCount();
  2180. for (unsigned long i=0; i<count; i++)
  2181. {
  2182. iPod_mhyp * m = GetPlaylist(i);
  2183. if (m->playlistID == playlistID)
  2184. return m;
  2185. }
  2186. return NULL;
  2187. }
  2188. // deletes the playlist at a position
  2189. bool iPod_mhlp::DeletePlaylist(const unsigned long pos)
  2190. {
  2191. if (GetChildrenCount() > pos)
  2192. {
  2193. iPod_mhyp *m = GetPlaylist(pos);
  2194. mhyp.erase(mhyp.begin() + pos);
  2195. delete m;
  2196. return true;
  2197. }
  2198. else return false;
  2199. }
  2200. bool iPod_mhlp::DeletePlaylistByID(const unsigned __int64 playlistID)
  2201. {
  2202. if(playlistID == 0)
  2203. return(false);
  2204. const unsigned int count = GetChildrenCount();
  2205. for(unsigned int i=0; i<count; i++)
  2206. {
  2207. iPod_mhyp *m = GetPlaylist(i);
  2208. ASSERT(m);
  2209. if(m == NULL)
  2210. continue;
  2211. if(m->playlistID == playlistID)
  2212. return(DeletePlaylist(i));
  2213. }
  2214. return(false);
  2215. }
  2216. iPod_mhyp * iPod_mhlp::GetDefaultPlaylist()
  2217. {
  2218. #ifdef IPODDB_PROFILER
  2219. profiler(iPodDB__iPod_mhlp_GetDefaultPlaylist);
  2220. #endif
  2221. if (!mhyp.empty())
  2222. return GetPlaylist(0);
  2223. else
  2224. {
  2225. // Create a new hidden playlist, and set a default title
  2226. iPod_mhyp * playlist = AddPlaylist();
  2227. ASSERT(playlist);
  2228. if(playlist)
  2229. {
  2230. playlist->hidden = 1;
  2231. iPod_mhod *mhod = playlist->AddString(MHOD_TITLE);
  2232. if(mhod)
  2233. mhod->SetString(L"iPod");
  2234. }
  2235. return playlist;
  2236. }
  2237. }
  2238. bool iPod_mhlp::ClearPlaylists(const bool createDefaultPlaylist)
  2239. {
  2240. #ifdef IPODDB_PROFILER
  2241. profiler(iPodDB__iPod_mhlp_ClearPlaylists);
  2242. #endif
  2243. const unsigned long count = GetChildrenCount();
  2244. for (unsigned long i=0;i<count;i++)
  2245. {
  2246. iPod_mhyp *m=GetPlaylist(i);
  2247. delete m;
  2248. }
  2249. if(!beingDeleted)
  2250. mhyp.clear();
  2251. // create the default playlist again, if it's gone
  2252. // XXX - Normally this is the right thing to do, but if we
  2253. // are about to parse the playlists from the iPod, we can't create
  2254. // the default playlist. Doing so will create two default/hidden
  2255. // playlists - this one and the one that will be created when
  2256. // the playlists are parsed!
  2257. if(createDefaultPlaylist)
  2258. GetDefaultPlaylist();
  2259. return true;
  2260. }
  2261. void iPod_mhlp::RemoveDeadPlaylistEntries(iPod_mhlt *mhlt)
  2262. {
  2263. #ifdef IPODDB_PROFILER
  2264. profiler(iPodDB__iPod_mhlp_RemoveDeadPlaylistEntries);
  2265. #endif
  2266. if(mhlt == NULL)
  2267. return;
  2268. const unsigned int playlistCount = GetChildrenCount();
  2269. for(unsigned int i=0; i<playlistCount; i++)
  2270. {
  2271. iPod_mhyp *m = mhyp[i];
  2272. ASSERT(m);
  2273. if(m == NULL)
  2274. continue;
  2275. std::vector<unsigned int> deleteList;
  2276. const unsigned int songCount = m->GetMhipChildrenCount();
  2277. for(unsigned int j=0; j<songCount; j++)
  2278. {
  2279. iPod_mhip *p = m->mhip.at(j);
  2280. ASSERT(p);
  2281. if(p == NULL)
  2282. continue;
  2283. if(mhlt->GetTrackByID(p->songindex) != NULL)
  2284. continue;
  2285. // Found a dead song
  2286. deleteList.push_back(p->songindex);
  2287. }
  2288. const unsigned int deleteCount = deleteList.size();
  2289. for(unsigned int k=0; k<deleteCount; k++)
  2290. {
  2291. const bool retval = m->DeletePlaylistEntryByID(deleteList[k]);
  2292. ASSERT(retval == true);
  2293. }
  2294. }
  2295. }
  2296. void iPod_mhlp::SortPlaylists() {
  2297. std::sort(mhyp.begin(),mhyp.end(),iPod_mhyp());
  2298. }
  2299. //////////////////////////////////////////////////////////////////////
  2300. // iPod_mhyp - A Playlist
  2301. //////////////////////////////////////////////////////////////////////
  2302. iPod_mhyp::iPod_mhyp() :
  2303. hidden(0),
  2304. timestamp(0),
  2305. unk3(0),
  2306. numStringMHODs(0),
  2307. podcastflag(0),
  2308. numLibraryMHODs(0),
  2309. mhod(),
  2310. mhip(),
  2311. mhit(NULL),
  2312. isSmartPlaylist(false),
  2313. isPopulated(true), // consider normal playlists to be populated always
  2314. writeLibraryMHODs(true)
  2315. {
  2316. timestamp = wintime_to_mactime(time(NULL));
  2317. // Create a highly randomized 64 bit value for the playlistID
  2318. playlistID = Generate64BitID();
  2319. }
  2320. iPod_mhyp::~iPod_mhyp()
  2321. {
  2322. #ifdef IPODDB_PROFILER
  2323. profiler(iPodDB__iPod_mhyp_destructor);
  2324. #endif
  2325. const unsigned long mhodCount = GetMhodChildrenCount();
  2326. const unsigned long mhipCount = GetMhipChildrenCount();
  2327. unsigned long i;
  2328. for (i=0;i<mhodCount;i++)
  2329. delete mhod[i];
  2330. for (i=0;i<mhipCount;i++)
  2331. delete mhip[i];
  2332. }
  2333. long iPod_mhyp::parse(const uint8_t *data)
  2334. {
  2335. size_t ptr=0;
  2336. //check mhyp header
  2337. if (_strnicmp((char *)&data[ptr],"mhyp",4)) return -1;
  2338. ptr+=4;
  2339. // get sizes
  2340. size_head=read_uint32_t(data, ptr);
  2341. size_total=read_uint32_t(data, ptr);
  2342. ASSERT(size_head == 0x6c || size_head == 0x8c);
  2343. const unsigned long mhodnum=read_uint32_t(data, ptr); // only used locally
  2344. const unsigned long numsongs=read_uint32_t(data, ptr); // only used locally
  2345. hidden=read_uint32_t(data, ptr);
  2346. timestamp=read_uint32_t(data, ptr);
  2347. playlistID = rev8(get8(&data[ptr]));
  2348. if(playlistID == 0)
  2349. {
  2350. // Force the playlistID to be a valid value.
  2351. // This may not always be the right thing to do, but I can't think of any reason why it wouldn't be ok...
  2352. playlistID = Generate64BitID();
  2353. }
  2354. ptr+=8;
  2355. unk3=read_uint32_t(data, ptr);
  2356. unsigned long temp = rev4(&data[ptr]);
  2357. numStringMHODs = temp && 0xFFFF;
  2358. podcastflag = (uint16_t)(temp >> 16);
  2359. ptr+=4;
  2360. numLibraryMHODs=read_uint32_t(data, ptr);
  2361. ptr=size_head;
  2362. long ret;
  2363. unsigned long i;
  2364. mhod.reserve(mhodnum); // pre allocate the space, for speed
  2365. mhip.reserve(numsongs);
  2366. for (i=0;i<mhodnum;i++)
  2367. {
  2368. iPod_mhod *m = new iPod_mhod;
  2369. // parseSmartPlaylists is an optimization for when dealing with smart playlists.
  2370. // Since the playlist has to be parsed in order to determine if it is a smart playlist,
  2371. // and if it is, parsed again as a smart playlist, this optimization prevents some duplicate parsing.
  2372. m->parseSmartPlaylists = isSmartPlaylist;
  2373. ret=m->parse(&data[ptr]);
  2374. ASSERT(ret >= 0);
  2375. if (ret<0)
  2376. {
  2377. delete m;
  2378. continue;
  2379. return ret;
  2380. }
  2381. ptr+=ret;
  2382. // Don't add Type 52 MHODs - if the file changes, the indexes are no longer valid
  2383. if(m->type == MHOD_LIBRARY || m->type == MHOD_LIBRARY_LETTER)
  2384. {
  2385. delete m;
  2386. continue;
  2387. }
  2388. // Reset the Type 52 MHOD count to zero
  2389. numLibraryMHODs = 0;
  2390. if(m->type == MHOD_PLAYLIST)
  2391. delete m; // fuck 'em!
  2392. else
  2393. mhod.push_back(m);
  2394. }
  2395. for (i=0;i<numsongs;i++)
  2396. {
  2397. iPod_mhip *m = new iPod_mhip;
  2398. ret=m->parse(&data[ptr]);
  2399. ASSERT(ret >= 0);
  2400. if (ret<0)
  2401. {
  2402. delete m;
  2403. return ret;
  2404. }
  2405. else
  2406. {
  2407. ptr+=ret;
  2408. }
  2409. mhip.push_back(m);
  2410. }
  2411. return ptr;
  2412. }
  2413. long iPod_mhyp::write(unsigned char * data, const unsigned long datasize, int index)
  2414. {
  2415. const unsigned int headsize=0x6c;
  2416. // check for header size
  2417. ASSERT(headsize <= datasize);
  2418. if (headsize>datasize) return -1;
  2419. size_t ptr=0;
  2420. // List of Type 52 MHODs to write
  2421. unsigned int indexType[] = { TYPE52_SONG_NAME, TYPE52_ARTIST, TYPE52_ALBUM, TYPE52_GENRE, TYPE52_COMPOSER };
  2422. const unsigned int indexTypeCount = sizeof(indexType) / sizeof(unsigned int);
  2423. //write mhyp header
  2424. data[0]='m';data[1]='h';data[2]='y';data[3]='p';
  2425. ptr+=4;
  2426. // write sizes
  2427. write_uint32_t(data, ptr, headsize);// header size
  2428. write_uint32_t(data, ptr, 0); // placeholder for total size (fill in later)
  2429. writeLibraryMHODs = true;
  2430. bool writeType52MHOD = writeLibraryMHODs && (hidden > 0 && mhit != NULL);
  2431. // fill in stuff
  2432. const unsigned long mhodnum = GetMhodChildrenCount();
  2433. numStringMHODs = (uint16_t)mhodnum;
  2434. if(writeType52MHOD)
  2435. {
  2436. write_uint32_t(data, ptr, mhodnum + indexTypeCount); // Include the extra MHOD Type 52s that aren't in the MHOD list
  2437. numLibraryMHODs = indexTypeCount;
  2438. }
  2439. else
  2440. {
  2441. write_uint32_t(data, ptr, mhodnum);
  2442. }
  2443. const unsigned long numsongs = GetMhipChildrenCount();
  2444. write_uint32_t(data, ptr, numsongs);
  2445. write_uint32_t(data, ptr, hidden);
  2446. write_uint32_t(data, ptr, timestamp);
  2447. put8(rev8(playlistID),&data[ptr]);
  2448. ptr+=8;
  2449. write_uint32_t(data, ptr, unk3);
  2450. unsigned long temp = numStringMHODs | podcastflag << 16;
  2451. rev4(temp,&data[ptr]);
  2452. ptr+=4;
  2453. write_uint32_t(data, ptr, numLibraryMHODs);
  2454. unsigned long i;
  2455. // fill up the rest of the header with nulls
  2456. for (i=ptr;i<headsize;i++)
  2457. data[i]=0;
  2458. ptr=headsize;
  2459. long ret;
  2460. for (i=0;i<mhodnum; i++)
  2461. {
  2462. ret=mhod[i]->write(&data[ptr],datasize-ptr);
  2463. ASSERT(ret >= 0);
  2464. if (ret<0) return ret;
  2465. else ptr+=ret;
  2466. }
  2467. // If this is the default hidden playlist, create the type 52 MHODs that are used to accelerate the browse menus
  2468. if(writeType52MHOD)
  2469. {
  2470. /*
  2471. header identifier | 4 | mhod
  2472. header length | 4 | size of the mhod header
  2473. total length | 4 | size of the header and all the index entries
  2474. type | 4 | the type indicator ( 52 )
  2475. unk1 | 4 | unknown (always zero)
  2476. unk2 | 4 | unknown (always zero)
  2477. index type | 4 | what this index is sorted on (see list above)
  2478. count | 4 | number of entries. Always the same as the number of entries in the playlist, which is the same as the number of songs on the iPod.
  2479. null padding | 40| lots of padding
  2480. -----
  2481. 72 bytes (0x48)
  2482. index entries | 4 * count | The index entries themselves. This is an index into the mhit list, in order, starting from 0 for the first mhit.
  2483. */
  2484. for(unsigned int i=0; i<indexTypeCount; i++)
  2485. {
  2486. unsigned int mhodType = 0;
  2487. const unsigned int mhod52Type = indexType[i];
  2488. // Map the index type to the MHOD type
  2489. switch(mhod52Type)
  2490. {
  2491. case TYPE52_SONG_NAME:
  2492. mhodType = MHOD_TITLE;
  2493. break;
  2494. case TYPE52_ALBUM:
  2495. mhodType = MHOD_ALBUM;
  2496. break;
  2497. case TYPE52_ARTIST:
  2498. mhodType = MHOD_ARTIST;
  2499. break;
  2500. case TYPE52_GENRE:
  2501. mhodType = MHOD_GENRE;
  2502. break;
  2503. case TYPE52_COMPOSER:
  2504. mhodType = MHOD_COMPOSER;
  2505. break;
  2506. default:
  2507. ASSERT(0); // unknown type
  2508. mhodType = 0;
  2509. }
  2510. if(mhodType == 0)
  2511. continue;
  2512. ASSERT(mhit->size() == numsongs);
  2513. if(mhit->size() != numsongs)
  2514. continue;
  2515. // Start writing the MHOD...
  2516. const unsigned long headsize = 0x18;
  2517. const unsigned long totalsize = 0x48 + (4 * numsongs);
  2518. //write mhod header
  2519. data[ptr++]='m';data[ptr++]='h';data[ptr++]='o';data[ptr++]='d';
  2520. // write sizes
  2521. write_uint32_t(data, ptr, headsize); // header size
  2522. write_uint32_t(data, ptr, totalsize); // total size = 72 * (4 * number of songs)
  2523. // This is type 52 MHOD
  2524. write_uint32_t(data, ptr, MHOD_LIBRARY);
  2525. // Unknowns (always zero)
  2526. unsigned long unk1 = 0, unk2 = 0;
  2527. write_uint32_t(data, ptr, unk1);
  2528. write_uint32_t(data, ptr, unk2);
  2529. // What kind of index is this?
  2530. write_uint32_t(data, ptr, mhod52Type);
  2531. // Song Count
  2532. write_uint32_t(data, ptr, numsongs);
  2533. // 40 NULLs
  2534. for(unsigned int j=0;j<40;j++)
  2535. data[ptr++]=0;
  2536. // Build the sort by string vector list
  2537. std::vector<indexMhit*> strList;
  2538. strList.reserve(numsongs);
  2539. unsigned int ki = 0;
  2540. /*
  2541. iPod_mhlt::mhit_map_t::const_iterator begin = mhit->begin();
  2542. iPod_mhlt::mhit_map_t::const_iterator end = mhit->end();
  2543. for(iPod_mhlt::mhit_map_t::const_iterator it = begin; it != end; it++)
  2544. {
  2545. iPod_mhit *m = static_cast<iPod_mhit*>((*it).second);
  2546. */
  2547. int kl = mhip.size();
  2548. for(int k=0; k < kl; k++) {
  2549. iPod_mhit *m = mhit->find(mhip.at(k)->songindex)->second;
  2550. ASSERT(m != NULL);
  2551. if(m == NULL)
  2552. continue;
  2553. indexMhit *foo = new indexMhit;
  2554. foo->index = ki++;
  2555. iPod_mhod *d;
  2556. if(mhod52Type == TYPE52_COMPOSER) {
  2557. foo->track = 0;
  2558. foo->str[0] = L"";
  2559. foo->str[1] = L"";
  2560. d = m->FindString(MHOD_COMPOSER);
  2561. foo->str[2] = d?d->str:L"";
  2562. } else {
  2563. foo->track = (int)m->tracknum;
  2564. d = (mhod52Type >= TYPE52_GENRE)?m->FindString(MHOD_GENRE):NULL;
  2565. foo->str[0] = d?d->str:L"";
  2566. d = (mhod52Type >= TYPE52_ARTIST)?m->FindString(MHOD_ARTIST):NULL;
  2567. foo->str[1] = d?d->str:L"";
  2568. d = (mhod52Type >= TYPE52_ALBUM)?m->FindString(MHOD_ALBUM):NULL;
  2569. foo->str[2] = d?d->str:L"";
  2570. }
  2571. d = m->FindString(MHOD_TITLE);
  2572. foo->str[3] = d?d->str:L"";
  2573. strList.push_back(foo);
  2574. }
  2575. // Sort the list alphabetically
  2576. std::sort(strList.begin(), strList.end(), indexMhit());
  2577. // Write out the index entries
  2578. const unsigned indexCount = strList.size();
  2579. ASSERT(indexCount == numsongs);
  2580. for(unsigned int mi =0; mi<indexCount; mi++)
  2581. {
  2582. const unsigned int index = strList[mi]->index;
  2583. write_uint32_t(data, ptr, index);
  2584. }
  2585. // Free the list of indexMhits
  2586. for(unsigned int li=0;li<indexCount;li++)
  2587. {
  2588. delete strList[li];
  2589. }
  2590. }
  2591. }
  2592. int SongNum = 0;
  2593. for (i=0;i<numsongs;i++)
  2594. {
  2595. //FUCKO: use index here to write out podcast list differently
  2596. if(index == 3 || mhip[i]->podcastgroupflag == 0)
  2597. {
  2598. if(mhip[i]->podcastgroupflag == 0)
  2599. SongNum++;
  2600. unsigned long temp=0;
  2601. if(index == 2)
  2602. {
  2603. temp = mhip[i]->podcastgroupref;
  2604. mhip[i]->podcastgroupref = 0;
  2605. }
  2606. ret=mhip[i]->write(&data[ptr],datasize-ptr, SongNum);
  2607. if(index == 2)
  2608. mhip[i]->podcastgroupref=temp;
  2609. ASSERT(ret >= 0);
  2610. if (ret<0)
  2611. return ret;
  2612. else
  2613. ptr+=ret;
  2614. }
  2615. }
  2616. // fix the total size
  2617. rev4(ptr,&data[8]);
  2618. // fix number of songs written
  2619. if(index == 2) rev4(SongNum,&data[16]);
  2620. return ptr;
  2621. }
  2622. long iPod_mhyp::AddPlaylistEntry(iPod_mhip * entry, const unsigned long id)
  2623. {
  2624. entry = new iPod_mhip;
  2625. ASSERT(entry != NULL);
  2626. if (entry !=NULL)
  2627. {
  2628. entry->songindex=id;
  2629. entry->timestamp = wintime_to_mactime(time(NULL));
  2630. mhip.push_back(entry);
  2631. return GetMhipChildrenCount()-1;
  2632. }
  2633. else return -1;
  2634. }
  2635. long iPod_mhyp::FindPlaylistEntry(const unsigned long id) const
  2636. {
  2637. const unsigned long children = GetMhipChildrenCount();
  2638. for (unsigned long i=0;i<children;i++)
  2639. {
  2640. if (mhip.at(i)->songindex==id)
  2641. return i;
  2642. }
  2643. return -1;
  2644. }
  2645. bool iPod_mhyp::DeletePlaylistEntry(unsigned long pos)
  2646. {
  2647. if (GetMhipChildrenCount() >= pos)
  2648. {
  2649. iPod_mhip * m = GetPlaylistEntry(pos);
  2650. if (pos < mhip.size())
  2651. {
  2652. mhip.erase(mhip.begin() + pos);
  2653. }
  2654. delete m;
  2655. return true;
  2656. }
  2657. return false;
  2658. }
  2659. bool iPod_mhyp::DeletePlaylistEntryByID(unsigned long songindex)
  2660. {
  2661. // Search the list of mhips until the matching mhip(s) are found
  2662. bool retval = false;
  2663. unsigned int count = GetMhipChildrenCount();
  2664. for(unsigned int i=0; i<count; i++)
  2665. {
  2666. iPod_mhip *m = GetPlaylistEntry(i);
  2667. if(m->songindex == songindex)
  2668. {
  2669. DeletePlaylistEntry(i);
  2670. count = GetMhipChildrenCount();
  2671. i=0;
  2672. retval = true;
  2673. continue;
  2674. }
  2675. }
  2676. return(retval);
  2677. }
  2678. bool iPod_mhyp::ClearPlaylist()
  2679. {
  2680. const unsigned long count = GetMhipChildrenCount();
  2681. for (unsigned long i=0;i<count;i++)
  2682. {
  2683. iPod_mhip * m = GetPlaylistEntry(i);
  2684. delete m;
  2685. }
  2686. mhip.clear();
  2687. return true;
  2688. }
  2689. long iPod_mhyp::PopulatePlaylist(iPod_mhlt * tracks, int hidden_field)
  2690. {
  2691. ASSERT(tracks != NULL);
  2692. if(tracks == NULL)
  2693. return(-1);
  2694. const unsigned long trackCount = tracks->GetChildrenCount();
  2695. if(trackCount == 0)
  2696. return(0);
  2697. ClearPlaylist();
  2698. // Speed up getting the id as follows:
  2699. // Iterate the whole tracks->mhit map, storing the ids in a local vector
  2700. std::vector<unsigned long> ids;
  2701. ids.reserve(trackCount);
  2702. iPod_mhlt::mhit_map_t::const_iterator begin = tracks->mhit.begin();
  2703. iPod_mhlt::mhit_map_t::const_iterator end = tracks->mhit.end();
  2704. for(iPod_mhlt::mhit_map_t::const_iterator it = begin; it != end; it++)
  2705. ids.push_back(static_cast<unsigned long>((*it).first));
  2706. for (unsigned long i=0;i<trackCount;i++)
  2707. {
  2708. // Add the playlist entry locally rather than using
  2709. // AddPlaylistEntry() for speed optimization reasons
  2710. iPod_mhip *entry = new iPod_mhip;
  2711. ASSERT(entry != NULL);
  2712. if(entry)
  2713. {
  2714. entry->songindex = ids[i];
  2715. mhip.push_back(entry);
  2716. }
  2717. }
  2718. hidden=hidden_field;
  2719. return GetMhipChildrenCount();
  2720. }
  2721. iPod_mhod * iPod_mhyp::AddString(const int type)
  2722. {
  2723. #ifdef IPODDB_PROFILER
  2724. profiler(iPodDB__iPod_mhyp_AddString);
  2725. #endif
  2726. iPod_mhod * m;
  2727. if (type)
  2728. {
  2729. m = FindString(type);
  2730. if (m!=NULL) return m;
  2731. }
  2732. m=new iPod_mhod;
  2733. if (m!=NULL && type) m->type=type;
  2734. mhod.push_back(m);
  2735. return m;
  2736. }
  2737. iPod_mhod * iPod_mhyp::FindString(const unsigned long type)
  2738. {
  2739. #ifdef IPODDB_PROFILER
  2740. profiler(iPodDB__iPod_mhyp_FindString);
  2741. #endif
  2742. const unsigned long children = GetMhodChildrenCount();
  2743. for (unsigned long i=0;i<children;i++)
  2744. {
  2745. if (mhod[i]->type == type) return mhod[i];
  2746. }
  2747. return NULL;
  2748. }
  2749. unsigned long iPod_mhyp::DeleteString(const unsigned long type)
  2750. {
  2751. #ifdef IPODDB_PROFILER
  2752. profiler(iPodDB__iPod_mhyp_DeleteString);
  2753. #endif
  2754. unsigned long count=0;
  2755. for (unsigned long i=0; i != GetMhodChildrenCount(); i++)
  2756. {
  2757. if (mhod[i]->type == type)
  2758. {
  2759. iPod_mhod * m = mhod.at(i);
  2760. mhod.erase(mhod.begin() + i);
  2761. delete m;
  2762. i = i > 0 ? i - 1 : 0; // do this to ensure that it checks the new entry in position i next
  2763. count++;
  2764. }
  2765. }
  2766. return count;
  2767. }
  2768. void iPod_mhyp::SetPlaylistTitle(const wchar_t *string)
  2769. {
  2770. #ifdef IPODDB_PROFILER
  2771. profiler(iPodDB__iPod_mhyp_SetPlaylistTitle);
  2772. #endif
  2773. if(string == NULL)
  2774. return;
  2775. iPod_mhod *mhod = AddString(MHOD_TITLE);
  2776. ASSERT(mhod);
  2777. if(mhod)
  2778. mhod->SetString(string);
  2779. }
  2780. void iPod_mhyp::Duplicate(iPod_mhyp *src, iPod_mhyp *dst)
  2781. {
  2782. if(src == NULL || dst == NULL)
  2783. return;
  2784. dst->hidden = src->hidden;
  2785. dst->timestamp = src->timestamp;
  2786. dst->playlistID = src->playlistID;
  2787. dst->unk3 = src->unk3;
  2788. dst->numStringMHODs = src->numStringMHODs;
  2789. dst->podcastflag = src->podcastflag;
  2790. dst->numLibraryMHODs = src->numLibraryMHODs;
  2791. dst->isSmartPlaylist = src->isSmartPlaylist;
  2792. dst->isPopulated = src->isPopulated;
  2793. const unsigned int mhodCount = src->mhod.size();
  2794. const unsigned int mhipCount = src->mhip.size();
  2795. unsigned int i;
  2796. for(i=0; i<mhodCount; i++)
  2797. {
  2798. iPod_mhod *mhod = dst->AddString();
  2799. ASSERT(mhod);
  2800. if(mhod)
  2801. {
  2802. iPod_mhod *srcMHOD = src->mhod[i];
  2803. ASSERT(srcMHOD);
  2804. if(srcMHOD)
  2805. mhod->Duplicate(srcMHOD, mhod);
  2806. }
  2807. }
  2808. for(i=0; i<mhipCount; i++)
  2809. {
  2810. iPod_mhip *mhip = NULL;
  2811. if(dst->AddPlaylistEntry(mhip) >= 0 && mhip != NULL)
  2812. {
  2813. iPod_mhip *srcMHIP = src->mhip[i];
  2814. ASSERT(srcMHIP);
  2815. if(srcMHIP)
  2816. mhip->Duplicate(srcMHIP, mhip);
  2817. }
  2818. }
  2819. }
  2820. bool iPod_mhyp::operator()(iPod_mhyp*& one, iPod_mhyp*& two) {
  2821. if(one->hidden & 0xff) return true;
  2822. if(two->hidden & 0xff) return false;
  2823. wchar_t * a = one->FindString(MHOD_TITLE)->str;
  2824. wchar_t * b = two->FindString(MHOD_TITLE)->str;
  2825. return _wcsicmp(a?a:L"",b?b:L"") < 0;
  2826. }
  2827. //////////////////////////////////////////////////////////////////////
  2828. // iPod_mhip - Playlist Entry
  2829. //////////////////////////////////////////////////////////////////////
  2830. iPod_mhip::iPod_mhip() :
  2831. dataobjectcount(1),
  2832. podcastgroupflag(0),
  2833. groupid(0),
  2834. songindex(0),
  2835. timestamp(0),
  2836. podcastgroupref(0)
  2837. {
  2838. }
  2839. iPod_mhip::~iPod_mhip()
  2840. {
  2841. #ifdef IPODDB_PROFILER
  2842. profiler(iPodDB__iPod_mhip_destructor);
  2843. #endif
  2844. }
  2845. long iPod_mhip::parse(const uint8_t *data)
  2846. {
  2847. long ptr=0;
  2848. //check mhyp header
  2849. if (_strnicmp((char *)&data[ptr],"mhip",4)) return -1;
  2850. ptr+=4;
  2851. // get sizes
  2852. size_head=rev4(&data[ptr]);
  2853. ptr+=4;
  2854. size_total=rev4(&data[ptr]);
  2855. ptr+=4;
  2856. ASSERT(size_head == 0x4c);
  2857. // read in the useful info
  2858. dataobjectcount=rev4(&data[ptr]); //data object count
  2859. ptr+=4;
  2860. podcastgroupflag=rev4(&data[ptr]); //podcast group flag
  2861. ptr+=4;
  2862. groupid=rev4(&data[ptr]); // group id
  2863. ptr+=4;
  2864. songindex=rev4(&data[ptr]); //trackid
  2865. ptr+=4;
  2866. timestamp=rev4(&data[ptr]); // timestamp
  2867. ptr+=4;
  2868. podcastgroupref=rev4(&data[ptr]); // group ref
  2869. ptr+=4;
  2870. ptr=size_head;
  2871. // dump the mhod after the mhip, as it's just a position number in the playlist
  2872. // and useless to read in since we get them in order anyway
  2873. for(uint32_t i=0; i!=dataobjectcount; i++) {
  2874. iPod_mhod *m = new iPod_mhod;
  2875. long ret = m->parse(&data[ptr]);
  2876. ASSERT(ret >= 0);
  2877. if(ret<0) return ret;
  2878. ptr+=ret;
  2879. if(m->type == 100) delete m; //fuck 'em
  2880. else mhod.push_back(m);
  2881. }
  2882. return ptr;
  2883. }
  2884. long iPod_mhip::write(unsigned char * data, const unsigned long datasize, int entrynum)
  2885. {
  2886. #ifdef IPODDB_PROFILER
  2887. profiler(iPodDB__iPod_mhip_write);
  2888. #endif
  2889. long ptr=0;
  2890. const unsigned int headsize=0x4c;
  2891. // check for header size and mhod size
  2892. if (headsize+0x2c>datasize)
  2893. {
  2894. ASSERT(0);
  2895. return -1;
  2896. }
  2897. //write mhip header
  2898. data[0]='m';data[1]='h';data[2]='i';data[3]='p';
  2899. ptr+=4;
  2900. // write sizes
  2901. rev4(headsize,&data[ptr]); // header size
  2902. ptr+=4;
  2903. //rev4(headsize,&data[ptr]); // mhips have no children or subdata
  2904. ptr+=4;
  2905. // fill in stuff
  2906. rev4(mhod.size() + ((podcastgroupflag!=0)?0:1),&data[ptr]);
  2907. ptr+=4;
  2908. rev4(podcastgroupflag,&data[ptr]);
  2909. ptr+=4;
  2910. rev4(groupid,&data[ptr]);
  2911. ptr+=4;
  2912. rev4(songindex,&data[ptr]);
  2913. ptr+=4;
  2914. rev4(timestamp,&data[ptr]);
  2915. ptr+=4;
  2916. rev4(podcastgroupref,&data[ptr]);
  2917. ptr+=4;
  2918. // fill up the rest of the header with nulls
  2919. for (unsigned int i=ptr;i<headsize;i++)
  2920. data[i]=0;
  2921. ptr=headsize;
  2922. if(!podcastgroupflag) {
  2923. // create an faked up mhod type 100 for position info
  2924. // (required at this point, albeit seemingly useless.. type 100 mhods are weird)
  2925. data[ptr]='m';data[ptr+1]='h';data[ptr+2]='o';data[ptr+3]='d';
  2926. ptr+=4;
  2927. rev4(0x18,&data[ptr]); // header size
  2928. ptr+=4;
  2929. rev4(0x2c,&data[ptr]); // total size
  2930. ptr+=4;
  2931. rev4(100,&data[ptr]); // type
  2932. ptr+=4;
  2933. rev4(0,&data[ptr]); // two nulls
  2934. ptr+=4;
  2935. rev4(0,&data[ptr]);
  2936. ptr+=4;
  2937. rev4(entrynum,&data[ptr]); // position in playlist
  2938. ptr+=4;
  2939. rev4(0,&data[ptr]); // four nulls
  2940. ptr+=4;
  2941. rev4(0,&data[ptr]);
  2942. ptr+=4;
  2943. rev4(0,&data[ptr]);
  2944. ptr+=4;
  2945. rev4(0,&data[ptr]);
  2946. ptr+=4;
  2947. // the above code could be more optimized, but this is simpler to read, methinks
  2948. }
  2949. for(unsigned long i = 0; i < mhod.size(); i++) {
  2950. long ret = mhod[i]->write(&data[ptr],datasize-ptr);
  2951. ASSERT(ret >= 0);
  2952. if(ret<0) return ret;
  2953. else ptr+=ret;
  2954. }
  2955. rev4(ptr,&data[8]);
  2956. return ptr;
  2957. }
  2958. void iPod_mhip::Duplicate(iPod_mhip *src, iPod_mhip *dst)
  2959. {
  2960. if(src == NULL || dst == NULL)
  2961. return;
  2962. dst->dataobjectcount = src->dataobjectcount;
  2963. dst->podcastgroupflag = src->podcastgroupflag;
  2964. dst->groupid = src->groupid;
  2965. dst->songindex = src->songindex;
  2966. dst->timestamp = src->timestamp;
  2967. dst->podcastgroupref = src->podcastgroupref;
  2968. }
  2969. //////////////////////////////////////////////////////////////////////
  2970. // iPod_slst - Smart Playlist
  2971. //////////////////////////////////////////////////////////////////////
  2972. iPod_slst::iPod_slst() :
  2973. splPref(NULL),
  2974. splData(NULL)
  2975. {
  2976. isSmartPlaylist = true;
  2977. isPopulated = false; // smart playlists are not considered populated by default
  2978. Reset();
  2979. }
  2980. iPod_slst::~iPod_slst()
  2981. {
  2982. RemoveAllRules();
  2983. }
  2984. iPod_slst::FieldType iPod_slst::GetFieldType(const unsigned long field)
  2985. {
  2986. #ifdef IPODDB_PROFILER
  2987. profiler(iPodDB__iPod_slst_GetFieldType);
  2988. #endif
  2989. switch(field)
  2990. {
  2991. case SPLFIELD_SONG_NAME:
  2992. case SPLFIELD_ALBUM:
  2993. case SPLFIELD_ARTIST:
  2994. case SPLFIELD_GENRE:
  2995. case SPLFIELD_KIND:
  2996. case SPLFIELD_COMMENT:
  2997. case SPLFIELD_COMPOSER:
  2998. case SPLFIELD_GROUPING:
  2999. return(ftString);
  3000. case SPLFIELD_BITRATE:
  3001. case SPLFIELD_SAMPLE_RATE:
  3002. case SPLFIELD_YEAR:
  3003. case SPLFIELD_TRACKNUMBER:
  3004. case SPLFIELD_SIZE:
  3005. case SPLFIELD_PLAYCOUNT:
  3006. case SPLFIELD_DISC_NUMBER:
  3007. case SPLFIELD_BPM:
  3008. case SPLFIELD_RATING:
  3009. case SPLFIELD_TIME: // time is the length of the track in milliseconds
  3010. case SPLFIELD_VIDEO_KIND:
  3011. return(ftInt);
  3012. case SPLFIELD_COMPILATION:
  3013. return(ftBoolean);
  3014. case SPLFIELD_DATE_MODIFIED:
  3015. case SPLFIELD_DATE_ADDED:
  3016. case SPLFIELD_LAST_PLAYED:
  3017. return(ftDate);
  3018. case SPLFIELD_PLAYLIST:
  3019. return(ftPlaylist);
  3020. default:
  3021. // Unknown field type
  3022. ASSERT(0);
  3023. }
  3024. return(ftUnknown);
  3025. }
  3026. iPod_slst::ActionType iPod_slst::GetActionType(const unsigned long field, const unsigned long action)
  3027. {
  3028. #ifdef IPODDB_PROFILER
  3029. profiler(iPodDB__iPod_slst_GetActionType);
  3030. #endif
  3031. const FieldType fieldType = GetFieldType(field);
  3032. switch(fieldType)
  3033. {
  3034. case ftString:
  3035. switch(action)
  3036. {
  3037. case SPLACTION_IS_STRING:
  3038. case SPLACTION_IS_NOT:
  3039. case SPLACTION_CONTAINS:
  3040. case SPLACTION_DOES_NOT_CONTAIN:
  3041. case SPLACTION_STARTS_WITH:
  3042. case SPLACTION_DOES_NOT_START_WITH:
  3043. case SPLACTION_ENDS_WITH:
  3044. case SPLACTION_DOES_NOT_END_WITH:
  3045. return(atString);
  3046. case SPLACTION_IS_NOT_IN_THE_RANGE:
  3047. case SPLACTION_IS_INT:
  3048. case SPLACTION_IS_NOT_INT:
  3049. case SPLACTION_IS_GREATER_THAN:
  3050. case SPLACTION_IS_NOT_GREATER_THAN:
  3051. case SPLACTION_IS_LESS_THAN:
  3052. case SPLACTION_IS_NOT_LESS_THAN:
  3053. case SPLACTION_IS_IN_THE_RANGE:
  3054. case SPLACTION_IS_IN_THE_LAST:
  3055. case SPLACTION_IS_NOT_IN_THE_LAST:
  3056. return(atInvalid);
  3057. default:
  3058. // Unknown action type
  3059. ASSERT(0);
  3060. return(atUnknown);
  3061. }
  3062. break;
  3063. case ftInt:
  3064. switch(action)
  3065. {
  3066. case SPLACTION_IS_INT:
  3067. case SPLACTION_IS_NOT_INT:
  3068. case SPLACTION_IS_GREATER_THAN:
  3069. case SPLACTION_IS_NOT_GREATER_THAN:
  3070. case SPLACTION_IS_LESS_THAN:
  3071. case SPLACTION_IS_NOT_LESS_THAN:
  3072. return(atInt);
  3073. case SPLACTION_IS_NOT_IN_THE_RANGE:
  3074. case SPLACTION_IS_IN_THE_RANGE:
  3075. return(atRange);
  3076. case SPLACTION_IS_STRING:
  3077. case SPLACTION_CONTAINS:
  3078. case SPLACTION_STARTS_WITH:
  3079. case SPLACTION_DOES_NOT_START_WITH:
  3080. case SPLACTION_ENDS_WITH:
  3081. case SPLACTION_DOES_NOT_END_WITH:
  3082. case SPLACTION_IS_IN_THE_LAST:
  3083. case SPLACTION_IS_NOT_IN_THE_LAST:
  3084. case SPLACTION_IS_NOT:
  3085. case SPLACTION_DOES_NOT_CONTAIN:
  3086. return(atInvalid);
  3087. default:
  3088. // Unknown action type
  3089. ASSERT(0);
  3090. return(atUnknown);
  3091. }
  3092. break;
  3093. case ftBoolean:
  3094. return(atNone);
  3095. case ftDate:
  3096. switch(action)
  3097. {
  3098. case SPLACTION_IS_INT:
  3099. case SPLACTION_IS_NOT_INT:
  3100. case SPLACTION_IS_GREATER_THAN:
  3101. case SPLACTION_IS_NOT_GREATER_THAN:
  3102. case SPLACTION_IS_LESS_THAN:
  3103. case SPLACTION_IS_NOT_LESS_THAN:
  3104. return(atDate);
  3105. case SPLACTION_IS_IN_THE_LAST:
  3106. case SPLACTION_IS_NOT_IN_THE_LAST:
  3107. return(atInTheLast);
  3108. case SPLACTION_IS_IN_THE_RANGE:
  3109. case SPLACTION_IS_NOT_IN_THE_RANGE:
  3110. return(atRange);
  3111. case SPLACTION_IS_STRING:
  3112. case SPLACTION_CONTAINS:
  3113. case SPLACTION_STARTS_WITH:
  3114. case SPLACTION_DOES_NOT_START_WITH:
  3115. case SPLACTION_ENDS_WITH:
  3116. case SPLACTION_DOES_NOT_END_WITH:
  3117. case SPLACTION_IS_NOT:
  3118. case SPLACTION_DOES_NOT_CONTAIN:
  3119. return(atInvalid);
  3120. default:
  3121. // Unknown action type
  3122. ASSERT(0);
  3123. return(atUnknown);
  3124. }
  3125. break;
  3126. case ftPlaylist:
  3127. switch(action)
  3128. {
  3129. case SPLACTION_IS_INT:
  3130. case SPLACTION_IS_NOT_INT:
  3131. return (atPlaylist);
  3132. case SPLACTION_IS_GREATER_THAN:
  3133. case SPLACTION_IS_NOT_GREATER_THAN:
  3134. case SPLACTION_IS_LESS_THAN:
  3135. case SPLACTION_IS_NOT_LESS_THAN:
  3136. case SPLACTION_IS_IN_THE_LAST:
  3137. case SPLACTION_IS_NOT_IN_THE_LAST:
  3138. case SPLACTION_IS_IN_THE_RANGE:
  3139. case SPLACTION_IS_NOT_IN_THE_RANGE:
  3140. case SPLACTION_IS_STRING:
  3141. case SPLACTION_CONTAINS:
  3142. case SPLACTION_STARTS_WITH:
  3143. case SPLACTION_DOES_NOT_START_WITH:
  3144. case SPLACTION_ENDS_WITH:
  3145. case SPLACTION_DOES_NOT_END_WITH:
  3146. case SPLACTION_IS_NOT:
  3147. case SPLACTION_DOES_NOT_CONTAIN:
  3148. return (atInvalid);
  3149. default:
  3150. ASSERT(0);
  3151. return(atUnknown);
  3152. }
  3153. case ftUnknown:
  3154. // Unknown action type
  3155. ASSERT(0);
  3156. break;
  3157. }
  3158. return(atUnknown);
  3159. }
  3160. void iPod_slst::UpdateMHODPointers()
  3161. {
  3162. if(IsSmartPlaylist() == false)
  3163. return;
  3164. splPref = AddString(MHOD_SPLPREF);
  3165. splData = AddString(MHOD_SPLDATA);
  3166. }
  3167. void iPod_slst::SetPrefs(const bool liveupdate, const bool rules_enabled, const bool limits_enabled,
  3168. const unsigned long limitvalue, const unsigned long limittype, const unsigned long limitsort)
  3169. {
  3170. UpdateMHODPointers();
  3171. ASSERT(splPref);
  3172. if(splPref)
  3173. {
  3174. splPref->liveupdate = liveupdate ? 1 : 0;
  3175. splPref->checkrules = rules_enabled ? 1 : 0;
  3176. splPref->checklimits = limits_enabled ? 1 : 0;
  3177. splPref->matchcheckedonly = 0;
  3178. splPref->limitsort_opposite = limitsort & 0x80000000 ? 1 : 0;
  3179. splPref->limittype = limittype;
  3180. splPref->limitsort = limitsort & 0x000000ff;
  3181. splPref->limitvalue = limitvalue;
  3182. }
  3183. }
  3184. unsigned long iPod_slst::GetRuleCount()
  3185. {
  3186. UpdateMHODPointers();
  3187. ASSERT(splData);
  3188. if(splData == NULL)
  3189. return(0);
  3190. return(splData->rule.size());
  3191. }
  3192. int iPod_slst::AddRule(const unsigned long field,
  3193. const unsigned long action,
  3194. const wchar_t * string, // use string for string based rules
  3195. const unsigned __int64 value, // use value for single variable rules
  3196. const unsigned __int64 from, // use from and to for range based rules
  3197. const unsigned __int64 to,
  3198. const unsigned __int64 units) // use units for "In The Last" based rules
  3199. {
  3200. #ifdef IPODDB_PROFILER
  3201. profiler(iPodDB__iPod_slst_AddRule);
  3202. #endif
  3203. UpdateMHODPointers();
  3204. ASSERT(splPref != NULL && splData != NULL);
  3205. if (splPref == NULL || splData == NULL) return -1;
  3206. // create a new rule
  3207. SPLRule *r = new SPLRule;
  3208. ASSERT(r);
  3209. if(r == NULL)
  3210. return(-1);
  3211. const FieldType ft = GetFieldType(field);
  3212. const ActionType at = GetActionType(field, action);
  3213. if(ft == ftUnknown || at == atUnknown)
  3214. {
  3215. ASSERT(0);
  3216. return(-1);
  3217. }
  3218. r->field = field;
  3219. r->action = action;
  3220. r->unk1 = 0;
  3221. r->unk2 = 0;
  3222. r->unk3 = 0;
  3223. r->unk4 = 0;
  3224. r->unk5 = 0;
  3225. if(ft == ftString)
  3226. {
  3227. // it's a string type (SetString() sets the length)
  3228. r->SetString(string);
  3229. }
  3230. else
  3231. {
  3232. // All non-string rules currently have a length of 68 bytes
  3233. r->length = 0x44;
  3234. /* Values based on ActionType:
  3235. * int: fromvalue = value, fromdate = 0, fromunits = 1, tovalue = value, todate = 0, tounits = 1
  3236. * playlist: same as int
  3237. * boolean: same as int, except fromvalue/tovalue are 1 if set, 0 if not set
  3238. * date: same as int
  3239. * range: same as int, except use from and to, instead of value
  3240. * in the last: fromvalue = 0x2dae2dae2dae2dae (SPLDATE_IDENTIFIER), fromdate = 0xffffffffffffffff - value, fromunits = seconds in period,
  3241. * tovalue = 0x2dae2dae2dae2dae (SPLDATE_IDENTIFIER), todate = 0xffffffffffffffff - value, tounits = seconds in period
  3242. */
  3243. switch(at)
  3244. {
  3245. case atInt:
  3246. case atPlaylist:
  3247. case atDate:
  3248. r->fromvalue = value;
  3249. r->fromdate = 0;
  3250. r->fromunits = 1;
  3251. r->tovalue = value;
  3252. r->todate = 0;
  3253. r->tounits = 1;
  3254. break;
  3255. case atBoolean:
  3256. r->fromvalue = value > 0 ? 1 : 0;
  3257. r->fromdate = 0;
  3258. r->fromunits = 1;
  3259. r->tovalue = r->fromvalue;
  3260. r->todate = 0;
  3261. r->tounits = 1;
  3262. break;
  3263. case atRange:
  3264. r->fromvalue = from;
  3265. r->fromdate = 0;
  3266. r->fromunits = 1;
  3267. r->tovalue = to;
  3268. r->todate = 0;
  3269. r->tounits = 1;
  3270. break;
  3271. case atInTheLast:
  3272. r->fromvalue = SPLDATE_IDENTIFIER;
  3273. r->fromdate = ConvertNumToDateValue(value);
  3274. r->fromunits = units;
  3275. r->tovalue = SPLDATE_IDENTIFIER;
  3276. r->todate = ConvertNumToDateValue(value);
  3277. r->tounits = units;
  3278. break;
  3279. case atNone:
  3280. break;
  3281. default:
  3282. ASSERT(0);
  3283. break;
  3284. }
  3285. }
  3286. // set isPopulated to false, since we're modifying the rules
  3287. isPopulated = false;
  3288. // push the rule into the mhod
  3289. splData->rule.push_back(r);
  3290. return(splData->rule.size() - 1);
  3291. }
  3292. int iPod_slst::AddRule(const SPLRule &rule)
  3293. {
  3294. UpdateMHODPointers();
  3295. ASSERT(splPref != NULL && splData != NULL);
  3296. if (splPref == NULL || splData == NULL)
  3297. return -1;
  3298. SPLRule *r = new SPLRule;
  3299. ASSERT(r);
  3300. if(r == NULL)
  3301. return(-1);
  3302. r->action = rule.action;
  3303. r->field = rule.field;
  3304. r->fromdate = rule.fromdate;
  3305. r->fromunits = rule.fromunits;
  3306. r->fromvalue = rule.fromvalue;
  3307. r->length = rule.length;
  3308. r->SetString(rule.string);
  3309. r->todate = rule.todate;
  3310. r->tounits = rule.tounits;
  3311. r->tovalue = rule.tovalue;
  3312. r->unk1 = rule.unk1;
  3313. r->unk2 = rule.unk2;
  3314. r->unk3 = rule.unk3;
  3315. r->unk4 = rule.unk4;
  3316. r->unk5 = rule.unk5;
  3317. // set isPopulated to false, since we're modifying the rules
  3318. isPopulated = false;
  3319. // push the rule into the mhod
  3320. splData->rule.push_back(r);
  3321. return(splData->rule.size() - 1);
  3322. }
  3323. void iPod_slst::RemoveAllRules()
  3324. {
  3325. #ifdef IPODDB_PROFILER
  3326. profiler(iPodDB__iPod_slst_RemoveAllRules);
  3327. #endif
  3328. // Note: Don't update MHOD pointers here...if they don't already exist, there is no point in creating them
  3329. if(splData == NULL)
  3330. return;
  3331. //while(splData->rule.size() > 0)
  3332. //{
  3333. // // set isPopulated to false, since we're modifying the rules
  3334. // isPopulated = false;
  3335. // SPLRule *r = splData->rule[0];
  3336. // splData->rule.eraseindex(0);
  3337. // delete r;
  3338. //}
  3339. auto it = splData->rule.begin();
  3340. while ( it != splData->rule.end())
  3341. {
  3342. // set isPopulated to false, since we're modifying the rules
  3343. isPopulated = false;
  3344. SPLRule* r = *it;
  3345. it = splData->rule.erase(it);
  3346. delete r;
  3347. }
  3348. splData->rule.clear();
  3349. }
  3350. void iPod_slst::Reset()
  3351. {
  3352. #ifdef IPODDB_PROFILER
  3353. profiler(iPodDB__iPod_slst_Reset);
  3354. #endif
  3355. // Note: Don't update MHOD pointers here...if they don't already exist, there is no point in creating them
  3356. RemoveAllRules();
  3357. isPopulated = false;
  3358. if(splPref)
  3359. {
  3360. splPref->liveupdate = 1;
  3361. splPref->checkrules = 1;
  3362. splPref->checklimits = 0;
  3363. splPref->matchcheckedonly = 0;
  3364. splPref->limittype = LIMITTYPE_SONGS;
  3365. splPref->limitsort = LIMITSORT_RANDOM;
  3366. splPref->limitsort_opposite = 0;
  3367. splPref->limitvalue = 25;
  3368. }
  3369. if(splData)
  3370. {
  3371. splData->rules_operator = SPLMATCH_AND;
  3372. splData->unk5 = 0;
  3373. }
  3374. }
  3375. //////////////////////////////////////////////////////////////////////
  3376. // iPod_mhdp - Class for parsing the Play Counts file
  3377. //////////////////////////////////////////////////////////////////////
  3378. iPod_mhdp::iPod_mhdp()
  3379. {
  3380. children = 0;
  3381. entry = 0;
  3382. }
  3383. iPod_mhdp::~iPod_mhdp()
  3384. {
  3385. free(entry);
  3386. }
  3387. long iPod_mhdp::parse(const uint8_t *data)
  3388. {
  3389. long ptr=0;
  3390. //check mhdp header
  3391. if (_strnicmp((char *)&data[ptr],"mhdp",4)) return -1;
  3392. ptr+=4;
  3393. // get sizes
  3394. size_head=rev4(&data[ptr]);
  3395. ptr+=4;
  3396. entrysize=rev4(&data[ptr]);
  3397. ptr+=4;
  3398. if (entrysize != 0x10 && entrysize != 0x0c && entrysize != 0x14 && entrysize != 0x1c)
  3399. {
  3400. ASSERT(0);
  3401. return -1; // can't understand new versions of this file
  3402. }
  3403. children=rev4(&data[ptr]);
  3404. ptr+=4;
  3405. // skip dummy space
  3406. ptr=size_head;
  3407. unsigned long i;
  3408. entry = (PCEntry *)malloc(children * sizeof(PCEntry));
  3409. for (i=0;i<children;i++)
  3410. {
  3411. PCEntry &e = entry[i];
  3412. e.playcount=rev4(&data[ptr]);
  3413. ptr+=4;
  3414. e.lastplayedtime=rev4(&data[ptr]);
  3415. ptr+=4;
  3416. e.bookmarktime=rev4(&data[ptr]);
  3417. ptr+=4;
  3418. if (entrysize >= 0x10)
  3419. {
  3420. e.stars=rev4(&data[ptr]);
  3421. ptr+=4;
  3422. }
  3423. else
  3424. e.stars = 0;
  3425. if (entrysize >= 0x14)
  3426. {
  3427. e.unk1 = rev4(&data[ptr]);
  3428. ptr+=4;
  3429. }
  3430. else
  3431. e.unk1 = 0;
  3432. if (entrysize >= 0x1c)
  3433. {
  3434. e.skipcount = rev4(&data[ptr]);
  3435. ptr+=4;
  3436. e.skippedtime = rev4(&data[ptr]);
  3437. ptr+=4;
  3438. }
  3439. else
  3440. {
  3441. e.skipcount = 0;
  3442. e.skippedtime = 0;
  3443. }
  3444. }
  3445. return children;
  3446. }
  3447. //////////////////////////////////////////////////////////////////////
  3448. // iPod_mhpo - Class for parsing the OTGPlaylist file
  3449. //////////////////////////////////////////////////////////////////////
  3450. iPod_mhpo::iPod_mhpo() :
  3451. size_head(0),
  3452. unk1(0),
  3453. unk2(0)
  3454. {
  3455. idList = 0;
  3456. children = 0;
  3457. }
  3458. iPod_mhpo::~iPod_mhpo()
  3459. {
  3460. #ifdef IPODDB_PROFILER
  3461. profiler(iPodDB__iPod_mhpo_destructor);
  3462. #endif
  3463. free(idList);
  3464. }
  3465. long iPod_mhpo::parse(const uint8_t *data)
  3466. {
  3467. long ptr=0;
  3468. //check mhdp header
  3469. if (_strnicmp((char *)&data[ptr],"mhpo",4)) return -1;
  3470. ptr+=4;
  3471. // get sizes
  3472. size_head=rev4(&data[ptr]);
  3473. ptr+=4;
  3474. unk1=rev4(&data[ptr]);
  3475. ptr+=4;
  3476. children=rev4(&data[ptr]); // Only used locally
  3477. ptr+=4;
  3478. unk2=rev4(&data[ptr]);
  3479. ptr+=4;
  3480. if (ptr!=size_head) return -1; // if this isn't true, I screwed up somewhere
  3481. unsigned long i;
  3482. idList = (uint32_t *)malloc(children * sizeof(uint32_t));
  3483. for (i=0;i<children;i++)
  3484. {
  3485. unsigned long temp;
  3486. temp=rev4(&data[ptr]);
  3487. ptr+=4;
  3488. idList[i]=temp;
  3489. }
  3490. return ptr;
  3491. }
  3492. long iPod_mhpo::write(unsigned char * data, const unsigned long datasize)
  3493. {
  3494. #ifdef IPODDB_PROFILER
  3495. profiler(iPodDB__iPod_mhpo_write);
  3496. #endif
  3497. long ptr=0;
  3498. const unsigned int headsize=0x14;
  3499. // check for header size + child size
  3500. if (headsize+(GetChildrenCount()*4)>datasize) return -1;
  3501. //write mhpo header
  3502. data[0]='m';data[1]='h';data[2]='p';data[3]='o';
  3503. ptr+=4;
  3504. // write size
  3505. rev4(headsize,&data[ptr]); // header size
  3506. ptr+=4;
  3507. // fill in stuff
  3508. rev4(unk1,&data[ptr]);
  3509. ptr+=4;
  3510. const unsigned long children = GetChildrenCount();
  3511. rev4(children,&data[ptr]);
  3512. ptr+=4;
  3513. rev4(unk2,&data[ptr]);
  3514. ptr+=4;
  3515. for (unsigned long i=0;i<children;i++)
  3516. {
  3517. rev4(idList[i],&data[ptr]);
  3518. ptr+=4;
  3519. }
  3520. return ptr;
  3521. }
  3522. iPod_mhyp * iPod_mhpo::CreatePlaylistFromOTG(iPod_mhbd * iPodDB, wchar_t * name)
  3523. {
  3524. // create playlist
  3525. iPod_mhyp * myplaylist = iPodDB->mhsdplaylists->mhlp->AddPlaylist();
  3526. if (myplaylist == NULL)
  3527. return NULL;
  3528. // set name
  3529. iPod_mhod * playlistName = myplaylist->AddString(MHOD_TITLE);
  3530. playlistName->SetString(name);
  3531. unsigned long count = GetChildrenCount();
  3532. // for every track
  3533. for (unsigned long i=0;i<count;i++)
  3534. {
  3535. // find the track
  3536. iPod_mhit * track = iPodDB->mhsdsongs->mhlt->GetTrack(idList[i]);
  3537. // myplaylist->AddPlaylistEntry(iPod_mhip * entry, track->id);
  3538. // Add the playlist entry locally rather than using
  3539. // AddPlaylistEntry() for speed optimization reasons
  3540. iPod_mhip *entry = new iPod_mhip;
  3541. ASSERT(entry != NULL);
  3542. if(entry && track)
  3543. {
  3544. entry->songindex = track->id;
  3545. myplaylist->mhip.push_back(entry);
  3546. }
  3547. }
  3548. return myplaylist;
  3549. }
  3550. //////////////////////////////////////////////////////////////////////
  3551. // iPod_mqed - Class for parsing the EQ Presets file
  3552. //////////////////////////////////////////////////////////////////////
  3553. iPod_mqed::iPod_mqed() :
  3554. unk1(1),
  3555. unk2(1),
  3556. eqList(),
  3557. size_head(0x68)
  3558. {
  3559. }
  3560. iPod_mqed::~iPod_mqed()
  3561. {
  3562. const unsigned long count = GetChildrenCount();
  3563. for (unsigned long i=0;i<count;i++)
  3564. {
  3565. iPod_pqed * m=eqList[i];
  3566. delete m;
  3567. }
  3568. eqList.clear();
  3569. }
  3570. long iPod_mqed::parse(const uint8_t *data)
  3571. {
  3572. unsigned long ptr=0;
  3573. uint32_t i;
  3574. //check mqed header
  3575. if (_strnicmp((char *)&data[ptr],"mqed",4)) return -1;
  3576. ptr+=4;
  3577. size_head=rev4(&data[ptr]);
  3578. ptr+=4;
  3579. ASSERT(size_head == 0x68);
  3580. unk1=rev4(&data[ptr]);
  3581. ptr+=4;
  3582. unk2=rev4(&data[ptr]);
  3583. ptr+=4;
  3584. unsigned long numchildren=rev4(&data[ptr]);
  3585. ptr+=4;
  3586. unsigned long childsize=rev4(&data[ptr]);
  3587. ptr+=4;
  3588. ASSERT(childsize == 588);
  3589. if (childsize != 588) return -1;
  3590. // skip the nulls
  3591. ptr=size_head;
  3592. for (i=0;i<numchildren;i++)
  3593. {
  3594. iPod_pqed * e = new iPod_pqed;
  3595. long ret = e->parse(&data[ptr]);
  3596. if (ret < 0)
  3597. {
  3598. delete e;
  3599. return ret;
  3600. }
  3601. eqList.push_back(e);
  3602. ptr+=ret;
  3603. }
  3604. return ptr;
  3605. }
  3606. long iPod_mqed::write(unsigned char * data, const unsigned long datasize)
  3607. {
  3608. unsigned long ptr=0;
  3609. uint32_t i;
  3610. //write mqed header
  3611. data[0]='m';data[1]='q';data[2]='e';data[3]='d';
  3612. ptr+=4;
  3613. rev4(size_head,&data[ptr]);
  3614. ptr+=4;
  3615. rev4(unk1,&data[ptr]);
  3616. ptr+=4;
  3617. rev4(unk2,&data[ptr]);
  3618. ptr+=4;
  3619. rev4(GetChildrenCount(),&data[ptr]);
  3620. ptr+=4;
  3621. rev4(588,&data[ptr]);
  3622. ptr+=4;
  3623. // fill with nulls
  3624. while (ptr<size_head)
  3625. {
  3626. data[ptr]=0; ptr++;
  3627. }
  3628. // write the eq settings
  3629. for (i=0;i<GetChildrenCount();i++)
  3630. {
  3631. long ret=eqList[i]->write(&data[ptr],datasize-ptr);
  3632. if (ret <0) return -1;
  3633. ptr+=ret;
  3634. }
  3635. return ptr;
  3636. }
  3637. //////////////////////////////////////////////////////////////////////
  3638. // iPod_pqed - Class for parsing the EQ Entries
  3639. //////////////////////////////////////////////////////////////////////
  3640. iPod_pqed::iPod_pqed() :
  3641. name(NULL),
  3642. preamp(0)
  3643. {
  3644. int i;
  3645. for (i=0;i<10;i++)
  3646. eq[i]=0;
  3647. for (i=0;i<5;i++)
  3648. short_eq[i]=0;
  3649. }
  3650. iPod_pqed::~iPod_pqed()
  3651. {
  3652. if (name) delete [] name;
  3653. }
  3654. long iPod_pqed::parse(const uint8_t *data)
  3655. {
  3656. unsigned long ptr=0;
  3657. uint32_t i;
  3658. //check pqed header
  3659. if (_strnicmp((char *)&data[ptr],"pqed",4)) return -1;
  3660. ptr+=4;
  3661. // get string length
  3662. length=data[ptr]; ptr++;
  3663. length+=data[ptr]*256; ptr++;
  3664. name=new wchar_t[length + 1];
  3665. memcpy(name,&data[ptr],length);
  3666. name[length / 2] = '\0';
  3667. // skip the nulls
  3668. ptr=516;
  3669. preamp = rev4(&data[ptr]);
  3670. ptr+=4;
  3671. unsigned long numbands;
  3672. numbands = rev4(&data[ptr]);
  3673. ptr+=4;
  3674. ASSERT (numbands == 10);
  3675. if (numbands != 10) return -1;
  3676. for (i=0;i!=numbands;i++)
  3677. {
  3678. eq[i]=rev4(&data[ptr]);
  3679. ptr+=4;
  3680. }
  3681. numbands = rev4(&data[ptr]);
  3682. ptr+=4;
  3683. ASSERT (numbands == 5);
  3684. if (numbands != 5) return -1;
  3685. for (i=0;i!=numbands;i++)
  3686. {
  3687. short_eq[i]=rev4(&data[ptr]);
  3688. ptr+=4;
  3689. }
  3690. return ptr;
  3691. }
  3692. long iPod_pqed::write(unsigned char * data, const unsigned long datasize)
  3693. {
  3694. long ptr=0;
  3695. uint32_t i;
  3696. //write pqed header
  3697. data[0]='p';data[1]='q';data[2]='e';data[3]='d';
  3698. ptr+=4;
  3699. // write 2 byte string length
  3700. data[ptr++]=(uint8_t)(length & 0xff);
  3701. data[ptr++]=(uint8_t)((length >> 8) & 0xff);
  3702. for (i=0;i!=length;i++)
  3703. {
  3704. data[ptr++]=name[i] & 0xff;
  3705. data[ptr++]=(name[i] >> 8) & 0xff;
  3706. }
  3707. // fill rest with nulls
  3708. while (ptr<516)
  3709. {
  3710. data[ptr++]=0;
  3711. }
  3712. rev4(preamp,&data[ptr]);
  3713. ptr+=4;
  3714. rev4(10,&data[ptr]);
  3715. ptr+=4;
  3716. for (i=0;i<10;i++)
  3717. {
  3718. rev4(eq[i],&data[ptr]);
  3719. ptr+=4;
  3720. }
  3721. rev4(5,&data[ptr]);
  3722. ptr+=4;
  3723. for (i=0;i<5;i++)
  3724. {
  3725. rev4(short_eq[i],&data[ptr]);
  3726. ptr+=4;
  3727. }
  3728. return ptr;
  3729. }
  3730. iTunesStats::iTunesStats() :
  3731. mhlt(NULL)
  3732. {
  3733. entry = 0;
  3734. children = 0;
  3735. }
  3736. iTunesStats::~iTunesStats()
  3737. {
  3738. free(entry);
  3739. }
  3740. long iTunesStats::parse(const uint8_t *data)
  3741. {
  3742. long ptr=0;
  3743. children = rev3(&data[ptr]);
  3744. ptr+=3;
  3745. unk1 = rev3(&data[ptr]);
  3746. ptr+=3;
  3747. unsigned long i;
  3748. entry = (iTunesStatsEntry *)malloc(children*sizeof(iTunesStatsEntry));
  3749. for (i=0;i<children;i++)
  3750. {
  3751. iTunesStatsEntry &e = entry[i];
  3752. e.entry_size = rev3(&data[ptr]);
  3753. ptr+=3;
  3754. e.bookmarktime = rev3(&data[ptr]);
  3755. ptr+=3;
  3756. e.unk1 = rev3(&data[ptr]);
  3757. ptr+=3;
  3758. e.unk2 = rev3(&data[ptr]);
  3759. ptr+=3;
  3760. e.playcount = rev3(&data[ptr]);
  3761. ptr+=3;
  3762. e.skippedcount = rev3(&data[ptr]);
  3763. ptr+=3;
  3764. #ifdef _DEBUG
  3765. // If any of these trigger an assertion, something new is in the database format
  3766. ASSERT(e.entry_size == 0x12);
  3767. //ASSERT(e.unk1 == 0);
  3768. ASSERT(e.unk2 == 0);
  3769. #endif
  3770. }
  3771. return children;
  3772. }
  3773. // Unlike Play Counts, iTunesStats needs to be created by the application - apparently only for the bookmark time
  3774. long iTunesStats::write(unsigned char * data, const unsigned long datasize)
  3775. {
  3776. ASSERT(mhlt != NULL);
  3777. if(mhlt == NULL)
  3778. return(-1);
  3779. const unsigned int numentries = mhlt->GetChildrenCount();
  3780. const unsigned int total_size = 6 + (numentries * sizeof(iTunesStatsEntry)); // 6 bytes for the header
  3781. ASSERT(datasize >= total_size);
  3782. if(datasize < total_size)
  3783. return(-1);
  3784. long ptr=0;
  3785. rev3(numentries, &data[ptr]);
  3786. ptr+=3;
  3787. put3(unk1, &data[ptr]);
  3788. ptr+=3;
  3789. // Create a new iTunesStatsEntry for each song, only preserving the bookmark time
  3790. long ret = 0;
  3791. for(unsigned int i=0; i<numentries; i++)
  3792. {
  3793. iPod_mhit *mhit = mhlt->GetTrack(i);
  3794. ASSERT(mhit);
  3795. if(mhit == NULL)
  3796. return(-1);
  3797. rev3(0x12, &data[ptr]); // Entry size
  3798. ptr+=3;
  3799. rev3(mhit->bookmarktime / 256, &data[ptr]);
  3800. ptr+=3;
  3801. rev3(0, &data[ptr]); // iTunesStatsEntry.unk1
  3802. ptr+=3;
  3803. rev3(0, &data[ptr]); // iTunesStatsEntry.unk2
  3804. ptr+=3;
  3805. rev3(0, &data[ptr]); // Don't write out the playcount
  3806. ptr+=3;
  3807. rev3(0, &data[ptr]); // or the skipped count
  3808. ptr+=3;
  3809. }
  3810. return(ptr);
  3811. }
  3812. iTunesShuffle::iTunesShuffle() :
  3813. datasize(0)
  3814. {
  3815. numentries=0;
  3816. entry = 0;
  3817. }
  3818. iTunesShuffle::~iTunesShuffle()
  3819. {
  3820. free(entry);
  3821. }
  3822. long iTunesShuffle::parse(const uint8_t *data)
  3823. {
  3824. ASSERT(datasize > 0);
  3825. // iTunesShuffle is simply a list of reversed 3 byte indexes
  3826. ASSERT(datasize % 3 == 0);
  3827. if(datasize % 3 != 0)
  3828. return(-1);
  3829. free(entry);
  3830. long ptr = 0;
  3831. numentries = datasize / 3;
  3832. entry = (uint32_t *)malloc(numentries*sizeof(uint32_t));
  3833. for(unsigned int i=0; i<numentries; i++)
  3834. {
  3835. unsigned int value = rev3(&data[ptr]);
  3836. if(value == 0xffffff) // This can happen if iTunesSD::playflags doesn't have the shuffle bit set
  3837. value = 0;
  3838. entry[i]=value;
  3839. ptr+=3;
  3840. }
  3841. return(ptr);
  3842. }
  3843. long iTunesShuffle::write(unsigned char *data, const unsigned long datasize)
  3844. {
  3845. #ifdef IPODDB_PROFILER
  3846. profiler(iPodDB__iTunesShuffle_write);
  3847. #endif
  3848. const unsigned int total_size = numentries * 3;
  3849. ASSERT(datasize >= total_size);
  3850. if(datasize < total_size)
  3851. return(-1);
  3852. long ptr = 0;
  3853. for(unsigned int i=0; i<numentries; i++)
  3854. {
  3855. rev3(entry[i], &data[ptr]);
  3856. ptr+=3;
  3857. }
  3858. return(ptr);
  3859. }
  3860. void iTunesShuffle::Randomize()
  3861. {
  3862. Randomize(numentries);
  3863. }
  3864. void iTunesShuffle::Randomize(const unsigned int numsongs)
  3865. {
  3866. #ifdef IPODDB_PROFILER
  3867. profiler(iPodDB__iTunesShuffle_randomize);
  3868. #endif
  3869. if(numsongs == 0)
  3870. return;
  3871. if (numentries < numsongs)
  3872. {
  3873. free(entry);
  3874. entry = (uint32_t *)malloc(numsongs*sizeof(uint32_t));
  3875. }
  3876. numentries=numsongs;
  3877. for (uint32_t i=0;i!=numsongs;i++)
  3878. {
  3879. entry[i] = i;
  3880. }
  3881. std::random_shuffle(entry, entry+numsongs);
  3882. }
  3883. //////////////////////////////////////////////////////////////////////
  3884. // MHIA - Album Item
  3885. //////////////////////////////////////////////////////////////////////
  3886. iPod_mhia::iPod_mhia()
  3887. : unk1(0), albumid(0), type(2)
  3888. {
  3889. dbid = Generate64BitID();
  3890. }
  3891. iPod_mhia::~iPod_mhia()
  3892. {
  3893. for (auto obj : mhod)
  3894. {
  3895. delete obj;
  3896. }
  3897. mhod.clear();
  3898. }
  3899. long iPod_mhia::parse(const uint8_t *data)
  3900. {
  3901. return 0;
  3902. /*
  3903. long ptr = 0;
  3904. if (_strnicmp((char *)&data[ptr],"mhia",4)) return -1;
  3905. ptr+=4;
  3906. uint32_t size_head=rev4(&data[ptr]);
  3907. ptr+=4;
  3908. uint32_t size_total=rev4(&data[ptr]);
  3909. ptr+=4;
  3910. uint32_t num_children=rev4(&data[ptr]);
  3911. ptr+=4;
  3912. unk1 = rev2(&data[ptr]);
  3913. ptr+=2;
  3914. albumid = rev4(&data[ptr]);
  3915. ptr+=4;
  3916. dbid = rev8(get8(&data[ptr]));
  3917. ptr+=8;
  3918. type = rev4(&data[ptr]);
  3919. ptr+=4;
  3920. ptr = size_head; // skip nulls
  3921. for(uint32_t i = 0; i < num_children; i++)
  3922. {
  3923. iPod_mhod* m = new iPod_mhod();
  3924. long ret = m->parse(data + ptr);
  3925. if(ret == -1)
  3926. {
  3927. delete m;
  3928. return -1;
  3929. }
  3930. mhod.push_back(m);
  3931. ptr += ret;
  3932. }
  3933. return ptr;
  3934. */
  3935. }
  3936. long iPod_mhia::write(unsigned char * data, const unsigned long datasize)
  3937. {
  3938. const unsigned int headsize=0x5C;
  3939. // check for header size
  3940. if (headsize>datasize) return -1;
  3941. long ptr=0;
  3942. //write mhla header
  3943. data[0]='m';data[1]='h';data[2]='i';data[3]='a';
  3944. ptr+=4;
  3945. rev4(headsize,&data[ptr]); // header size
  3946. ptr+=4;
  3947. rev4(-1,&data[ptr]); // total size (put this in later)
  3948. ptr+=4;
  3949. rev4((uint32_t)mhod.size(),&data[ptr]); // number of strings
  3950. ptr+=4;
  3951. rev2(unk1, &data[ptr]);
  3952. ptr+=2;
  3953. rev2(albumid, &data[ptr]);
  3954. ptr+=2;
  3955. put8(rev8(dbid), &data[ptr]);
  3956. ptr+=8;
  3957. rev4(type, &data[ptr]);
  3958. ptr+=4;
  3959. memset(&data[ptr], 0, 60); // a whole shitload of zeroes
  3960. ptr+=60;
  3961. for (size_t i=0;i!=mhod.size();i++)
  3962. {
  3963. long ret = mhod[i]->write(data + ptr, datasize - ptr);
  3964. if (ret == -1)
  3965. return -1;
  3966. ptr += ret;
  3967. }
  3968. // put in total size
  3969. rev4(ptr, &data[8]);
  3970. return ptr;
  3971. }
  3972. //////////////////////////////////////////////////////////////////////
  3973. // MHLA - Album List
  3974. //////////////////////////////////////////////////////////////////////
  3975. iPod_mhla::iPod_mhla() : nextAlbumId(400)
  3976. {
  3977. }
  3978. iPod_mhla::~iPod_mhla()
  3979. {
  3980. }
  3981. long iPod_mhla::parse(const uint8_t *data)
  3982. {
  3983. return 0;
  3984. /*
  3985. long ptr=0;
  3986. if (_strnicmp((char *)&data[ptr],"mhla",4)) return -1;
  3987. ptr+=4;
  3988. uint32_t size_head=rev4(&data[ptr]);
  3989. ptr+=4;
  3990. uint32_t num_children=rev4(&data[ptr]);
  3991. ptr+=4;
  3992. ptr = size_head; // skip nulls
  3993. for(uint32_t i = 0; i < num_children; i++)
  3994. {
  3995. iPod_mhia* m = new iPod_mhia();
  3996. long ret = m->parse(data + ptr);
  3997. if(ret == -1)
  3998. {
  3999. delete m;
  4000. return -1;
  4001. }
  4002. mhia.push_back(m);
  4003. ptr += ret;
  4004. }
  4005. return ptr;
  4006. */
  4007. }
  4008. long iPod_mhla::write(unsigned char * data, const unsigned long datasize)
  4009. {
  4010. const unsigned int headsize=0x5C;
  4011. // check for header size
  4012. if (headsize>datasize) return -1;
  4013. long ptr=0;
  4014. //write mhla header
  4015. data[0]='m';data[1]='h';data[2]='l';data[3]='a';
  4016. ptr+=4;
  4017. rev4(headsize,&data[ptr]); // header size
  4018. ptr+=4;
  4019. rev4((uint32_t)albums.size(),&data[ptr]); // number of albums
  4020. ptr+=4;
  4021. memset(&data[ptr], 0, 80); // a whole shitload of zeroes
  4022. ptr+=80;
  4023. /*
  4024. for (size_t i=0;i!=mhia.size();i++)
  4025. {
  4026. long ret = mhia[i]->write(data + ptr, datasize - ptr);
  4027. if (ret == -1)
  4028. return -1;
  4029. ptr += ret;
  4030. }
  4031. */
  4032. for(albums_map_t::iterator i = albums.begin(); i!=albums.end(); i++)
  4033. {
  4034. iPod_mhia mhia;
  4035. mhia.albumid = i->second;
  4036. iPod_mhod* artist = new iPod_mhod();
  4037. artist->SetString(i->first.artist);
  4038. artist->type = MHOD_ALBUMLIST_ARTIST;
  4039. mhia.mhod.push_back(artist);
  4040. iPod_mhod* album = new iPod_mhod();
  4041. album->SetString(i->first.album);
  4042. album->type = MHOD_ALBUMLIST_ALBUM;
  4043. mhia.mhod.push_back(album);
  4044. long ret = mhia.write(data + ptr, datasize - ptr);
  4045. if (ret == -1)
  4046. return -1;
  4047. ptr += ret;
  4048. }
  4049. return ptr;
  4050. }
  4051. uint16_t iPod_mhla::GetAlbumId(const wchar_t* artist, const wchar_t* album)
  4052. {
  4053. ArtistAlbumPair key(artist, album);
  4054. if(albums.find(key) == albums.end())
  4055. {
  4056. albums[key] = nextAlbumId;
  4057. return nextAlbumId++;
  4058. }
  4059. return albums[key];
  4060. }
  4061. void iPod_mhla::ClearAlbumsList()
  4062. {
  4063. nextAlbumId = 0;
  4064. albums.clear();
  4065. }