12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256 |
- /*
- *
- *
- * Copyright (c) 2004 Samuel Wood ([email protected])
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
- *
- *
- *
- */
- // For more information on how all this stuff works, see:
- // http://www.ipodlinux.org/ITunesDB
- // iPodDB.h: interface for the iPod classes.
- //
- //////////////////////////////////////////////////////////////////////
- #ifndef __IPODDB_H__
- #define __IPODDB_H__
- #pragma once
- #pragma warning( disable : 4786)
- #include <algorithm>
- #include <windows.h>
- #include <bfc/platform/types.h>
- #include <map>
- #include <vector>
- #ifdef _DEBUG
- #undef ASSERT
- #define ASSERT(x) assert(x)
- #else
- #define ASSERT(x) {}
- #endif
- // mhod types
- #define MHOD_TITLE 1
- #define MHOD_LOCATION 2
- #define MHOD_ALBUM 3
- #define MHOD_ARTIST 4
- #define MHOD_GENRE 5
- #define MHOD_FILETYPE 6
- #define MHOD_EQSETTING 7
- #define MHOD_COMMENT 8
- #define MHOD_CATEGORY 9 // iTunes Music Store Podcast category
- #define MHOD_COMPOSER 12
- #define MHOD_GROUPING 13
- #define MHOD_DESCRIPTION 14 // Podcast show notes text - accessible via the center iPod button
- #define MHOD_ENCLOSUREURL 15 // Used by iTunes 4.9 for a Podcast's original enclosure URL
- #define MHOD_RSSFEEDURL 16 // Used by iTunes 4.9 for a Podcast's RSS 2.0 feed URL
- #define MHOD_CHAPTER 17 // M4A-style tagged data that is used to support subsongs/chapters
- #define MHOD_SUBTITLE 18
- #define MHOD_SHOW 19
- #define MHOD_EPISODE 20
- #define MHOD_TVNETWORK 21
- #define MHOD_ALBUMARTIST 22
- #define MHOD_ARTIST_SORT 23
- #define MHOD_TITLE_SORT 27
- #define MHOD_ALBUM_SORT 28
- #define MHOD_ALBUMARTIST_SORT 29
- #define MHOD_COMPOSER_SORT 30
- #define MHOD_SHOW_SORT 31
- #define MHOD_SPLPREF 50
- #define MHOD_SPLDATA 51
- #define MHOD_LIBRARY 52 // Found in the default hidden playlist
- #define MHOD_LIBRARY_LETTER 53 // letter jump table
- #define MHOD_PLAYLIST 100
- #define MHOD_ALBUMLIST_ALBUM 200
- #define MHOD_ALBUMLIST_ARTIST 201
- #define MHOD_ALBUMLIST_ARTIST_SORT 202
- #define MHOD_ALBUMLIST_PODCASTURL 203
- #define MHOD_ALBUMLIST_SHOW 204
- // Equalizer defines
- #define EQ_NONE -1
- #define EQ_ACOUSTIC 100
- #define EQ_BASSBOOSTER 101
- #define EQ_BASSREDUCER 102
- #define EQ_CLASSICAL 103
- #define EQ_DANCE 104
- #define EQ_DEEP 105
- #define EQ_ELECTRONIC 106
- #define EQ_FLAT 107
- #define EQ_HIPHOP 108
- #define EQ_JAZZ 109
- #define EQ_LATIN 110
- #define EQ_LOUDNESS 111
- #define EQ_LOUNGE 112
- #define EQ_PIANO 113
- #define EQ_POP 114
- #define EQ_RNB 115
- #define EQ_ROCK 116
- #define EQ_SMALLSPEAKERS 117
- #define EQ_SPOKENWORD 118
- #define EQ_TREBLEBOOSTER 119
- #define EQ_TREBLEREDUCER 120
- #define EQ_VOCALBOOSTER 121
- // Smart Playlist stuff
- #define SPLMATCH_AND 0 // AND rule - all of the rules must be true in order for the combined rule to be applied
- #define SPLMATCH_OR 1 // OR rule
- // Limit Types.. like limit playlist to 100 minutes or to 100 songs
- #define LIMITTYPE_MINUTES 0x01
- #define LIMITTYPE_MB 0x02
- #define LIMITTYPE_SONGS 0x03
- #define LIMITTYPE_HOURS 0x04
- #define LIMITTYPE_GB 0x05
- // Limit Sorts.. Like which songs to pick when using a limit type
- // Special note: the values for LIMITSORT_LEAST_RECENTLY_ADDED, LIMITSORT_LEAST_OFTEN_PLAYED,
- // LIMITSORT_LEAST_RECENTLY_PLAYED, and LIMITSORT_LOWEST_RATING are really 0x10, 0x14,
- // 0x15, 0x17, with the 'limitsort_opposite' flag set. This is the same value as the
- // "positive" value (i.e. LIMITSORT_LEAST_RECENTLY_ADDED), and is really very terribly
- // awfully weird, so we map the values to iPodDB specific values with the high bit set.
- //
- // On writing, we check the high bit and write the limitsort_opposite from that. That
- // way, we don't have to deal with programs using the class needing to set the wrong
- // limit and then make it into the "opposite", which would be frickin' annoying.
- #define LIMITSORT_RANDOM 0x02
- #define LIMITSORT_SONG_NAME 0x03
- #define LIMITSORT_ALBUM 0x04
- #define LIMITSORT_ARTIST 0x05
- #define LIMITSORT_GENRE 0x07
- #define LIMITSORT_MOST_RECENTLY_ADDED 0x10
- #define LIMITSORT_COMPOSER 0x12 // Not used by iTunes, but inferred from the Type 52 MHOD's Composer type
- #define LIMITSORT_LEAST_RECENTLY_ADDED 0x80000010 // See note above
- #define LIMITSORT_MOST_OFTEN_PLAYED 0x14
- #define LIMITSORT_LEAST_OFTEN_PLAYED 0x80000014 // See note above
- #define LIMITSORT_MOST_RECENTLY_PLAYED 0x15
- #define LIMITSORT_LEAST_RECENTLY_PLAYED 0x80000015 // See note above
- #define LIMITSORT_HIGHEST_RATING 0x17
- #define LIMITSORT_LOWEST_RATING 0x80000017 // See note above
- // Smartlist Actions - Used in the rules.
- /*
- really this is a bitmapped field...
- high byte
- bit 0 = "string" values if set, "int" values if not set
- bit 1 = "not", or to negate the check.
- lower 2 bytes
- bit 0 = simple "IS" query
- bit 1 = contains
- bit 2 = begins with
- bit 3 = ends with
- bit 4 = greater than
- bit 5 = unknown, but probably greater than or equal to
- bit 6 = less than
- bit 7 = unknown, but probably less than or equal to
- bit 8 = a range selection
- bit 9 = "in the last"
- */
- #define SPLACTION_IS_INT 0x00000001 // Also called "Is Set" in iTunes
- #define SPLACTION_IS_GREATER_THAN 0x00000010 // Also called "Is After" in iTunes
- #define SPLACTION_IS_LESS_THAN 0x00000040 // Also called "Is Before" in iTunes
- #define SPLACTION_IS_IN_THE_RANGE 0x00000100
- #define SPLACTION_IS_IN_THE_LAST 0x00000200
- #define SPLACTION_BINARY_AND 0x00000400
- #define SPLACTION_IS_STRING 0x01000001
- #define SPLACTION_CONTAINS 0x01000002
- #define SPLACTION_STARTS_WITH 0x01000004
- #define SPLACTION_ENDS_WITH 0x01000008
- #define SPLACTION_IS_NOT_INT 0x02000001 // Also called "Is Not Set" in iTunes
- #define SPLACTION_IS_NOT_GREATER_THAN 0x02000010 // Note: Not available in iTunes
- #define SPLACTION_IS_NOT_LESS_THAN 0x02000040 // Note: Not available in iTunes
- #define SPLACTION_IS_NOT_IN_THE_RANGE 0x02000100 // Note: Not available in iTunes
- #define SPLACTION_IS_NOT_IN_THE_LAST 0x02000200
- #define SPLACTION_UNKNOWN2 0x02000800
- #define SPLACTION_IS_NOT 0x03000001
- #define SPLACTION_DOES_NOT_CONTAIN 0x03000002
- #define SPLACTION_DOES_NOT_START_WITH 0x03000004 // Note: Not available in iTunes
- #define SPLACTION_DOES_NOT_END_WITH 0x03000008 // Note: Not available in iTunes
- // these are to pass to AddRule() when you need a unit for the two "in the last" action types
- // Or, in theory, you can use any time range... iTunes might not like it, but the iPod might.
- #define SPLACTION_LAST_DAYS_VALUE 86400 // number of seconds in 24 hours
- #define SPLACTION_LAST_WEEKS_VALUE 604800 // number of seconds in 7 days
- #define SPLACTION_LAST_MONTHS_VALUE 2628000 // number of seconds in 30.4167 days ~= 1 month
- // Hey, why limit ourselves to what iTunes can do? If the iPod can deal with it, excellent!
- #define SPLACTION_LAST_SECONDS_RULE 1 // one second
- #define SPLACTION_LAST_HOURS_VALUE 3600 // number of seconds in 1 hour
- #define SPLACTION_LAST_MINUTES_VALUE 60 // number of seconds in 1 minute
- #define SPLACTION_LAST_YEARS_VALUE 31536000 // number of seconds in 365 days
- // fun ones.. Near as I can tell, all of these work. It's open like that. :)
- #define SPLACTION_LAST_LUNARCYCLE_VALUE 2551443 // a "lunar cycle" is the time it takes the moon to circle the earth
- #define SPLACTION_LAST_SIDEREAL_DAY 86164 // a "sidereal day" is time in one revolution of earth on its axis
- #define SPLACTION_LAST_SWATCH_BEAT 86 // a "swatch beat" is 1/1000th of a day.. search for "internet time" on google
- #define SPLACTION_LAST_MOMENT 90 // a "moment" is 1/40th of an hour, or 1.5 minutes
- #define SPLACTION_LAST_OSTENT 600 // an "ostent" is 1/10th of an hour, or 6 minutes
- #define SPLACTION_LAST_FORTNIGHT 1209600 // a "fortnight" is 14 days
- #define SPLACTION_LAST_VINAL 1728000 // a "vinal" is 20 days
- #define SPLACTION_LAST_QUARTER 7889231 // a "quarter" is a quarter year
- #define SPLACTION_LAST_SOLAR_YEAR 31556926 // a "solar year" is the time it takes the earth to go around the sun
- #define SPLACTION_LAST_SIDEREAL_YEAR 31558150 // a "sidereal year" is the time it takes the earth to reach the same point in space again, compared to the stars
- // Smartlist fields - Used for rules.
- #define SPLFIELD_SONG_NAME 0x02 // String
- #define SPLFIELD_ALBUM 0x03 // String
- #define SPLFIELD_ARTIST 0x04 // String
- #define SPLFIELD_BITRATE 0x05 // Int (e.g. from/to = 128)
- #define SPLFIELD_SAMPLE_RATE 0x06 // Int (e.g. from/to = 44100)
- #define SPLFIELD_YEAR 0x07 // Int (e.g. from/to = 2004)
- #define SPLFIELD_GENRE 0x08 // String
- #define SPLFIELD_KIND 0x09 // String
- #define SPLFIELD_DATE_MODIFIED 0x0a // Int/Mac Timestamp (e.g. from/to = bcf93280 == is before 6/19/2004)
- #define SPLFIELD_TRACKNUMBER 0x0b // Int (e.g. from = 1, to = 2)
- #define SPLFIELD_SIZE 0x0c // Int (e.g. from/to = 0x00600000 for 6MB)
- #define SPLFIELD_TIME 0x0d // Int (e.g. from/to = 83999 for 1:23/83 seconds)
- #define SPLFIELD_COMMENT 0x0e // String
- #define SPLFIELD_DATE_ADDED 0x10 // Int/Mac Timestamp (e.g. from/to = bcfa83ff == is after 6/19/2004)
- #define SPLFIELD_COMPOSER 0x12 // String
- #define SPLFIELD_PLAYCOUNT 0x16 // Int (e.g. from/to = 1)
- #define SPLFIELD_LAST_PLAYED 0x17 // Int/Mac Timestamp (e.g. from = bcfa83ff (6/19/2004), to = 0xbcfbd57f (6/20/2004))
- #define SPLFIELD_DISC_NUMBER 0x18 // Int (e.g. from/to = 1)
- #define SPLFIELD_RATING 0x19 // Int/Stars Rating (e.g. from/to = 60 (3 stars))
- #define SPLFIELD_COMPILATION 0x1f // Int (e.g. is set -> SPLACTION_IS_INT/from=1, is not set -> SPLACTION_IS_NOT_INT/from=1)
- #define SPLFIELD_BPM 0x23 // Int (e.g. from/to = 60)
- #define SPLFIELD_GROUPING 0x27 // String
- #define SPLFIELD_PLAYLIST 0x28 // XXX - Unknown...not parsed correctly...from/to = 0xb6fbad5f for "Purchased Music". Extra data after "to"...
- #define SPLFIELD_VIDEO_KIND 0x3C // Logic Int (???)
- #define SPLFIELD_TVSHOW 0x3E // Int
- #define SPLFIELD_SEASON_NR 0x3F // Int
- #define SPLFIELD_SKIPCOUNT 0x44 // Int
- #define SPLFIELD_ALBUMARTIST 0x47 // string
- #define SPLDATE_IDENTIFIER 0x2dae2dae2dae2dae
- // MHOD Type 52 types
- #define TYPE52_SONG_NAME 0x03
- #define TYPE52_ARTIST 0x05
- #define TYPE52_ALBUM 0x04
- #define TYPE52_GENRE 0x07
- #define TYPE52_COMPOSER 0x12
- static const uint32_t FILETYPE_M4A=0x4d344120;
- static const uint32_t FILETYPE_MP3=0x4d503320;
- static const uint32_t FILETYPE_WAV=0x57415620;
- // useful functions
- time_t mactime_to_wintime (const unsigned long mactime);
- unsigned long wintime_to_mactime (const __time64_t time);
- char * UTF16_to_char(wchar_t * str, int length);
- // Pre-declare iPod_* classes
- class iPod_mhbd;
- class iPod_mhsd;
- class iPod_mhlt;
- class iPod_mhit;
- class iPod_mhlp;
- class iPod_mhyp;
- class iPod_slst;
- class iPod_mhip;
- class iPod_mhod;
- class iPod_mqed;
- class iPod_mhpo;
- class iPod_pqed;
- class iPod_mhla;
- // Maximum string length that iTunes writes to the database
- #define SPL_MAXSTRINGLENGTH 255
- // a struct to hold smart playlist rules in mhods
- struct SPLRule
- {
- SPLRule() :
- field(0),
- action(0),
- length(0),
- fromvalue(0),
- fromdate(0),
- fromunits(0),
- tovalue(0),
- todate(0),
- tounits(0),
- unk1(0),
- unk2(0),
- unk3(0),
- unk4(0),
- unk5(0)
- {
- memset(string, 0, sizeof(string));
- }
- void SetString(const wchar_t *value)
- {
- if(value)
- {
- lstrcpynW(string, value, SPL_MAXSTRINGLENGTH);
- length = lstrlenW(string) * 2;
- }
- else
- {
- memset(string, 0, sizeof(string));
- length = 0;
- }
- }
- unsigned long field;
- unsigned long action;
- unsigned long length;
- wchar_t string[SPL_MAXSTRINGLENGTH + 1];
- // from and to are pretty stupid.. if it's a date type of field, then
- // value = 0x2dae2dae2dae2dae,
- // date = some number, like 2 or -2
- // units = unit in seconds, like 604800 = a week
- // but if this is actually some kind of integer comparison, like rating = 60 (3 stars)
- // value = the value we care about
- // date = 0
- // units = 1
- // So we leave these as they are, and will just deal with it in the rules functions.
- uint64_t fromvalue;
- int64_t fromdate;
- uint64_t fromunits;
- uint64_t tovalue;
- int64_t todate;
- uint64_t tounits;
- unsigned long unk1;
- unsigned long unk2;
- unsigned long unk3;
- unsigned long unk4;
- unsigned long unk5;
- };
- // PCEntry: Play Count struct for the entries in iPod_mhdp
- struct PCEntry
- {
- unsigned long playcount;
- unsigned long lastplayedtime;
- unsigned long bookmarktime;
- unsigned long stars;
- uint32_t unk1;
- uint32_t skipcount;
- uint32_t skippedtime;
- };
- /**************************************
- iTunesDB Database Layout
- MHBD (Database)
- |
- |-MHSD (Data Set)
- | |
- | |-MHLT (Track List)
- | | |
- | | |-MHIT (Track Item)
- | | | |
- | | | |-MHOD (Description Object)
- | | | |-MHOD
- | | | | ...
- | | |
- | | |-MHIT
- | | | |
- | | | |-MHOD
- | | | |-MHOD
- | | | | ...
- | | |
- | | |-...
- |
- |
- |-MHSD
- | |
- | |-MHLP (Playlists List)
- | | |
- | | |-MHYP (Playlist)
- | | | |
- | | | |-MHOD
- | | | |-MHIP (Playlist Item)
- | | | | ...
- | | |
- | | |-MHYP
- | | | |
- | | | |-MHOD
- | | | |-MHIP
- | | | | ...
- | | |
- | | |-...
- **************************************/
- // base class, not used directly
- class iPodObj
- {
- public:
- iPodObj();
- virtual ~iPodObj();
- // parse function is required in all subclasses
- // feed it a iTunesDB, it creates an object hierarchy
- virtual long parse(const uint8_t *data) = 0;
- // write function is required too
- // feed it a buffer and the size of the buffer, it fills it with an iTunesDB
- // return value is size of the resulting iTunesDB
- // return of -1 means the buffer was too small
- virtual long write(uint8_t * data, const unsigned long datasize) = 0;
- unsigned long size_head;
- unsigned long size_total;
- };
- // MHBD: The database - parent of all items
- class iPod_mhbd : public iPodObj
- {
- public:
- iPod_mhbd();
- virtual ~iPod_mhbd();
- virtual long parse(const uint8_t *data);
- virtual long write(uint8_t * data, const unsigned long datasize);
- virtual long write(uint8_t * data, const unsigned long datasize, uint8_t * fwid);
- uint32_t unk1;
- uint32_t dbversion;
- uint32_t children;
- uint64_t id;
- uint16_t platform;
- uint16_t language;
- uint64_t library_id;
- uint32_t unk80;
- uint32_t unk84;
- int32_t timezone; // in seconds
- uint16_t audio_language;
- uint16_t subtitle_language;
- uint16_t unk164;
- uint16_t unk166;
- uint16_t unk168;
- iPod_mhsd *mhsdsongs;
- iPod_mhsd *mhsdplaylists;
- iPod_mhsd *mhsdsmartplaylists;
- };
- // MHSD: List container - parent of MHLT or MHLP, child of MHBD
- class iPod_mhsd : public iPodObj
- {
- public:
- iPod_mhsd();
- iPod_mhsd(int newindex);
- virtual ~iPod_mhsd();
- virtual long parse(const uint8_t *data);
- virtual long write(unsigned char * data, const unsigned long datasize) {return write(data,datasize,1);}
- virtual long write(unsigned char * data, const unsigned long datasize, int index);
- uint32_t index; // 1 = mhlt, 3 = mhlp, 2 = legacy mhlp, 4 = album list, 5 = mhlp_smart
- iPod_mhlt * mhlt;
- iPod_mhlp * mhlp;
- iPod_mhlp * mhlp_smart;
- iPod_mhla * mhla;
- };
- class iPod_mhia : public iPodObj
- {
- public:
- iPod_mhia();
- virtual ~iPod_mhia();
- virtual long parse(const uint8_t *data);
- virtual long write(unsigned char * data, const unsigned long datasize);
- uint16_t unk1;
- uint16_t albumid;
- uint64_t dbid;
- uint32_t type;
- std::vector<iPod_mhod*> mhod;
- };
- class ArtistAlbumPair
- {
- public:
- const wchar_t* artist;
- const wchar_t* album;
- ArtistAlbumPair() : artist(0), album(0) {}
- ArtistAlbumPair(const wchar_t* artist, const wchar_t* album) : artist(artist), album(album) {}
- /*bool operator < (const ArtistAlbumPair& that) const
- {
- int yy = _wcsicmp(artist, that.artist);
- if(yy) return yy < 0;
- return _wcsicmp(album, that.album) < 0;
- }*/
- };
- struct ArtistAlbumPairComparer
- {
- int operator ()(const ArtistAlbumPair &a, const ArtistAlbumPair &b) const
- {
- int yy = _wcsicmp(a.artist, b.artist);
- if(yy) return yy;
- return _wcsicmp(a.album, b.album);
- }
- };
- class iPod_mhla : public iPodObj
- {
- public:
- iPod_mhla();
- virtual ~iPod_mhla();
- virtual long parse(const uint8_t *data);
- virtual long write(unsigned char * data, const unsigned long datasize);
- uint16_t GetAlbumId(const wchar_t* artist, const wchar_t* album);
- void ClearAlbumsList();
- //typedef std::map<ArtistAlbumPair, uint16_t> albums_map_t;
- typedef std::map<ArtistAlbumPair, uint16_t, ArtistAlbumPairComparer> albums_map_t;
- albums_map_t albums;
- uint16_t nextAlbumId;
- };
- // MHLT: song list container - parent of MHIT, child of MHSD
- class iPod_mhlt : public iPodObj
- {
- public:
- typedef std::map<uint32_t, iPod_mhit*> mhit_map_t;
- //typedef std::map<unsigned long, iPod_mhit*> mhit_map_t; // Map the unique mhit.id to a mhit object
- typedef mhit_map_t::value_type mhit_value_t;
- iPod_mhlt();
- virtual ~iPod_mhlt();
- virtual long parse(const uint8_t *data);
- virtual long write(unsigned char * data, const unsigned long datasize);
- const unsigned long GetChildrenCount() const { return mhit.size(); }
- // returns a pointer to the new iPod_mhit object in the track list, which you edit directly
- iPod_mhit *NewTrack();
- void AddTrack(iPod_mhit *new_track);
- // takes a position index, returns a pointer to the track itself, or NULL if the index isn't found.
- iPod_mhit *GetTrack(uint32_t index) const;
- // searches for a track based on the track's id number (mhit.id). returns mhit pointer, or NULL if the id isn't found.
- iPod_mhit * GetTrackByID(const unsigned long id);
- // couple of ways to delete a track
- bool DeleteTrack(const unsigned long index);
- bool DeleteTrackByID(const unsigned long id);
- // clears out the tracklist
- bool ClearTracks(const bool clearMap = true);
- // the map of the tracks themselves
- mhit_map_t mhit;
- std::vector<uint32_t> mhit_indexer;
- uint32_t GetNextID();
- private:
- volatile uint32_t next_mhit_id;
- };
- // MHIT: song item - parent of MHOD, child of MHLT
- class iPod_mhit : public iPodObj
- {
- public:
- iPod_mhit();
- virtual ~iPod_mhit();
- virtual long parse(const uint8_t *data);
- virtual long write(unsigned char * data, const unsigned long datasize);
- const unsigned long GetChildrenCount() const { return(mhod.size()); }
- // will add a new mhod string to the mhit
- // optional: pass in a type to get an existing string, if there is one,
- // or a new one with the type filled in already, if there is not one
- iPod_mhod * AddString(const int type=0);
- // Find a string by type
- iPod_mhod * FindString(const unsigned long type) const;
- // deletes a string from the track
- // if more than one string of given type exists, all of that type will be deleted,
- // to ensure consistency. Pointers to these strings will be invalid after this.
- // return val is how many strings were deleted
- unsigned long DeleteString(const unsigned long type);
- // Creates a copy of the mhit. The operator = is overloaded so you can
- // more easily copy mhit's.
- static void Duplicate(const iPod_mhit *src, iPod_mhit *dst);
- iPod_mhit& operator=(const iPod_mhit& src);
- int GetRating() { return stars/20; }
- void SetRating(int rating) { stars=rating*20; }
- int GetEQSetting();
- void SetEQSetting(int value);
- unsigned int GetFileTypeID(const wchar_t *filename);
- uint32_t id;
- uint32_t visible; // 0x01 means the song shows up on the iPod, all other values means it is hidden
- uint32_t filetype; // MP3 = 0x4d503320, M4A = 0x4d344120, M4B = 0x4d344220, M4P = 0x4d345020, WAV = 0x57415620, AA = ???
- uint8_t vbr;
- uint8_t type;
- uint8_t compilation;
- uint8_t stars;
- uint32_t lastmodifiedtime; // iTunes sets this the UTC time value for the Windows Last Modified timestamp
- uint32_t size;
- uint32_t length;
- uint32_t tracknum;
- uint32_t totaltracks;
- uint32_t year;
- uint32_t bitrate;
- uint16_t samplerate;
- uint16_t samplerate_fixedpoint;
- uint32_t volume;
- uint32_t starttime;
- uint32_t stoptime;
- uint32_t soundcheck;
- uint32_t playcount;
- uint32_t playcount2; // Seems to always be the same as playcount(?!?)
- uint32_t lastplayedtime;
- uint32_t cdnum;
- uint32_t totalcds;
- uint32_t userID; // Apple Store User ID
- uint32_t addedtime; // iTunes sets this to the UTC time value for when the file was added to the iTunes library
- uint32_t bookmarktime;
- uint64_t dbid; // 64 bit value that identifies this mhit across iPod databases. iTunes increments this by 1 for each additional song. (previously unk7 and unk8)
- uint32_t BPM;
- uint32_t app_rating; // The rating set by the application, as opposed to the rating set on the iPod itself
- uint8_t checked; // a "checked" song has the value of 0, a non-checked song is 1
- uint16_t unk9; // Seems to always be 0xffff...
- uint16_t artworkcount; // Number of artwork files attached to this song
- uint32_t artworksize; // Size of all artwork files attached to this song, in bytes. (was unk10);
- uint32_t unk11;
- float samplerate2;
- uint32_t releasedtime;
- uint32_t unk14;
- uint32_t unk15;
- uint32_t unk16;
- /* --- */
- uint32_t skipcount;
- uint32_t skippedtime;
- uint8_t hasArtwork;
- uint8_t skipShuffle;
- uint8_t rememberPosition;
- uint8_t unk19;
- uint64_t dbid2; // same as dbid?
- uint8_t lyrics_flag;
- uint8_t movie_flag;
- uint8_t mark_unplayed;
- uint8_t unk20;
- uint32_t unk21;
- uint32_t pregap;
- uint64_t samplecount;
- uint32_t unk25;
- uint32_t postgap;
- uint32_t unk27;
- uint32_t mediatype;
- uint32_t seasonNumber;
- uint32_t episodeNumber;
- uint32_t unk31;
- uint32_t unk32;
- uint32_t unk33;
- uint32_t unk34;
- uint32_t unk35;
- uint32_t unk36;
- /* --- */
- uint32_t unk37;
- uint32_t gaplessData;
- uint32_t unk39;
- uint16_t albumgapless;
- uint16_t trackgapless;
- uint32_t unk40;
- uint32_t unk41;
- uint32_t unk42;
- uint32_t unk43;
- uint32_t unk44;
- uint32_t unk45;
- uint32_t unk46;
- uint32_t album_id;
- uint32_t unk48;
- uint32_t unk49;
- uint32_t unk50;
- uint32_t unk51;
- uint32_t unk52;
- uint32_t unk53;
- uint32_t unk54;
- uint32_t unk55;
- uint32_t unk56;
- /* --- */
- // 22 bytes of unknown (we'll just write back zeroes)
-
- uint32_t mhii_link; // TODO: benski> figure this thing out
- // 32 more bytes of unknown (we'll just write back zeroes)
- /* benski> this is a hack. i'm putting this in here so we can retrieve album art from the transfer thread and add it in the main thread
- it doesn't really belong as part of this object, though! */
- // protect these members, so stuff doesn't fuck up my cache
- protected:
- std::vector<iPod_mhod*> mhod;
- iPod_mhod * mhodcache[25];
- };
- // MHLP: playlist container - parent of MHYP, child of MHSD
- // Important note: Playlist zero must always be the default playlist, containing every
- // track in the DB. To do this, always call "GetDefaultPlaylist()" before you create any
- // other playlists, if you start from scratch.
- // After you're done adding/deleting tracks in the database, and just before you call
- // write(), do the following: GetDefaultPlaylist()->PopulatePlaylist(ptr_to_mhlt);
- class iPod_mhlp : public iPodObj
- {
- public:
- iPod_mhlp();
- virtual ~iPod_mhlp();
- virtual long parse(const uint8_t *data);
- virtual long write(unsigned char * data, const unsigned long datasize) {return write(data,datasize,3);}
- virtual long write(unsigned char * data, const unsigned long datasize, int index);
- const unsigned long GetChildrenCount() const { return mhyp.size(); }
- // returns a new playlist for you
- iPod_mhyp * AddPlaylist();
- // gets a playlist
- iPod_mhyp * GetPlaylist(const unsigned long pos) const { return mhyp.at(pos); }
- // finds a playlist by its ID
- iPod_mhyp * FindPlaylist(const uint64_t playlistID);
- // deletes the playlist at a position
- bool DeletePlaylist(const unsigned long pos);
- // deletes the playlist matching the ID
- bool DeletePlaylistByID(const uint64_t playlistID);
- // gets the default playlist ( GetPlaylist(0); )
- // if there are no playlists yet (empty db), then it creates the default playlist
- // and returns a pointer to it
- iPod_mhyp * GetDefaultPlaylist();
- // erases all playlists, including the default one, so be careful here.
- // Set createDefaultPlaylist to create a new, empty default playlist
- bool ClearPlaylists(const bool createDefaultPlaylist = false);
- // Goes through all playlists and removed any songs that are no longer in the MHLT
- void RemoveDeadPlaylistEntries(iPod_mhlt *mhlt);
- std::vector<iPod_mhyp*> mhyp;
-
- void SortPlaylists();
- private:
- bool beingDeleted;
- };
- int STRCMP_NULLOK(const wchar_t *pa, const wchar_t *pb);
- // MHYP: playlist - parent of MHOD or MHIP, child of MHLP
- class iPod_mhyp : public iPodObj
- {
- public:
- iPod_mhyp();
- virtual ~iPod_mhyp();
- virtual long parse(const uint8_t *data);
- virtual long write(unsigned char * data, const unsigned long datasize) {return write(data,datasize,3);}
- virtual long write(unsigned char * data, const unsigned long datasize, int index);
- bool IsSmartPlaylist(void) const { return(isSmartPlaylist); }
- // add an entry to the playlist. Creates a new entry, returns the position in the vector
- // optionally fills in the songindex for you, with the ID from a track you might have
- long AddPlaylistEntry(iPod_mhip * entry, const unsigned long id=0);
- // give it a song id, it'll return a position in the playlist
- // -1, as always, means not found
- // if the same entry is in the playlist multiple times, this only gives back the first one
- long FindPlaylistEntry(const unsigned long id) const;
- // get an mhip given its position
- iPod_mhip * GetPlaylistEntry(const unsigned long pos) const { return mhip.at(pos); }
- // deletes an entry from the playlist. Pointers to that entry become invalid
- bool DeletePlaylistEntry(const unsigned long pos);
- // Removes all playlist entries matching the songindex parameter
- bool DeletePlaylistEntryByID(unsigned long songindex);
- // clears a playlist of all mhip entries
- bool ClearPlaylist();
- // populates a playlist to be the same as a track list you pass into it.
- // Mainly only useful for building the default playlist after you add/delete tracks
- // GetDefaultPlaylist()->PopulatePlaylist(ptr_to_mhlt);
- // for example...
- long PopulatePlaylist(iPod_mhlt * tracks, int hidden_field=1);
- // will add a new string to the playlist
- // optional: pass in a type to get an existing string, if there is one,
- // or a new one with the type filled in already, if there is not one
- iPod_mhod * AddString(const int type=0);
- // get an mhod given it's type.. Only really useful with MHOD_TITLE here, until
- // smartlists get worked out better
- iPod_mhod * FindString(const unsigned long type);
- // deletes a string from the playlist
- // if more than one string of given type exists, all of that type will be deleted,
- // to ensure consistency. Pointers to these strings will be invalid after this.
- // ret val is number of strings removed
- unsigned long DeleteString(const unsigned long type);
- void SetPlaylistTitle(const wchar_t *string);
- const unsigned long GetMhodChildrenCount() const { return mhod.size(); }
- const unsigned long GetMhipChildrenCount() const { return mhip.size(); }
- static void Duplicate(iPod_mhyp *src, iPod_mhyp *dst);
- unsigned long hidden;
- unsigned long timestamp;
- uint64_t playlistID; // ID of the playlist, used in smart playlist rules
- unsigned long unk3;
- unsigned short numStringMHODs;
- unsigned short podcastflag;
- unsigned long numLibraryMHODs;
- std::vector<iPod_mhod*> mhod;
- std::vector<iPod_mhip*> mhip;
- struct indexMhit
- {
- __forceinline bool operator()(indexMhit*& one, indexMhit*& two)
- {
- #define RETIFNZ(x) { int yy = x; if(yy != 0) return yy < 0; }
- //return(STRCMP_NULLOK(one->str.c_str(), two->str.c_str()) < 0 ? true : false);
- RETIFNZ(STRCMP_NULLOK(one->str[0],two->str[0]));
- RETIFNZ(STRCMP_NULLOK(one->str[1],two->str[1]));
- RETIFNZ(STRCMP_NULLOK(one->str[2],two->str[2]));
- RETIFNZ(one->track - two->track);
- RETIFNZ(STRCMP_NULLOK(one->str[3],two->str[3]));
- return true;
- #undef RETIFNZ
- }
- unsigned int index;
- const wchar_t *str[4];
- int track;
- };
- iPod_mhlt::mhit_map_t *mhit;
- std::vector<uint32_t> mhit_indexer;
- bool writeLibraryMHODs;
- bool operator()(iPod_mhyp*& one, iPod_mhyp*& two);
- protected:
- bool isSmartPlaylist;
- bool isPopulated;
- };
- // MHIP: playlist item - child of MHYP
- class iPod_mhip : public iPodObj
- {
- public:
- iPod_mhip();
- virtual ~iPod_mhip();
- virtual long parse(const uint8_t *data);
- virtual long write(unsigned char * data, const unsigned long datasize) { return write(data,datasize,0); }
- virtual long write(unsigned char * data, const unsigned long datasize, int entrynum);
- static void Duplicate(iPod_mhip *src, iPod_mhip *dst);
- unsigned long dataobjectcount; // was unk1
- unsigned long podcastgroupflag; // was corrid
- unsigned long groupid; // was unk2
- unsigned long songindex;
- unsigned long timestamp;
- unsigned long podcastgroupref;
- std::vector<iPod_mhod*> mhod;
- };
- // MHOD: string container item, child of MHIT or MHYP
- // MHOD: string container item, child of MHIT or MHYP
- class iPod_mhod : public iPodObj
- {
- public:
- iPod_mhod();
- virtual ~iPod_mhod();
- virtual long parse(const uint8_t *data);
- virtual long write(unsigned char * data, const unsigned long datasize);
- void SetString(const wchar_t *string);
- static void Duplicate(iPod_mhod *src, iPod_mhod *dst);
-
- static bool IsSimpleStringType(const unsigned int type);
- uint32_t type;
- uint32_t unk1;
- uint32_t unk2;
- // renamed this from corrid.. all it is is a position in the playlist
- // for type 100 mhods that come immediately after mhips.
- // for strings, this is the encoded type. 1 == UTF-16, 2 == UTF-8
- union
- {
- uint32_t position;
- uint32_t encoding_type;
- };
- uint32_t length;
- uint32_t unk3;
- uint32_t unk4;
- // string mhods get the string put here, unaltered, still byte reversed
- // Use unicode functions to work with this string.
- wchar_t *str;
- // mhod types 50 and up get the whole thing put here.
- // until I can figure out all of these, I won't bother to try to recreate them
- // and i'll just copy them back as needed when rewriting the iTunesDB file.
- uint8_t * binary;
- // stuff for type 50 mhod
- uint8_t liveupdate; // "Live Updating" check box
- uint8_t checkrules; // "Match X of the following conditions" check box
- uint8_t checklimits; // "Limit To..." check box. 1 = checked, 0 = not checked
- uint8_t matchcheckedonly; // "Match only checked songs" check box.
- uint8_t limitsort_opposite; // Limit Sort rule is reversed (e.g. limitsort == LIMIT_HIGHEST_RATING really means LIMIT_LOWEST_RATING...quite weird...)
- uint32_t limittype; // See Limit Types defines above
- uint32_t limitsort; // See Limit Sort defines above
- uint32_t limitvalue; // Whatever value you type next to "limit type".
- // stuff for type 51 mhod
- uint32_t unk5; // not sure, probably junk data
- uint32_t rules_operator; // "All" (logical AND / value = 0) or "Any" (logical OR / value = 1).
- std::vector<SPLRule*> rule;
- bool parseSmartPlaylists;
- };
- // Smart Playlist. A smart playlist doesn't act different from a regular playlist,
- // except that it contains a type 50 and type 51 MHOD. But deriving the iPod_slst
- // class makes sense, since there are a lot of functions that are only appropriate
- // for smart playlists, and it can guarantee that a type 50 and 51 MHOD will always
- // be available.
- class iPod_slst : public iPod_mhyp
- {
- public:
- enum FieldType
- {
- ftString,
- ftInt,
- ftBoolean,
- ftDate,
- ftPlaylist,
- ftUnknown,
- ftBinaryAnd,
- };
- enum ActionType
- {
- atString,
- atInt,
- atBoolean,
- atDate,
- atRange,
- atInTheLast,
- atPlaylist,
- atNone,
- atInvalid,
- atUnknown,
- atBinaryAnd,
- };
- iPod_slst();
- virtual ~iPod_slst();
- iPod_mhod* GetPrefs(void) { UpdateMHODPointers(); return(splPref); }
- void SetPrefs(const bool liveupdate = true, const bool rules_enabled = true, const bool limits_enabled = false,
- const unsigned long limitvalue = 0, const unsigned long limittype = 0, const unsigned long limitsort = 0);
- static FieldType GetFieldType(const unsigned long field);
- static ActionType GetActionType(const unsigned long field, const unsigned long action);
- static uint64_t ConvertDateValueToNum(const uint64_t val) { return(-(int64_t)val); }
- static uint64_t ConvertNumToDateValue(const uint64_t val) { return(-(int64_t)val); }
- // returns a pointer to the SPLDATA mhod
- iPod_mhod* GetRules() { UpdateMHODPointers(); return(splData); }
- // get the number of rules in the smart playlist
- unsigned long GetRuleCount();
- // Returns rule number (0 == first rule, -1 == error)
- int AddRule(const unsigned long field,
- const unsigned long action,
- const wchar_t * string = NULL, // use string for string based rules
- const uint64_t value = 0, // use value for single variable rules
- const uint64_t from = 0, // use from and to for range based rules
- const uint64_t to = 0,
- const uint64_t units = 0); // use units for "in the last" based rules
- int AddRule(const SPLRule& rule);
-
- void RemoveAllRules(void);
- // populates a smart playlist
- // Pass in the mhlt with all the songs on the iPod, and it populates the playlist
- // given those songs and the current rules
- // Return value is number of songs in the resulting playlist.
- long PopulateSmartPlaylist(iPod_mhlt * tracks, iPod_mhlp * playlists);
- // used in PopulateSmartPlaylist
- static bool EvalRule(
- SPLRule * r,
- iPod_mhit * track,
- iPod_mhlt * tracks = NULL, // if you're going to allow playlist type rules
- iPod_mhlp * playlists = NULL // these are required to be passed in
- );
- // Restore default prefs and remove all rules
- void Reset(void);
- protected:
- void UpdateMHODPointers(void);
- iPod_mhod *splPref;
- iPod_mhod *splData;
- };
- // MHDP: Play Count class
- class iPod_mhdp
- {
- public:
- iPod_mhdp();
- ~iPod_mhdp();
- unsigned long size_head;
- unsigned long entrysize;
- const unsigned long GetChildrenCount() const { return children; }
- // return value is number of songs or -1 if error.
- // you should probably check to make sure the number of songs is the same
- // as the number of songs you read in from parsing the iTunesDB
- virtual long parse(const uint8_t *data);
- // there is no write() function because there is no conceivable need to ever write a
- // play counts file.
- const PCEntry &GetPlayCount(const unsigned int pos) const { return entry[pos]; }
- // playcounts are stored in the Play Counts file, in the same order as the mhits are
- // stored in the iTunesDB. So you should apply the changes from these entries to the
- // mhits in order and then probably delete the Play Counts file entirely to prevent
- // doing it more than once.
- PCEntry *entry;
- uint32_t children;
- };
- // MHPO: On-The-Go Playlist class
- class iPod_mhpo
- {
- public:
- iPod_mhpo();
- virtual ~iPod_mhpo();
- unsigned long size_head;
- unsigned long unk1;
- unsigned long unk2; // this looks like a timestamp, sorta
- const unsigned long GetChildrenCount() const { return children; }
- virtual long parse(const uint8_t *data);
- virtual long write(unsigned char * data, const unsigned long datasize);
- // This will create a new playlist from the OTGPlaylist..
- // Give it the DB to create the playlist in and from, and a name for the playlist.
- // Return value is a pointer to the playlist itself, which will be inside the DB you
- // give to it as well.
- // Returns NULL on error (can't create the playlist)
- iPod_mhyp * CreatePlaylistFromOTG(iPod_mhbd * iPodDB, wchar_t * name);
- // OTGPlaylists are stored in the OTGPlaylist file. When iTunes copies them into a
- // new playlist, it deletes the file afterwards. I do not know if creating this file
- // will make the iPod have an OTGPlaylist after you undock it. I added the write function
- // anyway, in case somebody wants to try it. Not much use for it though, IMO.
- uint32_t *idList;
- uint32_t children;
- };
- // MQED: EQ Presets holder
- class iPod_mqed
- {
- public:
- iPod_mqed();
- virtual ~iPod_mqed();
- unsigned long size_head;
- unsigned long unk1;
- unsigned long unk2; // this looks like a timestamp, sorta
- const unsigned long GetChildrenCount() const { return eqList.size(); }
- virtual long parse(const uint8_t *data);
- virtual long write(unsigned char * data, const unsigned long datasize);
- std::vector<iPod_pqed*> eqList;
- };
- // PQED: A single EQ Preset
- class iPod_pqed
- {
- public:
- iPod_pqed();
- virtual ~iPod_pqed();
- unsigned long length; // length of name string
- wchar_t * name; // name string
- /*
- 10 band eq is not exactly what iTunes shows it to be.. It really is these:
- 32Hz, 64Hz, 128Hz, 256Hz, 512Hz, 1024Hz, 2048Hz, 4096Hz, 8192Hz, 16384Hz
- Also note that although these are longs, The range is only -1200 to +1200. That's dB * 100.
- */
- signed long preamp; // preamp setting
- signed long eq[10]; // iTunes shows 10 bands for EQ presets
- signed long short_eq[5]; // This is a 5 band version of the same thing (possibly what the iPod actually uses?)
- virtual long parse(const uint8_t *data);
- virtual long write(unsigned char * data, const unsigned long datasize);
- };
- struct iTunesStatsEntry
- {
- unsigned int GetBookmarkTimeInMilliseconds() { if(bookmarktime == 0xffffff) return(0); return(bookmarktime * 256); }
- // These are 3 byte values
- unsigned int entry_size;
- unsigned int bookmarktime; // In 0.256 seconds units
- unsigned int unk1; // Somehow associated with bookmark time
- unsigned int unk2;
- unsigned int playcount;
- unsigned int skippedcount;
- };
- class iTunesStats
- {
- public:
- iTunesStats();
- ~iTunesStats();
- virtual long parse(const uint8_t *data);
- virtual long write(unsigned char * data, const unsigned long datasize);
- const unsigned long GetChildrenCount() const { return children; }
- const iTunesStatsEntry &GetEntry(const unsigned int pos) const { return entry[pos];}
- // This is a 3 byte value
- unsigned int unk1;
- iTunesStatsEntry *entry;
- uint32_t children;
- iPod_mhlt *mhlt;
- };
- class iTunesShuffle
- {
- public:
- iTunesShuffle();
- ~iTunesShuffle();
- virtual long parse(const uint8_t *data);
- virtual long write(unsigned char *data, const unsigned long datasize);
- unsigned int GetChildrenCount() const { return numentries; }
- unsigned int GetEntry(const unsigned int pos) const { return entry[pos]; }
- //void AddEntry(const unsigned int index) { entry.push_back(index); }
- void Randomize();
- void Randomize(const unsigned int numsongs);
- uint32_t *entry;
- uint32_t numentries;
- unsigned int datasize;
- };
- #endif
|