diff --git a/.hgeol b/.hgeol new file mode 100644 index 0000000000..a4c8a76828 --- /dev/null +++ b/.hgeol @@ -0,0 +1,22 @@ +[repository] +native = CRLF + +[patterns] +**.cpp = CRLF +**.h = CRLF +**.txt = CRLF +**.lua = CRLF +**.sln = CRLF +**.ini = CRLF +**.redir = CRLF +**.sm = CRLF +**.ssc = CRLF +**.vcproj = CRLF +**.xsl = CRLF +**.xml = CRLF +**.jpg = BIN +**.png = BIN +**.jpeg = BIN +**.ogg = BIN +**.sh = LF +Makefile = LF diff --git a/BGAnimations/flash/default.lua b/BGAnimations/flash/default.lua index 7340bdc838..34c29f1505 100644 --- a/BGAnimations/flash/default.lua +++ b/BGAnimations/flash/default.lua @@ -1,4 +1,4 @@ -return Def.Quad { - InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;scaletoclipped,SCREEN_WIDTH*2,SCREEN_HEIGHT*2;diffuse, Var "Color1";); - GainFocusCommand=cmd(finishtweening;diffusealpha,1;accelerate,0.6;diffusealpha,0); +return Def.Quad { + InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;scaletoclipped,SCREEN_WIDTH*2,SCREEN_HEIGHT*2;diffuse, Var "Color1";); + GainFocusCommand=cmd(finishtweening;diffusealpha,1;accelerate,0.6;diffusealpha,0); }; \ No newline at end of file diff --git a/BGAnimations/white flash/default.lua b/BGAnimations/white flash/default.lua index 6b4bb74a03..45fed37319 100644 --- a/BGAnimations/white flash/default.lua +++ b/BGAnimations/white flash/default.lua @@ -1,4 +1,4 @@ -return Def.Quad { - InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;scaletoclipped,SCREEN_WIDTH*2,SCREEN_HEIGHT*2); - GainFocusCommand=cmd(finishtweening;diffusealpha,1;accelerate,0.6;diffusealpha,0); +return Def.Quad { + InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;scaletoclipped,SCREEN_WIDTH*2,SCREEN_HEIGHT*2); + GainFocusCommand=cmd(finishtweening;diffusealpha,1;accelerate,0.6;diffusealpha,0); }; \ No newline at end of file diff --git a/BGAnimations/yellow flash/default.lua b/BGAnimations/yellow flash/default.lua index 0681c212ce..935f8cd8be 100644 --- a/BGAnimations/yellow flash/default.lua +++ b/BGAnimations/yellow flash/default.lua @@ -1,4 +1,4 @@ -return Def.Quad { - InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;scaletoclipped,SCREEN_WIDTH*2,SCREEN_HEIGHT*2); - GainFocusCommand=cmd(finishtweening;diffuse,color("#FFFFA0");accelerate,0.6;diffusealpha,0); +return Def.Quad { + InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;scaletoclipped,SCREEN_WIDTH*2,SCREEN_HEIGHT*2); + GainFocusCommand=cmd(finishtweening;diffuse,color("#FFFFA0");accelerate,0.6;diffusealpha,0); }; \ No newline at end of file diff --git a/Docs/SimfileFormats/BMS/tmp.txt b/Docs/SimfileFormats/BMS/tmp.txt index 9ce2bbe99d..1f916d0d8a 100644 --- a/Docs/SimfileFormats/BMS/tmp.txt +++ b/Docs/SimfileFormats/BMS/tmp.txt @@ -1,187 +1,187 @@ -BMS Format Specification(Remake version.) -Written in June 28th 2003. - -original document written by Urao Yane. -edited by U(uhangel4u@yahoo.co.jp) - -"BMS" means a Be-Music Source file. A file which has BMS suffix is regarded as the BMS file. -This file format was produced by Urao Yane and NBK in 1998.and It revised sometime. -And I adopted this file format to BM98, Delight Delight Reduplication, MixWaver, nazoBMPlay and so on. -Now,anyone can use this format freely. - -BM98 Drink Edition -http://www5c.biglobe.ne.jp/~kbs/bm98/ (Japanese) -Delight Delight Reduplicaton -http://nickle.hey.to/ (Japanese) -MixWaver -http://hello.to/mixwaver/ (Korean) -nazoBMPlay -http://www.nothing.sh/nazobmplay/ (Japanese) - --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - - - -The line begining at '#' is the command line. All the rest are ignored (use for comments). -And this BMS file is compiled at runtime , so you can order any lines freely. -And there is no difference in the command line between using a capital letter or not. - --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -
- -#PLAYER [1-4] - -#PLAYER 1 -This data is for Single Play. -#PLAYER 2 -This data is for Two Players. -#PLAYER 3 -This data is for Double Play. -#PLAYER 4 -This data is for Two Players.(Players will plays same sequence) - -#GENRE xxxxxxxx -Definition of Genre. - -#TITLE xxxxxxxx -Definition of Title. - -#ARTIST xxxxxxxx -Definition of Artist. - -#BPM xxx -Definition of BPM.(Beats Per Minite) at the top of music. default : 130 value type : double. - -#MIDIFILE xxxxxxx.mid -Background music by MIDI.but,It's not recommend. - -#PLAYLEVEL x -Information of Game Level for player. - -#RANK [0-3] -judgement level. -x = 0 :very hard, 1: hard, 2: normal, 3: easy default : 2 - -#VOLWAV xxx -relative volume control (percentage) - -#TOTAL xxx -increments of Groove Gauge -ex. -#TOTAL 120 -It means when all sequence was played over great, Groove Gauge's value is 120% - -#WAVxx yyyyyyyy.wav(or .mp3) -definition of Wave Data. xx : 01 to FZ(01-09-0A-0Z-10-1Z...) , yyyyyyyy.wav : wave file name -When use mp3 files,you need mp3 CODEC. - -e.g. -#WAV01 HOUSE01.WAV // assign HOUSE01.WAV to 01 wav -#WAV02 HOUSE02.WAV // assign HOUSE02.WAV to 02 wav -#WAVFZ HOUSE03.mp3 // assign HOUSE03.mp3 to FZ wav - -#BMPxx yyyyyyyy.bmp(or gif,jpg,png) -definition of Bitmap file. xx : 01 to FF(Hex) , yyyyyyyy.bmp : bitmap file name -Bitmap size must be 256 * 256.(max color 65536) -If you use "gif or jpg or png", with Susie Plug-in. -gif : ifgif.spi jpg : ifjpg.spi png : ifpng.spi - -About Susie Plug-ins : http://www.digitalpad.co.jp/~takechin/ - -e.g. -#BMP01 HOUSE01.BMP // assign HOUSE01.BMP to 01 bitmap -#BMP02 HOUSE02.BMP // assign HOUSE02.BMP to 02 bitmap -#BMPEE HOUSE03.PNG // assign HOUSE03.PNG to EE bitmap - -#StageFile xxxx.bmp(or gif,jpg,png) -Show assigned Picture when loading bitmaps,wavs and compiling bms. - -#BPMxx yyy -Use to change BPM(Beats Per Minite). xx : 01 to ff(Hex) - -But ,the bitmap defined by #BMP00 is something special. -This bitmap shows when a player do a poor play. - -#STOPxx yyy -Use to stop sequence. xx : 01 to ff(Hex) -yyy : a quarter note = 48 - an eighth note = 24 - a whole note = 192 - note / n = 192/n - -#CDDA xx -Audio cds Track No. - -#BackBMP xxxx.bmp(or gif,jpg,png) -Set BackGround Picture.(size:640*480) - --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -// a sample of random loading function - -#random 2 // create a random number (1 or 2) - -#if 1 // if the number was equal to 1 then... -#00111:31313131 // this is effective... -#endif - -#if 2 // if the number was equal to 2 then... -#00113:32003232 // this is effective -#endif - --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - - - -#aaabb:cccccccc - -aaa: track number (from 000 to 999) -bb : channel number where you want to send message.(from 00 to FF) -cccccccc : - - - -01 : BGM(background music by WAVE) -02 : shortening note. -03 : changing a Tempo[1-255] -04 : BGA(background animation) -06 : changing Poor-bitmap -07 : BGA Layer. -08 : Extended BPM(Use assigned of #BPMxx) -09 : Stop the sequence(Use assigned of #STOPxx) - -11 to 19 : Object Channel of 1 player side -21 to 29 : Object Channel of 2 player side -31 to 39 : Can't show Object Channel of 1 player side -41 to 49 : Can't show Object Channel of 2 player side -51 to 59 : Long note Object Channel of 1 player side -61 to 69 : Long note Object Channel of 2 player side - - - -#00211:03030303 -This means 4 objects at the left of 1 player side in 002 track. -This object is assigned to wave No.03 which was defined by #WAV03 xxxx.wav. -And this 4 objects are arranged evenly in this track. - -Please try the following patterns. - -#00211:0303030303 - -#00211:0303000303 - -#00211:010101 -#00211:00020202 - -P.S. - -#00202:0.5 : Track2 have Half length. - - --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -This document and this format is free! -I hope the day will come when my BMS format will use all over the world. - +BMS Format Specification(Remake version.) +Written in June 28th 2003. + +original document written by Urao Yane. +edited by U(uhangel4u@yahoo.co.jp) + +"BMS" means a Be-Music Source file. A file which has BMS suffix is regarded as the BMS file. +This file format was produced by Urao Yane and NBK in 1998.and It revised sometime. +And I adopted this file format to BM98, Delight Delight Reduplication, MixWaver, nazoBMPlay and so on. +Now,anyone can use this format freely. + +BM98 Drink Edition +http://www5c.biglobe.ne.jp/~kbs/bm98/ (Japanese) +Delight Delight Reduplicaton +http://nickle.hey.to/ (Japanese) +MixWaver +http://hello.to/mixwaver/ (Korean) +nazoBMPlay +http://www.nothing.sh/nazobmplay/ (Japanese) + +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + + +The line begining at '#' is the command line. All the rest are ignored (use for comments). +And this BMS file is compiled at runtime , so you can order any lines freely. +And there is no difference in the command line between using a capital letter or not. + +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +
+ +#PLAYER [1-4] + +#PLAYER 1 +This data is for Single Play. +#PLAYER 2 +This data is for Two Players. +#PLAYER 3 +This data is for Double Play. +#PLAYER 4 +This data is for Two Players.(Players will plays same sequence) + +#GENRE xxxxxxxx +Definition of Genre. + +#TITLE xxxxxxxx +Definition of Title. + +#ARTIST xxxxxxxx +Definition of Artist. + +#BPM xxx +Definition of BPM.(Beats Per Minite) at the top of music. default : 130 value type : double. + +#MIDIFILE xxxxxxx.mid +Background music by MIDI.but,It's not recommend. + +#PLAYLEVEL x +Information of Game Level for player. + +#RANK [0-3] +judgement level. +x = 0 :very hard, 1: hard, 2: normal, 3: easy default : 2 + +#VOLWAV xxx +relative volume control (percentage) + +#TOTAL xxx +increments of Groove Gauge +ex. +#TOTAL 120 +It means when all sequence was played over great, Groove Gauge's value is 120% + +#WAVxx yyyyyyyy.wav(or .mp3) +definition of Wave Data. xx : 01 to FZ(01-09-0A-0Z-10-1Z...) , yyyyyyyy.wav : wave file name +When use mp3 files,you need mp3 CODEC. + +e.g. +#WAV01 HOUSE01.WAV // assign HOUSE01.WAV to 01 wav +#WAV02 HOUSE02.WAV // assign HOUSE02.WAV to 02 wav +#WAVFZ HOUSE03.mp3 // assign HOUSE03.mp3 to FZ wav + +#BMPxx yyyyyyyy.bmp(or gif,jpg,png) +definition of Bitmap file. xx : 01 to FF(Hex) , yyyyyyyy.bmp : bitmap file name +Bitmap size must be 256 * 256.(max color 65536) +If you use "gif or jpg or png", with Susie Plug-in. +gif : ifgif.spi jpg : ifjpg.spi png : ifpng.spi + +About Susie Plug-ins : http://www.digitalpad.co.jp/~takechin/ + +e.g. +#BMP01 HOUSE01.BMP // assign HOUSE01.BMP to 01 bitmap +#BMP02 HOUSE02.BMP // assign HOUSE02.BMP to 02 bitmap +#BMPEE HOUSE03.PNG // assign HOUSE03.PNG to EE bitmap + +#StageFile xxxx.bmp(or gif,jpg,png) +Show assigned Picture when loading bitmaps,wavs and compiling bms. + +#BPMxx yyy +Use to change BPM(Beats Per Minite). xx : 01 to ff(Hex) + +But ,the bitmap defined by #BMP00 is something special. +This bitmap shows when a player do a poor play. + +#STOPxx yyy +Use to stop sequence. xx : 01 to ff(Hex) +yyy : a quarter note = 48 + an eighth note = 24 + a whole note = 192 + note / n = 192/n + +#CDDA xx +Audio cds Track No. + +#BackBMP xxxx.bmp(or gif,jpg,png) +Set BackGround Picture.(size:640*480) + +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +// a sample of random loading function + +#random 2 // create a random number (1 or 2) + +#if 1 // if the number was equal to 1 then... +#00111:31313131 // this is effective... +#endif + +#if 2 // if the number was equal to 2 then... +#00113:32003232 // this is effective +#endif + +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + + +#aaabb:cccccccc + +aaa: track number (from 000 to 999) +bb : channel number where you want to send message.(from 00 to FF) +cccccccc : + + + +01 : BGM(background music by WAVE) +02 : shortening note. +03 : changing a Tempo[1-255] +04 : BGA(background animation) +06 : changing Poor-bitmap +07 : BGA Layer. +08 : Extended BPM(Use assigned of #BPMxx) +09 : Stop the sequence(Use assigned of #STOPxx) + +11 to 19 : Object Channel of 1 player side +21 to 29 : Object Channel of 2 player side +31 to 39 : Can't show Object Channel of 1 player side +41 to 49 : Can't show Object Channel of 2 player side +51 to 59 : Long note Object Channel of 1 player side +61 to 69 : Long note Object Channel of 2 player side + + + +#00211:03030303 +This means 4 objects at the left of 1 player side in 002 track. +This object is assigned to wave No.03 which was defined by #WAV03 xxxx.wav. +And this 4 objects are arranged evenly in this track. + +Please try the following patterns. + +#00211:0303030303 + +#00211:0303000303 + +#00211:010101 +#00211:00020202 + +P.S. + +#00202:0.5 : Track2 have Half length. + + +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +This document and this format is free! +I hope the day will come when my BMS format will use all over the world. + Urao Yane \ No newline at end of file diff --git a/Docs/SimfileFormats/KSF/ksf-format.txt b/Docs/SimfileFormats/KSF/ksf-format.txt index 4ad838f457..b52689280c 100644 --- a/Docs/SimfileFormats/KSF/ksf-format.txt +++ b/Docs/SimfileFormats/KSF/ksf-format.txt @@ -1,157 +1,157 @@ -Documentation on the KSF Format -------------------------------- -The KSF format is designed for representing steps for 5 panel diagonal -dancing games, such as Pump It Up. It was originally used in the Kick It Up -simulator, but can also be parsed by other programs. However, this seems -to be the only actual format description available. - -The intention of this document is not to encourage creation of KSF files. -I believe the format to be broken, and provide this reference only for -people wishing to implement legacy file readers. Any new 5 panel dancing -patterns should use a well-defined format such as .dance or .sm. - -Directory Layout ----------------- -KSF filenames are case-insensitive. - -A KSF directory contains the following files: - -- At least one file matching *.KSF, containing the step data. -- A file named SONG.MP3, SONG.WAV, or SONG.OGG. -- A file named INTRO.MP3, INTRO.WAV, or INTRO.OGG, containing a sound clip, - used to preview the song in song selectors. -- Disc.bmp, a 300x200 image used in song selectors. -- Back.bmp or Title.bmp, a 640x480 image used as a background during the song. - -KSF directories may not have a special naming format, but some simulators -will use the directory name to get the artist and title name, if it's not -available in the KSF files themseleves. The format is "Title", -"Title - Artist", or "Title - Artist - Difficulty". Difficulty can be -ignored here, as it can be gotten from the KSF filename. Using the path -name to determine the metadata for the song should only be used if it's -not available in #TITLE. - -Concievably other audio or image formats could be used. None have been -seen in the wild. - -KSF Filenames -------------- -KSF filenames describe the game type and difficulty. Each file holds the -data for only one level of difficulty. There are two possible forms of -the name: **.ksf, or *_*.ksf. - -The first type is used for double mode, and half-double mode. Double.ksf -contains the steps for "Double" mode, where one player uses both paths. -Stepmania supports Halfdouble.ksf, which ignores the outer 4 panels. - -The latter type is used for single ("unison", which is not the same -as Dance Dance Revolution's Unison mode in early mixes) steps, where both -players have the same steps, and couple steps, where players have different -ones. If the player number is 1, they are single steps; if it's 2, they're -couple steps. Difficulty is a difficulty name. - -KSF Headers ------------ -The basic KSF format is similar to DWI, SM, and MSD. Metadata is given -in the format of: -#TAGNAME:VALUE; - -The exception being the #STEPS tag, which has a newline between the ":" -and the first line of steps, and ends in "2222222222222" on a line by -itself instead of ";". - -KSF files seem to use CRLF (Windows-style) line termination. The vast -majority of KSF files are in CP942/KSC 5601 encoding, but some are -in EUC-KR. If ASCII alternatives are needed for these encodings, the -path name must be checked as above. - -Common headers in KSF files are as follows: - -#TITLE: The artist and title of the song, and sometimes the difficulty. -These are separated by " - "s, so the format is either "Title", -"Artist - Title", or "Artist - Title - Difficulty". Information missing -from this line can be filled in via path or file names. - -#BPM: The BPM of the song. This is analogous to the BPM value for every other -dance format. - -#STARTTIME: The time into the song to offset events, in centiseconds. This -is the opposite of .dance's gap and .sm's offset, and the same as .dwi's -gap (although they use different units). - -#TICKCOUNT: Each step line specifies 1/TICKCOUNT beats. That is, if -TICKCOUNT is 1, each line is the equivalent of a 'q' in .dance. If it's -2, each line is the same as a normal length note in DWI (an 'e' in .dance). - -#STEP: Until a line of "2222222222222" is encountered, each line after this -one represents a set of steps. - -Step Lines ----------- -Each line in the step section represents one "line" of steps, like SM -or .dance. Each line is 13 digits long; in single (unison) modes, only the -first 5 are used; in couple and double, the first 10 are used. - -The order of the steps is Down Left, Up Left, Center, Up Right, Down Right. -The second player's (or second pad in double) steps are the same order, -but in positions 6-10 instead of 1-5. - -A 0 in a position indicates no step. A 1 indicates a regular step. A 4 -indicates a hold, for as long as a 4 is found in that column. The hold -ends on the beat of the last 4, not on the first 0. - -Some files have been seen with repeated '1's in this manner as well; -it is unknown if any dance simulator supports this use of KSF, and since -a perfectly good non-ambiguous means of representing holds is available, -its use is not recommended. - -A 2 (or a line of 13 2s) indicates the end of the step pattern. - -BPM Changes ------------ -BPM changes are handled by header values; they are specified by a pair -of values #BPMx and #BUNKIx, where x is an integer. An example is: - -#BPM:146.10; -#BPM2:180.20; -#BPM3:195.00; -#TICKCOUNT:2; -#STARTTIME:0; -#BUNKI:4200; -#BUNKI2:10000; - -BPMn+1 starts at the time specified in centiseconds by BUNKIn (where n -is omitted if it is 1). In the above, 42 seconds (4200 centiseconds) -into the song, the BPM changes from its initial 146.1 to 180.2, and -then 100 seconds into the song, from 180.2 to 195. - -BUNKIs can be a decimal value. - -Syntax Exceptions ------------------ -Unlike DWI files, KSF files seem to have few exceptions or violations of -their syntax in the files seen in the wild. This may be because the format -is so mind-numbingly stupid. - -Still Unknown -------------- -Some files contain a #STARTTIMEx (like #BPMx or #BUNKIx). - -KSF step lines are 13 digits wide; only 10 digits appear to specify steps, -but the last 3 are not always 0. They probably represent something. - -Author ------- -This document was written by Joe Wreschnig . It is -released into the public domain. - -Changes -------- -2003.08.15 - - Initial check in / release. - -Acknowledgements ----------------- -This document is based primarily off of extensive work done by Matt Reppert. -The Stepmania KSF loader source code (src/NotesLoaderKSF.cpp) also proved -useful in verifying some information. +Documentation on the KSF Format +------------------------------- +The KSF format is designed for representing steps for 5 panel diagonal +dancing games, such as Pump It Up. It was originally used in the Kick It Up +simulator, but can also be parsed by other programs. However, this seems +to be the only actual format description available. + +The intention of this document is not to encourage creation of KSF files. +I believe the format to be broken, and provide this reference only for +people wishing to implement legacy file readers. Any new 5 panel dancing +patterns should use a well-defined format such as .dance or .sm. + +Directory Layout +---------------- +KSF filenames are case-insensitive. + +A KSF directory contains the following files: + +- At least one file matching *.KSF, containing the step data. +- A file named SONG.MP3, SONG.WAV, or SONG.OGG. +- A file named INTRO.MP3, INTRO.WAV, or INTRO.OGG, containing a sound clip, + used to preview the song in song selectors. +- Disc.bmp, a 300x200 image used in song selectors. +- Back.bmp or Title.bmp, a 640x480 image used as a background during the song. + +KSF directories may not have a special naming format, but some simulators +will use the directory name to get the artist and title name, if it's not +available in the KSF files themseleves. The format is "Title", +"Title - Artist", or "Title - Artist - Difficulty". Difficulty can be +ignored here, as it can be gotten from the KSF filename. Using the path +name to determine the metadata for the song should only be used if it's +not available in #TITLE. + +Concievably other audio or image formats could be used. None have been +seen in the wild. + +KSF Filenames +------------- +KSF filenames describe the game type and difficulty. Each file holds the +data for only one level of difficulty. There are two possible forms of +the name: **.ksf, or *_*.ksf. + +The first type is used for double mode, and half-double mode. Double.ksf +contains the steps for "Double" mode, where one player uses both paths. +Stepmania supports Halfdouble.ksf, which ignores the outer 4 panels. + +The latter type is used for single ("unison", which is not the same +as Dance Dance Revolution's Unison mode in early mixes) steps, where both +players have the same steps, and couple steps, where players have different +ones. If the player number is 1, they are single steps; if it's 2, they're +couple steps. Difficulty is a difficulty name. + +KSF Headers +----------- +The basic KSF format is similar to DWI, SM, and MSD. Metadata is given +in the format of: +#TAGNAME:VALUE; + +The exception being the #STEPS tag, which has a newline between the ":" +and the first line of steps, and ends in "2222222222222" on a line by +itself instead of ";". + +KSF files seem to use CRLF (Windows-style) line termination. The vast +majority of KSF files are in CP942/KSC 5601 encoding, but some are +in EUC-KR. If ASCII alternatives are needed for these encodings, the +path name must be checked as above. + +Common headers in KSF files are as follows: + +#TITLE: The artist and title of the song, and sometimes the difficulty. +These are separated by " - "s, so the format is either "Title", +"Artist - Title", or "Artist - Title - Difficulty". Information missing +from this line can be filled in via path or file names. + +#BPM: The BPM of the song. This is analogous to the BPM value for every other +dance format. + +#STARTTIME: The time into the song to offset events, in centiseconds. This +is the opposite of .dance's gap and .sm's offset, and the same as .dwi's +gap (although they use different units). + +#TICKCOUNT: Each step line specifies 1/TICKCOUNT beats. That is, if +TICKCOUNT is 1, each line is the equivalent of a 'q' in .dance. If it's +2, each line is the same as a normal length note in DWI (an 'e' in .dance). + +#STEP: Until a line of "2222222222222" is encountered, each line after this +one represents a set of steps. + +Step Lines +---------- +Each line in the step section represents one "line" of steps, like SM +or .dance. Each line is 13 digits long; in single (unison) modes, only the +first 5 are used; in couple and double, the first 10 are used. + +The order of the steps is Down Left, Up Left, Center, Up Right, Down Right. +The second player's (or second pad in double) steps are the same order, +but in positions 6-10 instead of 1-5. + +A 0 in a position indicates no step. A 1 indicates a regular step. A 4 +indicates a hold, for as long as a 4 is found in that column. The hold +ends on the beat of the last 4, not on the first 0. + +Some files have been seen with repeated '1's in this manner as well; +it is unknown if any dance simulator supports this use of KSF, and since +a perfectly good non-ambiguous means of representing holds is available, +its use is not recommended. + +A 2 (or a line of 13 2s) indicates the end of the step pattern. + +BPM Changes +----------- +BPM changes are handled by header values; they are specified by a pair +of values #BPMx and #BUNKIx, where x is an integer. An example is: + +#BPM:146.10; +#BPM2:180.20; +#BPM3:195.00; +#TICKCOUNT:2; +#STARTTIME:0; +#BUNKI:4200; +#BUNKI2:10000; + +BPMn+1 starts at the time specified in centiseconds by BUNKIn (where n +is omitted if it is 1). In the above, 42 seconds (4200 centiseconds) +into the song, the BPM changes from its initial 146.1 to 180.2, and +then 100 seconds into the song, from 180.2 to 195. + +BUNKIs can be a decimal value. + +Syntax Exceptions +----------------- +Unlike DWI files, KSF files seem to have few exceptions or violations of +their syntax in the files seen in the wild. This may be because the format +is so mind-numbingly stupid. + +Still Unknown +------------- +Some files contain a #STARTTIMEx (like #BPMx or #BUNKIx). + +KSF step lines are 13 digits wide; only 10 digits appear to specify steps, +but the last 3 are not always 0. They probably represent something. + +Author +------ +This document was written by Joe Wreschnig . It is +released into the public domain. + +Changes +------- +2003.08.15 + - Initial check in / release. + +Acknowledgements +---------------- +This document is based primarily off of extensive work done by Matt Reppert. +The Stepmania KSF loader source code (src/NotesLoaderKSF.cpp) also proved +useful in verifying some information. diff --git a/Docs/SimfileFormats/dance-spec.txt b/Docs/SimfileFormats/dance-spec.txt index a658d3947f..1d81fa4972 100644 --- a/Docs/SimfileFormats/dance-spec.txt +++ b/Docs/SimfileFormats/dance-spec.txt @@ -1,337 +1,337 @@ -The "Dance" Format ------------------- -The goals of this format are easy parsability, easy human readability, -brevity, and disambiguity. - -Generic Information -------------------- -All strings are case-sensitive. Filenames are case-sensitive. The -directory separator is '/' regardless of the platform. All text -is encoded in UTF-8. Byte-order marking is not allowed. - -Enhanced Backus-Naur Form (ENBF) Specification ----------------------------------------------- -This is purely the grammar. A semantic explanation is below. - -Although this is given as a CFG specification, .dance is designed to be -parsed by a table-based DFA (as in pydance's fileparsers.py) - -Primitives: - ::= a sequence of characters - ::= 0.0 to Inf, decimal value - ::= 0 | -1 | -2 | -3 ... - ::= 0 | 1 | 2 | 3 ... - -Almost primitives: - ::= (" " | "\t")+ - ::= "\n" | "\r\n" | "\r" - ::= ( )* - ::= "end" - ::= | - ::= [("#" ) | ] - -Basic Structure: - ::= [+] + - -Metadata Storage: - ::= ( | )+ - ::= ( | | <Subtitle> | <Artist> | <Mix> | - <BPM> | <Offset> | <BG> | <Banner> | <Preview> | - <Checksum> | <StartAt> | <EndAt> | <Author> | <CDTitle> | - <RevisionDate> | <Valid> | <Movie>) <Newline> -<Filename> ::= "filename" <Whitespace> <LongString> -<Title> ::= "title" <Whitespace> <LongString> -<Subtitle> ::= "subtitle" <Whitespace> <LongString> -<Artist> ::= "artist" <Whitespace> <LongString> -<Mix> ::= "mix" <Whitespace> <LongString> -<BPM> ::= "bpm" <Whitespace> <Float> -<BPMDisplay> :: "bpmdisplay" ((<Whitespace> <Float>)+ | "*") -<Gap> ::= "gap" <Whitespace> <Int> -<StartAt> ::= "startat" <Whitespace> <Float> -<EndAt> ::= "endat" <Whitespace> <Float> -<BG> ::= "background" <Whitespace> <LongString> -<Banner> ::= "banner" <Whitespace> <LongString> -<Banner> ::= "cdtitle" <Whitespace> <LongString> -<Preview> :: "preview" <Whitespace> <Float> <Whitespace> <Float> -<Checksum> ::= "md5sum" <Whitespace> <String> -<Author> ::= "author" <Whitespace> <LongString> -<Movie> ::= "movie" <Whitespace> <LongString> -<RevisionDate> ::= "revision" <Whitespace> <LongString> -<Valid> ::= "valid" <Whitespace> 1 | 0 - -Text Sections: -<TextSection> ::= [<Description>] [<Lyrics>] -<Lyrics> ::= "LYRICS" <Newline> (<LyricLine>)+ <EndToken> -<LyricLine> ::= <Float> <Whitespace> <PosInt> <Whitespace> <LongString> <Newline> -<Description> ::= "DESCRIPTION" <Newline> (<LongString> <Newline>)+ <EndToken> - -Step Sections: -<StepSection> ::= <GameMode> <Difficulty> <Sequence>+ <EndToken> -<GameMode> ::= <String> <Newline> -<Difficulty> ::= <String> <Whitespace> <PosInt> <Newline> -<Sequence> ::= (<Comment> | <Buttons> | <Command>) <Newline> - -Note Sequences: -<Buttons> ::= <NoteType> (<Whitespace> <ButtonPresses>)+ -<NoteType> ::= "u" | "n" | "x" | "t" | "f" | "s" | "w" | "e" | "q" | "h" | "o" -<ButtonPresses> ::= (0 | 1 | 3 | 5 | 7)+ - -Song Commands: -<Command> ::= <ChangeBPM> | <Ready> | <Wait> | <Stop> | <Delay> | <Lyric> -<ChangeBPM> ::= "B" <Whitespace> <Float> -<Ready> ::= "R" -<Wait> ::= "W" <Whitespace> <Float> -<Stop> ::= "S" <Whitespace> <Float> -<Delay> ::= "D" <Whitespace> <Float> -<Lyric> ::= "L" <Whitespace> <Float> <Whitespace> <PosInt> <Whitespace> - <LongString> - -Informal & Semantic Description -------------------------------- -The dance format is basically the step format, but generalized, smaller, -and more readable. A script to convert .step files to .dance files is -forthcoming. - -A simple file might look like: - -filename asong.ogg -title A Song -subtitle Crazy Mix -artist Someone -# This is a comment -end -DESCRIPTION - This is an example song. - It's pretty uninteresting. -end -SINGLE -BASIC 0 -q 1010 -# This is another comment. -q 0101 -q 3030 -q 1010 -end - -Metadata Section: - -The metadata section of the song is the first section, and contains -important data about the file. An explanation of the keys follow: - -'filename': The filename of the audio file to play. - -'title': The name of the song. This should not include "Foo Mix". - -'subtitle': "Foo Mix", "Crazy Version", whatever. Default none. - -'artist': The name of the artist(s) and any remixers. - -'bpm': The beats per minute of the song. - -'gap': The millisecond offset into the song at which the arrows should - start. If the first beat is 0.3 seconds into the song, for example, - this should be -300. This can be negative. Default 0. - -'bpmdisplay': A whitespace-separated list of floats, which will be - cycled through on the song selector's BPM display. If - not present this defaults to the BPM if the song. If "*", - the BPM is displayed as constantly changing. - -'background': A background image (to display while the song is playing). - Default none. - -'banner': A banner for the song (to display in the song select). Default none. - -'cdtitle': A small (64x40) image to use as a CD title. Default none. This - path should either be relative to a special CD title directory, - or to the directory the file is in. - -'preview': An offset to seconds to start a song preview at, and a length to - play the preview. Default 45.0 and 10.0. - -'startat', 'endat': Start and end the music at these positions in seconds. - offset and the steps are then relative to the startat - position. Default 0.0 and the length of the song. - -'md5sum': If present, the MD5 checksum of the 'filename' file. If it's - present and the file doesn't match, a warning can be issued. - -'author': The person who wrote this file. Default none. - -'revision': The date of the last revision of this file, in YYYY.MM.DD format. - Defaults to "1970.01.01". - -'movie': The filename of a background movie; defaults to none. - -'valid': If not true, this song should be not selected using in random play - modes (e.g., it's not finished, hasn't been timed, etc). Default 1. - -The 'filename', 'title', 'artist', and 'bpm' keys are mandatory. - -Note that songs in this format will *NOT* have any files autodetected. If -you want them to be found, explicitly state them in the file. - -The metadata section, like all sections, must end with "end" on a line -by itself. - -Text Sections: - -There are two "text" sections in dance files; these are essentially -extended metadata sections. - -The DESCRIPTION section contains a description of the song. The format -roughly follows the DPKG description format: All lines of text start -with a space. Whitespace, including newlines, is ignored. A period ('.') -on a line by itself (with a space before it!) is to be interpreted as a -paragraph separator. An 'end' token on a single line, with no space before -it, ends the description. - -The LYRICS section contains lyric timing information. The format -of each line is, an integer, a float, and then a string. The integer -specifies the lyric "channel"; lyrics in the same channel should overwrite -each other, appear in the same place on the screen, etc. The float is the -time into the song during which the lyric should appear, irrespective -of the 'gap' value. - -Step Sections: - -The meat of the file is in the step sections, which actually describe -the game-related stuff. A step section is started as soon as an unknown -section token is encounter (i.e. currently not LYRICS or DESCRIPTION). -This first token is then taken as the "game mode". The two tokens on the -next line are the difficulty name and rating number. - -Then, until the "end" token, there are lines describing the steps. These -may be either a command, or a set of buttons to press. The "base" is 'q', -the quarter note, which represents one beat in the song. - -o Whole note (4 on-beat arrows) -h 1/2 note -q 1/4 note -e 1/8 note -w 1/12 note -s 1/16 note -f 1/24 note -t 1/32 note -u 1/48 note -x 1/64 note -n 1/192 note - -After the note comes a string of buttons. All these strings should be -the same length across game modes. Example strings might "1001" or "0030". - -0 No button at this time -1 A regular press at this time -3 This button must be pressed here and held down until a 1 is encounted -5 A secret step at this time. -7 A secret step and hold at this time. - -(Note - With bitwise &, - num & 1 => pressed here, - num & 2 => hold here, - num & 4 => this is a secret note. - -This correspondance is not necesarily guaranateed to be true for all -future additions to the .dance format, but will be maintained if possible.) - -Possible commands are: - -B <Float> Change the BPM of the song to this number at this point. -R "Ready? Go!" graphics/sound, if any. -W <Float> Wait this many seconds before the next event. -S <Float> Stop scrolling for this many seconds before the next event. -D <Float> The same as a sequence of 0 note strings for this many beats. -L <PosInt> <LongString> Display some lyrics at this point. - -Failing Gracefully ------------------- -Often, your parsers may come across tokens they don't know; maybe because -someone made an invalid file, or because the parser doesn't support all -of this format (or an old version of this format). If this is a section -token, this isn't a big problem; jump to the next end token and keep -going. Metadata tokens are equally easy to skip. - -Tokens in steps are more complicated. In general, you should treat -them as comments, treat unknown note types as 0s, and hope for the -best. - -Bad files shouldn't make your parser crash. It should return an error to -the program, which behaves accordingly. - -Future Extensions ------------------ -If this format is found to be inadaquate, the following extensions -may be added: - -New metadata keys. This would be a new line in the metadata section. -It is unlikely such a line would be mandatory, since current songs -work fine without them. - -New note types and commands. These would be new lowercase or uppercase -single characters in the song section. - -Standard Game Modes -------------------- -SINGLE - Normal single player with up, down, left, and right, or versus - mode, if no VERSUS is found. -VERSUS - Two players, both with the same steps. -COUPLE - Two players with different steps. -DOUBLE - Doubles, one player on both pads. - -5PANEL - Diagonal directions, and the center, for one player. -5VERSUS, 5COUPLE, 5DOUBLE - Similar to the 4 panel relationships. - -6PANEL, 6VERSUS, 6DOUBLE, 6COUPLE: Up left, up right, up, down, left, - and right. -8PANEL, etc: All directions except center. -9PANEL, etc: All directions including center. -3PANEL, etc: Up left, down, and up right. - -Changes: --------- -2004.03.01 - - Version 1.2, released with pydance 1.0. - - Add 9 panel game mode. - -2004.01.16 - - Include comments in the example. - -2003.12.23 - - 3 panel modes. - - bpmdisplay metadata key. - -2003.12.22 - - 'cdtitle' metadata line. - -2003.08.15 - - Specify note types more exactly. - - Fix the broken DESCRIPTION in the example. - - Remove obsolete notes about the pydance implementation. - - Add more game modes to the list (especially of note is VERSUS). - -2003.07.30 - - Fix example of 'gap' attribute (-300 instead of 300). - - Fix nonsensical hold arrow example. - -2003.06.29 - - Fix a typo ("::" => "::="). - -2003.06.27 - - Add EBNF for COUPLE-style modes (spaces in Buttons) - -2003.06.26 - - Add a missing newline to LyricLine. - - Add (currently unexplained) BACKGROUNDS section. - -2003.06.03 - - Version 1.1 - - Add 192nd notes with 'n', 48th with 'u'. - -2003.06.01 - - Version 1.0 - - No more I command. - -2003.05.23: - - Started changes. - - v1.0 draft preparation. - - Need to explain the I command. +The "Dance" Format +------------------ +The goals of this format are easy parsability, easy human readability, +brevity, and disambiguity. + +Generic Information +------------------- +All strings are case-sensitive. Filenames are case-sensitive. The +directory separator is '/' regardless of the platform. All text +is encoded in UTF-8. Byte-order marking is not allowed. + +Enhanced Backus-Naur Form (ENBF) Specification +---------------------------------------------- +This is purely the grammar. A semantic explanation is below. + +Although this is given as a CFG specification, .dance is designed to be +parsed by a table-based DFA (as in pydance's fileparsers.py) + +Primitives: +<String> ::= a sequence of characters +<Float> ::= 0.0 to Inf, decimal value +<NegInt> ::= 0 | -1 | -2 | -3 ... +<PosInt> ::= 0 | 1 | 2 | 3 ... + +Almost primitives: +<Whitespace> ::= (" " | "\t")+ +<Newline> ::= "\n" | "\r\n" | "\r" +<LongString> ::= <String> (<Whitespace> <String>)* +<EndToken> ::= "end" <Newline> +<Int> ::= <NegInt> | <PosInt> +<Comment> ::= [("#" <LongString>) | <Whitespace>] <Newline> + +Basic Structure: +<File> ::= <Metadata> [<TextSection>+] <StepSection>+ + +Metadata Storage: +<Metadata> ::= (<Comment> | <MetadataLine>)+ <EndToken> +<MetadataLine> ::= (<Filename> | <Title> | <Subtitle> | <Artist> | <Mix> | + <BPM> | <Offset> | <BG> | <Banner> | <Preview> | + <Checksum> | <StartAt> | <EndAt> | <Author> | <CDTitle> | + <RevisionDate> | <Valid> | <Movie>) <Newline> +<Filename> ::= "filename" <Whitespace> <LongString> +<Title> ::= "title" <Whitespace> <LongString> +<Subtitle> ::= "subtitle" <Whitespace> <LongString> +<Artist> ::= "artist" <Whitespace> <LongString> +<Mix> ::= "mix" <Whitespace> <LongString> +<BPM> ::= "bpm" <Whitespace> <Float> +<BPMDisplay> :: "bpmdisplay" ((<Whitespace> <Float>)+ | "*") +<Gap> ::= "gap" <Whitespace> <Int> +<StartAt> ::= "startat" <Whitespace> <Float> +<EndAt> ::= "endat" <Whitespace> <Float> +<BG> ::= "background" <Whitespace> <LongString> +<Banner> ::= "banner" <Whitespace> <LongString> +<Banner> ::= "cdtitle" <Whitespace> <LongString> +<Preview> :: "preview" <Whitespace> <Float> <Whitespace> <Float> +<Checksum> ::= "md5sum" <Whitespace> <String> +<Author> ::= "author" <Whitespace> <LongString> +<Movie> ::= "movie" <Whitespace> <LongString> +<RevisionDate> ::= "revision" <Whitespace> <LongString> +<Valid> ::= "valid" <Whitespace> 1 | 0 + +Text Sections: +<TextSection> ::= [<Description>] [<Lyrics>] +<Lyrics> ::= "LYRICS" <Newline> (<LyricLine>)+ <EndToken> +<LyricLine> ::= <Float> <Whitespace> <PosInt> <Whitespace> <LongString> <Newline> +<Description> ::= "DESCRIPTION" <Newline> (<LongString> <Newline>)+ <EndToken> + +Step Sections: +<StepSection> ::= <GameMode> <Difficulty> <Sequence>+ <EndToken> +<GameMode> ::= <String> <Newline> +<Difficulty> ::= <String> <Whitespace> <PosInt> <Newline> +<Sequence> ::= (<Comment> | <Buttons> | <Command>) <Newline> + +Note Sequences: +<Buttons> ::= <NoteType> (<Whitespace> <ButtonPresses>)+ +<NoteType> ::= "u" | "n" | "x" | "t" | "f" | "s" | "w" | "e" | "q" | "h" | "o" +<ButtonPresses> ::= (0 | 1 | 3 | 5 | 7)+ + +Song Commands: +<Command> ::= <ChangeBPM> | <Ready> | <Wait> | <Stop> | <Delay> | <Lyric> +<ChangeBPM> ::= "B" <Whitespace> <Float> +<Ready> ::= "R" +<Wait> ::= "W" <Whitespace> <Float> +<Stop> ::= "S" <Whitespace> <Float> +<Delay> ::= "D" <Whitespace> <Float> +<Lyric> ::= "L" <Whitespace> <Float> <Whitespace> <PosInt> <Whitespace> + <LongString> + +Informal & Semantic Description +------------------------------- +The dance format is basically the step format, but generalized, smaller, +and more readable. A script to convert .step files to .dance files is +forthcoming. + +A simple file might look like: + +filename asong.ogg +title A Song +subtitle Crazy Mix +artist Someone +# This is a comment +end +DESCRIPTION + This is an example song. + It's pretty uninteresting. +end +SINGLE +BASIC 0 +q 1010 +# This is another comment. +q 0101 +q 3030 +q 1010 +end + +Metadata Section: + +The metadata section of the song is the first section, and contains +important data about the file. An explanation of the keys follow: + +'filename': The filename of the audio file to play. + +'title': The name of the song. This should not include "Foo Mix". + +'subtitle': "Foo Mix", "Crazy Version", whatever. Default none. + +'artist': The name of the artist(s) and any remixers. + +'bpm': The beats per minute of the song. + +'gap': The millisecond offset into the song at which the arrows should + start. If the first beat is 0.3 seconds into the song, for example, + this should be -300. This can be negative. Default 0. + +'bpmdisplay': A whitespace-separated list of floats, which will be + cycled through on the song selector's BPM display. If + not present this defaults to the BPM if the song. If "*", + the BPM is displayed as constantly changing. + +'background': A background image (to display while the song is playing). + Default none. + +'banner': A banner for the song (to display in the song select). Default none. + +'cdtitle': A small (64x40) image to use as a CD title. Default none. This + path should either be relative to a special CD title directory, + or to the directory the file is in. + +'preview': An offset to seconds to start a song preview at, and a length to + play the preview. Default 45.0 and 10.0. + +'startat', 'endat': Start and end the music at these positions in seconds. + offset and the steps are then relative to the startat + position. Default 0.0 and the length of the song. + +'md5sum': If present, the MD5 checksum of the 'filename' file. If it's + present and the file doesn't match, a warning can be issued. + +'author': The person who wrote this file. Default none. + +'revision': The date of the last revision of this file, in YYYY.MM.DD format. + Defaults to "1970.01.01". + +'movie': The filename of a background movie; defaults to none. + +'valid': If not true, this song should be not selected using in random play + modes (e.g., it's not finished, hasn't been timed, etc). Default 1. + +The 'filename', 'title', 'artist', and 'bpm' keys are mandatory. + +Note that songs in this format will *NOT* have any files autodetected. If +you want them to be found, explicitly state them in the file. + +The metadata section, like all sections, must end with "end" on a line +by itself. + +Text Sections: + +There are two "text" sections in dance files; these are essentially +extended metadata sections. + +The DESCRIPTION section contains a description of the song. The format +roughly follows the DPKG description format: All lines of text start +with a space. Whitespace, including newlines, is ignored. A period ('.') +on a line by itself (with a space before it!) is to be interpreted as a +paragraph separator. An 'end' token on a single line, with no space before +it, ends the description. + +The LYRICS section contains lyric timing information. The format +of each line is, an integer, a float, and then a string. The integer +specifies the lyric "channel"; lyrics in the same channel should overwrite +each other, appear in the same place on the screen, etc. The float is the +time into the song during which the lyric should appear, irrespective +of the 'gap' value. + +Step Sections: + +The meat of the file is in the step sections, which actually describe +the game-related stuff. A step section is started as soon as an unknown +section token is encounter (i.e. currently not LYRICS or DESCRIPTION). +This first token is then taken as the "game mode". The two tokens on the +next line are the difficulty name and rating number. + +Then, until the "end" token, there are lines describing the steps. These +may be either a command, or a set of buttons to press. The "base" is 'q', +the quarter note, which represents one beat in the song. + +o Whole note (4 on-beat arrows) +h 1/2 note +q 1/4 note +e 1/8 note +w 1/12 note +s 1/16 note +f 1/24 note +t 1/32 note +u 1/48 note +x 1/64 note +n 1/192 note + +After the note comes a string of buttons. All these strings should be +the same length across game modes. Example strings might "1001" or "0030". + +0 No button at this time +1 A regular press at this time +3 This button must be pressed here and held down until a 1 is encounted +5 A secret step at this time. +7 A secret step and hold at this time. + +(Note - With bitwise &, + num & 1 => pressed here, + num & 2 => hold here, + num & 4 => this is a secret note. + +This correspondance is not necesarily guaranateed to be true for all +future additions to the .dance format, but will be maintained if possible.) + +Possible commands are: + +B <Float> Change the BPM of the song to this number at this point. +R "Ready? Go!" graphics/sound, if any. +W <Float> Wait this many seconds before the next event. +S <Float> Stop scrolling for this many seconds before the next event. +D <Float> The same as a sequence of 0 note strings for this many beats. +L <PosInt> <LongString> Display some lyrics at this point. + +Failing Gracefully +------------------ +Often, your parsers may come across tokens they don't know; maybe because +someone made an invalid file, or because the parser doesn't support all +of this format (or an old version of this format). If this is a section +token, this isn't a big problem; jump to the next end token and keep +going. Metadata tokens are equally easy to skip. + +Tokens in steps are more complicated. In general, you should treat +them as comments, treat unknown note types as 0s, and hope for the +best. + +Bad files shouldn't make your parser crash. It should return an error to +the program, which behaves accordingly. + +Future Extensions +----------------- +If this format is found to be inadaquate, the following extensions +may be added: + +New metadata keys. This would be a new line in the metadata section. +It is unlikely such a line would be mandatory, since current songs +work fine without them. + +New note types and commands. These would be new lowercase or uppercase +single characters in the song section. + +Standard Game Modes +------------------- +SINGLE - Normal single player with up, down, left, and right, or versus + mode, if no VERSUS is found. +VERSUS - Two players, both with the same steps. +COUPLE - Two players with different steps. +DOUBLE - Doubles, one player on both pads. + +5PANEL - Diagonal directions, and the center, for one player. +5VERSUS, 5COUPLE, 5DOUBLE - Similar to the 4 panel relationships. + +6PANEL, 6VERSUS, 6DOUBLE, 6COUPLE: Up left, up right, up, down, left, + and right. +8PANEL, etc: All directions except center. +9PANEL, etc: All directions including center. +3PANEL, etc: Up left, down, and up right. + +Changes: +-------- +2004.03.01 + - Version 1.2, released with pydance 1.0. + - Add 9 panel game mode. + +2004.01.16 + - Include comments in the example. + +2003.12.23 + - 3 panel modes. + - bpmdisplay metadata key. + +2003.12.22 + - 'cdtitle' metadata line. + +2003.08.15 + - Specify note types more exactly. + - Fix the broken DESCRIPTION in the example. + - Remove obsolete notes about the pydance implementation. + - Add more game modes to the list (especially of note is VERSUS). + +2003.07.30 + - Fix example of 'gap' attribute (-300 instead of 300). + - Fix nonsensical hold arrow example. + +2003.06.29 + - Fix a typo ("::" => "::="). + +2003.06.27 + - Add EBNF for COUPLE-style modes (spaces in Buttons) + +2003.06.26 + - Add a missing newline to LyricLine. + - Add (currently unexplained) BACKGROUNDS section. + +2003.06.03 + - Version 1.1 + - Add 192nd notes with 'n', 48th with 'u'. + +2003.06.01 + - Version 1.0 + - No more I command. + +2003.05.23: + - Started changes. + - v1.0 draft preparation. + - Need to explain the I command. diff --git a/Docs/Themerdocs/ThemePrefs.txt b/Docs/Themerdocs/ThemePrefs.txt index d0307503ba..f9f60a3a19 100644 --- a/Docs/Themerdocs/ThemePrefs.txt +++ b/Docs/Themerdocs/ThemePrefs.txt @@ -1,88 +1,88 @@ -ThemePrefs, v0.7 ----------------- - -ThemePrefs is a system for handling theme-specific preferences in a standard, -efficient, and predictable way. All you do, basically, is declare a table of -preferences and options and use GetThemePref(name) to get your preference -values as needed. This system will handle all disk I/O as well. - -Additionally, it can work in combination with ThemePrefsRows to generate -OptionsRows for all preferences, saving you (most of) the trouble with -integrating it into your theme. More on that later. - -The prefs are written, using IniFile, into Save/ThemePrefs.ini, written under -the section corresponding to your theme name (if ThemeInfo exists, it will -use the Name field listed there; otherwise, it will use the folder name). - ----------------------- -Section 1: Declaration ----------------------- - -To declare preferences for your theme to use, make a table with named -tables in it; its name is used for the preference, and the tables hold -the options for that preference. All you need to know for now is that -Default is required; for more options, check ThemePrefsRows. - -After the table is declared, pass it to the function ThemePrefs.InitAll(). -(If you're planning not to use any OptionsRows at all, you can just use -ThemePrefs.Init() to save some processing time, but seriously give the -ThemePrefsRows system a look before you disregard it.) - -[code] -local Prefs = -{ - BoolPref = { Default = false }, - IntPref = { Default = 3 }, -} - -ThemePrefs.InitAll( Prefs ) -[/code] - -If your theme is "default", this will generate a ThemePrefs.ini like so: - -[default] -BoolPref=false -IntPref=3 - ----------------- -Section 2: Usage ----------------- - -You can access the value with ThemePrefs.Get(name) or GetThemePref(name): -both calls work identically. The return type will be based on whatever you set -it to, but the subsystem will always try number, then bool, then string, in -that order. Use true and false for bools, not 1 and 0. - -For example, if you wanted to branch something in the metrics based on -the value of BoolPref (which is a boolean), you could use the following: - -NextScreen=GetThemePref('BoolPref') and "ScreenTrue" or "ScreenFalse" - -If you want to set a preference value for some reason, you can use either -ThemePrefs.Set(name, value) or SetThemePref(name, value), but the point of -this API is to simplify and standardize prefs handling, so you really should -not need it. (Use ThemePrefsRows instead.) - ------------------------ -Section 3: Localization ------------------------ - -ThemePrefs has two strings that can be localized, to be placed under -[ThemePrefs] in the appropriate language INI. - -IniFileMissing - displayed when IniFile.lua is not found, which means - ThemePrefs cannot be loaded from or written to disk - -UnknownPreference - displayed when an attempt is made to read or write - a preference that does not exist in the system. Uses %s for the - name of the unknown preference. - ---------------------- -Section 4: Disclaimer ---------------------- - -Though this is working fine so far, it is still experimental! If you run -into problems, or have suggestions, comments, questions, etc., please talk -to "vyhd" in #sm-ssc on irc.badnik.net, as it's his code to maintain; he -hates subjecting other people to his code (and occasionally vice versa), -but will gladly address concerns that come up. +ThemePrefs, v0.7 +---------------- + +ThemePrefs is a system for handling theme-specific preferences in a standard, +efficient, and predictable way. All you do, basically, is declare a table of +preferences and options and use GetThemePref(name) to get your preference +values as needed. This system will handle all disk I/O as well. + +Additionally, it can work in combination with ThemePrefsRows to generate +OptionsRows for all preferences, saving you (most of) the trouble with +integrating it into your theme. More on that later. + +The prefs are written, using IniFile, into Save/ThemePrefs.ini, written under +the section corresponding to your theme name (if ThemeInfo exists, it will +use the Name field listed there; otherwise, it will use the folder name). + +---------------------- +Section 1: Declaration +---------------------- + +To declare preferences for your theme to use, make a table with named +tables in it; its name is used for the preference, and the tables hold +the options for that preference. All you need to know for now is that +Default is required; for more options, check ThemePrefsRows. + +After the table is declared, pass it to the function ThemePrefs.InitAll(). +(If you're planning not to use any OptionsRows at all, you can just use +ThemePrefs.Init() to save some processing time, but seriously give the +ThemePrefsRows system a look before you disregard it.) + +[code] +local Prefs = +{ + BoolPref = { Default = false }, + IntPref = { Default = 3 }, +} + +ThemePrefs.InitAll( Prefs ) +[/code] + +If your theme is "default", this will generate a ThemePrefs.ini like so: + +[default] +BoolPref=false +IntPref=3 + +---------------- +Section 2: Usage +---------------- + +You can access the value with ThemePrefs.Get(name) or GetThemePref(name): +both calls work identically. The return type will be based on whatever you set +it to, but the subsystem will always try number, then bool, then string, in +that order. Use true and false for bools, not 1 and 0. + +For example, if you wanted to branch something in the metrics based on +the value of BoolPref (which is a boolean), you could use the following: + +NextScreen=GetThemePref('BoolPref') and "ScreenTrue" or "ScreenFalse" + +If you want to set a preference value for some reason, you can use either +ThemePrefs.Set(name, value) or SetThemePref(name, value), but the point of +this API is to simplify and standardize prefs handling, so you really should +not need it. (Use ThemePrefsRows instead.) + +----------------------- +Section 3: Localization +----------------------- + +ThemePrefs has two strings that can be localized, to be placed under +[ThemePrefs] in the appropriate language INI. + +IniFileMissing - displayed when IniFile.lua is not found, which means + ThemePrefs cannot be loaded from or written to disk + +UnknownPreference - displayed when an attempt is made to read or write + a preference that does not exist in the system. Uses %s for the + name of the unknown preference. + +--------------------- +Section 4: Disclaimer +--------------------- + +Though this is working fine so far, it is still experimental! If you run +into problems, or have suggestions, comments, questions, etc., please talk +to "vyhd" in #sm-ssc on irc.badnik.net, as it's his code to maintain; he +hates subjecting other people to his code (and occasionally vice versa), +but will gladly address concerns that come up. diff --git a/Docs/Themerdocs/ThemePrefsRows.txt b/Docs/Themerdocs/ThemePrefsRows.txt index 42a9d6bf14..750843d798 100644 --- a/Docs/Themerdocs/ThemePrefsRows.txt +++ b/Docs/Themerdocs/ThemePrefsRows.txt @@ -1,145 +1,145 @@ -ThemePrefsRows, v0.5 --------------------- - -ThemePrefsRows is an optional system that works with ThemePrefs to generate -Lua-based OptionsRows for every preference used in the system. All you do is -declare a table of preferences and pass it to ThemePrefs.InitAll(), which will -also initialize ThemePrefs. Note that you do need to add an entry for each -preference in [OptionTitles] and [OptionExplanations] to give the row its name -and describe what it does; I hope to find a (clean) way to do it from Lua. - ----------------------- -Section 1: Declaration ----------------------- - -Declaring preferences is the same basic concept as ThemePrefs; see that doc -for the basics. So I'll go into the stuff that's important to this API. - -As mentioned in ThemePrefs, the table contains options. The possible options -and their types are outlaid here. (The pref's type is defined by Default.) - -Default: whatever the value is set to by default. For sanity's sake, you - should have this in your Choices table. - -Choices (table): an indexed array containing all the possible OptionsRow - choices. If you're using a Values table, the array values should be - strings. If not, you can use any type that can cast to a string. - -Values (table): indexed array of the pref's type containing the value used when - the Choices entry with the same index is chosen in the row. If that - confused you, don't worry: it'll make more sense in the example. - This is optional, if your pref type can cast to strings. - -Params (table): optional modifications to the OptionsRow. I'll cover this in - more detail in a later section. You probably won't need it. - -To make this clearer, have an example of a valid prefs table: - -[code] -local prefs = -{ - BoolPref = - { - Default = false, - Choices = { "On", "Off" }, - Values = { true, false }, - }, - - IntPref = - { - Default = 3, - Choices = { 1, 2, 3, 4, 5 }, - Params = { SelectType = "ShowOneInRow" } - } -} - -ThemePrefs.InitAll( prefs ) -[/code] - -So when "On" is selected, BoolPref will be set to true, and selecting "Off" -will set it false. Simple enough, yeah? This will scale to any type you like. -Enumerations, strings, whatever. - ------------------ -Section 2: Params ------------------ - -We did promise a more in-depth look at Params, so here it is. - -The following arguments and values are currently accepted for Params: - -LayoutType (string): "ShowAllInRow" (default), "ShowOneInRow". - -ExportOnChange (bool): currently disabled in the source, but available to - set in case it's enabled later. If true, the Save function (which - handles actually setting the preference) is called whenever a value - is changed rather than when the screen changes. - -EnabledForPlayers (function): has 'self' as an argument, returns a table of - PlayerNumbers who are allowed to select stuff. Not important yet. - -ReloadRowMessages (table): contains an indexed array of strings. Whenever - any of the messages in this table are broadcast, the Load function - (which loads the list of possible options and sets the selected - value/s) is called again. - -LoadSelections (function): takes self, list, pn, overrides the default - function. This is advanced usage, so you should probably know - what you're doing to use it. Probably unnecessary. - -SaveSelections (function): takes self, list, pn, and overrides the default - function. This is advanced as well, for the same reasons. Fortunately, - you probably won't need it. - ----------------- -Section 3: Usage ----------------- - -To get the OptionsRow for the preference you want, use ThemePrefRow(name) -or ThemePrefsRows.GetRow(name); they're the same function. You'd use this -as, for example in the metrics: - -Line1="lua,ThemePrefRow('BoolPref')" - -Unfortunately, you do need to do some more work with the Language INIs too. -For each declared preference, you need an entry under [OptionTitles] for its -title and an entry under [OptionExplanations] for its description. The key for -both is the name of the preference. With the above example, that'd be e.g. - -[OptionTitles] -(...) -BoolPref=BoolPref -IntPref=IntPref - -[OptionExplanations] -(...) -BoolPref=Toggles a simple boolean preference between true and false. -IntPref=Sets an integer value between 1 and 5. - ------------------------ -Section 4: Localization ------------------------ - -ThemePrefsRows has three themable strings: - -NoDefaultInValues - if the default value isn't actually in choices or values, - this is displayed. Takes %s for the affected preference's name. - -TypeMismatch - if the default type and a value type mismatch, this is shown. - Takes %s, %d, and %s for the default's type, the index of the - mismatching value, and the value's type respectively. - -ChoicesSizeMismatch - if the Choices and Values arrays have different - lengths, this is displayed. Takes %d and %d for the size of - Choices and Values, respectively. - ---------------------- -Section 5: Disclaimer ---------------------- - -This isn't as tested as I'd like. For this version, it remains experimental. -Quite experimental. If you run into problems, please let me know so I can -fix them. - -Please direct all questions, comments, complaints, bug reports, etc. to "vyhd" -in #sm-ssc on irc.badnik.net or whatever other form of communication you like. +ThemePrefsRows, v0.5 +-------------------- + +ThemePrefsRows is an optional system that works with ThemePrefs to generate +Lua-based OptionsRows for every preference used in the system. All you do is +declare a table of preferences and pass it to ThemePrefs.InitAll(), which will +also initialize ThemePrefs. Note that you do need to add an entry for each +preference in [OptionTitles] and [OptionExplanations] to give the row its name +and describe what it does; I hope to find a (clean) way to do it from Lua. + +---------------------- +Section 1: Declaration +---------------------- + +Declaring preferences is the same basic concept as ThemePrefs; see that doc +for the basics. So I'll go into the stuff that's important to this API. + +As mentioned in ThemePrefs, the table contains options. The possible options +and their types are outlaid here. (The pref's type is defined by Default.) + +Default: whatever the value is set to by default. For sanity's sake, you + should have this in your Choices table. + +Choices (table): an indexed array containing all the possible OptionsRow + choices. If you're using a Values table, the array values should be + strings. If not, you can use any type that can cast to a string. + +Values (table): indexed array of the pref's type containing the value used when + the Choices entry with the same index is chosen in the row. If that + confused you, don't worry: it'll make more sense in the example. + This is optional, if your pref type can cast to strings. + +Params (table): optional modifications to the OptionsRow. I'll cover this in + more detail in a later section. You probably won't need it. + +To make this clearer, have an example of a valid prefs table: + +[code] +local prefs = +{ + BoolPref = + { + Default = false, + Choices = { "On", "Off" }, + Values = { true, false }, + }, + + IntPref = + { + Default = 3, + Choices = { 1, 2, 3, 4, 5 }, + Params = { SelectType = "ShowOneInRow" } + } +} + +ThemePrefs.InitAll( prefs ) +[/code] + +So when "On" is selected, BoolPref will be set to true, and selecting "Off" +will set it false. Simple enough, yeah? This will scale to any type you like. +Enumerations, strings, whatever. + +----------------- +Section 2: Params +----------------- + +We did promise a more in-depth look at Params, so here it is. + +The following arguments and values are currently accepted for Params: + +LayoutType (string): "ShowAllInRow" (default), "ShowOneInRow". + +ExportOnChange (bool): currently disabled in the source, but available to + set in case it's enabled later. If true, the Save function (which + handles actually setting the preference) is called whenever a value + is changed rather than when the screen changes. + +EnabledForPlayers (function): has 'self' as an argument, returns a table of + PlayerNumbers who are allowed to select stuff. Not important yet. + +ReloadRowMessages (table): contains an indexed array of strings. Whenever + any of the messages in this table are broadcast, the Load function + (which loads the list of possible options and sets the selected + value/s) is called again. + +LoadSelections (function): takes self, list, pn, overrides the default + function. This is advanced usage, so you should probably know + what you're doing to use it. Probably unnecessary. + +SaveSelections (function): takes self, list, pn, and overrides the default + function. This is advanced as well, for the same reasons. Fortunately, + you probably won't need it. + +---------------- +Section 3: Usage +---------------- + +To get the OptionsRow for the preference you want, use ThemePrefRow(name) +or ThemePrefsRows.GetRow(name); they're the same function. You'd use this +as, for example in the metrics: + +Line1="lua,ThemePrefRow('BoolPref')" + +Unfortunately, you do need to do some more work with the Language INIs too. +For each declared preference, you need an entry under [OptionTitles] for its +title and an entry under [OptionExplanations] for its description. The key for +both is the name of the preference. With the above example, that'd be e.g. + +[OptionTitles] +(...) +BoolPref=BoolPref +IntPref=IntPref + +[OptionExplanations] +(...) +BoolPref=Toggles a simple boolean preference between true and false. +IntPref=Sets an integer value between 1 and 5. + +----------------------- +Section 4: Localization +----------------------- + +ThemePrefsRows has three themable strings: + +NoDefaultInValues - if the default value isn't actually in choices or values, + this is displayed. Takes %s for the affected preference's name. + +TypeMismatch - if the default type and a value type mismatch, this is shown. + Takes %s, %d, and %s for the default's type, the index of the + mismatching value, and the value's type respectively. + +ChoicesSizeMismatch - if the Choices and Values arrays have different + lengths, this is displayed. Takes %d and %d for the size of + Choices and Values, respectively. + +--------------------- +Section 5: Disclaimer +--------------------- + +This isn't as tested as I'd like. For this version, it remains experimental. +Quite experimental. If you run into problems, please let me know so I can +fix them. + +Please direct all questions, comments, complaints, bug reports, etc. to "vyhd" +in #sm-ssc on irc.badnik.net or whatever other form of communication you like. diff --git a/NoteSkins/dance/default/Down Receptor.lua b/NoteSkins/dance/default/Down Receptor.lua index eda1a4c957..aaeb0937e8 100644 --- a/NoteSkins/dance/default/Down Receptor.lua +++ b/NoteSkins/dance/default/Down Receptor.lua @@ -1,19 +1,19 @@ -local t = Def.ActorFrame { - Def.Sprite { - Texture="_receptor"; - Frame0000=0; - Delay0000=1; - InitCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'InitCommand'); - NoneCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'NoneCommand'); - }; - Def.Sprite { - Texture="_rflash"; - Frame0000=0; - Delay0000=1; - InitCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'InitCommand'); - PressCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'PressCommand'); - LiftCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'LiftCommand'); - NoneCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'NoneCommand'); - }; -}; -return t; +local t = Def.ActorFrame { + Def.Sprite { + Texture="_receptor"; + Frame0000=0; + Delay0000=1; + InitCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'InitCommand'); + NoneCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'NoneCommand'); + }; + Def.Sprite { + Texture="_rflash"; + Frame0000=0; + Delay0000=1; + InitCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'InitCommand'); + PressCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'PressCommand'); + LiftCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'LiftCommand'); + NoneCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'NoneCommand'); + }; +}; +return t; diff --git a/NoteSkins/kb7/default/Space Tap Note.lua b/NoteSkins/kb7/default/Space Tap Note.lua index 916fabe7e5..a3e5658a56 100644 --- a/NoteSkins/kb7/default/Space Tap Note.lua +++ b/NoteSkins/kb7/default/Space Tap Note.lua @@ -1,5 +1,5 @@ -return Def.Sprite { - Texture=NOTESKIN:GetPath( '_space', 'tap note' ); - -- probably don't need this line - Frames = Sprite.LinearFrames( 1, 1 ); -}; +return Def.Sprite { + Texture=NOTESKIN:GetPath( '_space', 'tap note' ); + -- probably don't need this line + Frames = Sprite.LinearFrames( 1, 1 ); +}; diff --git a/NoteSkins/kb7/orbital/model/grey.txt b/NoteSkins/kb7/orbital/model/grey.txt index 9537f3cdb4..170e5dfd75 100644 --- a/NoteSkins/kb7/orbital/model/grey.txt +++ b/NoteSkins/kb7/orbital/model/grey.txt @@ -1,19 +1,19 @@ -Materials: 2 -"scroll" -0.000000 0.000000 0.000000 1.000000 -0.800000 0.800000 0.800000 1.000000 -1.000000 1.000000 1.000000 1.000000 -0.000000 0.000000 0.000000 1.000000 -0.000000 -1.000000 -"scroller.ini" -"" -"frame" -0.000000 0.000000 0.000000 1.000000 -0.800000 0.800000 0.800000 1.000000 -1.000000 1.000000 1.000000 1.000000 -0.000000 0.000000 0.000000 1.000000 -0.000000 -1.000000 -"_grey (no mipmaps).png" -"" +Materials: 2 +"scroll" +0.000000 0.000000 0.000000 1.000000 +0.800000 0.800000 0.800000 1.000000 +1.000000 1.000000 1.000000 1.000000 +0.000000 0.000000 0.000000 1.000000 +0.000000 +1.000000 +"scroller.ini" +"" +"frame" +0.000000 0.000000 0.000000 1.000000 +0.800000 0.800000 0.800000 1.000000 +1.000000 1.000000 1.000000 1.000000 +0.000000 0.000000 0.000000 1.000000 +0.000000 +1.000000 +"_grey (no mipmaps).png" +"" diff --git a/NoteSkins/kb7/orbital/model/note-wide.txt b/NoteSkins/kb7/orbital/model/note-wide.txt index be213d8a14..b88aea4fdf 100644 --- a/NoteSkins/kb7/orbital/model/note-wide.txt +++ b/NoteSkins/kb7/orbital/model/note-wide.txt @@ -1,316 +1,316 @@ -// MilkShape 3D ASCII - -Frames: 30 -Frame: 1 - -Meshes: 2 -"scroll" 0 0 -17 -0 28.576029 12.295176 2.879607 0.114769 0.235221 -1 -0 22.456854 18.468002 2.879607 0.103466 0.102288 -1 -0 0.000001 -0.000001 2.879607 0.061984 0.500000 -1 -0 31.867174 4.250518 2.879607 0.120849 0.408464 -1 -0 31.829239 -4.441243 2.879607 0.120779 0.595643 -1 -0 28.467997 -12.456865 2.879607 0.114570 0.768261 -1 -0 22.295166 -18.576036 2.879607 0.103167 0.900038 -1 -0 14.250505 -21.867176 2.879607 0.088308 0.970913 -1 -0 -14.441256 -21.829237 2.879607 0.035309 0.970096 -1 -0 -22.456873 -18.467987 2.879607 0.020503 0.897711 -1 -0 -28.576046 -12.295153 2.879607 0.009200 0.764778 -1 -0 -31.867182 -4.250491 2.879607 0.003120 0.591535 -1 -0 -31.829235 4.441269 2.879607 0.003190 0.404357 -1 -0 -28.467979 12.456886 2.879607 0.009399 0.231739 -1 -0 -22.295141 18.576052 2.879607 0.020802 0.099962 -1 -0 -14.250477 21.867180 2.879607 0.035661 0.029087 -1 -0 14.441284 21.829229 2.879607 0.088660 0.029904 -1 -1 -0.000000 0.000000 1.000000 -16 -0 0 1 2 0 0 0 1 -0 2 3 0 0 0 0 1 -0 2 4 3 0 0 0 1 -0 2 5 4 0 0 0 1 -0 2 6 5 0 0 0 1 -0 2 7 6 0 0 0 1 -0 2 8 7 0 0 0 1 -0 2 9 8 0 0 0 1 -0 2 10 9 0 0 0 1 -0 2 11 10 0 0 0 1 -0 2 12 11 0 0 0 1 -0 2 13 12 0 0 0 1 -0 2 14 13 0 0 0 1 -0 2 15 14 0 0 0 1 -0 2 16 15 0 0 0 1 -0 2 1 16 0 0 0 1 -"frame" 1 1 -65 -1 0.000000 -0.000000 3.321190 0.500000 0.500000 -1 -1 27.639259 11.675143 3.321190 0.856463 0.427477 -1 -1 21.828669 17.536682 3.321190 0.801575 0.296586 -1 -1 30.764435 4.036170 3.321190 0.857082 0.569410 -1 -1 30.728415 -4.217276 3.321190 0.803338 0.700776 -1 -1 27.536673 -11.828679 3.321190 0.703414 0.801575 -1 -1 21.675133 -17.639269 3.321190 0.572522 0.856463 -1 -1 14.036156 -20.764439 3.321190 0.430590 0.857082 -1 -1 -14.217289 -20.728411 3.321190 0.299224 0.803338 -1 -1 -21.828686 -17.536667 3.321190 0.198425 0.703414 -1 -1 -27.639275 -11.675121 3.321190 0.143537 0.572522 -1 -1 -30.764442 -4.036143 3.321190 0.142919 0.430589 -1 -1 -30.728407 4.217301 3.321190 0.196662 0.299224 -1 -1 -27.536659 11.828699 3.321190 0.296586 0.198425 -1 -1 -21.675112 17.639282 3.321190 0.427478 0.143538 -1 -1 -14.036130 20.764444 3.321190 0.569411 0.142919 -1 -1 14.217316 20.728405 3.321190 0.700777 0.196662 -1 -1 23.683174 20.286118 3.156490 0.848857 0.264694 -1 -1 30.404764 13.505603 3.156490 0.912349 0.416107 -1 -1 34.019917 4.668982 3.156490 0.913065 0.580292 -1 -1 33.978256 -4.878449 3.156490 0.850896 0.732254 -1 -1 30.286112 -13.683181 3.156490 0.735306 0.848857 -1 -1 23.505600 -20.404768 3.156490 0.583893 0.912349 -1 -1 14.668977 -24.019918 3.156490 0.419708 0.913065 -1 -1 -14.878452 -23.978252 3.156490 0.267746 0.850896 -1 -1 -23.683182 -20.286110 3.156490 0.151143 0.735306 -1 -1 -30.404770 -13.505592 3.156490 0.087651 0.583893 -1 -1 -34.019920 -4.668968 3.156490 0.086935 0.419708 -1 -1 -33.978249 4.878465 3.156490 0.149104 0.267746 -1 -1 -30.286102 13.683196 3.156490 0.264694 0.151143 -1 -1 -23.505577 20.404779 3.156490 0.416107 0.087651 -1 -1 -14.668951 24.019922 3.156490 0.580293 0.086935 -1 -1 14.878481 23.978243 3.156490 0.732254 0.149104 -1 -1 26.305698 24.174189 -0.301926 0.917477 0.218408 -1 -1 25.196014 22.529018 1.012907 0.887427 0.238677 -1 -1 32.660770 14.998834 1.012907 0.957940 0.406831 -1 -1 34.315567 16.094122 -0.301926 0.993459 0.399605 -1 -1 36.675629 5.185213 1.012907 0.958735 0.589169 -1 -1 38.623604 5.563864 -0.301926 0.994316 0.596085 -1 -1 36.629364 -5.417810 1.012907 0.889693 0.757932 -1 -1 38.573959 -5.813441 -0.301926 0.919919 0.777938 -1 -1 32.529015 -15.196017 1.012907 0.761323 0.887427 -1 -1 34.174187 -16.305698 -0.301926 0.781592 0.917477 -1 -1 24.998833 -22.660772 1.012907 0.593169 0.957940 -1 -1 26.094122 -24.315565 -0.301926 0.600395 0.993459 -1 -1 15.185220 -26.675629 1.012907 0.410831 0.958735 -1 -1 15.563870 -28.623604 -0.301926 0.403915 0.994316 -1 -1 -15.417803 -26.629364 1.012907 0.242068 0.889693 -1 -1 -15.813432 -28.573965 -0.301926 0.222062 0.919919 -1 -1 -25.196011 -22.529020 1.012907 0.112573 0.761323 -1 -1 -26.305689 -24.174196 -0.301926 0.082523 0.781592 -1 -1 -32.660770 -14.998836 1.012907 0.042060 0.593169 -1 -1 -34.315559 -16.094126 -0.301926 0.006541 0.600395 -1 -1 -36.675629 -5.185212 1.012907 0.041265 0.410831 -1 -1 -38.623604 -5.563865 -0.301926 0.005684 0.403915 -1 -1 -36.629356 5.417814 1.012907 0.110308 0.242068 -1 -1 -38.573959 5.813443 -0.301926 0.080082 0.222062 -1 -1 -32.529011 15.196029 1.012907 0.238677 0.112573 -1 -1 -34.174187 16.305708 -0.301926 0.218408 0.082523 -1 -1 -24.998821 22.660780 1.012907 0.406831 0.042060 -1 -1 -26.094109 24.315575 -0.301926 0.399605 0.006541 -1 -1 -15.185204 26.675629 1.012907 0.589169 0.041265 -1 -1 -15.563847 28.623608 -0.301926 0.596086 0.005684 -1 -1 15.417831 26.629356 1.012907 0.757932 0.110308 -1 -1 15.813461 28.573956 -0.301926 0.777938 0.080082 -1 -65 -0.000000 0.000000 1.000000 -0.023734 0.018076 0.999555 -0.015010 0.025783 0.999555 -0.028845 0.007618 0.999555 -0.029564 -0.004001 0.999555 -0.025783 -0.015010 0.999555 -0.018076 -0.023734 0.999555 -0.007649 -0.028839 0.999555 --0.003940 -0.029565 0.999555 --0.015010 -0.025783 0.999555 --0.023734 -0.018076 0.999555 --0.028845 -0.007618 0.999555 --0.029565 0.004001 0.999555 --0.025783 0.015010 0.999555 --0.018076 0.023734 0.999555 --0.007649 0.028839 0.999555 -0.003940 0.029565 0.999555 -0.179817 0.302000 0.936196 -0.281699 0.210198 0.936196 -0.340695 0.086397 0.936196 -0.347824 -0.050559 0.936196 -0.302000 -0.179817 0.936196 -0.210198 -0.281699 0.936196 -0.086772 -0.340640 0.936181 --0.049893 -0.347841 0.936225 --0.179817 -0.301999 0.936196 --0.281699 -0.210198 0.936196 --0.340695 -0.086396 0.936196 --0.347824 0.050559 0.936196 --0.302000 0.179817 0.936196 --0.210198 0.281699 0.936196 --0.086772 0.340641 0.936181 -0.049893 0.347841 0.936225 -0.338996 0.437135 0.833064 -0.330211 0.485536 0.809454 -0.490881 0.322210 0.809454 -0.480475 0.274131 0.833064 -0.576820 0.109832 0.809454 -0.548807 0.069395 0.833063 -0.574943 -0.119268 0.809454 -0.533588 -0.145907 0.833063 -0.485536 -0.330211 0.809454 -0.437135 -0.338996 0.833064 -0.322211 -0.490881 0.809454 -0.274132 -0.480475 0.833064 -0.110702 -0.576729 0.809400 -0.070446 -0.548768 0.833001 --0.118450 -0.575039 0.809506 --0.145397 -0.533702 0.833080 --0.330210 -0.485536 0.809454 --0.338996 -0.437135 0.833064 --0.490881 -0.322211 0.809454 --0.480475 -0.274132 0.833064 --0.576820 -0.109831 0.809454 --0.548807 -0.069395 0.833064 --0.574943 0.119268 0.809454 --0.533587 0.145907 0.833064 --0.485535 0.330210 0.809454 --0.437134 0.338996 0.833064 --0.322210 0.490881 0.809454 --0.274131 0.480475 0.833064 --0.110701 0.576729 0.809400 --0.070446 0.548768 0.833001 -0.118450 0.575039 0.809506 -0.145397 0.533702 0.833080 -112 -1 0 1 2 0 1 2 2 -1 0 3 1 0 3 1 2 -1 0 4 3 0 4 3 2 -1 0 5 4 0 5 4 2 -1 0 6 5 0 6 5 2 -1 0 7 6 0 7 6 2 -1 0 8 7 0 8 7 2 -1 0 9 8 0 9 8 2 -1 0 10 9 0 10 9 2 -1 0 11 10 0 11 10 2 -1 0 12 11 0 12 11 2 -1 0 13 12 0 13 12 2 -1 0 14 13 0 14 13 2 -1 0 15 14 0 15 14 2 -1 0 16 15 0 16 15 2 -1 0 2 16 0 2 16 2 -1 17 2 1 17 2 1 2 -1 17 1 18 17 1 18 2 -1 18 1 3 18 1 3 2 -1 18 3 19 18 3 19 2 -1 19 3 4 19 3 4 2 -1 19 4 20 19 4 20 2 -1 20 4 5 20 4 5 2 -1 20 5 21 20 5 21 2 -1 21 5 6 21 5 6 2 -1 21 6 22 21 6 22 2 -1 22 6 7 22 6 7 2 -1 22 7 23 22 7 23 2 -1 23 7 8 23 7 8 2 -1 23 8 24 23 8 24 2 -1 24 8 9 24 8 9 2 -1 24 9 25 24 9 25 2 -1 25 9 10 25 9 10 2 -1 25 10 26 25 10 26 2 -1 26 10 11 26 10 11 2 -1 26 11 27 26 11 27 2 -1 27 11 12 27 11 12 2 -1 27 12 28 27 12 28 2 -1 28 12 13 28 12 13 2 -1 28 13 29 28 13 29 2 -1 29 13 14 29 13 14 2 -1 29 14 30 29 14 30 2 -1 30 14 15 30 14 15 2 -1 30 15 31 30 15 31 2 -1 31 15 16 31 15 16 2 -1 31 16 32 31 16 32 2 -1 2 17 32 2 17 32 2 -1 2 32 16 2 32 16 2 -1 33 34 35 33 34 35 2 -1 33 35 36 33 35 36 2 -1 34 17 18 34 17 18 2 -1 34 18 35 34 18 35 2 -1 36 35 37 36 35 37 2 -1 36 37 38 36 37 38 2 -1 35 18 19 35 18 19 2 -1 35 19 37 35 19 37 2 -1 38 37 39 38 37 39 2 -1 38 39 40 38 39 40 2 -1 37 19 20 37 19 20 2 -1 37 20 39 37 20 39 2 -1 40 39 41 40 39 41 2 -1 40 41 42 40 41 42 2 -1 39 20 21 39 20 21 2 -1 39 21 41 39 21 41 2 -1 42 41 43 42 41 43 2 -1 42 43 44 42 43 44 2 -1 41 21 22 41 21 22 2 -1 41 22 43 41 22 43 2 -1 44 43 45 44 43 45 2 -1 44 45 46 44 45 46 2 -1 43 22 23 43 22 23 2 -1 43 23 45 43 23 45 2 -1 46 45 47 46 45 47 2 -1 46 47 48 46 47 48 2 -1 45 23 24 45 23 24 2 -1 45 24 47 45 24 47 2 -1 48 47 49 48 47 49 2 -1 48 49 50 48 49 50 2 -1 47 24 25 47 24 25 2 -1 47 25 49 47 25 49 2 -1 50 49 51 50 49 51 2 -1 50 51 52 50 51 52 2 -1 49 25 26 49 25 26 2 -1 49 26 51 49 26 51 2 -1 52 51 53 52 51 53 2 -1 52 53 54 52 53 54 2 -1 51 26 27 51 26 27 2 -1 51 27 53 51 27 53 2 -1 54 53 55 54 53 55 2 -1 54 55 56 54 55 56 2 -1 53 27 28 53 27 28 2 -1 53 28 55 53 28 55 2 -1 56 55 57 56 55 57 2 -1 56 57 58 56 57 58 2 -1 55 28 29 55 28 29 2 -1 55 29 57 55 29 57 2 -1 58 57 59 58 57 59 2 -1 58 59 60 58 59 60 2 -1 57 29 30 57 29 30 2 -1 57 30 59 57 30 59 2 -1 60 59 61 60 59 61 2 -1 60 61 62 60 61 62 2 -1 59 30 31 59 30 31 2 -1 59 31 61 59 31 61 2 -1 62 61 63 62 61 63 2 -1 62 63 64 62 63 64 2 -1 61 31 32 61 31 32 2 -1 61 32 63 61 32 63 2 -1 17 34 63 17 34 63 2 -1 17 63 32 17 63 32 2 -1 34 33 64 34 33 64 2 -1 34 64 63 34 64 63 2 - -Materials: 2 -"scroll" -0.000000 0.000000 0.000000 1.000000 -0.800000 0.800000 0.800000 1.000000 -1.000000 1.000000 1.000000 1.000000 -0.000000 0.000000 0.000000 1.000000 -0.000000 -1.000000 -"" -"" -"frame" -0.000000 0.000000 0.000000 1.000000 -0.800000 0.800000 0.800000 1.000000 -1.000000 1.000000 1.000000 1.000000 -0.000000 0.000000 0.000000 1.000000 -0.000000 -1.000000 -"" -"" - -Bones: 0 -GroupComments: 0 -MaterialComments: 0 -BoneComments: 0 -ModelComment: 0 +// MilkShape 3D ASCII + +Frames: 30 +Frame: 1 + +Meshes: 2 +"scroll" 0 0 +17 +0 28.576029 12.295176 2.879607 0.114769 0.235221 -1 +0 22.456854 18.468002 2.879607 0.103466 0.102288 -1 +0 0.000001 -0.000001 2.879607 0.061984 0.500000 -1 +0 31.867174 4.250518 2.879607 0.120849 0.408464 -1 +0 31.829239 -4.441243 2.879607 0.120779 0.595643 -1 +0 28.467997 -12.456865 2.879607 0.114570 0.768261 -1 +0 22.295166 -18.576036 2.879607 0.103167 0.900038 -1 +0 14.250505 -21.867176 2.879607 0.088308 0.970913 -1 +0 -14.441256 -21.829237 2.879607 0.035309 0.970096 -1 +0 -22.456873 -18.467987 2.879607 0.020503 0.897711 -1 +0 -28.576046 -12.295153 2.879607 0.009200 0.764778 -1 +0 -31.867182 -4.250491 2.879607 0.003120 0.591535 -1 +0 -31.829235 4.441269 2.879607 0.003190 0.404357 -1 +0 -28.467979 12.456886 2.879607 0.009399 0.231739 -1 +0 -22.295141 18.576052 2.879607 0.020802 0.099962 -1 +0 -14.250477 21.867180 2.879607 0.035661 0.029087 -1 +0 14.441284 21.829229 2.879607 0.088660 0.029904 -1 +1 +0.000000 0.000000 1.000000 +16 +0 0 1 2 0 0 0 1 +0 2 3 0 0 0 0 1 +0 2 4 3 0 0 0 1 +0 2 5 4 0 0 0 1 +0 2 6 5 0 0 0 1 +0 2 7 6 0 0 0 1 +0 2 8 7 0 0 0 1 +0 2 9 8 0 0 0 1 +0 2 10 9 0 0 0 1 +0 2 11 10 0 0 0 1 +0 2 12 11 0 0 0 1 +0 2 13 12 0 0 0 1 +0 2 14 13 0 0 0 1 +0 2 15 14 0 0 0 1 +0 2 16 15 0 0 0 1 +0 2 1 16 0 0 0 1 +"frame" 1 1 +65 +1 0.000000 -0.000000 3.321190 0.500000 0.500000 -1 +1 27.639259 11.675143 3.321190 0.856463 0.427477 -1 +1 21.828669 17.536682 3.321190 0.801575 0.296586 -1 +1 30.764435 4.036170 3.321190 0.857082 0.569410 -1 +1 30.728415 -4.217276 3.321190 0.803338 0.700776 -1 +1 27.536673 -11.828679 3.321190 0.703414 0.801575 -1 +1 21.675133 -17.639269 3.321190 0.572522 0.856463 -1 +1 14.036156 -20.764439 3.321190 0.430590 0.857082 -1 +1 -14.217289 -20.728411 3.321190 0.299224 0.803338 -1 +1 -21.828686 -17.536667 3.321190 0.198425 0.703414 -1 +1 -27.639275 -11.675121 3.321190 0.143537 0.572522 -1 +1 -30.764442 -4.036143 3.321190 0.142919 0.430589 -1 +1 -30.728407 4.217301 3.321190 0.196662 0.299224 -1 +1 -27.536659 11.828699 3.321190 0.296586 0.198425 -1 +1 -21.675112 17.639282 3.321190 0.427478 0.143538 -1 +1 -14.036130 20.764444 3.321190 0.569411 0.142919 -1 +1 14.217316 20.728405 3.321190 0.700777 0.196662 -1 +1 23.683174 20.286118 3.156490 0.848857 0.264694 -1 +1 30.404764 13.505603 3.156490 0.912349 0.416107 -1 +1 34.019917 4.668982 3.156490 0.913065 0.580292 -1 +1 33.978256 -4.878449 3.156490 0.850896 0.732254 -1 +1 30.286112 -13.683181 3.156490 0.735306 0.848857 -1 +1 23.505600 -20.404768 3.156490 0.583893 0.912349 -1 +1 14.668977 -24.019918 3.156490 0.419708 0.913065 -1 +1 -14.878452 -23.978252 3.156490 0.267746 0.850896 -1 +1 -23.683182 -20.286110 3.156490 0.151143 0.735306 -1 +1 -30.404770 -13.505592 3.156490 0.087651 0.583893 -1 +1 -34.019920 -4.668968 3.156490 0.086935 0.419708 -1 +1 -33.978249 4.878465 3.156490 0.149104 0.267746 -1 +1 -30.286102 13.683196 3.156490 0.264694 0.151143 -1 +1 -23.505577 20.404779 3.156490 0.416107 0.087651 -1 +1 -14.668951 24.019922 3.156490 0.580293 0.086935 -1 +1 14.878481 23.978243 3.156490 0.732254 0.149104 -1 +1 26.305698 24.174189 -0.301926 0.917477 0.218408 -1 +1 25.196014 22.529018 1.012907 0.887427 0.238677 -1 +1 32.660770 14.998834 1.012907 0.957940 0.406831 -1 +1 34.315567 16.094122 -0.301926 0.993459 0.399605 -1 +1 36.675629 5.185213 1.012907 0.958735 0.589169 -1 +1 38.623604 5.563864 -0.301926 0.994316 0.596085 -1 +1 36.629364 -5.417810 1.012907 0.889693 0.757932 -1 +1 38.573959 -5.813441 -0.301926 0.919919 0.777938 -1 +1 32.529015 -15.196017 1.012907 0.761323 0.887427 -1 +1 34.174187 -16.305698 -0.301926 0.781592 0.917477 -1 +1 24.998833 -22.660772 1.012907 0.593169 0.957940 -1 +1 26.094122 -24.315565 -0.301926 0.600395 0.993459 -1 +1 15.185220 -26.675629 1.012907 0.410831 0.958735 -1 +1 15.563870 -28.623604 -0.301926 0.403915 0.994316 -1 +1 -15.417803 -26.629364 1.012907 0.242068 0.889693 -1 +1 -15.813432 -28.573965 -0.301926 0.222062 0.919919 -1 +1 -25.196011 -22.529020 1.012907 0.112573 0.761323 -1 +1 -26.305689 -24.174196 -0.301926 0.082523 0.781592 -1 +1 -32.660770 -14.998836 1.012907 0.042060 0.593169 -1 +1 -34.315559 -16.094126 -0.301926 0.006541 0.600395 -1 +1 -36.675629 -5.185212 1.012907 0.041265 0.410831 -1 +1 -38.623604 -5.563865 -0.301926 0.005684 0.403915 -1 +1 -36.629356 5.417814 1.012907 0.110308 0.242068 -1 +1 -38.573959 5.813443 -0.301926 0.080082 0.222062 -1 +1 -32.529011 15.196029 1.012907 0.238677 0.112573 -1 +1 -34.174187 16.305708 -0.301926 0.218408 0.082523 -1 +1 -24.998821 22.660780 1.012907 0.406831 0.042060 -1 +1 -26.094109 24.315575 -0.301926 0.399605 0.006541 -1 +1 -15.185204 26.675629 1.012907 0.589169 0.041265 -1 +1 -15.563847 28.623608 -0.301926 0.596086 0.005684 -1 +1 15.417831 26.629356 1.012907 0.757932 0.110308 -1 +1 15.813461 28.573956 -0.301926 0.777938 0.080082 -1 +65 +0.000000 0.000000 1.000000 +0.023734 0.018076 0.999555 +0.015010 0.025783 0.999555 +0.028845 0.007618 0.999555 +0.029564 -0.004001 0.999555 +0.025783 -0.015010 0.999555 +0.018076 -0.023734 0.999555 +0.007649 -0.028839 0.999555 +-0.003940 -0.029565 0.999555 +-0.015010 -0.025783 0.999555 +-0.023734 -0.018076 0.999555 +-0.028845 -0.007618 0.999555 +-0.029565 0.004001 0.999555 +-0.025783 0.015010 0.999555 +-0.018076 0.023734 0.999555 +-0.007649 0.028839 0.999555 +0.003940 0.029565 0.999555 +0.179817 0.302000 0.936196 +0.281699 0.210198 0.936196 +0.340695 0.086397 0.936196 +0.347824 -0.050559 0.936196 +0.302000 -0.179817 0.936196 +0.210198 -0.281699 0.936196 +0.086772 -0.340640 0.936181 +-0.049893 -0.347841 0.936225 +-0.179817 -0.301999 0.936196 +-0.281699 -0.210198 0.936196 +-0.340695 -0.086396 0.936196 +-0.347824 0.050559 0.936196 +-0.302000 0.179817 0.936196 +-0.210198 0.281699 0.936196 +-0.086772 0.340641 0.936181 +0.049893 0.347841 0.936225 +0.338996 0.437135 0.833064 +0.330211 0.485536 0.809454 +0.490881 0.322210 0.809454 +0.480475 0.274131 0.833064 +0.576820 0.109832 0.809454 +0.548807 0.069395 0.833063 +0.574943 -0.119268 0.809454 +0.533588 -0.145907 0.833063 +0.485536 -0.330211 0.809454 +0.437135 -0.338996 0.833064 +0.322211 -0.490881 0.809454 +0.274132 -0.480475 0.833064 +0.110702 -0.576729 0.809400 +0.070446 -0.548768 0.833001 +-0.118450 -0.575039 0.809506 +-0.145397 -0.533702 0.833080 +-0.330210 -0.485536 0.809454 +-0.338996 -0.437135 0.833064 +-0.490881 -0.322211 0.809454 +-0.480475 -0.274132 0.833064 +-0.576820 -0.109831 0.809454 +-0.548807 -0.069395 0.833064 +-0.574943 0.119268 0.809454 +-0.533587 0.145907 0.833064 +-0.485535 0.330210 0.809454 +-0.437134 0.338996 0.833064 +-0.322210 0.490881 0.809454 +-0.274131 0.480475 0.833064 +-0.110701 0.576729 0.809400 +-0.070446 0.548768 0.833001 +0.118450 0.575039 0.809506 +0.145397 0.533702 0.833080 +112 +1 0 1 2 0 1 2 2 +1 0 3 1 0 3 1 2 +1 0 4 3 0 4 3 2 +1 0 5 4 0 5 4 2 +1 0 6 5 0 6 5 2 +1 0 7 6 0 7 6 2 +1 0 8 7 0 8 7 2 +1 0 9 8 0 9 8 2 +1 0 10 9 0 10 9 2 +1 0 11 10 0 11 10 2 +1 0 12 11 0 12 11 2 +1 0 13 12 0 13 12 2 +1 0 14 13 0 14 13 2 +1 0 15 14 0 15 14 2 +1 0 16 15 0 16 15 2 +1 0 2 16 0 2 16 2 +1 17 2 1 17 2 1 2 +1 17 1 18 17 1 18 2 +1 18 1 3 18 1 3 2 +1 18 3 19 18 3 19 2 +1 19 3 4 19 3 4 2 +1 19 4 20 19 4 20 2 +1 20 4 5 20 4 5 2 +1 20 5 21 20 5 21 2 +1 21 5 6 21 5 6 2 +1 21 6 22 21 6 22 2 +1 22 6 7 22 6 7 2 +1 22 7 23 22 7 23 2 +1 23 7 8 23 7 8 2 +1 23 8 24 23 8 24 2 +1 24 8 9 24 8 9 2 +1 24 9 25 24 9 25 2 +1 25 9 10 25 9 10 2 +1 25 10 26 25 10 26 2 +1 26 10 11 26 10 11 2 +1 26 11 27 26 11 27 2 +1 27 11 12 27 11 12 2 +1 27 12 28 27 12 28 2 +1 28 12 13 28 12 13 2 +1 28 13 29 28 13 29 2 +1 29 13 14 29 13 14 2 +1 29 14 30 29 14 30 2 +1 30 14 15 30 14 15 2 +1 30 15 31 30 15 31 2 +1 31 15 16 31 15 16 2 +1 31 16 32 31 16 32 2 +1 2 17 32 2 17 32 2 +1 2 32 16 2 32 16 2 +1 33 34 35 33 34 35 2 +1 33 35 36 33 35 36 2 +1 34 17 18 34 17 18 2 +1 34 18 35 34 18 35 2 +1 36 35 37 36 35 37 2 +1 36 37 38 36 37 38 2 +1 35 18 19 35 18 19 2 +1 35 19 37 35 19 37 2 +1 38 37 39 38 37 39 2 +1 38 39 40 38 39 40 2 +1 37 19 20 37 19 20 2 +1 37 20 39 37 20 39 2 +1 40 39 41 40 39 41 2 +1 40 41 42 40 41 42 2 +1 39 20 21 39 20 21 2 +1 39 21 41 39 21 41 2 +1 42 41 43 42 41 43 2 +1 42 43 44 42 43 44 2 +1 41 21 22 41 21 22 2 +1 41 22 43 41 22 43 2 +1 44 43 45 44 43 45 2 +1 44 45 46 44 45 46 2 +1 43 22 23 43 22 23 2 +1 43 23 45 43 23 45 2 +1 46 45 47 46 45 47 2 +1 46 47 48 46 47 48 2 +1 45 23 24 45 23 24 2 +1 45 24 47 45 24 47 2 +1 48 47 49 48 47 49 2 +1 48 49 50 48 49 50 2 +1 47 24 25 47 24 25 2 +1 47 25 49 47 25 49 2 +1 50 49 51 50 49 51 2 +1 50 51 52 50 51 52 2 +1 49 25 26 49 25 26 2 +1 49 26 51 49 26 51 2 +1 52 51 53 52 51 53 2 +1 52 53 54 52 53 54 2 +1 51 26 27 51 26 27 2 +1 51 27 53 51 27 53 2 +1 54 53 55 54 53 55 2 +1 54 55 56 54 55 56 2 +1 53 27 28 53 27 28 2 +1 53 28 55 53 28 55 2 +1 56 55 57 56 55 57 2 +1 56 57 58 56 57 58 2 +1 55 28 29 55 28 29 2 +1 55 29 57 55 29 57 2 +1 58 57 59 58 57 59 2 +1 58 59 60 58 59 60 2 +1 57 29 30 57 29 30 2 +1 57 30 59 57 30 59 2 +1 60 59 61 60 59 61 2 +1 60 61 62 60 61 62 2 +1 59 30 31 59 30 31 2 +1 59 31 61 59 31 61 2 +1 62 61 63 62 61 63 2 +1 62 63 64 62 63 64 2 +1 61 31 32 61 31 32 2 +1 61 32 63 61 32 63 2 +1 17 34 63 17 34 63 2 +1 17 63 32 17 63 32 2 +1 34 33 64 34 33 64 2 +1 34 64 63 34 64 63 2 + +Materials: 2 +"scroll" +0.000000 0.000000 0.000000 1.000000 +0.800000 0.800000 0.800000 1.000000 +1.000000 1.000000 1.000000 1.000000 +0.000000 0.000000 0.000000 1.000000 +0.000000 +1.000000 +"" +"" +"frame" +0.000000 0.000000 0.000000 1.000000 +0.800000 0.800000 0.800000 1.000000 +1.000000 1.000000 1.000000 1.000000 +0.000000 0.000000 0.000000 1.000000 +0.000000 +1.000000 +"" +"" + +Bones: 0 +GroupComments: 0 +MaterialComments: 0 +BoneComments: 0 +ModelComment: 0 diff --git a/NoteSkins/kb7/orbital/model/note.txt b/NoteSkins/kb7/orbital/model/note.txt index cf74519852..b524ceef63 100644 --- a/NoteSkins/kb7/orbital/model/note.txt +++ b/NoteSkins/kb7/orbital/model/note.txt @@ -1,316 +1,316 @@ -// MilkShape 3D ASCII - -Frames: 30 -Frame: 1 - -Meshes: 2 -"scroll" 0 0 -17 -0 18.576029 12.295176 2.879607 0.112493 0.233639 -1 -0 12.456854 18.468002 2.879607 0.095922 0.099912 -1 -0 0.000001 -0.000001 2.879607 0.062189 0.500000 -1 -0 21.867174 4.250518 2.879607 0.121405 0.407917 -1 -0 21.829239 -4.441243 2.879607 0.121302 0.596214 -1 -0 18.467995 -12.456865 2.879607 0.112200 0.769864 -1 -0 12.295166 -18.576036 2.879607 0.095484 0.902428 -1 -0 4.250505 -21.867176 2.879607 0.073699 0.973727 -1 -0 -4.441256 -21.829237 2.879607 0.050162 0.972905 -1 -0 -12.456874 -18.467987 2.879607 0.028456 0.900088 -1 -0 -18.576044 -12.295153 2.879607 0.011886 0.766360 -1 -0 -21.867182 -4.250491 2.879607 0.002973 0.592082 -1 -0 -21.829233 4.441269 2.879607 0.003076 0.403785 -1 -0 -18.467979 12.456886 2.879607 0.012178 0.230136 -1 -0 -12.295140 18.576052 2.879607 0.028894 0.097571 -1 -0 -4.250477 21.867180 2.879607 0.050679 0.026273 -1 -0 4.441284 21.829229 2.879607 0.074216 0.027095 -1 -1 -0.000000 0.000000 1.000000 -16 -0 0 1 2 0 0 0 1 -0 2 3 0 0 0 0 1 -0 2 4 3 0 0 0 1 -0 2 5 4 0 0 0 1 -0 2 6 5 0 0 0 1 -0 2 7 6 0 0 0 1 -0 2 8 7 0 0 0 1 -0 2 9 8 0 0 0 1 -0 2 10 9 0 0 0 1 -0 2 11 10 0 0 0 1 -0 2 12 11 0 0 0 1 -0 2 13 12 0 0 0 1 -0 2 14 13 0 0 0 1 -0 2 15 14 0 0 0 1 -0 2 16 15 0 0 0 1 -0 2 1 16 0 0 0 1 -"frame" 1 1 -65 -1 0.000000 -0.000000 3.321190 0.500000 0.500000 -1 -1 17.639259 11.675143 3.321190 0.856463 0.427477 -1 -1 11.828669 17.536682 3.321190 0.801575 0.296586 -1 -1 20.764435 4.036170 3.321190 0.857082 0.569410 -1 -1 20.728415 -4.217276 3.321190 0.803338 0.700776 -1 -1 17.536673 -11.828679 3.321190 0.703414 0.801575 -1 -1 11.675133 -17.639269 3.321190 0.572522 0.856463 -1 -1 4.036156 -20.764439 3.321190 0.430590 0.857082 -1 -1 -4.217289 -20.728411 3.321190 0.299224 0.803338 -1 -1 -11.828687 -17.536667 3.321190 0.198425 0.703414 -1 -1 -17.639275 -11.675121 3.321190 0.143537 0.572522 -1 -1 -20.764442 -4.036143 3.321190 0.142919 0.430589 -1 -1 -20.728407 4.217301 3.321190 0.196662 0.299224 -1 -1 -17.536659 11.828699 3.321190 0.296586 0.198425 -1 -1 -11.675112 17.639282 3.321190 0.427478 0.143538 -1 -1 -4.036130 20.764444 3.321190 0.569411 0.142919 -1 -1 4.217315 20.728405 3.321190 0.700777 0.196662 -1 -1 13.683175 20.286118 3.156490 0.848857 0.264694 -1 -1 20.404764 13.505603 3.156490 0.912349 0.416107 -1 -1 24.019917 4.668982 3.156490 0.913065 0.580292 -1 -1 23.978254 -4.878449 3.156490 0.850896 0.732254 -1 -1 20.286112 -13.683181 3.156490 0.735306 0.848857 -1 -1 13.505599 -20.404768 3.156490 0.583893 0.912349 -1 -1 4.668977 -24.019918 3.156490 0.419708 0.913065 -1 -1 -4.878453 -23.978252 3.156490 0.267746 0.850896 -1 -1 -13.683182 -20.286110 3.156490 0.151143 0.735306 -1 -1 -20.404770 -13.505592 3.156490 0.087651 0.583893 -1 -1 -24.019920 -4.668968 3.156490 0.086935 0.419708 -1 -1 -23.978251 4.878465 3.156490 0.149104 0.267746 -1 -1 -20.286102 13.683196 3.156490 0.264694 0.151143 -1 -1 -13.505578 20.404779 3.156490 0.416107 0.087651 -1 -1 -4.668952 24.019922 3.156490 0.580293 0.086935 -1 -1 4.878480 23.978243 3.156490 0.732254 0.149104 -1 -1 16.305698 24.174189 -0.301926 0.917477 0.218408 -1 -1 15.196015 22.529018 1.012907 0.887427 0.238677 -1 -1 22.660770 14.998834 1.012907 0.957940 0.406831 -1 -1 24.315565 16.094122 -0.301926 0.993459 0.399605 -1 -1 26.675631 5.185213 1.012907 0.958735 0.589169 -1 -1 28.623606 5.563864 -0.301926 0.994316 0.596085 -1 -1 26.629364 -5.417810 1.012907 0.889693 0.757932 -1 -1 28.573961 -5.813441 -0.301926 0.919919 0.777938 -1 -1 22.529016 -15.196017 1.012907 0.761323 0.887427 -1 -1 24.174189 -16.305698 -0.301926 0.781592 0.917477 -1 -1 14.998834 -22.660772 1.012907 0.593169 0.957940 -1 -1 16.094122 -24.315565 -0.301926 0.600395 0.993459 -1 -1 5.185220 -26.675629 1.012907 0.410831 0.958735 -1 -1 5.563870 -28.623604 -0.301926 0.403915 0.994316 -1 -1 -5.417803 -26.629364 1.012907 0.242068 0.889693 -1 -1 -5.813432 -28.573965 -0.301926 0.222062 0.919919 -1 -1 -15.196011 -22.529020 1.012907 0.112573 0.761323 -1 -1 -16.305689 -24.174196 -0.301926 0.082523 0.781592 -1 -1 -22.660770 -14.998836 1.012907 0.042060 0.593169 -1 -1 -24.315561 -16.094126 -0.301926 0.006541 0.600395 -1 -1 -26.675631 -5.185212 1.012907 0.041265 0.410831 -1 -1 -28.623606 -5.563865 -0.301926 0.005684 0.403915 -1 -1 -26.629358 5.417814 1.012907 0.110308 0.242068 -1 -1 -28.573961 5.813443 -0.301926 0.080082 0.222062 -1 -1 -22.529011 15.196029 1.012907 0.238677 0.112573 -1 -1 -24.174185 16.305708 -0.301926 0.218408 0.082523 -1 -1 -14.998822 22.660780 1.012907 0.406831 0.042060 -1 -1 -16.094109 24.315575 -0.301926 0.399605 0.006541 -1 -1 -5.185204 26.675629 1.012907 0.589169 0.041265 -1 -1 -5.563847 28.623608 -0.301926 0.596086 0.005684 -1 -1 5.417831 26.629356 1.012907 0.757932 0.110308 -1 -1 5.813461 28.573956 -0.301926 0.777938 0.080082 -1 -65 -0.000000 0.000000 1.000000 -0.023734 0.018076 0.999555 -0.015010 0.025783 0.999555 -0.028845 0.007618 0.999555 -0.029564 -0.004001 0.999555 -0.025783 -0.015010 0.999555 -0.018076 -0.023734 0.999555 -0.007618 -0.028845 0.999555 --0.004001 -0.029564 0.999555 --0.015010 -0.025783 0.999555 --0.023734 -0.018076 0.999555 --0.028845 -0.007618 0.999555 --0.029564 0.004001 0.999555 --0.025783 0.015010 0.999555 --0.018076 0.023734 0.999555 --0.007618 0.028845 0.999555 -0.004001 0.029565 0.999555 -0.179817 0.302000 0.936196 -0.281699 0.210198 0.936196 -0.340695 0.086397 0.936196 -0.347824 -0.050559 0.936196 -0.301999 -0.179816 0.936196 -0.210198 -0.281699 0.936196 -0.086396 -0.340695 0.936196 --0.050559 -0.347824 0.936196 --0.179817 -0.301999 0.936196 --0.281699 -0.210198 0.936196 --0.340695 -0.086396 0.936196 --0.347824 0.050559 0.936196 --0.301999 0.179817 0.936196 --0.210198 0.281699 0.936196 --0.086396 0.340695 0.936196 -0.050559 0.347824 0.936196 -0.338996 0.437135 0.833064 -0.330211 0.485536 0.809454 -0.490881 0.322211 0.809454 -0.480475 0.274132 0.833064 -0.576820 0.109832 0.809454 -0.548807 0.069395 0.833064 -0.574943 -0.119268 0.809454 -0.533588 -0.145907 0.833064 -0.485536 -0.330211 0.809454 -0.437135 -0.338996 0.833064 -0.322211 -0.490881 0.809454 -0.274132 -0.480475 0.833064 -0.109832 -0.576820 0.809454 -0.069395 -0.548807 0.833064 --0.119268 -0.574943 0.809454 --0.145907 -0.533588 0.833064 --0.330210 -0.485536 0.809454 --0.338996 -0.437135 0.833064 --0.490881 -0.322211 0.809454 --0.480475 -0.274132 0.833064 --0.576820 -0.109831 0.809454 --0.548807 -0.069395 0.833064 --0.574943 0.119268 0.809454 --0.533587 0.145907 0.833064 --0.485536 0.330211 0.809454 --0.437135 0.338996 0.833064 --0.322210 0.490881 0.809454 --0.274131 0.480475 0.833064 --0.109831 0.576820 0.809454 --0.069394 0.548807 0.833064 -0.119268 0.574943 0.809454 -0.145907 0.533588 0.833064 -112 -1 0 1 2 0 1 2 2 -1 0 3 1 0 3 1 2 -1 0 4 3 0 4 3 2 -1 0 5 4 0 5 4 2 -1 0 6 5 0 6 5 2 -1 0 7 6 0 7 6 2 -1 0 8 7 0 8 7 2 -1 0 9 8 0 9 8 2 -1 0 10 9 0 10 9 2 -1 0 11 10 0 11 10 2 -1 0 12 11 0 12 11 2 -1 0 13 12 0 13 12 2 -1 0 14 13 0 14 13 2 -1 0 15 14 0 15 14 2 -1 0 16 15 0 16 15 2 -1 0 2 16 0 2 16 2 -1 17 2 1 17 2 1 2 -1 17 1 18 17 1 18 2 -1 18 1 3 18 1 3 2 -1 18 3 19 18 3 19 2 -1 19 3 4 19 3 4 2 -1 19 4 20 19 4 20 2 -1 20 4 5 20 4 5 2 -1 20 5 21 20 5 21 2 -1 21 5 6 21 5 6 2 -1 21 6 22 21 6 22 2 -1 22 6 7 22 6 7 2 -1 22 7 23 22 7 23 2 -1 23 7 8 23 7 8 2 -1 23 8 24 23 8 24 2 -1 24 8 9 24 8 9 2 -1 24 9 25 24 9 25 2 -1 25 9 10 25 9 10 2 -1 25 10 26 25 10 26 2 -1 26 10 11 26 10 11 2 -1 26 11 27 26 11 27 2 -1 27 11 12 27 11 12 2 -1 27 12 28 27 12 28 2 -1 28 12 13 28 12 13 2 -1 28 13 29 28 13 29 2 -1 29 13 14 29 13 14 2 -1 29 14 30 29 14 30 2 -1 30 14 15 30 14 15 2 -1 30 15 31 30 15 31 2 -1 31 15 16 31 15 16 2 -1 31 16 32 31 16 32 2 -1 2 17 32 2 17 32 2 -1 2 32 16 2 32 16 2 -1 33 34 35 33 34 35 2 -1 33 35 36 33 35 36 2 -1 34 17 18 34 17 18 2 -1 34 18 35 34 18 35 2 -1 36 35 37 36 35 37 2 -1 36 37 38 36 37 38 2 -1 35 18 19 35 18 19 2 -1 35 19 37 35 19 37 2 -1 38 37 39 38 37 39 2 -1 38 39 40 38 39 40 2 -1 37 19 20 37 19 20 2 -1 37 20 39 37 20 39 2 -1 40 39 41 40 39 41 2 -1 40 41 42 40 41 42 2 -1 39 20 21 39 20 21 2 -1 39 21 41 39 21 41 2 -1 42 41 43 42 41 43 2 -1 42 43 44 42 43 44 2 -1 41 21 22 41 21 22 2 -1 41 22 43 41 22 43 2 -1 44 43 45 44 43 45 2 -1 44 45 46 44 45 46 2 -1 43 22 23 43 22 23 2 -1 43 23 45 43 23 45 2 -1 46 45 47 46 45 47 2 -1 46 47 48 46 47 48 2 -1 45 23 24 45 23 24 2 -1 45 24 47 45 24 47 2 -1 48 47 49 48 47 49 2 -1 48 49 50 48 49 50 2 -1 47 24 25 47 24 25 2 -1 47 25 49 47 25 49 2 -1 50 49 51 50 49 51 2 -1 50 51 52 50 51 52 2 -1 49 25 26 49 25 26 2 -1 49 26 51 49 26 51 2 -1 52 51 53 52 51 53 2 -1 52 53 54 52 53 54 2 -1 51 26 27 51 26 27 2 -1 51 27 53 51 27 53 2 -1 54 53 55 54 53 55 2 -1 54 55 56 54 55 56 2 -1 53 27 28 53 27 28 2 -1 53 28 55 53 28 55 2 -1 56 55 57 56 55 57 2 -1 56 57 58 56 57 58 2 -1 55 28 29 55 28 29 2 -1 55 29 57 55 29 57 2 -1 58 57 59 58 57 59 2 -1 58 59 60 58 59 60 2 -1 57 29 30 57 29 30 2 -1 57 30 59 57 30 59 2 -1 60 59 61 60 59 61 2 -1 60 61 62 60 61 62 2 -1 59 30 31 59 30 31 2 -1 59 31 61 59 31 61 2 -1 62 61 63 62 61 63 2 -1 62 63 64 62 63 64 2 -1 61 31 32 61 31 32 2 -1 61 32 63 61 32 63 2 -1 17 34 63 17 34 63 2 -1 17 63 32 17 63 32 2 -1 34 33 64 34 33 64 2 -1 34 64 63 34 64 63 2 - -Materials: 2 -"scroll" -0.000000 0.000000 0.000000 1.000000 -0.800000 0.800000 0.800000 1.000000 -1.000000 1.000000 1.000000 1.000000 -0.000000 0.000000 0.000000 1.000000 -0.000000 -1.000000 -"" -"" -"frame" -0.000000 0.000000 0.000000 1.000000 -0.800000 0.800000 0.800000 1.000000 -1.000000 1.000000 1.000000 1.000000 -0.000000 0.000000 0.000000 1.000000 -0.000000 -1.000000 -"" -"" - -Bones: 0 -GroupComments: 0 -MaterialComments: 0 -BoneComments: 0 -ModelComment: 0 +// MilkShape 3D ASCII + +Frames: 30 +Frame: 1 + +Meshes: 2 +"scroll" 0 0 +17 +0 18.576029 12.295176 2.879607 0.112493 0.233639 -1 +0 12.456854 18.468002 2.879607 0.095922 0.099912 -1 +0 0.000001 -0.000001 2.879607 0.062189 0.500000 -1 +0 21.867174 4.250518 2.879607 0.121405 0.407917 -1 +0 21.829239 -4.441243 2.879607 0.121302 0.596214 -1 +0 18.467995 -12.456865 2.879607 0.112200 0.769864 -1 +0 12.295166 -18.576036 2.879607 0.095484 0.902428 -1 +0 4.250505 -21.867176 2.879607 0.073699 0.973727 -1 +0 -4.441256 -21.829237 2.879607 0.050162 0.972905 -1 +0 -12.456874 -18.467987 2.879607 0.028456 0.900088 -1 +0 -18.576044 -12.295153 2.879607 0.011886 0.766360 -1 +0 -21.867182 -4.250491 2.879607 0.002973 0.592082 -1 +0 -21.829233 4.441269 2.879607 0.003076 0.403785 -1 +0 -18.467979 12.456886 2.879607 0.012178 0.230136 -1 +0 -12.295140 18.576052 2.879607 0.028894 0.097571 -1 +0 -4.250477 21.867180 2.879607 0.050679 0.026273 -1 +0 4.441284 21.829229 2.879607 0.074216 0.027095 -1 +1 +0.000000 0.000000 1.000000 +16 +0 0 1 2 0 0 0 1 +0 2 3 0 0 0 0 1 +0 2 4 3 0 0 0 1 +0 2 5 4 0 0 0 1 +0 2 6 5 0 0 0 1 +0 2 7 6 0 0 0 1 +0 2 8 7 0 0 0 1 +0 2 9 8 0 0 0 1 +0 2 10 9 0 0 0 1 +0 2 11 10 0 0 0 1 +0 2 12 11 0 0 0 1 +0 2 13 12 0 0 0 1 +0 2 14 13 0 0 0 1 +0 2 15 14 0 0 0 1 +0 2 16 15 0 0 0 1 +0 2 1 16 0 0 0 1 +"frame" 1 1 +65 +1 0.000000 -0.000000 3.321190 0.500000 0.500000 -1 +1 17.639259 11.675143 3.321190 0.856463 0.427477 -1 +1 11.828669 17.536682 3.321190 0.801575 0.296586 -1 +1 20.764435 4.036170 3.321190 0.857082 0.569410 -1 +1 20.728415 -4.217276 3.321190 0.803338 0.700776 -1 +1 17.536673 -11.828679 3.321190 0.703414 0.801575 -1 +1 11.675133 -17.639269 3.321190 0.572522 0.856463 -1 +1 4.036156 -20.764439 3.321190 0.430590 0.857082 -1 +1 -4.217289 -20.728411 3.321190 0.299224 0.803338 -1 +1 -11.828687 -17.536667 3.321190 0.198425 0.703414 -1 +1 -17.639275 -11.675121 3.321190 0.143537 0.572522 -1 +1 -20.764442 -4.036143 3.321190 0.142919 0.430589 -1 +1 -20.728407 4.217301 3.321190 0.196662 0.299224 -1 +1 -17.536659 11.828699 3.321190 0.296586 0.198425 -1 +1 -11.675112 17.639282 3.321190 0.427478 0.143538 -1 +1 -4.036130 20.764444 3.321190 0.569411 0.142919 -1 +1 4.217315 20.728405 3.321190 0.700777 0.196662 -1 +1 13.683175 20.286118 3.156490 0.848857 0.264694 -1 +1 20.404764 13.505603 3.156490 0.912349 0.416107 -1 +1 24.019917 4.668982 3.156490 0.913065 0.580292 -1 +1 23.978254 -4.878449 3.156490 0.850896 0.732254 -1 +1 20.286112 -13.683181 3.156490 0.735306 0.848857 -1 +1 13.505599 -20.404768 3.156490 0.583893 0.912349 -1 +1 4.668977 -24.019918 3.156490 0.419708 0.913065 -1 +1 -4.878453 -23.978252 3.156490 0.267746 0.850896 -1 +1 -13.683182 -20.286110 3.156490 0.151143 0.735306 -1 +1 -20.404770 -13.505592 3.156490 0.087651 0.583893 -1 +1 -24.019920 -4.668968 3.156490 0.086935 0.419708 -1 +1 -23.978251 4.878465 3.156490 0.149104 0.267746 -1 +1 -20.286102 13.683196 3.156490 0.264694 0.151143 -1 +1 -13.505578 20.404779 3.156490 0.416107 0.087651 -1 +1 -4.668952 24.019922 3.156490 0.580293 0.086935 -1 +1 4.878480 23.978243 3.156490 0.732254 0.149104 -1 +1 16.305698 24.174189 -0.301926 0.917477 0.218408 -1 +1 15.196015 22.529018 1.012907 0.887427 0.238677 -1 +1 22.660770 14.998834 1.012907 0.957940 0.406831 -1 +1 24.315565 16.094122 -0.301926 0.993459 0.399605 -1 +1 26.675631 5.185213 1.012907 0.958735 0.589169 -1 +1 28.623606 5.563864 -0.301926 0.994316 0.596085 -1 +1 26.629364 -5.417810 1.012907 0.889693 0.757932 -1 +1 28.573961 -5.813441 -0.301926 0.919919 0.777938 -1 +1 22.529016 -15.196017 1.012907 0.761323 0.887427 -1 +1 24.174189 -16.305698 -0.301926 0.781592 0.917477 -1 +1 14.998834 -22.660772 1.012907 0.593169 0.957940 -1 +1 16.094122 -24.315565 -0.301926 0.600395 0.993459 -1 +1 5.185220 -26.675629 1.012907 0.410831 0.958735 -1 +1 5.563870 -28.623604 -0.301926 0.403915 0.994316 -1 +1 -5.417803 -26.629364 1.012907 0.242068 0.889693 -1 +1 -5.813432 -28.573965 -0.301926 0.222062 0.919919 -1 +1 -15.196011 -22.529020 1.012907 0.112573 0.761323 -1 +1 -16.305689 -24.174196 -0.301926 0.082523 0.781592 -1 +1 -22.660770 -14.998836 1.012907 0.042060 0.593169 -1 +1 -24.315561 -16.094126 -0.301926 0.006541 0.600395 -1 +1 -26.675631 -5.185212 1.012907 0.041265 0.410831 -1 +1 -28.623606 -5.563865 -0.301926 0.005684 0.403915 -1 +1 -26.629358 5.417814 1.012907 0.110308 0.242068 -1 +1 -28.573961 5.813443 -0.301926 0.080082 0.222062 -1 +1 -22.529011 15.196029 1.012907 0.238677 0.112573 -1 +1 -24.174185 16.305708 -0.301926 0.218408 0.082523 -1 +1 -14.998822 22.660780 1.012907 0.406831 0.042060 -1 +1 -16.094109 24.315575 -0.301926 0.399605 0.006541 -1 +1 -5.185204 26.675629 1.012907 0.589169 0.041265 -1 +1 -5.563847 28.623608 -0.301926 0.596086 0.005684 -1 +1 5.417831 26.629356 1.012907 0.757932 0.110308 -1 +1 5.813461 28.573956 -0.301926 0.777938 0.080082 -1 +65 +0.000000 0.000000 1.000000 +0.023734 0.018076 0.999555 +0.015010 0.025783 0.999555 +0.028845 0.007618 0.999555 +0.029564 -0.004001 0.999555 +0.025783 -0.015010 0.999555 +0.018076 -0.023734 0.999555 +0.007618 -0.028845 0.999555 +-0.004001 -0.029564 0.999555 +-0.015010 -0.025783 0.999555 +-0.023734 -0.018076 0.999555 +-0.028845 -0.007618 0.999555 +-0.029564 0.004001 0.999555 +-0.025783 0.015010 0.999555 +-0.018076 0.023734 0.999555 +-0.007618 0.028845 0.999555 +0.004001 0.029565 0.999555 +0.179817 0.302000 0.936196 +0.281699 0.210198 0.936196 +0.340695 0.086397 0.936196 +0.347824 -0.050559 0.936196 +0.301999 -0.179816 0.936196 +0.210198 -0.281699 0.936196 +0.086396 -0.340695 0.936196 +-0.050559 -0.347824 0.936196 +-0.179817 -0.301999 0.936196 +-0.281699 -0.210198 0.936196 +-0.340695 -0.086396 0.936196 +-0.347824 0.050559 0.936196 +-0.301999 0.179817 0.936196 +-0.210198 0.281699 0.936196 +-0.086396 0.340695 0.936196 +0.050559 0.347824 0.936196 +0.338996 0.437135 0.833064 +0.330211 0.485536 0.809454 +0.490881 0.322211 0.809454 +0.480475 0.274132 0.833064 +0.576820 0.109832 0.809454 +0.548807 0.069395 0.833064 +0.574943 -0.119268 0.809454 +0.533588 -0.145907 0.833064 +0.485536 -0.330211 0.809454 +0.437135 -0.338996 0.833064 +0.322211 -0.490881 0.809454 +0.274132 -0.480475 0.833064 +0.109832 -0.576820 0.809454 +0.069395 -0.548807 0.833064 +-0.119268 -0.574943 0.809454 +-0.145907 -0.533588 0.833064 +-0.330210 -0.485536 0.809454 +-0.338996 -0.437135 0.833064 +-0.490881 -0.322211 0.809454 +-0.480475 -0.274132 0.833064 +-0.576820 -0.109831 0.809454 +-0.548807 -0.069395 0.833064 +-0.574943 0.119268 0.809454 +-0.533587 0.145907 0.833064 +-0.485536 0.330211 0.809454 +-0.437135 0.338996 0.833064 +-0.322210 0.490881 0.809454 +-0.274131 0.480475 0.833064 +-0.109831 0.576820 0.809454 +-0.069394 0.548807 0.833064 +0.119268 0.574943 0.809454 +0.145907 0.533588 0.833064 +112 +1 0 1 2 0 1 2 2 +1 0 3 1 0 3 1 2 +1 0 4 3 0 4 3 2 +1 0 5 4 0 5 4 2 +1 0 6 5 0 6 5 2 +1 0 7 6 0 7 6 2 +1 0 8 7 0 8 7 2 +1 0 9 8 0 9 8 2 +1 0 10 9 0 10 9 2 +1 0 11 10 0 11 10 2 +1 0 12 11 0 12 11 2 +1 0 13 12 0 13 12 2 +1 0 14 13 0 14 13 2 +1 0 15 14 0 15 14 2 +1 0 16 15 0 16 15 2 +1 0 2 16 0 2 16 2 +1 17 2 1 17 2 1 2 +1 17 1 18 17 1 18 2 +1 18 1 3 18 1 3 2 +1 18 3 19 18 3 19 2 +1 19 3 4 19 3 4 2 +1 19 4 20 19 4 20 2 +1 20 4 5 20 4 5 2 +1 20 5 21 20 5 21 2 +1 21 5 6 21 5 6 2 +1 21 6 22 21 6 22 2 +1 22 6 7 22 6 7 2 +1 22 7 23 22 7 23 2 +1 23 7 8 23 7 8 2 +1 23 8 24 23 8 24 2 +1 24 8 9 24 8 9 2 +1 24 9 25 24 9 25 2 +1 25 9 10 25 9 10 2 +1 25 10 26 25 10 26 2 +1 26 10 11 26 10 11 2 +1 26 11 27 26 11 27 2 +1 27 11 12 27 11 12 2 +1 27 12 28 27 12 28 2 +1 28 12 13 28 12 13 2 +1 28 13 29 28 13 29 2 +1 29 13 14 29 13 14 2 +1 29 14 30 29 14 30 2 +1 30 14 15 30 14 15 2 +1 30 15 31 30 15 31 2 +1 31 15 16 31 15 16 2 +1 31 16 32 31 16 32 2 +1 2 17 32 2 17 32 2 +1 2 32 16 2 32 16 2 +1 33 34 35 33 34 35 2 +1 33 35 36 33 35 36 2 +1 34 17 18 34 17 18 2 +1 34 18 35 34 18 35 2 +1 36 35 37 36 35 37 2 +1 36 37 38 36 37 38 2 +1 35 18 19 35 18 19 2 +1 35 19 37 35 19 37 2 +1 38 37 39 38 37 39 2 +1 38 39 40 38 39 40 2 +1 37 19 20 37 19 20 2 +1 37 20 39 37 20 39 2 +1 40 39 41 40 39 41 2 +1 40 41 42 40 41 42 2 +1 39 20 21 39 20 21 2 +1 39 21 41 39 21 41 2 +1 42 41 43 42 41 43 2 +1 42 43 44 42 43 44 2 +1 41 21 22 41 21 22 2 +1 41 22 43 41 22 43 2 +1 44 43 45 44 43 45 2 +1 44 45 46 44 45 46 2 +1 43 22 23 43 22 23 2 +1 43 23 45 43 23 45 2 +1 46 45 47 46 45 47 2 +1 46 47 48 46 47 48 2 +1 45 23 24 45 23 24 2 +1 45 24 47 45 24 47 2 +1 48 47 49 48 47 49 2 +1 48 49 50 48 49 50 2 +1 47 24 25 47 24 25 2 +1 47 25 49 47 25 49 2 +1 50 49 51 50 49 51 2 +1 50 51 52 50 51 52 2 +1 49 25 26 49 25 26 2 +1 49 26 51 49 26 51 2 +1 52 51 53 52 51 53 2 +1 52 53 54 52 53 54 2 +1 51 26 27 51 26 27 2 +1 51 27 53 51 27 53 2 +1 54 53 55 54 53 55 2 +1 54 55 56 54 55 56 2 +1 53 27 28 53 27 28 2 +1 53 28 55 53 28 55 2 +1 56 55 57 56 55 57 2 +1 56 57 58 56 57 58 2 +1 55 28 29 55 28 29 2 +1 55 29 57 55 29 57 2 +1 58 57 59 58 57 59 2 +1 58 59 60 58 59 60 2 +1 57 29 30 57 29 30 2 +1 57 30 59 57 30 59 2 +1 60 59 61 60 59 61 2 +1 60 61 62 60 61 62 2 +1 59 30 31 59 30 31 2 +1 59 31 61 59 31 61 2 +1 62 61 63 62 61 63 2 +1 62 63 64 62 63 64 2 +1 61 31 32 61 31 32 2 +1 61 32 63 61 32 63 2 +1 17 34 63 17 34 63 2 +1 17 63 32 17 63 32 2 +1 34 33 64 34 33 64 2 +1 34 64 63 34 64 63 2 + +Materials: 2 +"scroll" +0.000000 0.000000 0.000000 1.000000 +0.800000 0.800000 0.800000 1.000000 +1.000000 1.000000 1.000000 1.000000 +0.000000 0.000000 0.000000 1.000000 +0.000000 +1.000000 +"" +"" +"frame" +0.000000 0.000000 0.000000 1.000000 +0.800000 0.800000 0.800000 1.000000 +1.000000 1.000000 1.000000 1.000000 +0.000000 0.000000 0.000000 1.000000 +0.000000 +1.000000 +"" +"" + +Bones: 0 +GroupComments: 0 +MaterialComments: 0 +BoneComments: 0 +ModelComment: 0 diff --git a/NoteSkins/kb7/orbital/model/scroller.ini b/NoteSkins/kb7/orbital/model/scroller.ini index 62119a1e81..853ab82d79 100644 --- a/NoteSkins/kb7/orbital/model/scroller.ini +++ b/NoteSkins/kb7/orbital/model/scroller.ini @@ -1,5 +1,5 @@ -[AnimatedTexture] -TexVelocityY=1 -TexOffsetX=0 -Frame0000=scroller.png -Delay0000=1.0 +[AnimatedTexture] +TexVelocityY=1 +TexOffsetX=0 +Frame0000=scroller.png +Delay0000=1.0 diff --git a/NoteSkins/kb7/orbital/model/yellow.txt b/NoteSkins/kb7/orbital/model/yellow.txt index 0767ba8c67..2c41d89cd2 100644 --- a/NoteSkins/kb7/orbital/model/yellow.txt +++ b/NoteSkins/kb7/orbital/model/yellow.txt @@ -1,19 +1,19 @@ -Materials: 2 -"scroll" -0.000000 0.000000 0.000000 1.000000 -0.800000 0.800000 0.800000 1.000000 -1.000000 1.000000 1.000000 1.000000 -0.000000 0.000000 0.000000 1.000000 -0.000000 -1.000000 -"scroller.ini" -"" -"frame" -0.000000 0.000000 0.000000 1.000000 -0.800000 0.800000 0.800000 1.000000 -1.000000 1.000000 1.000000 1.000000 -0.000000 0.000000 0.000000 1.000000 -0.000000 -1.000000 -"_yellow (no mipmaps).png" -"" +Materials: 2 +"scroll" +0.000000 0.000000 0.000000 1.000000 +0.800000 0.800000 0.800000 1.000000 +1.000000 1.000000 1.000000 1.000000 +0.000000 0.000000 0.000000 1.000000 +0.000000 +1.000000 +"scroller.ini" +"" +"frame" +0.000000 0.000000 0.000000 1.000000 +0.800000 0.800000 0.800000 1.000000 +1.000000 1.000000 1.000000 1.000000 +0.000000 0.000000 0.000000 1.000000 +0.000000 +1.000000 +"_yellow (no mipmaps).png" +"" diff --git a/NoteSkins/pump/default/Center Tap Lift.lua b/NoteSkins/pump/default/Center Tap Lift.lua index 3691eba751..6b52abbc20 100644 --- a/NoteSkins/pump/default/Center Tap Lift.lua +++ b/NoteSkins/pump/default/Center Tap Lift.lua @@ -1,3 +1,3 @@ -return NOTESKIN:LoadActor("Center","Tap Note")..{ - InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0); +return NOTESKIN:LoadActor("Center","Tap Note")..{ + InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0); }; \ No newline at end of file diff --git a/NoteSkins/pump/default/DownLeft Tap Lift.lua b/NoteSkins/pump/default/DownLeft Tap Lift.lua index 90a29250be..c39c45f311 100644 --- a/NoteSkins/pump/default/DownLeft Tap Lift.lua +++ b/NoteSkins/pump/default/DownLeft Tap Lift.lua @@ -1,3 +1,3 @@ -return NOTESKIN:LoadActor("DownLeft","Tap Note")..{ - InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0) +return NOTESKIN:LoadActor("DownLeft","Tap Note")..{ + InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0) }; \ No newline at end of file diff --git a/NoteSkins/pump/default/DownRight Tap Lift.lua b/NoteSkins/pump/default/DownRight Tap Lift.lua index ee18e3364f..e133f1c528 100644 --- a/NoteSkins/pump/default/DownRight Tap Lift.lua +++ b/NoteSkins/pump/default/DownRight Tap Lift.lua @@ -1,3 +1,3 @@ -return NOTESKIN:LoadActor("DownRight","Tap Note")..{ - InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0) +return NOTESKIN:LoadActor("DownRight","Tap Note")..{ + InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0) }; \ No newline at end of file diff --git a/NoteSkins/pump/default/UpLeft Tap Lift.lua b/NoteSkins/pump/default/UpLeft Tap Lift.lua index 9096d27dec..e764dae2dc 100644 --- a/NoteSkins/pump/default/UpLeft Tap Lift.lua +++ b/NoteSkins/pump/default/UpLeft Tap Lift.lua @@ -1,3 +1,3 @@ -return NOTESKIN:LoadActor("UpLeft","Tap Note")..{ - InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0) +return NOTESKIN:LoadActor("UpLeft","Tap Note")..{ + InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0) }; \ No newline at end of file diff --git a/NoteSkins/pump/default/UpRight Tap Lift.lua b/NoteSkins/pump/default/UpRight Tap Lift.lua index 91c4f11011..415cab765e 100644 --- a/NoteSkins/pump/default/UpRight Tap Lift.lua +++ b/NoteSkins/pump/default/UpRight Tap Lift.lua @@ -1,3 +1,3 @@ -return NOTESKIN:LoadActor("UpRight","Tap Note")..{ - InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0) +return NOTESKIN:LoadActor("UpRight","Tap Note")..{ + InitCommand=cmd(effectclock,"beat";effectmagnitude,0.5,1,0) }; \ No newline at end of file diff --git a/Themes/_fallback/BGAnimations/ScreenSelectProfile overlay.lua b/Themes/_fallback/BGAnimations/ScreenSelectProfile overlay.lua index 8355b85580..2094ef1054 100644 --- a/Themes/_fallback/BGAnimations/ScreenSelectProfile overlay.lua +++ b/Themes/_fallback/BGAnimations/ScreenSelectProfile overlay.lua @@ -1,299 +1,299 @@ -function GetLocalProfiles() - local ret = {}; - - for p = 0,PROFILEMAN:GetNumLocalProfiles()-1 do - local profile=PROFILEMAN:GetLocalProfileFromIndex(p); - local item = Def.ActorFrame { ---[[ Def.Quad { - InitCommand=cmd(zoomto,200,1;y,40/2); - OnCommand=cmd(diffuse,Color('Outline');); - }; --]] - LoadFont("Common Normal") .. { - Text=profile:GetDisplayName(); - InitCommand=cmd(shadowlength,1;y,-10;zoom,1;ztest,true); - }; - LoadFont("Common Normal") .. { - InitCommand=cmd(shadowlength,1;y,8;zoom,0.5;vertspacing,-8;ztest,true); - BeginCommand=function(self) - local numSongsPlayed = profile:GetNumTotalSongsPlayed(); - local s = numSongsPlayed == 1 and "Song" or "Songs"; - -- todo: localize - self:settext( numSongsPlayed.." "..s.." Played" ); - end; - }; - }; - table.insert( ret, item ); - end; - - return ret; -end; - -function LoadCard(cColor) - local t = Def.ActorFrame { - LoadActor( THEME:GetPathG("ScreenSelectProfile","CardBackground") ) .. { - InitCommand=cmd(diffuse,cColor); - }; - LoadActor( THEME:GetPathG("ScreenSelectProfile","CardFrame") ); - }; - return t -end -function LoadPlayerStuff(Player) - local ret = {}; - - local pn = (Player == PLAYER_1) and 1 or 2; - ---[[ local t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 200, 230) .. { - Name = 'BigFrame'; - }; --]] - local t = Def.ActorFrame { - Name = 'JoinFrame'; - LoadCard(Color('Orange')); ---[[ Def.Quad { - InitCommand=cmd(zoomto,200+4,230+4); - OnCommand=cmd(shadowlength,1;diffuse,color("0,0,0,0.5")); - }; - Def.Quad { - InitCommand=cmd(zoomto,200,230); - OnCommand=cmd(diffuse,Color('Orange');diffusealpha,0.5); - }; --]] - LoadFont("Common Normal") .. { - Text="Press &START; to join."; - InitCommand=cmd(shadowlength,1); - OnCommand=cmd(diffuseshift;effectcolor1,Color('White');effectcolor2,color("0.5,0.5,0.5")); - }; - }; - table.insert( ret, t ); - - t = Def.ActorFrame { - Name = 'BigFrame'; - LoadCard(PlayerColor(Player)); - }; - table.insert( ret, t ); - ---[[ t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 170, 20) .. { - Name = 'SmallFrame'; - }; --]] - t = Def.ActorFrame { - Name = 'SmallFrame'; ---[[ Def.Quad { - InitCommand=cmd(zoomto,170+4,32+4); - OnCommand=cmd(shadowlength,1); - }; --]] - InitCommand=cmd(y,-2); - Def.Quad { - InitCommand=cmd(zoomto,200-10,40+2); - OnCommand=cmd(diffuse,Color('Black');diffusealpha,0.5); - }; - Def.Quad { - InitCommand=cmd(zoomto,200-10,40); - OnCommand=cmd(diffuse,PlayerColor(Player);fadeleft,0.25;faderight,0.25;glow,color("1,1,1,0.25")); - }; - Def.Quad { - InitCommand=cmd(zoomto,200-10,40;y,-40/2+20); - OnCommand=cmd(diffuse,Color("Black");fadebottom,1;diffusealpha,0.35); - }; - Def.Quad { - InitCommand=cmd(zoomto,200-10,1;y,-40/2+1); - OnCommand=cmd(diffuse,PlayerColor(Player);glow,color("1,1,1,0.25")); - }; - }; - table.insert( ret, t ); - - t = Def.ActorScroller{ - Name = 'Scroller'; - NumItemsToDraw=6; --- InitCommand=cmd(y,-230/2+20;); - OnCommand=cmd(y,1;SetFastCatchup,true;SetMask,200,58;SetSecondsPerItem,0.15); - TransformFunction=function(self, offset, itemIndex, numItems) - local focus = scale(math.abs(offset),0,2,1,0); - self:visible(false); - self:y(math.floor( offset*40 )); --- self:zoomy( focus ); --- self:z(-math.abs(offset)); --- self:zoom(focus); - end; - children = GetLocalProfiles(); - }; - table.insert( ret, t ); - - t = Def.ActorFrame { - Name = "EffectFrame"; - --[[ Def.Quad { - InitCommand=cmd(y,-230/2;vertalign,top;zoomto,200,8;fadebottom,1); - OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25); - }; - Def.Quad { - InitCommand=cmd(y,230/2;vertalign,bottom;zoomto,200,8;fadetop,1); - OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25); - }; --]] - }; - table.insert( ret, t ); ---[[ t = Def.BitmapText { - OnCommand = cmd(y,160); - Name = 'SelectedProfileText'; - Font = "Common Normal"; - Text = 'No profile'; - }; --]] - t = LoadFont("Common Normal") .. { - Name = 'SelectedProfileText'; - --InitCommand=cmd(y,160;shadowlength,1;diffuse,PlayerColor(Player)); - InitCommand=cmd(y,160;shadowlength,1;); - }; - table.insert( ret, t ); - - return ret; -end; - -function UpdateInternal3(self, Player) - local pn = (Player == PLAYER_1) and 1 or 2; - local frame = self:GetChild(string.format('P%uFrame', pn)); - local scroller = frame:GetChild('Scroller'); - local seltext = frame:GetChild('SelectedProfileText'); - local joinframe = frame:GetChild('JoinFrame'); - local smallframe = frame:GetChild('SmallFrame'); - local bigframe = frame:GetChild('BigFrame'); - - if GAMESTATE:IsHumanPlayer(Player) then - frame:visible(true); - if MEMCARDMAN:GetCardState(Player) == 'MemoryCardState_none' then - --using profile if any - joinframe:visible(false); - smallframe:visible(true); - bigframe:visible(true); - seltext:visible(true); - scroller:visible(true); - local ind = SCREENMAN:GetTopScreen():GetProfileIndex(Player); - if ind > 0 then - scroller:SetDestinationItem(ind-1); - seltext:settext(PROFILEMAN:GetLocalProfileFromIndex(ind-1):GetDisplayName()); - else - if SCREENMAN:GetTopScreen():SetProfileIndex(Player, 1) then - scroller:SetDestinationItem(0); - self:queuecommand('UpdateInternal2'); - else - joinframe:visible(true); - smallframe:visible(false); - bigframe:visible(false); - scroller:visible(false); - seltext:settext('No profile'); - end; - end; - else - --using card - smallframe:visible(false); - scroller:visible(false); - seltext:settext('CARD'); - SCREENMAN:GetTopScreen():SetProfileIndex(Player, 0); - end; - else - joinframe:visible(true); - scroller:visible(false); - seltext:visible(false); - smallframe:visible(false); - bigframe:visible(false); - end; -end; - -local t = Def.ActorFrame { - - StorageDevicesChangedMessageCommand=function(self, params) - self:queuecommand('UpdateInternal2'); - end; - - CodeMessageCommand = function(self, params) - if params.Name == 'Start' or params.Name == 'Center' then - MESSAGEMAN:Broadcast("StartButton"); - if not GAMESTATE:IsHumanPlayer(params.PlayerNumber) then - SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -1); - else - SCREENMAN:GetTopScreen():Finish(); - end; - end; - if params.Name == 'Up' or params.Name == 'Up2' or params.Name == 'DownLeft' then - if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then - local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber); - if ind > 1 then - if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind - 1 ) then - MESSAGEMAN:Broadcast("DirectionButton"); - self:queuecommand('UpdateInternal2'); - end; - end; - end; - end; - if params.Name == 'Down' or params.Name == 'Down2' or params.Name == 'DownRight' then - if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then - local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber); - if ind > 0 then - if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind + 1 ) then - MESSAGEMAN:Broadcast("DirectionButton"); - self:queuecommand('UpdateInternal2'); - end; - end; - end; - end; - if params.Name == 'Back' then - if GAMESTATE:GetNumPlayersEnabled()==0 then - SCREENMAN:GetTopScreen():Cancel(); - else - MESSAGEMAN:Broadcast("BackButton"); - SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -2); - end; - end; - end; - - PlayerJoinedMessageCommand=function(self, params) - self:queuecommand('UpdateInternal2'); - end; - - PlayerUnjoinedMessageCommand=function(self, params) - self:queuecommand('UpdateInternal2'); - end; - - OnCommand=function(self, params) - self:queuecommand('UpdateInternal2'); - end; - - UpdateInternal2Command=function(self) - UpdateInternal3(self, PLAYER_1); - UpdateInternal3(self, PLAYER_2); - end; - - children = { - Def.ActorFrame { - Name = 'P1Frame'; - InitCommand=cmd(x,SCREEN_CENTER_X-160;y,SCREEN_CENTER_Y); - OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1); - OffCommand=cmd(bouncebegin,0.35;zoom,0); - PlayerJoinedMessageCommand=function(self,param) - if param.Player == PLAYER_1 then - (cmd(;zoom,1.15;bounceend,0.175;zoom,1.0;))(self); - end; - end; - children = LoadPlayerStuff(PLAYER_1); - }; - Def.ActorFrame { - Name = 'P2Frame'; - InitCommand=cmd(x,SCREEN_CENTER_X+160;y,SCREEN_CENTER_Y); - OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1); - OffCommand=cmd(bouncebegin,0.35;zoom,0); - PlayerJoinedMessageCommand=function(self,param) - if param.Player == PLAYER_2 then - (cmd(zoom,1.15;bounceend,0.175;zoom,1.0;))(self); - end; - end; - children = LoadPlayerStuff(PLAYER_2); - }; - -- sounds - LoadActor( THEME:GetPathS("Common","start") )..{ - StartButtonMessageCommand=cmd(play); - }; - LoadActor( THEME:GetPathS("Common","cancel") )..{ - BackButtonMessageCommand=cmd(play); - }; - LoadActor( THEME:GetPathS("Common","value") )..{ - DirectionButtonMessageCommand=cmd(play); - }; - }; -}; - -return t; +function GetLocalProfiles() + local ret = {}; + + for p = 0,PROFILEMAN:GetNumLocalProfiles()-1 do + local profile=PROFILEMAN:GetLocalProfileFromIndex(p); + local item = Def.ActorFrame { +--[[ Def.Quad { + InitCommand=cmd(zoomto,200,1;y,40/2); + OnCommand=cmd(diffuse,Color('Outline');); + }; --]] + LoadFont("Common Normal") .. { + Text=profile:GetDisplayName(); + InitCommand=cmd(shadowlength,1;y,-10;zoom,1;ztest,true); + }; + LoadFont("Common Normal") .. { + InitCommand=cmd(shadowlength,1;y,8;zoom,0.5;vertspacing,-8;ztest,true); + BeginCommand=function(self) + local numSongsPlayed = profile:GetNumTotalSongsPlayed(); + local s = numSongsPlayed == 1 and "Song" or "Songs"; + -- todo: localize + self:settext( numSongsPlayed.." "..s.." Played" ); + end; + }; + }; + table.insert( ret, item ); + end; + + return ret; +end; + +function LoadCard(cColor) + local t = Def.ActorFrame { + LoadActor( THEME:GetPathG("ScreenSelectProfile","CardBackground") ) .. { + InitCommand=cmd(diffuse,cColor); + }; + LoadActor( THEME:GetPathG("ScreenSelectProfile","CardFrame") ); + }; + return t +end +function LoadPlayerStuff(Player) + local ret = {}; + + local pn = (Player == PLAYER_1) and 1 or 2; + +--[[ local t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 200, 230) .. { + Name = 'BigFrame'; + }; --]] + local t = Def.ActorFrame { + Name = 'JoinFrame'; + LoadCard(Color('Orange')); +--[[ Def.Quad { + InitCommand=cmd(zoomto,200+4,230+4); + OnCommand=cmd(shadowlength,1;diffuse,color("0,0,0,0.5")); + }; + Def.Quad { + InitCommand=cmd(zoomto,200,230); + OnCommand=cmd(diffuse,Color('Orange');diffusealpha,0.5); + }; --]] + LoadFont("Common Normal") .. { + Text="Press &START; to join."; + InitCommand=cmd(shadowlength,1); + OnCommand=cmd(diffuseshift;effectcolor1,Color('White');effectcolor2,color("0.5,0.5,0.5")); + }; + }; + table.insert( ret, t ); + + t = Def.ActorFrame { + Name = 'BigFrame'; + LoadCard(PlayerColor(Player)); + }; + table.insert( ret, t ); + +--[[ t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 170, 20) .. { + Name = 'SmallFrame'; + }; --]] + t = Def.ActorFrame { + Name = 'SmallFrame'; +--[[ Def.Quad { + InitCommand=cmd(zoomto,170+4,32+4); + OnCommand=cmd(shadowlength,1); + }; --]] + InitCommand=cmd(y,-2); + Def.Quad { + InitCommand=cmd(zoomto,200-10,40+2); + OnCommand=cmd(diffuse,Color('Black');diffusealpha,0.5); + }; + Def.Quad { + InitCommand=cmd(zoomto,200-10,40); + OnCommand=cmd(diffuse,PlayerColor(Player);fadeleft,0.25;faderight,0.25;glow,color("1,1,1,0.25")); + }; + Def.Quad { + InitCommand=cmd(zoomto,200-10,40;y,-40/2+20); + OnCommand=cmd(diffuse,Color("Black");fadebottom,1;diffusealpha,0.35); + }; + Def.Quad { + InitCommand=cmd(zoomto,200-10,1;y,-40/2+1); + OnCommand=cmd(diffuse,PlayerColor(Player);glow,color("1,1,1,0.25")); + }; + }; + table.insert( ret, t ); + + t = Def.ActorScroller{ + Name = 'Scroller'; + NumItemsToDraw=6; +-- InitCommand=cmd(y,-230/2+20;); + OnCommand=cmd(y,1;SetFastCatchup,true;SetMask,200,58;SetSecondsPerItem,0.15); + TransformFunction=function(self, offset, itemIndex, numItems) + local focus = scale(math.abs(offset),0,2,1,0); + self:visible(false); + self:y(math.floor( offset*40 )); +-- self:zoomy( focus ); +-- self:z(-math.abs(offset)); +-- self:zoom(focus); + end; + children = GetLocalProfiles(); + }; + table.insert( ret, t ); + + t = Def.ActorFrame { + Name = "EffectFrame"; + --[[ Def.Quad { + InitCommand=cmd(y,-230/2;vertalign,top;zoomto,200,8;fadebottom,1); + OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25); + }; + Def.Quad { + InitCommand=cmd(y,230/2;vertalign,bottom;zoomto,200,8;fadetop,1); + OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25); + }; --]] + }; + table.insert( ret, t ); +--[[ t = Def.BitmapText { + OnCommand = cmd(y,160); + Name = 'SelectedProfileText'; + Font = "Common Normal"; + Text = 'No profile'; + }; --]] + t = LoadFont("Common Normal") .. { + Name = 'SelectedProfileText'; + --InitCommand=cmd(y,160;shadowlength,1;diffuse,PlayerColor(Player)); + InitCommand=cmd(y,160;shadowlength,1;); + }; + table.insert( ret, t ); + + return ret; +end; + +function UpdateInternal3(self, Player) + local pn = (Player == PLAYER_1) and 1 or 2; + local frame = self:GetChild(string.format('P%uFrame', pn)); + local scroller = frame:GetChild('Scroller'); + local seltext = frame:GetChild('SelectedProfileText'); + local joinframe = frame:GetChild('JoinFrame'); + local smallframe = frame:GetChild('SmallFrame'); + local bigframe = frame:GetChild('BigFrame'); + + if GAMESTATE:IsHumanPlayer(Player) then + frame:visible(true); + if MEMCARDMAN:GetCardState(Player) == 'MemoryCardState_none' then + --using profile if any + joinframe:visible(false); + smallframe:visible(true); + bigframe:visible(true); + seltext:visible(true); + scroller:visible(true); + local ind = SCREENMAN:GetTopScreen():GetProfileIndex(Player); + if ind > 0 then + scroller:SetDestinationItem(ind-1); + seltext:settext(PROFILEMAN:GetLocalProfileFromIndex(ind-1):GetDisplayName()); + else + if SCREENMAN:GetTopScreen():SetProfileIndex(Player, 1) then + scroller:SetDestinationItem(0); + self:queuecommand('UpdateInternal2'); + else + joinframe:visible(true); + smallframe:visible(false); + bigframe:visible(false); + scroller:visible(false); + seltext:settext('No profile'); + end; + end; + else + --using card + smallframe:visible(false); + scroller:visible(false); + seltext:settext('CARD'); + SCREENMAN:GetTopScreen():SetProfileIndex(Player, 0); + end; + else + joinframe:visible(true); + scroller:visible(false); + seltext:visible(false); + smallframe:visible(false); + bigframe:visible(false); + end; +end; + +local t = Def.ActorFrame { + + StorageDevicesChangedMessageCommand=function(self, params) + self:queuecommand('UpdateInternal2'); + end; + + CodeMessageCommand = function(self, params) + if params.Name == 'Start' or params.Name == 'Center' then + MESSAGEMAN:Broadcast("StartButton"); + if not GAMESTATE:IsHumanPlayer(params.PlayerNumber) then + SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -1); + else + SCREENMAN:GetTopScreen():Finish(); + end; + end; + if params.Name == 'Up' or params.Name == 'Up2' or params.Name == 'DownLeft' then + if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then + local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber); + if ind > 1 then + if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind - 1 ) then + MESSAGEMAN:Broadcast("DirectionButton"); + self:queuecommand('UpdateInternal2'); + end; + end; + end; + end; + if params.Name == 'Down' or params.Name == 'Down2' or params.Name == 'DownRight' then + if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then + local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber); + if ind > 0 then + if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind + 1 ) then + MESSAGEMAN:Broadcast("DirectionButton"); + self:queuecommand('UpdateInternal2'); + end; + end; + end; + end; + if params.Name == 'Back' then + if GAMESTATE:GetNumPlayersEnabled()==0 then + SCREENMAN:GetTopScreen():Cancel(); + else + MESSAGEMAN:Broadcast("BackButton"); + SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -2); + end; + end; + end; + + PlayerJoinedMessageCommand=function(self, params) + self:queuecommand('UpdateInternal2'); + end; + + PlayerUnjoinedMessageCommand=function(self, params) + self:queuecommand('UpdateInternal2'); + end; + + OnCommand=function(self, params) + self:queuecommand('UpdateInternal2'); + end; + + UpdateInternal2Command=function(self) + UpdateInternal3(self, PLAYER_1); + UpdateInternal3(self, PLAYER_2); + end; + + children = { + Def.ActorFrame { + Name = 'P1Frame'; + InitCommand=cmd(x,SCREEN_CENTER_X-160;y,SCREEN_CENTER_Y); + OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1); + OffCommand=cmd(bouncebegin,0.35;zoom,0); + PlayerJoinedMessageCommand=function(self,param) + if param.Player == PLAYER_1 then + (cmd(;zoom,1.15;bounceend,0.175;zoom,1.0;))(self); + end; + end; + children = LoadPlayerStuff(PLAYER_1); + }; + Def.ActorFrame { + Name = 'P2Frame'; + InitCommand=cmd(x,SCREEN_CENTER_X+160;y,SCREEN_CENTER_Y); + OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1); + OffCommand=cmd(bouncebegin,0.35;zoom,0); + PlayerJoinedMessageCommand=function(self,param) + if param.Player == PLAYER_2 then + (cmd(zoom,1.15;bounceend,0.175;zoom,1.0;))(self); + end; + end; + children = LoadPlayerStuff(PLAYER_2); + }; + -- sounds + LoadActor( THEME:GetPathS("Common","start") )..{ + StartButtonMessageCommand=cmd(play); + }; + LoadActor( THEME:GetPathS("Common","cancel") )..{ + BackButtonMessageCommand=cmd(play); + }; + LoadActor( THEME:GetPathS("Common","value") )..{ + DirectionButtonMessageCommand=cmd(play); + }; + }; +}; + +return t; diff --git a/Themes/_fallback/Fonts/_16px fonts.ini b/Themes/_fallback/Fonts/_16px fonts.ini index d56c851b17..79f5845f2f 100644 --- a/Themes/_fallback/Fonts/_16px fonts.ini +++ b/Themes/_fallback/Fonts/_16px fonts.ini @@ -1,8 +1,8 @@ -# _16px fonts is a "virtual font" that assembles various fonts into a unified -# place. _16px fonts in particular is imported in Common default.ini. - -# Also, themes can create new fonts, and overload this file to -# have them pulled in for every 16-pixel font. -# xxx: we don't have 16px japanese or korean fonts -[main] -import=_Thai 16px,_misc 16px,_game chars 16px +# _16px fonts is a "virtual font" that assembles various fonts into a unified +# place. _16px fonts in particular is imported in Common default.ini. + +# Also, themes can create new fonts, and overload this file to +# have them pulled in for every 16-pixel font. +# xxx: we don't have 16px japanese or korean fonts +[main] +import=_Thai 16px,_misc 16px,_game chars 16px diff --git a/Themes/_fallback/Fonts/_20px fonts.ini b/Themes/_fallback/Fonts/_20px fonts.ini index 915647249d..80a5bc177b 100644 --- a/Themes/_fallback/Fonts/_20px fonts.ini +++ b/Themes/_fallback/Fonts/_20px fonts.ini @@ -1,13 +1,13 @@ -# This "font" just pulls in default characters for a 20-pixel -# font. Other import fonts can be created for other sizes. - -# Also, themes can create new fonts, and overload this file to -# have them pulled in for every 20-pixel font. -[main] -# We don't have a 20px Japanese font, so use the 24px one instead; -# pulling in a Kanji font that's a little too big looks fine, but -# pulling in one that's a little too small looks bad. - -# The characters in _game chars 16px are actually very large; -# they'll look fine here, too. -import=_japanese 24px,_korean 24px,_game chars 16px,_misc 16px +# This "font" just pulls in default characters for a 20-pixel +# font. Other import fonts can be created for other sizes. + +# Also, themes can create new fonts, and overload this file to +# have them pulled in for every 20-pixel font. +[main] +# We don't have a 20px Japanese font, so use the 24px one instead; +# pulling in a Kanji font that's a little too big looks fine, but +# pulling in one that's a little too small looks bad. + +# The characters in _game chars 16px are actually very large; +# they'll look fine here, too. +import=_japanese 24px,_korean 24px,_game chars 16px,_misc 16px diff --git a/Themes/_fallback/Graphics/CombinedLifeMeterTug separator.lua b/Themes/_fallback/Graphics/CombinedLifeMeterTug separator.lua index 26c8a67907..2891a47698 100644 --- a/Themes/_fallback/Graphics/CombinedLifeMeterTug separator.lua +++ b/Themes/_fallback/Graphics/CombinedLifeMeterTug separator.lua @@ -1,3 +1,3 @@ -return Def.Quad{ - InitCommand=cmd(zoomto,4,22;diffuse,color("#AABBDD")); +return Def.Quad{ + InitCommand=cmd(zoomto,4,22;diffuse,color("#AABBDD")); }; \ No newline at end of file diff --git a/Themes/_fallback/Scripts/03 IniFile.lua b/Themes/_fallback/Scripts/03 IniFile.lua index 2bad1403db..93674d6133 100644 --- a/Themes/_fallback/Scripts/03 IniFile.lua +++ b/Themes/_fallback/Scripts/03 IniFile.lua @@ -1,119 +1,119 @@ ---[[ -IniFile: basically a Lua rewrite of SM's IniFile class that serves as the -basis for the sm-ssc UserPrefs and ThemePrefs configuration systems. -Note that this is a namespace, not a class per se. ---]] - --- TODO: move this into a more general section --- func takes a key and a value -function foreach_ordered( tbl, func ) - local keys = { } - for k,_ in pairs(tbl) do keys[#keys+1] = k end - - table.sort( keys ) - - -- iterate in sorted order - for _,key in ipairs(keys) do func( key, tbl[key]) end -end - --- redeclared here for my sanity's sake --- TODO: declare these as global variables -local RageFile = -{ - READ = 1, - WRITE = 2, - STREAMED = 4, - SLOW_FLUSH = 8 -} - --- IniFile namespace -IniFile = -{ - StrToKeyVal = function( str ) - local _, _, key, value = str:find( "(.+)=(.*)" ) - - -- key is always a string, but value may be num, bool, or nil. - -- do a few quick checks to see which one it is. - - -- if it's a nil, convert it to an empty string and return - if value == nil then value = ""; return key, value; end - - -- if it's a number, convert it in place and return - if tonumber(value) ~= nil then value = tonumber(value); return key, value; end - - -- not a number, so let's try a boolean value - if value == "true" then value = true; - elseif value == "false" then value = false; - end - - return key, value - end, - - ReadFile = function( file_path ) - Trace( "IniFile.ReadFile( " .. file_path .. " )" ) - local file = RageFileUtil.CreateRageFile() - - if not file:Open(file_path, RageFile.READ) then - Warn( string.format("ReadFile(%s): %s",file_path,file:GetError()) ) - file:destroy() - return { } -- return a blank table - end - - local tbl = { } - local current = tbl - - while not file:AtEOF() do - local str = file:GetLine() - - -- is this a section? - local _, _, sec = str:find( "%[(.+)%]" ) - - -- if so, set focus there; otherwise, try to - -- read a key/value pair (ignore blank lines) - if sec then - -- if this section doesn't exist, create it - tbl[sec] = tbl[sec] and tbl[sec] or { } - current = tbl[sec] - Warn( "Switching section to " .. sec ) - else - local k, v = IniFile.StrToKeyVal( str ) - if k and v then current[k] = v end - end - end - - file:Close() - file:destroy() - - return tbl - end, - - WriteFile = function( file_path, tbl ) - Trace( "IniFile.WriteFile( " .. file_path .. " )" ) - local file = RageFileUtil.CreateRageFile() - - if not file:Open(file_path, RageFile.WRITE) then - Warn( string.format("WriteFile(%s): %s",file_path.file:GetError()) ) - file:destroy() - return false - end - - -- declare functions so we can write with foreach_ordered - local function put_pair( k, v ) - file:PutLine( string.format("%s=%s", k, tostring(v)) ) - end - - local function put_section( section, pair ) - file:PutLine( "[" .. section .. "]" ) - foreach_ordered( pair, put_pair ) - file:PutLine("") -- put a blank line between sections - end - - -- each base key is a section and its value is a - -- table of key-value pairs under that section. - foreach_ordered( tbl, put_section ) - - file:Close() - file:destroy() - return true - end -}; +--[[ +IniFile: basically a Lua rewrite of SM's IniFile class that serves as the +basis for the sm-ssc UserPrefs and ThemePrefs configuration systems. +Note that this is a namespace, not a class per se. +--]] + +-- TODO: move this into a more general section +-- func takes a key and a value +function foreach_ordered( tbl, func ) + local keys = { } + for k,_ in pairs(tbl) do keys[#keys+1] = k end + + table.sort( keys ) + + -- iterate in sorted order + for _,key in ipairs(keys) do func( key, tbl[key]) end +end + +-- redeclared here for my sanity's sake +-- TODO: declare these as global variables +local RageFile = +{ + READ = 1, + WRITE = 2, + STREAMED = 4, + SLOW_FLUSH = 8 +} + +-- IniFile namespace +IniFile = +{ + StrToKeyVal = function( str ) + local _, _, key, value = str:find( "(.+)=(.*)" ) + + -- key is always a string, but value may be num, bool, or nil. + -- do a few quick checks to see which one it is. + + -- if it's a nil, convert it to an empty string and return + if value == nil then value = ""; return key, value; end + + -- if it's a number, convert it in place and return + if tonumber(value) ~= nil then value = tonumber(value); return key, value; end + + -- not a number, so let's try a boolean value + if value == "true" then value = true; + elseif value == "false" then value = false; + end + + return key, value + end, + + ReadFile = function( file_path ) + Trace( "IniFile.ReadFile( " .. file_path .. " )" ) + local file = RageFileUtil.CreateRageFile() + + if not file:Open(file_path, RageFile.READ) then + Warn( string.format("ReadFile(%s): %s",file_path,file:GetError()) ) + file:destroy() + return { } -- return a blank table + end + + local tbl = { } + local current = tbl + + while not file:AtEOF() do + local str = file:GetLine() + + -- is this a section? + local _, _, sec = str:find( "%[(.+)%]" ) + + -- if so, set focus there; otherwise, try to + -- read a key/value pair (ignore blank lines) + if sec then + -- if this section doesn't exist, create it + tbl[sec] = tbl[sec] and tbl[sec] or { } + current = tbl[sec] + Warn( "Switching section to " .. sec ) + else + local k, v = IniFile.StrToKeyVal( str ) + if k and v then current[k] = v end + end + end + + file:Close() + file:destroy() + + return tbl + end, + + WriteFile = function( file_path, tbl ) + Trace( "IniFile.WriteFile( " .. file_path .. " )" ) + local file = RageFileUtil.CreateRageFile() + + if not file:Open(file_path, RageFile.WRITE) then + Warn( string.format("WriteFile(%s): %s",file_path.file:GetError()) ) + file:destroy() + return false + end + + -- declare functions so we can write with foreach_ordered + local function put_pair( k, v ) + file:PutLine( string.format("%s=%s", k, tostring(v)) ) + end + + local function put_section( section, pair ) + file:PutLine( "[" .. section .. "]" ) + foreach_ordered( pair, put_pair ) + file:PutLine("") -- put a blank line between sections + end + + -- each base key is a section and its value is a + -- table of key-value pairs under that section. + foreach_ordered( tbl, put_section ) + + file:Close() + file:destroy() + return true + end +}; diff --git a/Themes/_fallback/Scripts/03 ThemePrefs.lua b/Themes/_fallback/Scripts/03 ThemePrefs.lua index 0a61da5741..aeca8f7a04 100644 --- a/Themes/_fallback/Scripts/03 ThemePrefs.lua +++ b/Themes/_fallback/Scripts/03 ThemePrefs.lua @@ -1,141 +1,141 @@ ---[[ -ThemePrefs: handles the underlying structure for ThemePrefs, so any themes -built off of this can simply declare their prefs and default values, and -access them through this system. - -v0.7.1: Dec. 28, 2010. Added language support. -v0.7.0: Dec. 15, 2010. Initial version. - -vyhd wrote this for sm-ssc. <3 you guys ---]] - --- local function to handle themed error strings --- (and to ensure we're getting all of them from the same section) -local function GetString( name ) - return THEME:GetString( "ThemePrefs", name ) -end - -function PrintTable( tbl ) - Trace( "Printing table" ) - for k,v in pairs(tbl) do - Trace( ("[%s] -> %s"):format(tostring(k),tostring(v)) ) - end -end - -local ThemePrefsPath = "Save/ThemePrefs.ini"; -local FallbackTheme = "_fallback"; - --- This will be set on load. -local PrefsTable = nil; - --- Gets the name of the current theme using themeInfo --- if available and the ThemeManager name otherwise. -local function GetThemeName() - return themeInfo and themeInfo.Name or THEME:GetThemeDisplayName() -end - --- Given a preference name, returns the table it's in. Checks the current --- theme first, then _fallback, then all other sections, in that order. -local function ResolveTable( pref ) - -- check the section for this theme - local name = GetThemeName() - local val = PrefsTable[name][pref] - - if val ~= nil then - Trace( ("ResolveTable(%s): found in %s"):format(pref,name) ) - return PrefsTable[name] - end - - -- not in the current theme; check the fallback if it exists - if PrefsTable[FallbackTheme] then - val = PrefsTable[FallbackTheme][pref] - if val ~= nil then - Trace( ("ResolveTable(%s): found in fallback"):format(pref) ) - return PrefsTable[FallbackTheme] - end - end - - -- not there either. check every section. - -- XXX: we should do this less redundantly. - for section, _ in pairs(PrefsTable) do - val = PrefsTable[section][pref] - if val ~= nil then - Trace( ("ResolveTable(%s): found in section %s"):format(pref,section) ) - return PrefsTable[section] end - end - - -- not found at all - Trace( ("ResolveTable(%s): pref not found"):format(pref) ) - return nil -end - -ThemePrefs = -{ - NeedsSaved = false, - - -- Loads preferences from Save/ThemePrefs.ini, then adds theme - -- preferences (and default values if applicable) to PrefsTable. - -- Only read from disk once, when _fallback calls this; we just - -- need the base set once to add prefs onto. - Init = function( prefs, bLoadFromDisk ) - -- If we don't have IniFile, we can't read/write from/to disk - if not IniFile then Warn( GetString("IniFileMissing") ) end - - Trace( ("ThemePrefs.Init(prefs, %s)"):format(tostring(bLoadFromDisk)) ) - if bLoadFromDisk then - Trace( "ThemePrefs.Init: loading from disk" ) - if not ThemePrefs.Load() then return false end - end - - Trace( "ThemePrefs.Init: not loading from disk" ) - - -- create the section if it doesn't exist - local section = GetThemeName() - PrefsTable[section] = PrefsTable[section] and PrefsTable[section] or { } - - Trace( "Using section " .. section ) - - -- if the key doesn't exist, add it with our default value - for k, tbl in pairs(prefs) do - if not PrefsTable[section][k] then - Trace( k .. " doesn't exist, creating" ) - PrefsTable[section][k] = tbl.Default - end - end - - PrintTable( PrefsTable[section] ) - end, - - Load = function() - if not IniFile then return false end - PrefsTable = IniFile.ReadFile( ThemePrefsPath ) - return true - end, - - Save = function() - Trace( "ThemePrefs.Save" ) - if not IniFile then return false end - if not NeedsSaved then return end - NeedsSaved = false - IniFile.WriteFile( ThemePrefsPath, PrefsTable ) - end, - - Get = function( name ) - Trace( ("ThemePrefs.Get(%s)"):format(name) ) - local tbl = ResolveTable(name) - if tbl then return tbl[name] end - Warn( "Get: "..GetString("UnknownPreference"):format(name) ) - return nil - end, - - Set = function( name, value ) - Trace( ("ThemePrefs.Set(%s, %s)"):format(name, tostring(value)) ) - local tbl = ResolveTable(name) - if tbl then tbl[name] = value; NeedsSaved = true; return end - Warn( "Set: "..GetString("UnknownPreference"):format(name) ) - end, -}; - --- global aliases -GetThemePref = ThemePrefs.Get -SetThemePref = ThemePrefs.Set +--[[ +ThemePrefs: handles the underlying structure for ThemePrefs, so any themes +built off of this can simply declare their prefs and default values, and +access them through this system. + +v0.7.1: Dec. 28, 2010. Added language support. +v0.7.0: Dec. 15, 2010. Initial version. + +vyhd wrote this for sm-ssc. <3 you guys +--]] + +-- local function to handle themed error strings +-- (and to ensure we're getting all of them from the same section) +local function GetString( name ) + return THEME:GetString( "ThemePrefs", name ) +end + +function PrintTable( tbl ) + Trace( "Printing table" ) + for k,v in pairs(tbl) do + Trace( ("[%s] -> %s"):format(tostring(k),tostring(v)) ) + end +end + +local ThemePrefsPath = "Save/ThemePrefs.ini"; +local FallbackTheme = "_fallback"; + +-- This will be set on load. +local PrefsTable = nil; + +-- Gets the name of the current theme using themeInfo +-- if available and the ThemeManager name otherwise. +local function GetThemeName() + return themeInfo and themeInfo.Name or THEME:GetThemeDisplayName() +end + +-- Given a preference name, returns the table it's in. Checks the current +-- theme first, then _fallback, then all other sections, in that order. +local function ResolveTable( pref ) + -- check the section for this theme + local name = GetThemeName() + local val = PrefsTable[name][pref] + + if val ~= nil then + Trace( ("ResolveTable(%s): found in %s"):format(pref,name) ) + return PrefsTable[name] + end + + -- not in the current theme; check the fallback if it exists + if PrefsTable[FallbackTheme] then + val = PrefsTable[FallbackTheme][pref] + if val ~= nil then + Trace( ("ResolveTable(%s): found in fallback"):format(pref) ) + return PrefsTable[FallbackTheme] + end + end + + -- not there either. check every section. + -- XXX: we should do this less redundantly. + for section, _ in pairs(PrefsTable) do + val = PrefsTable[section][pref] + if val ~= nil then + Trace( ("ResolveTable(%s): found in section %s"):format(pref,section) ) + return PrefsTable[section] end + end + + -- not found at all + Trace( ("ResolveTable(%s): pref not found"):format(pref) ) + return nil +end + +ThemePrefs = +{ + NeedsSaved = false, + + -- Loads preferences from Save/ThemePrefs.ini, then adds theme + -- preferences (and default values if applicable) to PrefsTable. + -- Only read from disk once, when _fallback calls this; we just + -- need the base set once to add prefs onto. + Init = function( prefs, bLoadFromDisk ) + -- If we don't have IniFile, we can't read/write from/to disk + if not IniFile then Warn( GetString("IniFileMissing") ) end + + Trace( ("ThemePrefs.Init(prefs, %s)"):format(tostring(bLoadFromDisk)) ) + if bLoadFromDisk then + Trace( "ThemePrefs.Init: loading from disk" ) + if not ThemePrefs.Load() then return false end + end + + Trace( "ThemePrefs.Init: not loading from disk" ) + + -- create the section if it doesn't exist + local section = GetThemeName() + PrefsTable[section] = PrefsTable[section] and PrefsTable[section] or { } + + Trace( "Using section " .. section ) + + -- if the key doesn't exist, add it with our default value + for k, tbl in pairs(prefs) do + if not PrefsTable[section][k] then + Trace( k .. " doesn't exist, creating" ) + PrefsTable[section][k] = tbl.Default + end + end + + PrintTable( PrefsTable[section] ) + end, + + Load = function() + if not IniFile then return false end + PrefsTable = IniFile.ReadFile( ThemePrefsPath ) + return true + end, + + Save = function() + Trace( "ThemePrefs.Save" ) + if not IniFile then return false end + if not NeedsSaved then return end + NeedsSaved = false + IniFile.WriteFile( ThemePrefsPath, PrefsTable ) + end, + + Get = function( name ) + Trace( ("ThemePrefs.Get(%s)"):format(name) ) + local tbl = ResolveTable(name) + if tbl then return tbl[name] end + Warn( "Get: "..GetString("UnknownPreference"):format(name) ) + return nil + end, + + Set = function( name, value ) + Trace( ("ThemePrefs.Set(%s, %s)"):format(name, tostring(value)) ) + local tbl = ResolveTable(name) + if tbl then tbl[name] = value; NeedsSaved = true; return end + Warn( "Set: "..GetString("UnknownPreference"):format(name) ) + end, +}; + +-- global aliases +GetThemePref = ThemePrefs.Get +SetThemePref = ThemePrefs.Set diff --git a/Themes/_fallback/Scripts/03 ThemePrefsRows.lua b/Themes/_fallback/Scripts/03 ThemePrefsRows.lua index 21ad8973c2..3938c922e3 100644 --- a/Themes/_fallback/Scripts/03 ThemePrefsRows.lua +++ b/Themes/_fallback/Scripts/03 ThemePrefsRows.lua @@ -1,164 +1,164 @@ ---[[ -ThemePrefsRows: you give it the choices, values, and params, and it'll -generate the rest; quirky behavior to be outlined below. Documentation -will be provided once this system is stabilized. - -v0.5.2: Dec. 28, 2010. Throw an error for default/value type mismatches. -v0.5.1: Dec. 27, 2010. Fix Choices not necessarily being strings. -v0.5.0: Dec. 15, 2010. Initial version. Not very well tested. - -vyhd wrote this for sm-ssc ---]] - --- unless overridden, these parameters will be used for the OptionsRow -local DefaultParams = -{ - LayoutType = "ShowAllInRow", - SelectType = "SelectOne", - OneChoiceForAllPlayers = true, - ExportOnChange = false, - EnabledForPlayers = nil, - ReloadRowMessages = nil, - - -- takes a function(self, list, pn); - -- if not used, we use the default - LoadSelections = nil, - SaveSelections = nil, -} - --- local alias to simplify error reporting -local function GetString( name ) - return THEME:GetString( "ThemePrefsRows", name ) -end - -local function DefaultLoad( pref, default, choices, values ) - return function(self, list, pn) - local val = ThemePrefs.Get( pref ) - - -- if our current value is here, set focus to that - for i=1, #choices do - if values[i] == val then list[i] = true return end - end - - -- try the default value - for i=1, #choices do - if values[i] == default then list[i] = true return end - end - - -- set to the first value and output a warning - Warn( GetString("NoDefaultInValues"):format(pref) ) - list[1] = true - end -end - -local function DefaultSave( pref, choices, values ) - local msg = "ThemePrefChanged" - local params = { Name = pref } - - return function(self, list, pn) - for i=1, #choices do - if list[i] then ThemePrefs.Set( pref, values[i] ) break end - MESSAGEMAN:Broadcast( msg, params ) - end - end -end - --- This function checks for mismatches between the default value and the --- values table passed to the ThemePrefRow, e.g. it will return false if --- you have a boolean default and an integer value. I'm somewhat stricter --- about types than Lua is because I don't like the unpredictability and --- complexity of coercing values transparently in a bunch of places. -local function TypesMatch( Values, Default ) - local DefaultType = type(Default) - - for i, value in ipairs(Values) do - local ValueType = type(value) - if ValueType ~= DefaultType then - Warn( GetString("TypeMismatch"):format(DefaultType, i, ValueType) ) - return false - end - end - - return true -end - -local function CreateThemePrefRow( pref, tbl ) - -- can't make an option handler without options - if not tbl.Choices then return nil end - - local Choices = tbl.Choices - local Default = tbl.Default - local Values = tbl.Values and tbl.Values or Choices - local Params = tbl.Params and tbl.Params or { } - - -- if the choices aren't strings, make them strings now - for i, str in ipairs(Choices) do - Choices[i] = tostring( Choices[i] ) - end - - -- check to see that Values and Choices have the same length - if #Choices ~= #Values then - Warn( GetString("ChoicesSizeMismatch") ) - return nil - end - - -- check to see that everything in Values matches the type of Default - if not TypesMatch( Values, Default ) then return nil end - - -- set the name and choices here; we'll do the rest below - local Handler = { Name = pref, Choices = Choices } - - -- add all the keys in DefaultParams, get the value from - -- Params if it exists and DefaultParams otherwise - -- (note that we explicitly check for nil, due to bools.) - for k, _ in pairs(DefaultParams) do - Handler[k] = Params[k] ~= nil and Params[k] or DefaultParams[k] - end - - -- if we don't have LoadSelections and SaveSelections, make them - if not Handler.LoadSelections then - Handler.LoadSelections = DefaultLoad( pref, Default, Choices, Values ) - end - - if not Handler.SaveSelections then - Handler.SaveSelections = DefaultSave( pref, Choices, Values ) - end - - return Handler -end - --- All OptionsRows for preferences are stuck in this table, accessible --- through GetRow('name') in the namespace or ThemePrefRow('name') in --- the global namespace. (I like to keep pollution to a minimum.) -local Rows = { } - -ThemePrefsRows = -{ - IsInitted = false, - - Init = function( prefs ) - for pref, tbl in pairs(prefs) do - Rows[pref] = CreateThemePrefRow( pref, tbl ) - end - end, - - GetRow = function( pref ) - Trace( ("GetRow(%s), type %s"):format(pref, type(Rows[pref])) ) - return Rows[pref] - end, - -} - --- Global namespace alias -ThemePrefRow = ThemePrefsRows.GetRow - --- UGLY: declare this here, even though it's in the previous namespace, --- so we can have one call to initialize both systems (ThemePrefsRow is --- declared after ThemePrefs, so it can't actually be in that file...) - -ThemePrefs.InitAll = function( prefs ) - Trace( "ThemePrefs.InitAll( prefs )" ) - - ThemePrefs.Init( prefs, true ) - ThemePrefsRows.Init( prefs ) -end +--[[ +ThemePrefsRows: you give it the choices, values, and params, and it'll +generate the rest; quirky behavior to be outlined below. Documentation +will be provided once this system is stabilized. + +v0.5.2: Dec. 28, 2010. Throw an error for default/value type mismatches. +v0.5.1: Dec. 27, 2010. Fix Choices not necessarily being strings. +v0.5.0: Dec. 15, 2010. Initial version. Not very well tested. + +vyhd wrote this for sm-ssc +--]] + +-- unless overridden, these parameters will be used for the OptionsRow +local DefaultParams = +{ + LayoutType = "ShowAllInRow", + SelectType = "SelectOne", + OneChoiceForAllPlayers = true, + ExportOnChange = false, + EnabledForPlayers = nil, + ReloadRowMessages = nil, + + -- takes a function(self, list, pn); + -- if not used, we use the default + LoadSelections = nil, + SaveSelections = nil, +} + +-- local alias to simplify error reporting +local function GetString( name ) + return THEME:GetString( "ThemePrefsRows", name ) +end + +local function DefaultLoad( pref, default, choices, values ) + return function(self, list, pn) + local val = ThemePrefs.Get( pref ) + + -- if our current value is here, set focus to that + for i=1, #choices do + if values[i] == val then list[i] = true return end + end + + -- try the default value + for i=1, #choices do + if values[i] == default then list[i] = true return end + end + + -- set to the first value and output a warning + Warn( GetString("NoDefaultInValues"):format(pref) ) + list[1] = true + end +end + +local function DefaultSave( pref, choices, values ) + local msg = "ThemePrefChanged" + local params = { Name = pref } + + return function(self, list, pn) + for i=1, #choices do + if list[i] then ThemePrefs.Set( pref, values[i] ) break end + MESSAGEMAN:Broadcast( msg, params ) + end + end +end + +-- This function checks for mismatches between the default value and the +-- values table passed to the ThemePrefRow, e.g. it will return false if +-- you have a boolean default and an integer value. I'm somewhat stricter +-- about types than Lua is because I don't like the unpredictability and +-- complexity of coercing values transparently in a bunch of places. +local function TypesMatch( Values, Default ) + local DefaultType = type(Default) + + for i, value in ipairs(Values) do + local ValueType = type(value) + if ValueType ~= DefaultType then + Warn( GetString("TypeMismatch"):format(DefaultType, i, ValueType) ) + return false + end + end + + return true +end + +local function CreateThemePrefRow( pref, tbl ) + -- can't make an option handler without options + if not tbl.Choices then return nil end + + local Choices = tbl.Choices + local Default = tbl.Default + local Values = tbl.Values and tbl.Values or Choices + local Params = tbl.Params and tbl.Params or { } + + -- if the choices aren't strings, make them strings now + for i, str in ipairs(Choices) do + Choices[i] = tostring( Choices[i] ) + end + + -- check to see that Values and Choices have the same length + if #Choices ~= #Values then + Warn( GetString("ChoicesSizeMismatch") ) + return nil + end + + -- check to see that everything in Values matches the type of Default + if not TypesMatch( Values, Default ) then return nil end + + -- set the name and choices here; we'll do the rest below + local Handler = { Name = pref, Choices = Choices } + + -- add all the keys in DefaultParams, get the value from + -- Params if it exists and DefaultParams otherwise + -- (note that we explicitly check for nil, due to bools.) + for k, _ in pairs(DefaultParams) do + Handler[k] = Params[k] ~= nil and Params[k] or DefaultParams[k] + end + + -- if we don't have LoadSelections and SaveSelections, make them + if not Handler.LoadSelections then + Handler.LoadSelections = DefaultLoad( pref, Default, Choices, Values ) + end + + if not Handler.SaveSelections then + Handler.SaveSelections = DefaultSave( pref, Choices, Values ) + end + + return Handler +end + +-- All OptionsRows for preferences are stuck in this table, accessible +-- through GetRow('name') in the namespace or ThemePrefRow('name') in +-- the global namespace. (I like to keep pollution to a minimum.) +local Rows = { } + +ThemePrefsRows = +{ + IsInitted = false, + + Init = function( prefs ) + for pref, tbl in pairs(prefs) do + Rows[pref] = CreateThemePrefRow( pref, tbl ) + end + end, + + GetRow = function( pref ) + Trace( ("GetRow(%s), type %s"):format(pref, type(Rows[pref])) ) + return Rows[pref] + end, + +} + +-- Global namespace alias +ThemePrefRow = ThemePrefsRows.GetRow + +-- UGLY: declare this here, even though it's in the previous namespace, +-- so we can have one call to initialize both systems (ThemePrefsRow is +-- declared after ThemePrefs, so it can't actually be in that file...) + +ThemePrefs.InitAll = function( prefs ) + Trace( "ThemePrefs.InitAll( prefs )" ) + + ThemePrefs.Init( prefs, true ) + ThemePrefsRows.Init( prefs ) +end diff --git a/Themes/default/BGAnimations/ScreenSelectProfile overlay.lua b/Themes/default/BGAnimations/ScreenSelectProfile overlay.lua index 8355b85580..2094ef1054 100644 --- a/Themes/default/BGAnimations/ScreenSelectProfile overlay.lua +++ b/Themes/default/BGAnimations/ScreenSelectProfile overlay.lua @@ -1,299 +1,299 @@ -function GetLocalProfiles() - local ret = {}; - - for p = 0,PROFILEMAN:GetNumLocalProfiles()-1 do - local profile=PROFILEMAN:GetLocalProfileFromIndex(p); - local item = Def.ActorFrame { ---[[ Def.Quad { - InitCommand=cmd(zoomto,200,1;y,40/2); - OnCommand=cmd(diffuse,Color('Outline');); - }; --]] - LoadFont("Common Normal") .. { - Text=profile:GetDisplayName(); - InitCommand=cmd(shadowlength,1;y,-10;zoom,1;ztest,true); - }; - LoadFont("Common Normal") .. { - InitCommand=cmd(shadowlength,1;y,8;zoom,0.5;vertspacing,-8;ztest,true); - BeginCommand=function(self) - local numSongsPlayed = profile:GetNumTotalSongsPlayed(); - local s = numSongsPlayed == 1 and "Song" or "Songs"; - -- todo: localize - self:settext( numSongsPlayed.." "..s.." Played" ); - end; - }; - }; - table.insert( ret, item ); - end; - - return ret; -end; - -function LoadCard(cColor) - local t = Def.ActorFrame { - LoadActor( THEME:GetPathG("ScreenSelectProfile","CardBackground") ) .. { - InitCommand=cmd(diffuse,cColor); - }; - LoadActor( THEME:GetPathG("ScreenSelectProfile","CardFrame") ); - }; - return t -end -function LoadPlayerStuff(Player) - local ret = {}; - - local pn = (Player == PLAYER_1) and 1 or 2; - ---[[ local t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 200, 230) .. { - Name = 'BigFrame'; - }; --]] - local t = Def.ActorFrame { - Name = 'JoinFrame'; - LoadCard(Color('Orange')); ---[[ Def.Quad { - InitCommand=cmd(zoomto,200+4,230+4); - OnCommand=cmd(shadowlength,1;diffuse,color("0,0,0,0.5")); - }; - Def.Quad { - InitCommand=cmd(zoomto,200,230); - OnCommand=cmd(diffuse,Color('Orange');diffusealpha,0.5); - }; --]] - LoadFont("Common Normal") .. { - Text="Press &START; to join."; - InitCommand=cmd(shadowlength,1); - OnCommand=cmd(diffuseshift;effectcolor1,Color('White');effectcolor2,color("0.5,0.5,0.5")); - }; - }; - table.insert( ret, t ); - - t = Def.ActorFrame { - Name = 'BigFrame'; - LoadCard(PlayerColor(Player)); - }; - table.insert( ret, t ); - ---[[ t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 170, 20) .. { - Name = 'SmallFrame'; - }; --]] - t = Def.ActorFrame { - Name = 'SmallFrame'; ---[[ Def.Quad { - InitCommand=cmd(zoomto,170+4,32+4); - OnCommand=cmd(shadowlength,1); - }; --]] - InitCommand=cmd(y,-2); - Def.Quad { - InitCommand=cmd(zoomto,200-10,40+2); - OnCommand=cmd(diffuse,Color('Black');diffusealpha,0.5); - }; - Def.Quad { - InitCommand=cmd(zoomto,200-10,40); - OnCommand=cmd(diffuse,PlayerColor(Player);fadeleft,0.25;faderight,0.25;glow,color("1,1,1,0.25")); - }; - Def.Quad { - InitCommand=cmd(zoomto,200-10,40;y,-40/2+20); - OnCommand=cmd(diffuse,Color("Black");fadebottom,1;diffusealpha,0.35); - }; - Def.Quad { - InitCommand=cmd(zoomto,200-10,1;y,-40/2+1); - OnCommand=cmd(diffuse,PlayerColor(Player);glow,color("1,1,1,0.25")); - }; - }; - table.insert( ret, t ); - - t = Def.ActorScroller{ - Name = 'Scroller'; - NumItemsToDraw=6; --- InitCommand=cmd(y,-230/2+20;); - OnCommand=cmd(y,1;SetFastCatchup,true;SetMask,200,58;SetSecondsPerItem,0.15); - TransformFunction=function(self, offset, itemIndex, numItems) - local focus = scale(math.abs(offset),0,2,1,0); - self:visible(false); - self:y(math.floor( offset*40 )); --- self:zoomy( focus ); --- self:z(-math.abs(offset)); --- self:zoom(focus); - end; - children = GetLocalProfiles(); - }; - table.insert( ret, t ); - - t = Def.ActorFrame { - Name = "EffectFrame"; - --[[ Def.Quad { - InitCommand=cmd(y,-230/2;vertalign,top;zoomto,200,8;fadebottom,1); - OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25); - }; - Def.Quad { - InitCommand=cmd(y,230/2;vertalign,bottom;zoomto,200,8;fadetop,1); - OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25); - }; --]] - }; - table.insert( ret, t ); ---[[ t = Def.BitmapText { - OnCommand = cmd(y,160); - Name = 'SelectedProfileText'; - Font = "Common Normal"; - Text = 'No profile'; - }; --]] - t = LoadFont("Common Normal") .. { - Name = 'SelectedProfileText'; - --InitCommand=cmd(y,160;shadowlength,1;diffuse,PlayerColor(Player)); - InitCommand=cmd(y,160;shadowlength,1;); - }; - table.insert( ret, t ); - - return ret; -end; - -function UpdateInternal3(self, Player) - local pn = (Player == PLAYER_1) and 1 or 2; - local frame = self:GetChild(string.format('P%uFrame', pn)); - local scroller = frame:GetChild('Scroller'); - local seltext = frame:GetChild('SelectedProfileText'); - local joinframe = frame:GetChild('JoinFrame'); - local smallframe = frame:GetChild('SmallFrame'); - local bigframe = frame:GetChild('BigFrame'); - - if GAMESTATE:IsHumanPlayer(Player) then - frame:visible(true); - if MEMCARDMAN:GetCardState(Player) == 'MemoryCardState_none' then - --using profile if any - joinframe:visible(false); - smallframe:visible(true); - bigframe:visible(true); - seltext:visible(true); - scroller:visible(true); - local ind = SCREENMAN:GetTopScreen():GetProfileIndex(Player); - if ind > 0 then - scroller:SetDestinationItem(ind-1); - seltext:settext(PROFILEMAN:GetLocalProfileFromIndex(ind-1):GetDisplayName()); - else - if SCREENMAN:GetTopScreen():SetProfileIndex(Player, 1) then - scroller:SetDestinationItem(0); - self:queuecommand('UpdateInternal2'); - else - joinframe:visible(true); - smallframe:visible(false); - bigframe:visible(false); - scroller:visible(false); - seltext:settext('No profile'); - end; - end; - else - --using card - smallframe:visible(false); - scroller:visible(false); - seltext:settext('CARD'); - SCREENMAN:GetTopScreen():SetProfileIndex(Player, 0); - end; - else - joinframe:visible(true); - scroller:visible(false); - seltext:visible(false); - smallframe:visible(false); - bigframe:visible(false); - end; -end; - -local t = Def.ActorFrame { - - StorageDevicesChangedMessageCommand=function(self, params) - self:queuecommand('UpdateInternal2'); - end; - - CodeMessageCommand = function(self, params) - if params.Name == 'Start' or params.Name == 'Center' then - MESSAGEMAN:Broadcast("StartButton"); - if not GAMESTATE:IsHumanPlayer(params.PlayerNumber) then - SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -1); - else - SCREENMAN:GetTopScreen():Finish(); - end; - end; - if params.Name == 'Up' or params.Name == 'Up2' or params.Name == 'DownLeft' then - if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then - local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber); - if ind > 1 then - if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind - 1 ) then - MESSAGEMAN:Broadcast("DirectionButton"); - self:queuecommand('UpdateInternal2'); - end; - end; - end; - end; - if params.Name == 'Down' or params.Name == 'Down2' or params.Name == 'DownRight' then - if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then - local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber); - if ind > 0 then - if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind + 1 ) then - MESSAGEMAN:Broadcast("DirectionButton"); - self:queuecommand('UpdateInternal2'); - end; - end; - end; - end; - if params.Name == 'Back' then - if GAMESTATE:GetNumPlayersEnabled()==0 then - SCREENMAN:GetTopScreen():Cancel(); - else - MESSAGEMAN:Broadcast("BackButton"); - SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -2); - end; - end; - end; - - PlayerJoinedMessageCommand=function(self, params) - self:queuecommand('UpdateInternal2'); - end; - - PlayerUnjoinedMessageCommand=function(self, params) - self:queuecommand('UpdateInternal2'); - end; - - OnCommand=function(self, params) - self:queuecommand('UpdateInternal2'); - end; - - UpdateInternal2Command=function(self) - UpdateInternal3(self, PLAYER_1); - UpdateInternal3(self, PLAYER_2); - end; - - children = { - Def.ActorFrame { - Name = 'P1Frame'; - InitCommand=cmd(x,SCREEN_CENTER_X-160;y,SCREEN_CENTER_Y); - OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1); - OffCommand=cmd(bouncebegin,0.35;zoom,0); - PlayerJoinedMessageCommand=function(self,param) - if param.Player == PLAYER_1 then - (cmd(;zoom,1.15;bounceend,0.175;zoom,1.0;))(self); - end; - end; - children = LoadPlayerStuff(PLAYER_1); - }; - Def.ActorFrame { - Name = 'P2Frame'; - InitCommand=cmd(x,SCREEN_CENTER_X+160;y,SCREEN_CENTER_Y); - OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1); - OffCommand=cmd(bouncebegin,0.35;zoom,0); - PlayerJoinedMessageCommand=function(self,param) - if param.Player == PLAYER_2 then - (cmd(zoom,1.15;bounceend,0.175;zoom,1.0;))(self); - end; - end; - children = LoadPlayerStuff(PLAYER_2); - }; - -- sounds - LoadActor( THEME:GetPathS("Common","start") )..{ - StartButtonMessageCommand=cmd(play); - }; - LoadActor( THEME:GetPathS("Common","cancel") )..{ - BackButtonMessageCommand=cmd(play); - }; - LoadActor( THEME:GetPathS("Common","value") )..{ - DirectionButtonMessageCommand=cmd(play); - }; - }; -}; - -return t; +function GetLocalProfiles() + local ret = {}; + + for p = 0,PROFILEMAN:GetNumLocalProfiles()-1 do + local profile=PROFILEMAN:GetLocalProfileFromIndex(p); + local item = Def.ActorFrame { +--[[ Def.Quad { + InitCommand=cmd(zoomto,200,1;y,40/2); + OnCommand=cmd(diffuse,Color('Outline');); + }; --]] + LoadFont("Common Normal") .. { + Text=profile:GetDisplayName(); + InitCommand=cmd(shadowlength,1;y,-10;zoom,1;ztest,true); + }; + LoadFont("Common Normal") .. { + InitCommand=cmd(shadowlength,1;y,8;zoom,0.5;vertspacing,-8;ztest,true); + BeginCommand=function(self) + local numSongsPlayed = profile:GetNumTotalSongsPlayed(); + local s = numSongsPlayed == 1 and "Song" or "Songs"; + -- todo: localize + self:settext( numSongsPlayed.." "..s.." Played" ); + end; + }; + }; + table.insert( ret, item ); + end; + + return ret; +end; + +function LoadCard(cColor) + local t = Def.ActorFrame { + LoadActor( THEME:GetPathG("ScreenSelectProfile","CardBackground") ) .. { + InitCommand=cmd(diffuse,cColor); + }; + LoadActor( THEME:GetPathG("ScreenSelectProfile","CardFrame") ); + }; + return t +end +function LoadPlayerStuff(Player) + local ret = {}; + + local pn = (Player == PLAYER_1) and 1 or 2; + +--[[ local t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 200, 230) .. { + Name = 'BigFrame'; + }; --]] + local t = Def.ActorFrame { + Name = 'JoinFrame'; + LoadCard(Color('Orange')); +--[[ Def.Quad { + InitCommand=cmd(zoomto,200+4,230+4); + OnCommand=cmd(shadowlength,1;diffuse,color("0,0,0,0.5")); + }; + Def.Quad { + InitCommand=cmd(zoomto,200,230); + OnCommand=cmd(diffuse,Color('Orange');diffusealpha,0.5); + }; --]] + LoadFont("Common Normal") .. { + Text="Press &START; to join."; + InitCommand=cmd(shadowlength,1); + OnCommand=cmd(diffuseshift;effectcolor1,Color('White');effectcolor2,color("0.5,0.5,0.5")); + }; + }; + table.insert( ret, t ); + + t = Def.ActorFrame { + Name = 'BigFrame'; + LoadCard(PlayerColor(Player)); + }; + table.insert( ret, t ); + +--[[ t = LoadActor(THEME:GetPathB('', '_frame 3x3'), 'metal', 170, 20) .. { + Name = 'SmallFrame'; + }; --]] + t = Def.ActorFrame { + Name = 'SmallFrame'; +--[[ Def.Quad { + InitCommand=cmd(zoomto,170+4,32+4); + OnCommand=cmd(shadowlength,1); + }; --]] + InitCommand=cmd(y,-2); + Def.Quad { + InitCommand=cmd(zoomto,200-10,40+2); + OnCommand=cmd(diffuse,Color('Black');diffusealpha,0.5); + }; + Def.Quad { + InitCommand=cmd(zoomto,200-10,40); + OnCommand=cmd(diffuse,PlayerColor(Player);fadeleft,0.25;faderight,0.25;glow,color("1,1,1,0.25")); + }; + Def.Quad { + InitCommand=cmd(zoomto,200-10,40;y,-40/2+20); + OnCommand=cmd(diffuse,Color("Black");fadebottom,1;diffusealpha,0.35); + }; + Def.Quad { + InitCommand=cmd(zoomto,200-10,1;y,-40/2+1); + OnCommand=cmd(diffuse,PlayerColor(Player);glow,color("1,1,1,0.25")); + }; + }; + table.insert( ret, t ); + + t = Def.ActorScroller{ + Name = 'Scroller'; + NumItemsToDraw=6; +-- InitCommand=cmd(y,-230/2+20;); + OnCommand=cmd(y,1;SetFastCatchup,true;SetMask,200,58;SetSecondsPerItem,0.15); + TransformFunction=function(self, offset, itemIndex, numItems) + local focus = scale(math.abs(offset),0,2,1,0); + self:visible(false); + self:y(math.floor( offset*40 )); +-- self:zoomy( focus ); +-- self:z(-math.abs(offset)); +-- self:zoom(focus); + end; + children = GetLocalProfiles(); + }; + table.insert( ret, t ); + + t = Def.ActorFrame { + Name = "EffectFrame"; + --[[ Def.Quad { + InitCommand=cmd(y,-230/2;vertalign,top;zoomto,200,8;fadebottom,1); + OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25); + }; + Def.Quad { + InitCommand=cmd(y,230/2;vertalign,bottom;zoomto,200,8;fadetop,1); + OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25); + }; --]] + }; + table.insert( ret, t ); +--[[ t = Def.BitmapText { + OnCommand = cmd(y,160); + Name = 'SelectedProfileText'; + Font = "Common Normal"; + Text = 'No profile'; + }; --]] + t = LoadFont("Common Normal") .. { + Name = 'SelectedProfileText'; + --InitCommand=cmd(y,160;shadowlength,1;diffuse,PlayerColor(Player)); + InitCommand=cmd(y,160;shadowlength,1;); + }; + table.insert( ret, t ); + + return ret; +end; + +function UpdateInternal3(self, Player) + local pn = (Player == PLAYER_1) and 1 or 2; + local frame = self:GetChild(string.format('P%uFrame', pn)); + local scroller = frame:GetChild('Scroller'); + local seltext = frame:GetChild('SelectedProfileText'); + local joinframe = frame:GetChild('JoinFrame'); + local smallframe = frame:GetChild('SmallFrame'); + local bigframe = frame:GetChild('BigFrame'); + + if GAMESTATE:IsHumanPlayer(Player) then + frame:visible(true); + if MEMCARDMAN:GetCardState(Player) == 'MemoryCardState_none' then + --using profile if any + joinframe:visible(false); + smallframe:visible(true); + bigframe:visible(true); + seltext:visible(true); + scroller:visible(true); + local ind = SCREENMAN:GetTopScreen():GetProfileIndex(Player); + if ind > 0 then + scroller:SetDestinationItem(ind-1); + seltext:settext(PROFILEMAN:GetLocalProfileFromIndex(ind-1):GetDisplayName()); + else + if SCREENMAN:GetTopScreen():SetProfileIndex(Player, 1) then + scroller:SetDestinationItem(0); + self:queuecommand('UpdateInternal2'); + else + joinframe:visible(true); + smallframe:visible(false); + bigframe:visible(false); + scroller:visible(false); + seltext:settext('No profile'); + end; + end; + else + --using card + smallframe:visible(false); + scroller:visible(false); + seltext:settext('CARD'); + SCREENMAN:GetTopScreen():SetProfileIndex(Player, 0); + end; + else + joinframe:visible(true); + scroller:visible(false); + seltext:visible(false); + smallframe:visible(false); + bigframe:visible(false); + end; +end; + +local t = Def.ActorFrame { + + StorageDevicesChangedMessageCommand=function(self, params) + self:queuecommand('UpdateInternal2'); + end; + + CodeMessageCommand = function(self, params) + if params.Name == 'Start' or params.Name == 'Center' then + MESSAGEMAN:Broadcast("StartButton"); + if not GAMESTATE:IsHumanPlayer(params.PlayerNumber) then + SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -1); + else + SCREENMAN:GetTopScreen():Finish(); + end; + end; + if params.Name == 'Up' or params.Name == 'Up2' or params.Name == 'DownLeft' then + if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then + local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber); + if ind > 1 then + if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind - 1 ) then + MESSAGEMAN:Broadcast("DirectionButton"); + self:queuecommand('UpdateInternal2'); + end; + end; + end; + end; + if params.Name == 'Down' or params.Name == 'Down2' or params.Name == 'DownRight' then + if GAMESTATE:IsHumanPlayer(params.PlayerNumber) then + local ind = SCREENMAN:GetTopScreen():GetProfileIndex(params.PlayerNumber); + if ind > 0 then + if SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, ind + 1 ) then + MESSAGEMAN:Broadcast("DirectionButton"); + self:queuecommand('UpdateInternal2'); + end; + end; + end; + end; + if params.Name == 'Back' then + if GAMESTATE:GetNumPlayersEnabled()==0 then + SCREENMAN:GetTopScreen():Cancel(); + else + MESSAGEMAN:Broadcast("BackButton"); + SCREENMAN:GetTopScreen():SetProfileIndex(params.PlayerNumber, -2); + end; + end; + end; + + PlayerJoinedMessageCommand=function(self, params) + self:queuecommand('UpdateInternal2'); + end; + + PlayerUnjoinedMessageCommand=function(self, params) + self:queuecommand('UpdateInternal2'); + end; + + OnCommand=function(self, params) + self:queuecommand('UpdateInternal2'); + end; + + UpdateInternal2Command=function(self) + UpdateInternal3(self, PLAYER_1); + UpdateInternal3(self, PLAYER_2); + end; + + children = { + Def.ActorFrame { + Name = 'P1Frame'; + InitCommand=cmd(x,SCREEN_CENTER_X-160;y,SCREEN_CENTER_Y); + OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1); + OffCommand=cmd(bouncebegin,0.35;zoom,0); + PlayerJoinedMessageCommand=function(self,param) + if param.Player == PLAYER_1 then + (cmd(;zoom,1.15;bounceend,0.175;zoom,1.0;))(self); + end; + end; + children = LoadPlayerStuff(PLAYER_1); + }; + Def.ActorFrame { + Name = 'P2Frame'; + InitCommand=cmd(x,SCREEN_CENTER_X+160;y,SCREEN_CENTER_Y); + OnCommand=cmd(zoom,0;bounceend,0.35;zoom,1); + OffCommand=cmd(bouncebegin,0.35;zoom,0); + PlayerJoinedMessageCommand=function(self,param) + if param.Player == PLAYER_2 then + (cmd(zoom,1.15;bounceend,0.175;zoom,1.0;))(self); + end; + end; + children = LoadPlayerStuff(PLAYER_2); + }; + -- sounds + LoadActor( THEME:GetPathS("Common","start") )..{ + StartButtonMessageCommand=cmd(play); + }; + LoadActor( THEME:GetPathS("Common","cancel") )..{ + BackButtonMessageCommand=cmd(play); + }; + LoadActor( THEME:GetPathS("Common","value") )..{ + DirectionButtonMessageCommand=cmd(play); + }; + }; +}; + +return t; diff --git a/Themes/default/Graphics/Combo 1000milestone/default.lua b/Themes/default/Graphics/Combo 1000milestone/default.lua index 80789ecc72..a146c031d6 100644 --- a/Themes/default/Graphics/Combo 1000milestone/default.lua +++ b/Themes/default/Graphics/Combo 1000milestone/default.lua @@ -1,12 +1,12 @@ -return Def.ActorFrame { - FOV=90; ---[[ LoadActor("shot") .. { - InitCommand=cmd(diffusealpha,0;zoom,2;blend,'BlendMode_Add'); - MilestoneCommand=cmd(diffusealpha,0.75;rotationz,0;accelerate,2.5;diffusealpha,0;rotationz,360;zoom,2.5); - }; --]] ---[[ LoadActor("shot") .. { - InitCommand=cmd(diffusealpha,0;zoom,2;zoomx,-2;blend,'BlendMode_Add'); - MilestoneCommand=cmd(diffusealpha,0.75;rotationz,-360;x,0;linear,2.5;diffusealpha,0;rotationz,0;zoom,2.5); - }; --]] - LoadActor(THEME:GetPathG("Combo","100Milestone")); -}; +return Def.ActorFrame { + FOV=90; +--[[ LoadActor("shot") .. { + InitCommand=cmd(diffusealpha,0;zoom,2;blend,'BlendMode_Add'); + MilestoneCommand=cmd(diffusealpha,0.75;rotationz,0;accelerate,2.5;diffusealpha,0;rotationz,360;zoom,2.5); + }; --]] +--[[ LoadActor("shot") .. { + InitCommand=cmd(diffusealpha,0;zoom,2;zoomx,-2;blend,'BlendMode_Add'); + MilestoneCommand=cmd(diffusealpha,0.75;rotationz,-360;x,0;linear,2.5;diffusealpha,0;rotationz,0;zoom,2.5); + }; --]] + LoadActor(THEME:GetPathG("Combo","100Milestone")); +}; diff --git a/Themes/default/Graphics/Combo 100milestone/default.lua b/Themes/default/Graphics/Combo 100milestone/default.lua index 0d7279c583..093cf52340 100644 --- a/Themes/default/Graphics/Combo 100milestone/default.lua +++ b/Themes/default/Graphics/Combo 100milestone/default.lua @@ -1,11 +1,11 @@ -local ShowFlashyCombo = GetUserPrefB("UserPrefFlashyCombo") -return Def.ActorFrame { - LoadActor("explosion") .. { - InitCommand=cmd(diffusealpha,0;blend,'BlendMode_Add';hide_if,not ShowFlashyCombo); - MilestoneCommand=cmd(rotationz,0;zoom,2;diffusealpha,0.5;linear,0.5;rotationz,90;zoom,1.75;diffusealpha,0); - }; - LoadActor("explosion") .. { - InitCommand=cmd(diffusealpha,0;blend,'BlendMode_Add';hide_if,not ShowFlashyCombo); - MilestoneCommand=cmd(rotationz,0;zoom,2;diffusealpha,0.5;linear,0.5;rotationz,-90;zoom,2.5;diffusealpha,0); - }; +local ShowFlashyCombo = GetUserPrefB("UserPrefFlashyCombo") +return Def.ActorFrame { + LoadActor("explosion") .. { + InitCommand=cmd(diffusealpha,0;blend,'BlendMode_Add';hide_if,not ShowFlashyCombo); + MilestoneCommand=cmd(rotationz,0;zoom,2;diffusealpha,0.5;linear,0.5;rotationz,90;zoom,1.75;diffusealpha,0); + }; + LoadActor("explosion") .. { + InitCommand=cmd(diffusealpha,0;blend,'BlendMode_Add';hide_if,not ShowFlashyCombo); + MilestoneCommand=cmd(rotationz,0;zoom,2;diffusealpha,0.5;linear,0.5;rotationz,-90;zoom,2.5;diffusealpha,0); + }; }; \ No newline at end of file diff --git a/Themes/default/Scripts/04 SpecialScoring.lua b/Themes/default/Scripts/04 SpecialScoring.lua index 2f24ebff05..80cf1d4656 100644 --- a/Themes/default/Scripts/04 SpecialScoring.lua +++ b/Themes/default/Scripts/04 SpecialScoring.lua @@ -1,157 +1,157 @@ ---Special Scoring types. -local r = {}; -local DisabledScoringModes = { 'DDR Extreme', '[SSC] Radar Master' }; ---the following metatable makes any missing value in a table 0 instead of nil. -local ZeroIfNotFound = { __index = function() return 0 end; }; - --- Retrieve the amount of taps/holds/rolls involved. Used for some formulas. -function GetTotalItems(radars) - return radars:GetValue('RadarCategory_TapsAndHolds') - + radars:GetValue('RadarCategory_Holds') - + radars:GetValue('RadarCategory_Rolls'); -end; - --- Determine whether marvelous timing is to be considered. -function IsW1Allowed(tapScore) - return tapScore == 'TapNoteScore_W2' - and (PREFSMAN:GetPreference("AllowW1") ~= 'AllowW1_Never' - or not (GAMESTATE:IsCourseMode() and - PREFSMAN:GetPreference("AllowW1") == 'AllowW1_CoursesOnly')); -end; - --- Get the radar values directly. The individual steps aren't used much. -function GetDirectRadar(player) - return GAMESTATE:GetCurrentSteps(player):GetRadarValues(player); -end; - ------------------------------------------------------------ ---DDR 1st Mix and 2nd Mix Scoring ------------------------------------------------------------ -r['DDR 1stMIX'] = function(params, pss) - local dCombo = math.floor((pss:GetCurrentCombo()+1)/4); - local bScore = (dCombo^2+1) * 100; - local multLookup = { ['TapNoteScore_W1']=3, ['TapNoteScore_W2']=3, ['TapNoteScore_W3']=1 }; - setmetatable(multLookup, ZeroIfNotFound); - --if score increases above the boundaries of a 32-bit signed - --(about 2.15 billion), it stops increasing. Conveniently, - --1st Mix clamped score as well. - pss:SetScore(clamp(pss:GetScore()+(bScore*multLookup[params.TapNoteScore]),0,999999999)); -end; ------------------------------------------------------------ ---DDR 4th Mix/Extra Mix/Konamix/GB3/DDRPC Scoring ------------------------------------------------------------ -r['DDR 4thMIX'] = function(params, pss) - local scoreLookupTable = { ['TapNoteScore_W1']=777, ['TapNoteScore_W2']=777, ['TapNoteScore_W3']=555 }; - setmetatable(scoreLookupTable, ZeroIfNotFound); - local comboBonusForThisStep = (pss:GetCurrentCombo()+1)*333; - pss:SetScore(clamp(pss:GetScore()+scoreLookupTable[params.TapNoteScore]+(scoreLookupTable[params.TapNoteScore] and comboBonusForThisStep or 0),0,999999999)); -end; ------------------------------------------------------------ ---DDR MAX2/Extreme Scoring ---This scoring system doesn't work and is locked out. ------------------------------------------------------------ -r['DDR Extreme'] = function(params, pss) - local judgmentBase = { - ['TapNoteScore_W1'] = 10, - ['TapNoteScore_W2'] = 9, - ['TapNoteScore_W3'] = 5 - }; - setmetatable(judgmentBase, ZeroIfNotFound); - local steps = GAMESTATE:GetCurrentSteps(params.Player); - local radarValues = steps:GetRadarValues(params.Player); - local baseScore = (steps:IsAnEdit() and - 5 or steps:GetMeter()) * 10000000; - local currentStep = 0; -- TODO: Get current step/hold. - local totalItems = GetTotalItems(radarValues); - local singleStep = (1 + totalItems) * totalItems / 2; - local stepLast = math.floor(baseScore / singleStep) * currentStep; - local judgeScore = 0; - if (params.HoldNoteScore == 'HoldNoteScore_Held') then - judgeScore = judgmentBase['TapNoteScore_W1']; - else - judgeScore = judgmentBase[params.TapNoteScore]; - if (IsW1Allowed(params.TapNoteScore)) then - judgeScore = judgmentBase['TapNoteScore_W1']; - end; - end; - local stepScore = judgeScore * stepLast; - - pss:SetScore(pss:GetScore() + stepScore); -end; ------------------------------------------------------------ ---DDR SuperNOVA(-esque) scoring ------------------------------------------------------------ -r['DDR SuperNOVA'] = function(params, pss) - local multLookup = { ['TapNoteScore_W1'] = 1, ['TapNoteScore_W2'] = 1, ['TapNoteScore_W3'] = 0.5 }; - setmetatable(multLookup, ZeroIfNotFound); - local radarValues = GetDirectRadar(params.Player); - local totalItems = GetTotalItems(radarValues); - local buildScore = (10000000 / totalItems * multLookup[params.TapNoteScore]) + (10000000 / totalItems * (params.HoldNoteScore == 'HoldNoteScore_Held' and 1 or 0)); - pss:SetScore(pss:GetScore() + math.round(buildScore)); -end; ------------------------------------------------------------ ---DDR SuperNOVA 2(-esque) scoring ------------------------------------------------------------ -r['DDR SuperNOVA 2'] = function(params, pss) - local multLookup = { ['TapNoteScore_W1'] = 1, ['TapNoteScore_W2'] = 1, ['TapNoteScore_W3'] = 0.5 }; - setmetatable(multLookup, ZeroIfNotFound); - local radarValues = GetDirectRadar(params.Player); - local totalItems = GetTotalItems(radarValues); - local buildScore = (100000 / totalItems * multLookup[params.TapNoteScore] - (IsW1Allowed(params.TapNoteScore) and 10 or 0)) + (100000 / totalItems * (params.HoldNoteScore == 'HoldNoteScore_Held' and 1 or 0)); - pss:SetScore(pss:GetScore() + (math.round(buildScore) * 10)); -end; ------------------------------------------------------------ ---Radar Master (doesn't work in 1.2.1, disabled) ---don't try to "fix it up", either. you *cannot* make it work in 1.2.1. ------------------------------------------------------------ -r['[SSC] Radar Master'] = function(params, pss) - local masterTable = { - ['RadarCategory_Stream'] = 0, - ['RadarCategory_Voltage'] = 0, - ['RadarCategory_Air'] = 0, - ['RadarCategory_Freeze'] = 0, - ['RadarCategory_Chaos'] = 0 - }; - local totalRadar = 0; - local finalScore = 0; - for k,v in pairs(masterTable) do - local firstRadar = GetDirectRadar(params.Player):GetValue(k); - if firstRadar == 0 then - masterTable[k] = nil; - else - masterTable[k] = firstRadar; - totalRadar = totalRadar + firstRadar; - end; - end; - --two loops are needed because we need to calculate totalRadar - --to actually calculate any part of the score - for k,v in pairs(masterTable) do - local curPortion = pss:GetRadarActual():GetValue(k) / v; - finalScore = finalScore + curPortion*(500000000*(v/totalRadar)); - end; - pss:SetScore(finalScore); -end; ------------------------------------------------------------- ---Marvelous Incorporated Grading System (or MIGS for short) ---basically like DP scoring with locked DP values ------------------------------------------------------------- -r['MIGS'] = function(params,pss) - local curScore = 0; - local tapScoreTable = { ['TapNoteScore_W1'] = 3, ['TapNoteScore_W2'] = 2, ['TapNoteScore_W3'] = 1, ['TapNoteScore_W5'] = -4, ['TapNoteScore_Miss'] = -8 }; - for k,v in pairs(tapScoreTable) do - curScore = curScore + ( pss:GetTapNoteScores(k) * v ); - end; - curScore = curScore + ( pss:GetHoldNoteScores('HoldNoteScore_Held') * 6 ); - pss:SetScore(clamp(curScore,0,math.huge)); -end; -SpecialScoring = {}; -setmetatable(SpecialScoring, { - __metatable = { "Letting you change the metatable sort of defeats the purpose." }; - __index = function(tbl, key) - for v in ivalues(DisabledScoringModes) do - if key == v then return r['DDR 1stMIX']; end; - end; - return r[key]; - end; - } -); +--Special Scoring types. +local r = {}; +local DisabledScoringModes = { 'DDR Extreme', '[SSC] Radar Master' }; +--the following metatable makes any missing value in a table 0 instead of nil. +local ZeroIfNotFound = { __index = function() return 0 end; }; + +-- Retrieve the amount of taps/holds/rolls involved. Used for some formulas. +function GetTotalItems(radars) + return radars:GetValue('RadarCategory_TapsAndHolds') + + radars:GetValue('RadarCategory_Holds') + + radars:GetValue('RadarCategory_Rolls'); +end; + +-- Determine whether marvelous timing is to be considered. +function IsW1Allowed(tapScore) + return tapScore == 'TapNoteScore_W2' + and (PREFSMAN:GetPreference("AllowW1") ~= 'AllowW1_Never' + or not (GAMESTATE:IsCourseMode() and + PREFSMAN:GetPreference("AllowW1") == 'AllowW1_CoursesOnly')); +end; + +-- Get the radar values directly. The individual steps aren't used much. +function GetDirectRadar(player) + return GAMESTATE:GetCurrentSteps(player):GetRadarValues(player); +end; + +----------------------------------------------------------- +--DDR 1st Mix and 2nd Mix Scoring +----------------------------------------------------------- +r['DDR 1stMIX'] = function(params, pss) + local dCombo = math.floor((pss:GetCurrentCombo()+1)/4); + local bScore = (dCombo^2+1) * 100; + local multLookup = { ['TapNoteScore_W1']=3, ['TapNoteScore_W2']=3, ['TapNoteScore_W3']=1 }; + setmetatable(multLookup, ZeroIfNotFound); + --if score increases above the boundaries of a 32-bit signed + --(about 2.15 billion), it stops increasing. Conveniently, + --1st Mix clamped score as well. + pss:SetScore(clamp(pss:GetScore()+(bScore*multLookup[params.TapNoteScore]),0,999999999)); +end; +----------------------------------------------------------- +--DDR 4th Mix/Extra Mix/Konamix/GB3/DDRPC Scoring +----------------------------------------------------------- +r['DDR 4thMIX'] = function(params, pss) + local scoreLookupTable = { ['TapNoteScore_W1']=777, ['TapNoteScore_W2']=777, ['TapNoteScore_W3']=555 }; + setmetatable(scoreLookupTable, ZeroIfNotFound); + local comboBonusForThisStep = (pss:GetCurrentCombo()+1)*333; + pss:SetScore(clamp(pss:GetScore()+scoreLookupTable[params.TapNoteScore]+(scoreLookupTable[params.TapNoteScore] and comboBonusForThisStep or 0),0,999999999)); +end; +----------------------------------------------------------- +--DDR MAX2/Extreme Scoring +--This scoring system doesn't work and is locked out. +----------------------------------------------------------- +r['DDR Extreme'] = function(params, pss) + local judgmentBase = { + ['TapNoteScore_W1'] = 10, + ['TapNoteScore_W2'] = 9, + ['TapNoteScore_W3'] = 5 + }; + setmetatable(judgmentBase, ZeroIfNotFound); + local steps = GAMESTATE:GetCurrentSteps(params.Player); + local radarValues = steps:GetRadarValues(params.Player); + local baseScore = (steps:IsAnEdit() and + 5 or steps:GetMeter()) * 10000000; + local currentStep = 0; -- TODO: Get current step/hold. + local totalItems = GetTotalItems(radarValues); + local singleStep = (1 + totalItems) * totalItems / 2; + local stepLast = math.floor(baseScore / singleStep) * currentStep; + local judgeScore = 0; + if (params.HoldNoteScore == 'HoldNoteScore_Held') then + judgeScore = judgmentBase['TapNoteScore_W1']; + else + judgeScore = judgmentBase[params.TapNoteScore]; + if (IsW1Allowed(params.TapNoteScore)) then + judgeScore = judgmentBase['TapNoteScore_W1']; + end; + end; + local stepScore = judgeScore * stepLast; + + pss:SetScore(pss:GetScore() + stepScore); +end; +----------------------------------------------------------- +--DDR SuperNOVA(-esque) scoring +----------------------------------------------------------- +r['DDR SuperNOVA'] = function(params, pss) + local multLookup = { ['TapNoteScore_W1'] = 1, ['TapNoteScore_W2'] = 1, ['TapNoteScore_W3'] = 0.5 }; + setmetatable(multLookup, ZeroIfNotFound); + local radarValues = GetDirectRadar(params.Player); + local totalItems = GetTotalItems(radarValues); + local buildScore = (10000000 / totalItems * multLookup[params.TapNoteScore]) + (10000000 / totalItems * (params.HoldNoteScore == 'HoldNoteScore_Held' and 1 or 0)); + pss:SetScore(pss:GetScore() + math.round(buildScore)); +end; +----------------------------------------------------------- +--DDR SuperNOVA 2(-esque) scoring +----------------------------------------------------------- +r['DDR SuperNOVA 2'] = function(params, pss) + local multLookup = { ['TapNoteScore_W1'] = 1, ['TapNoteScore_W2'] = 1, ['TapNoteScore_W3'] = 0.5 }; + setmetatable(multLookup, ZeroIfNotFound); + local radarValues = GetDirectRadar(params.Player); + local totalItems = GetTotalItems(radarValues); + local buildScore = (100000 / totalItems * multLookup[params.TapNoteScore] - (IsW1Allowed(params.TapNoteScore) and 10 or 0)) + (100000 / totalItems * (params.HoldNoteScore == 'HoldNoteScore_Held' and 1 or 0)); + pss:SetScore(pss:GetScore() + (math.round(buildScore) * 10)); +end; +----------------------------------------------------------- +--Radar Master (doesn't work in 1.2.1, disabled) +--don't try to "fix it up", either. you *cannot* make it work in 1.2.1. +----------------------------------------------------------- +r['[SSC] Radar Master'] = function(params, pss) + local masterTable = { + ['RadarCategory_Stream'] = 0, + ['RadarCategory_Voltage'] = 0, + ['RadarCategory_Air'] = 0, + ['RadarCategory_Freeze'] = 0, + ['RadarCategory_Chaos'] = 0 + }; + local totalRadar = 0; + local finalScore = 0; + for k,v in pairs(masterTable) do + local firstRadar = GetDirectRadar(params.Player):GetValue(k); + if firstRadar == 0 then + masterTable[k] = nil; + else + masterTable[k] = firstRadar; + totalRadar = totalRadar + firstRadar; + end; + end; + --two loops are needed because we need to calculate totalRadar + --to actually calculate any part of the score + for k,v in pairs(masterTable) do + local curPortion = pss:GetRadarActual():GetValue(k) / v; + finalScore = finalScore + curPortion*(500000000*(v/totalRadar)); + end; + pss:SetScore(finalScore); +end; +------------------------------------------------------------ +--Marvelous Incorporated Grading System (or MIGS for short) +--basically like DP scoring with locked DP values +------------------------------------------------------------ +r['MIGS'] = function(params,pss) + local curScore = 0; + local tapScoreTable = { ['TapNoteScore_W1'] = 3, ['TapNoteScore_W2'] = 2, ['TapNoteScore_W3'] = 1, ['TapNoteScore_W5'] = -4, ['TapNoteScore_Miss'] = -8 }; + for k,v in pairs(tapScoreTable) do + curScore = curScore + ( pss:GetTapNoteScores(k) * v ); + end; + curScore = curScore + ( pss:GetHoldNoteScores('HoldNoteScore_Held') * 6 ); + pss:SetScore(clamp(curScore,0,math.huge)); +end; +SpecialScoring = {}; +setmetatable(SpecialScoring, { + __metatable = { "Letting you change the metatable sort of defeats the purpose." }; + __index = function(tbl, key) + for v in ivalues(DisabledScoringModes) do + if key == v then return r['DDR 1stMIX']; end; + end; + return r[key]; + end; + } +); diff --git a/Utils/GetProductVer.sh b/Utils/GetProductVer.sh index 52adbbb154..6aca9076ad 100644 --- a/Utils/GetProductVer.sh +++ b/Utils/GetProductVer.sh @@ -1,25 +1,25 @@ -#!/bin/bash -set -e - -if test "$1" = ""; then - echo Expected argument - exit 1 -fi - -if ! test -e $1; then - echo "File $1 doesn't exist" - exit 1 -fi - -PRODUCT=`cat $1 | grep -w '^.define PRODUCT_FAMILY_BARE' | sed -re 's/.*_BARE +(.*)/\1/'` -VER=`cat $1 | grep -w '^.define PRODUCT_VER_BARE' | sed -re 's/.*_BARE +(.*)/\1/'` - -# "3.9 alpha 1" -> "3.9 alpha1" -VER=`echo "$VER" | sed -e 's/alpha /alpha/'` -# "3.9 beta 1" -> "3.9 beta1" -VER=`echo "$VER" | sed -e 's/beta /beta/'` -# "3.9 alpha1" -> "3.9-alpha1" -VER=`echo "$VER" | sed -e 's/ /-/g'` - -PRODUCTVER="$PRODUCT-$VER" - +#!/bin/bash +set -e + +if test "$1" = ""; then + echo Expected argument + exit 1 +fi + +if ! test -e $1; then + echo "File $1 doesn't exist" + exit 1 +fi + +PRODUCT=`cat $1 | grep -w '^.define PRODUCT_FAMILY_BARE' | sed -re 's/.*_BARE +(.*)/\1/'` +VER=`cat $1 | grep -w '^.define PRODUCT_VER_BARE' | sed -re 's/.*_BARE +(.*)/\1/'` + +# "3.9 alpha 1" -> "3.9 alpha1" +VER=`echo "$VER" | sed -e 's/alpha /alpha/'` +# "3.9 beta 1" -> "3.9 beta1" +VER=`echo "$VER" | sed -e 's/beta /beta/'` +# "3.9 alpha1" -> "3.9-alpha1" +VER=`echo "$VER" | sed -e 's/ /-/g'` + +PRODUCTVER="$PRODUCT-$VER" + diff --git a/Utils/make-src-archive.sh b/Utils/make-src-archive.sh index 6e7ad662ee..22829896c2 100644 --- a/Utils/make-src-archive.sh +++ b/Utils/make-src-archive.sh @@ -1,65 +1,65 @@ -#!/bin/bash -set -e - -test -e ProductInfo.h && cd .. -if ! test -d src; then - echo Run this script from the top directory. - exit 1 -fi - -source Utils/GetProductVer.sh src/ProductInfo.h -PRODUCTVER="$PRODUCTVER-src" - -if test -e $PRODUCTVER; then - echo "\"$PRODUCTVER\" already exists." - exit 1 -fi -echo Copying... - -mkdir $PRODUCTVER -cp -dpR autoconf $PRODUCTVER/ -#cp -dpR Utils $PRODUCTVER/ -cp -dpR src $PRODUCTVER/ - -cp Docs/Copying.MAD Docs/Licenses.txt Makefile.am aclocal.m4 \ - configure Makefile.in configure.ac $PRODUCTVER - -echo Pruning... -cd $PRODUCTVER/src -# Obsolete and going away: -rm -rf SDL-1.2.5 -rm -rf SDL-1.2.6 -# Incomplete: -rm -rf Texture Font Generator -# Xbox: -rm -rf SDLx-0.02 -# Unused: -rm -rf smlobby - -# Windows-only stuff. Let's leave some in the archive to make the GPL happy. -# I don't want to spend an extra half hour to upload separate Windows and -# *nix source archives. -#rm -rf mad-0.15.0b - -rm -rf lua-5.0 -rm -rf vorbis -rm -rf BaseClasses -rm -rf ddk -rm -rf smpackage -rm -rf sdl_xbox_includes -rm -rf SDLx-0.02.rar - -cd .. - -find . -type d -name 'CVS' | xargs rm -rf -find . -type f -name '*.lib' | xargs rm -rf -find . -type f -name '*.exe' | xargs rm -rf -find . -type f -name '*.a' | xargs rm -rf -find . -type f -name '*.o' | xargs rm -rf - -cd .. -#rm -rf Utils/Font\ generation/ - -echo Archiving... -tar zchvf "$PRODUCTVER".tar.gz $PRODUCTVER/ - +#!/bin/bash +set -e + +test -e ProductInfo.h && cd .. +if ! test -d src; then + echo Run this script from the top directory. + exit 1 +fi + +source Utils/GetProductVer.sh src/ProductInfo.h +PRODUCTVER="$PRODUCTVER-src" + +if test -e $PRODUCTVER; then + echo "\"$PRODUCTVER\" already exists." + exit 1 +fi +echo Copying... + +mkdir $PRODUCTVER +cp -dpR autoconf $PRODUCTVER/ +#cp -dpR Utils $PRODUCTVER/ +cp -dpR src $PRODUCTVER/ + +cp Docs/Copying.MAD Docs/Licenses.txt Makefile.am aclocal.m4 \ + configure Makefile.in configure.ac $PRODUCTVER + +echo Pruning... +cd $PRODUCTVER/src +# Obsolete and going away: +rm -rf SDL-1.2.5 +rm -rf SDL-1.2.6 +# Incomplete: +rm -rf Texture Font Generator +# Xbox: +rm -rf SDLx-0.02 +# Unused: +rm -rf smlobby + +# Windows-only stuff. Let's leave some in the archive to make the GPL happy. +# I don't want to spend an extra half hour to upload separate Windows and +# *nix source archives. +#rm -rf mad-0.15.0b + +rm -rf lua-5.0 +rm -rf vorbis +rm -rf BaseClasses +rm -rf ddk +rm -rf smpackage +rm -rf sdl_xbox_includes +rm -rf SDLx-0.02.rar + +cd .. + +find . -type d -name 'CVS' | xargs rm -rf +find . -type f -name '*.lib' | xargs rm -rf +find . -type f -name '*.exe' | xargs rm -rf +find . -type f -name '*.a' | xargs rm -rf +find . -type f -name '*.o' | xargs rm -rf + +cd .. +#rm -rf Utils/Font\ generation/ + +echo Archiving... +tar zchvf "$PRODUCTVER".tar.gz $PRODUCTVER/ + diff --git a/Xcode/Libraries/guard-ffmpeg.sh b/Xcode/Libraries/guard-ffmpeg.sh index 4fc3b26da7..9720dca4dc 100644 --- a/Xcode/Libraries/guard-ffmpeg.sh +++ b/Xcode/Libraries/guard-ffmpeg.sh @@ -1,15 +1,15 @@ -#!/bin/sh - -for i in ffmpeg/libavcodec/ppc/*.[hc] \ -ffmpeg/libswscale/yuv2rgb_altivec.c; do - sed -i '' -e '1i\ -#ifdef __ppc__ -$a\ -#endif' $i -done -for i in ffmpeg/libavcodec/i386/*.[hc]; do - sed -i '' -e '1i\ -#ifdef __i386__ -$a\ -#endif' $i -done +#!/bin/sh + +for i in ffmpeg/libavcodec/ppc/*.[hc] \ +ffmpeg/libswscale/yuv2rgb_altivec.c; do + sed -i '' -e '1i\ +#ifdef __ppc__ +$a\ +#endif' $i +done +for i in ffmpeg/libavcodec/i386/*.[hc]; do + sed -i '' -e '1i\ +#ifdef __i386__ +$a\ +#endif' $i +done diff --git a/src/NotesLoaderSMA.cpp b/src/NotesLoaderSMA.cpp index 2d60122764..0068525ef9 100644 --- a/src/NotesLoaderSMA.cpp +++ b/src/NotesLoaderSMA.cpp @@ -1,764 +1,764 @@ -#include "global.h" -#include "NotesLoaderSMA.h" -#include "BackgroundUtil.h" -#include "GameManager.h" -#include "MsdFile.h" -#include "NoteTypes.h" -#include "NotesLoaderSM.h" // may need this. -#include "PrefsManager.h" -#include "RageFileManager.h" -#include "RageLog.h" -#include "RageUtil.h" -#include "Song.h" -#include "SongManager.h" -#include "Steps.h" - -/** - * @brief A custom .edit file can only be so big before we have to reject it. - */ -const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60 KB - -void SMALoader::LoadFromSMATokens( - RString sStepsType, - RString sDescription, - RString sDifficulty, - RString sMeter, - RString sRadarValues, - RString sNoteData, - Steps &out -) -{ - // we're loading from disk, so this is by definition already saved: - out.SetSavedToDisk( true ); - - Trim( sStepsType ); - Trim( sDescription ); - Trim( sDifficulty ); - Trim( sNoteData ); - - // LOG->Trace( "Steps::LoadFromSMTokens()" ); - - // insert stepstype hacks from GameManager.cpp here? -aj - out.m_StepsType = GAMEMAN->StringToStepsType( sStepsType ); - out.SetDescription( sDescription ); - out.SetCredit( sDescription ); // this is often used for both. - out.SetDifficulty( DwiCompatibleStringToDifficulty(sDifficulty) ); - - sDescription.MakeLower(); - - // Handle hacks that originated back when StepMania didn't have - // Difficulty_Challenge. (At least v1.64, possibly v3.0 final...) - if( out.GetDifficulty() == Difficulty_Hard ) - { - // HACK: SMANIAC used to be Difficulty_Hard with a special description. - if( sDescription == "smaniac" ) - out.SetDifficulty( Difficulty_Challenge ); - - // HACK: CHALLENGE used to be Difficulty_Hard with a special description. - if( sDescription == "challenge" ) - out.SetDifficulty( Difficulty_Challenge ); - } - - out.SetMeter( atoi(sMeter) ); - vector<RString> saValues; - split( sRadarValues, ",", saValues, true ); - int categories = NUM_RadarCategory - 1; // Fakes aren't counted in the radar values. - if( saValues.size() == (unsigned)categories * NUM_PLAYERS ) - { - RadarValues v[NUM_PLAYERS]; - FOREACH_PlayerNumber( pn ) - { - // Can't use the foreach anymore due to flexible radar lines. - for( RadarCategory rc = (RadarCategory)0; rc < categories; - enum_add<RadarCategory>( rc, 1 ) ) - { - v[pn][rc] = StringToFloat( saValues[pn*categories + rc] ); - } - } - out.SetCachedRadarValues( v ); - } - - out.SetSMNoteData( sNoteData ); - - out.TidyUpData(); -} - -bool SMALoader::LoadFromDir( const RString &sPath, Song &out ) -{ - vector<RString> aFileNames; - GetApplicableFiles( sPath, aFileNames ); - - if( aFileNames.size() > 1 ) - { - LOG->UserLog( "Song", sPath, "has more than one SMA file. There can be only one!" ); - return false; - } - ASSERT( aFileNames.size() == 1 ); - return LoadFromSMAFile( sPath + aFileNames[0], out ); -} - -void SMALoader::TidyUpData( Song &song, bool bFromCache ) -{ - SMLoader::TidyUpData( song, bFromCache ); -} - -bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out ) -{ - LOG->Trace( "Song::LoadFromSMAFile(%s)", sPath.c_str() ); - - MsdFile msd; - if( !msd.ReadFile( sPath, true ) ) // unescape - { - LOG->UserLog( "Song file", sPath, "couldn't be opened: %s", msd.GetError().c_str() ); - return false; - } - - out.m_Timing.m_sFile = sPath; - LoadTimingFromSMAFile( msd, out.m_Timing ); - - for( unsigned i=0; i<msd.GetNumValues(); i++ ) - { - int iNumParams = msd.GetNumParams(i); - const MsdFile::value_t &sParams = msd.GetValue(i); - RString sValueName = sParams[0]; - sValueName.MakeUpper(); - - // handle the data - /* Don't use GetMainAndSubTitlesFromFullTitle; that's only for heuristically - * splitting other formats that *don't* natively support #SUBTITLE. */ - if( sValueName=="TITLE" ) - out.m_sMainTitle = sParams[1]; - - else if( sValueName=="SUBTITLE" ) - out.m_sSubTitle = sParams[1]; - - else if( sValueName=="ARTIST" ) - out.m_sArtist = sParams[1]; - - else if( sValueName=="TITLETRANSLIT" ) - out.m_sMainTitleTranslit = sParams[1]; - - else if( sValueName=="SUBTITLETRANSLIT" ) - out.m_sSubTitleTranslit = sParams[1]; - - else if( sValueName=="ARTISTTRANSLIT" ) - out.m_sArtistTranslit = sParams[1]; - - else if( sValueName=="GENRE" ) - out.m_sGenre = sParams[1]; - - else if( sValueName=="CREDIT" ) - out.m_sCredit = sParams[1]; - - else if( sValueName=="BANNER" ) - out.m_sBannerFile = sParams[1]; - - else if( sValueName=="BACKGROUND" ) - out.m_sBackgroundFile = sParams[1]; - - // Save "#LYRICS" for later, so we can add an internal lyrics tag. - else if( sValueName=="LYRICSPATH" ) - out.m_sLyricsFile = sParams[1]; - - else if( sValueName=="CDTITLE" ) - out.m_sCDTitleFile = sParams[1]; - - else if( sValueName=="MUSIC" ) - out.m_sMusicFile = sParams[1]; - - else if( sValueName=="INSTRUMENTTRACK" ) - { - vector<RString> vs1; - split( sParams[1], ",", vs1 ); - FOREACH_CONST( RString, vs1, s ) - { - vector<RString> vs2; - split( *s, "=", vs2 ); - if( vs2.size() >= 2 ) - { - InstrumentTrack it = StringToInstrumentTrack( vs2[0] ); - if( it != InstrumentTrack_Invalid ) - out.m_sInstrumentTrackFile[it] = vs2[1]; - } - } - } - - else if( sValueName=="MUSICLENGTH" ) - { - continue; - } - - else if( sValueName=="LASTBEATHINT" ) - out.m_fSpecifiedLastBeat = StringToFloat( sParams[1] ); - - else if( sValueName=="MUSICBYTES" ) - ; /* ignore */ - - /* We calculate these. Some SMs in circulation have bogus values for - * these, so make sure we always calculate it ourself. */ - else if( sValueName=="FIRSTBEAT" ) - { - ; - } - else if( sValueName=="LASTBEAT" ) - { - ; } - else if( sValueName=="SONGFILENAME" ) - { - ; - } - else if( sValueName=="HASMUSIC" ) - { - ; - } - else if( sValueName=="HASBANNER" ) - { - ; - } - - else if( sValueName=="SAMPLESTART" ) - out.m_fMusicSampleStartSeconds = HHMMSSToSeconds( sParams[1] ); - - else if( sValueName=="SAMPLELENGTH" ) - out.m_fMusicSampleLengthSeconds = HHMMSSToSeconds( sParams[1] ); - - // SamplePath is used when the song has a separate preview clip. -aj - //else if( sValueName=="SAMPLEPATH" ) - //out.m_sMusicSamplePath = sParams[1]; - - else if( sValueName=="DISPLAYBPM" ) - { - // #DISPLAYBPM:[xxx][xxx:xxx]|[*]; - if( sParams[1] == "*" ) - out.m_DisplayBPMType = Song::DISPLAY_RANDOM; - else - { - out.m_DisplayBPMType = Song::DISPLAY_SPECIFIED; - out.m_fSpecifiedBPMMin = StringToFloat( sParams[1] ); - if( sParams[2].empty() ) - out.m_fSpecifiedBPMMax = out.m_fSpecifiedBPMMin; - else - out.m_fSpecifiedBPMMax = StringToFloat( sParams[2] ); - } - } - - else if( sValueName=="SELECTABLE" ) - { - if(!stricmp(sParams[1],"YES")) - out.m_SelectionDisplay = out.SHOW_ALWAYS; - else if(!stricmp(sParams[1],"NO")) - out.m_SelectionDisplay = out.SHOW_NEVER; - // ROULETTE from 3.9. It was removed since UnlockManager can serve - // the same purpose somehow. This, of course, assumes you're using - // unlocks. -aj - else if(!stricmp(sParams[1],"ROULETTE")) - out.m_SelectionDisplay = out.SHOW_ALWAYS; - /* The following two cases are just fixes to make sure simfiles that - * used 3.9+ features are not excluded here */ - else if(!stricmp(sParams[1],"ES") || !stricmp(sParams[1],"OMES")) - out.m_SelectionDisplay = out.SHOW_ALWAYS; - else if( atoi(sParams[1]) > 0 ) - out.m_SelectionDisplay = out.SHOW_ALWAYS; - else - LOG->UserLog( "Song file", sPath, "has an unknown #SELECTABLE value, \"%s\"; ignored.", sParams[1].c_str() ); - } - - else if( sValueName.Left(strlen("BGCHANGES"))=="BGCHANGES" || sValueName=="ANIMATIONS" ) - { - BackgroundLayer iLayer = BACKGROUND_LAYER_1; - if( sscanf(sValueName, "BGCHANGES%d", &*ConvertValue<int>(&iLayer)) == 1 ) - enum_add(iLayer, -1); // #BGCHANGES2 = BACKGROUND_LAYER_2 - - bool bValid = iLayer>=0 && iLayer<NUM_BackgroundLayer; - if( !bValid ) - { - LOG->UserLog( "Song file", sPath, "has a #BGCHANGES tag \"%s\" that is out of range.", sValueName.c_str() ); - } - else - { - vector<RString> aBGChangeExpressions; - split( sParams[1], ",", aBGChangeExpressions ); - - for( unsigned b=0; b<aBGChangeExpressions.size(); b++ ) - { - BackgroundChange change; - if( LoadFromBGChangesString( change, aBGChangeExpressions[b] ) ) - out.AddBackgroundChange( iLayer, change ); - } - } - } - - else if( sValueName=="FGCHANGES" ) - { - vector<RString> aFGChangeExpressions; - split( sParams[1], ",", aFGChangeExpressions ); - - for( unsigned b=0; b<aFGChangeExpressions.size(); b++ ) - { - BackgroundChange change; - if( LoadFromBGChangesString( change, aFGChangeExpressions[b] ) ) - out.AddForegroundChange( change ); - } - } - - else if( sValueName=="KEYSOUNDS" ) - { - split( sParams[1], ",", out.m_vsKeysoundFile ); - } - - // Attacks loaded from file - else if( sValueName=="ATTACKS" ) - { - // Build the RString vector here so we can write it to file again later - for( unsigned s=1; s < sParams.params.size(); ++s ) - out.m_sAttackString.push_back( sParams[s] ); - - Attack attack; - float end = -9999; - - for( unsigned j=1; j < sParams.params.size(); ++j ) - { - vector<RString> sBits; - split( sParams[j], "=", sBits, false ); - - // Need an identifer and a value for this to work - if( sBits.size() < 2 ) - continue; - - TrimLeft( sBits[0] ); - TrimRight( sBits[0] ); - - if( !sBits[0].CompareNoCase("TIME") ) - attack.fStartSecond = strtof( sBits[1], NULL ); - else if( !sBits[0].CompareNoCase("LEN") ) - attack.fSecsRemaining = strtof( sBits[1], NULL ); - else if( !sBits[0].CompareNoCase("END") ) - end = strtof( sBits[1], NULL ); - else if( !sBits[0].CompareNoCase("MODS") ) - { - attack.sModifiers = sBits[1]; - - if( end != -9999 ) - { - attack.fSecsRemaining = end - attack.fStartSecond; - end = -9999; - } - - if( attack.fSecsRemaining < 0.0f ) - attack.fSecsRemaining = 0.0f; - - out.m_Attacks.push_back( attack ); - } - } - } - - else if( sValueName=="NOTES" || sValueName=="NOTES2" ) - { - if( iNumParams < 7 ) - { - LOG->UserLog( "Song file", sPath, "has %d fields in a #NOTES tag, but should have at least 7.", iNumParams ); - continue; - } - - Steps* pNewNotes = new Steps; - LoadFromSMATokens( - sParams[1], - sParams[2], - sParams[3], - sParams[4], - sParams[5], - sParams[6], - *pNewNotes ); - - out.AddSteps( pNewNotes ); - } - /* - * We used to check for timing data in this section. That has - * since been moved to a dedicated function. - */ - else if( sValueName=="OFFSET" || sValueName=="BPMS" || sValueName=="STOPS" || sValueName=="FREEZES" || sValueName=="DELAYS" || sValueName=="TIMESIGNATURES" || sValueName=="LEADTRACK" || sValueName=="TICKCOUNTS" ) - ; - else - LOG->UserLog( "Song file", sPath, "has an unexpected value named \"%s\".", sValueName.c_str() ); - } - - return true; -} - -void SMALoader::GetApplicableFiles( const RString &sPath, vector<RString> &out ) -{ - GetDirListing( sPath + RString("*.sma"), out ); -} - -bool SMALoader::LoadTimingFromFile( const RString &fn, TimingData &out ) -{ - MsdFile msd; - if( !msd.ReadFile( fn, true ) ) // unescape - { - LOG->UserLog( "Song file", fn, "couldn't be loaded: %s", msd.GetError().c_str() ); - return false; - } - - out.m_sFile = fn; - LoadTimingFromSMAFile( msd, out ); - return true; -} - -void SMALoader::LoadTimingFromSMAFile( const MsdFile &msd, TimingData &out ) -{ - out.m_fBeat0OffsetInSeconds = 0; - out.m_BPMSegments.clear(); - out.m_StopSegments.clear(); - out.m_WarpSegments.clear(); - out.m_vTimeSignatureSegments.clear(); - - vector<WarpSegment> arrayWarpsFromNegativeBPMs; - //vector<WarpSegment> arrayWarpsFromNegativeStops; - int rowsPerMeasure = 0; - bool encountered = false; - - for( unsigned i=0; i<msd.GetNumValues(); i++ ) - { - const MsdFile::value_t &sParams = msd.GetValue(i); - RString sValueName = sParams[0]; - sValueName.MakeUpper(); - - if( sValueName=="ROWSPERBEAT") - { - if( encountered ) - { - break; - } - encountered = true; - rowsPerMeasure = atoi( sParams[1] ); - } - else if( sValueName=="BEATSPERMEASURE" ) - { - TimeSignatureSegment new_seg; - new_seg.m_iStartRow = 0; - new_seg.m_iNumerator = atoi( sParams[1] ); - new_seg.m_iDenominator = 4; - out.AddTimeSignatureSegment( new_seg ); - } - else if( sValueName=="OFFSET" ) - { - out.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); - } - else if( sValueName=="STOPS" ) - { - vector<RString> arrayFreezeExpressions; - split( sParams[1], ",", arrayFreezeExpressions ); - - for( unsigned f=0; f<arrayFreezeExpressions.size(); f++ ) - { - vector<RString> arrayFreezeValues; - split( arrayFreezeExpressions[f], "=", arrayFreezeValues ); - if( arrayFreezeValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayFreezeExpressions[f].c_str() ); - continue; - } - - float fFreezeBeat = 0; - RString beat = arrayFreezeValues[0]; - if( beat.Right(0).MakeUpper() == "R" ) - { - beat = beat.Left(beat.size()-1); - fFreezeBeat = StringToFloat( beat ) / rowsPerMeasure; - } - else - { - fFreezeBeat = StringToFloat(beat); - } - - //float fFreezeBeat = StringToFloat( arrayBPMChangeValues[0] ); - const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); - StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); - // XXX: Remove Negatives Bug? - new_seg.m_iStartRow = BeatToNoteRow(fFreezeBeat); - new_seg.m_fStopSeconds = fFreezeSeconds; - - if(fFreezeSeconds > 0.0f) - { - // LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); - out.AddStopSegment( new_seg ); - } - else - { - // negative stops (hi JS!) -aj - if( PREFSMAN->m_bQuirksMode ) - { - // LOG->Trace( "Adding a negative freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); - out.AddStopSegment( new_seg ); - } - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid stop at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); - } - } - } - - else if( sValueName=="BPMS" ) - { - vector<RString> arrayBPMChangeExpressions; - split( sParams[1], ",", arrayBPMChangeExpressions ); - - for( unsigned b=0; b<arrayBPMChangeExpressions.size(); b++ ) - { - vector<RString> arrayBPMChangeValues; - split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues ); - // XXX: Hard to tell which file caused this. - if( arrayBPMChangeValues.size() != 2 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() ); - continue; - } - - float fBeat = 0; - RString beat = arrayBPMChangeValues[0]; - if( beat.Right(0).MakeUpper() == "R" ) - { - beat = beat.Left(beat.size()-1); - fBeat = StringToFloat( beat ) / rowsPerMeasure; - } - else - { - fBeat = StringToFloat(beat); - } - - //float fBeat = StringToFloat( arrayBPMChangeValues[0] ); - const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); - // XXX: Remove Negatives Bug? - BPMSegment new_seg; - new_seg.m_iStartRow = BeatToNoteRow(fBeat); - new_seg.SetBPM( fNewBPM ); - - // convert negative BPMs into Warp segments - if( fNewBPM < 0.0f ) - { - vector<RString> arrayNextBPMChangeValues; - // get next bpm in sequence - if((b+1) < arrayBPMChangeExpressions.size()) - { - split( arrayBPMChangeExpressions[b+1], "=", arrayNextBPMChangeValues ); - const float fNextPositiveBeat = StringToFloat( arrayNextBPMChangeValues[0] ); - const float fNextPositiveBPM = StringToFloat( arrayNextBPMChangeValues[1] ); - - // tJumpPos = (tPosBPS-abs(negBPS)) + (gPosBPMPosition - fNegPosition) - float fDeltaBeat = ((fNextPositiveBPM/60.0f)-abs(fNewBPM/60.0f)) + (fNextPositiveBeat-fBeat); - //float fWarpLengthBeats = fNextPositiveBeat + fDeltaBeat; - WarpSegment wsTemp(BeatToNoteRow(fBeat),fDeltaBeat); - arrayWarpsFromNegativeBPMs.push_back(wsTemp); - - /* - LOG->Trace( ssprintf("==NotesLoSM negbpm==\nfnextposbeat = %f, fnextposbpm = %f,\nfdelta = %f, fwarpto = %f", - fNextPositiveBeat, - fNextPositiveBPM, - fDeltaBeat, - fWarpToBeat - ) ); - */ - /* - LOG->Trace( ssprintf("==Negative/Subtractive BPM in NotesLoader==\nNegBPM has noterow = %i, BPM = %f\nNextBPM @ noterow %i\nDelta value = %i noterows\nThis warp will have us end up at noterow %i", - BeatToNoteRow(fBeat), fNewBPM, - BeatToNoteRow(fNextPositiveBeat), - BeatToNoteRow(fDeltaBeat), - BeatToNoteRow(fWarpToBeat)) - ); - */ - //float fDeltaBeat = ((fNextPositiveBPM/60.0f)-abs(fNewBPM/60.0f)) + (fNextPositiveBeat-fBeat); - /* - LOG->Trace( ssprintf("==NotesLoader Delta as NoteRows==\nfDeltaBeat = %f (beat)\nfDeltaBeat = (NextBPMSeg %f - abs(fBPS %f)) + (nextStartRow %i - thisRow %i)", - fDeltaBeat,(fNextPositiveBPM/60.0f),abs(fNewBPM/60.0f),BeatToNoteRow(fNextPositiveBeat),BeatToNoteRow(fBeat)) - ); - */ - - out.AddBPMSegment( new_seg ); - - continue; - } - else - { - // last BPM is a negative one? ugh. -aj (MAX_NOTE_ROW exists btw) - out.AddBPMSegment( new_seg ); - } - } - - if(fNewBPM > 0.0f) - out.AddBPMSegment( new_seg ); - else - { - out.m_bHasNegativeBpms = true; - // only add Negative BPMs in quirks mode -aj - if( PREFSMAN->m_bQuirksMode ) - out.AddBPMSegment( new_seg ); - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid BPM change at beat %f, BPM %f.", fBeat, fNewBPM ); - } - } - } - - - // Note: Even though it is possible to have Negative BPMs and Stops in - // a song along with Warps, we should not support files that contain - // both styles of warp tricks (Negatives vs. #WARPS). - // If Warps have been populated from Negative BPMs, then go through that - // instead of using the data in the Warps tag. This should be above, - // but it breaks compiling so... - if(arrayWarpsFromNegativeBPMs.size() > 0) - { - // zomg we already have some warps... - for( unsigned j=0; j<arrayWarpsFromNegativeBPMs.size(); j++ ) - { - out.AddWarpSegment( arrayWarpsFromNegativeBPMs[j] ); - } - } - // warp sorting will need to take place. - //sort(out.m_WarpSegments.begin(), out.m_WarpSegments.end()); - } -} - -bool SMALoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ) -{ - LOG->Trace( "SMALoader::LoadEditFromFile(%s)", sEditFilePath.c_str() ); - - int iBytes = FILEMAN->GetFileSizeInBytes( sEditFilePath ); - if( iBytes > MAX_EDIT_STEPS_SIZE_BYTES ) - { - LOG->UserLog( "Edit file", sEditFilePath, "is unreasonably large. It won't be loaded." ); - return false; - } - - MsdFile msd; - if( !msd.ReadFile( sEditFilePath, true ) ) // unescape - { - LOG->UserLog( "Edit file", sEditFilePath, "couldn't be opened: %s", msd.GetError().c_str() ); - return false; - } - - return LoadEditFromMsd( msd, sEditFilePath, slot, bAddStepsToSong ); -} - -bool SMALoader::LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot ) -{ - MsdFile msd; - msd.ReadFromString( sBuffer, true ); // unescape - return LoadEditFromMsd( msd, sEditFilePath, slot, true ); -} - -bool SMALoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ) -{ - Song* pSong = NULL; - - for( unsigned i=0; i<msd.GetNumValues(); i++ ) - { - int iNumParams = msd.GetNumParams(i); - const MsdFile::value_t &sParams = msd.GetValue(i); - RString sValueName = sParams[0]; - sValueName.MakeUpper(); - - // handle the data - if( sValueName=="SONG" ) - { - if( pSong ) - { - LOG->UserLog( "Edit file", sEditFilePath, "has more than one #SONG tag." ); - return false; - } - - RString sSongFullTitle = sParams[1]; - sSongFullTitle.Replace( '\\', '/' ); - - pSong = SONGMAN->FindSong( sSongFullTitle ); - if( pSong == NULL ) - { - LOG->UserLog( "Edit file", sEditFilePath, "requires a song \"%s\" that isn't present.", sSongFullTitle.c_str() ); - return false; - } - - if( pSong->GetNumStepsLoadedFromProfile(slot) >= MAX_EDITS_PER_SONG_PER_PROFILE ) - { - LOG->UserLog( "Song file", sSongFullTitle, "already has the maximum number of edits allowed for ProfileSlotP%d.", slot+1 ); - return false; - } - } - - else if( sValueName=="NOTES" ) - { - if( pSong == NULL ) - { - LOG->UserLog( "Edit file", sEditFilePath, "doesn't have a #SONG tag preceeding the first #NOTES tag." ); - return false; - } - - if( iNumParams < 7 ) - { - LOG->UserLog( "Edit file", sEditFilePath, "has %d fields in a #NOTES tag, but should have at least 7.", iNumParams ); - continue; - } - - if( !bAddStepsToSong ) - return true; - - Steps* pNewNotes = new Steps; - LoadFromSMATokens( - sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6], - *pNewNotes); - - pNewNotes->SetLoadedFromProfile( slot ); - pNewNotes->SetDifficulty( Difficulty_Edit ); - pNewNotes->SetFilename( sEditFilePath ); - - if( pSong->IsEditAlreadyLoaded(pNewNotes) ) - { - LOG->UserLog( "Edit file", sEditFilePath, "is a duplicate of another edit that was already loaded." ); - SAFE_DELETE( pNewNotes ); - return false; - } - - pSong->AddSteps( pNewNotes ); - return true; // Only allow one Steps per edit file! - } - else - { - LOG->UserLog( "Edit file", sEditFilePath, "has an unexpected value \"%s\".", sValueName.c_str() ); - } - } - - return true; -} - -bool SMALoader::LoadFromBGChangesString( BackgroundChange &change, - const RString &sBGChangeExpression ) -{ - return SMLoader::LoadFromBGChangesString(change, sBGChangeExpression); -} - -/** - * @file - * @author Aldo Fregoso, Jason Felds (c) 2009-2011 - * @section LICENSE - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +#include "global.h" +#include "NotesLoaderSMA.h" +#include "BackgroundUtil.h" +#include "GameManager.h" +#include "MsdFile.h" +#include "NoteTypes.h" +#include "NotesLoaderSM.h" // may need this. +#include "PrefsManager.h" +#include "RageFileManager.h" +#include "RageLog.h" +#include "RageUtil.h" +#include "Song.h" +#include "SongManager.h" +#include "Steps.h" + +/** + * @brief A custom .edit file can only be so big before we have to reject it. + */ +const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60 KB + +void SMALoader::LoadFromSMATokens( + RString sStepsType, + RString sDescription, + RString sDifficulty, + RString sMeter, + RString sRadarValues, + RString sNoteData, + Steps &out +) +{ + // we're loading from disk, so this is by definition already saved: + out.SetSavedToDisk( true ); + + Trim( sStepsType ); + Trim( sDescription ); + Trim( sDifficulty ); + Trim( sNoteData ); + + // LOG->Trace( "Steps::LoadFromSMTokens()" ); + + // insert stepstype hacks from GameManager.cpp here? -aj + out.m_StepsType = GAMEMAN->StringToStepsType( sStepsType ); + out.SetDescription( sDescription ); + out.SetCredit( sDescription ); // this is often used for both. + out.SetDifficulty( DwiCompatibleStringToDifficulty(sDifficulty) ); + + sDescription.MakeLower(); + + // Handle hacks that originated back when StepMania didn't have + // Difficulty_Challenge. (At least v1.64, possibly v3.0 final...) + if( out.GetDifficulty() == Difficulty_Hard ) + { + // HACK: SMANIAC used to be Difficulty_Hard with a special description. + if( sDescription == "smaniac" ) + out.SetDifficulty( Difficulty_Challenge ); + + // HACK: CHALLENGE used to be Difficulty_Hard with a special description. + if( sDescription == "challenge" ) + out.SetDifficulty( Difficulty_Challenge ); + } + + out.SetMeter( atoi(sMeter) ); + vector<RString> saValues; + split( sRadarValues, ",", saValues, true ); + int categories = NUM_RadarCategory - 1; // Fakes aren't counted in the radar values. + if( saValues.size() == (unsigned)categories * NUM_PLAYERS ) + { + RadarValues v[NUM_PLAYERS]; + FOREACH_PlayerNumber( pn ) + { + // Can't use the foreach anymore due to flexible radar lines. + for( RadarCategory rc = (RadarCategory)0; rc < categories; + enum_add<RadarCategory>( rc, 1 ) ) + { + v[pn][rc] = StringToFloat( saValues[pn*categories + rc] ); + } + } + out.SetCachedRadarValues( v ); + } + + out.SetSMNoteData( sNoteData ); + + out.TidyUpData(); +} + +bool SMALoader::LoadFromDir( const RString &sPath, Song &out ) +{ + vector<RString> aFileNames; + GetApplicableFiles( sPath, aFileNames ); + + if( aFileNames.size() > 1 ) + { + LOG->UserLog( "Song", sPath, "has more than one SMA file. There can be only one!" ); + return false; + } + ASSERT( aFileNames.size() == 1 ); + return LoadFromSMAFile( sPath + aFileNames[0], out ); +} + +void SMALoader::TidyUpData( Song &song, bool bFromCache ) +{ + SMLoader::TidyUpData( song, bFromCache ); +} + +bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out ) +{ + LOG->Trace( "Song::LoadFromSMAFile(%s)", sPath.c_str() ); + + MsdFile msd; + if( !msd.ReadFile( sPath, true ) ) // unescape + { + LOG->UserLog( "Song file", sPath, "couldn't be opened: %s", msd.GetError().c_str() ); + return false; + } + + out.m_Timing.m_sFile = sPath; + LoadTimingFromSMAFile( msd, out.m_Timing ); + + for( unsigned i=0; i<msd.GetNumValues(); i++ ) + { + int iNumParams = msd.GetNumParams(i); + const MsdFile::value_t &sParams = msd.GetValue(i); + RString sValueName = sParams[0]; + sValueName.MakeUpper(); + + // handle the data + /* Don't use GetMainAndSubTitlesFromFullTitle; that's only for heuristically + * splitting other formats that *don't* natively support #SUBTITLE. */ + if( sValueName=="TITLE" ) + out.m_sMainTitle = sParams[1]; + + else if( sValueName=="SUBTITLE" ) + out.m_sSubTitle = sParams[1]; + + else if( sValueName=="ARTIST" ) + out.m_sArtist = sParams[1]; + + else if( sValueName=="TITLETRANSLIT" ) + out.m_sMainTitleTranslit = sParams[1]; + + else if( sValueName=="SUBTITLETRANSLIT" ) + out.m_sSubTitleTranslit = sParams[1]; + + else if( sValueName=="ARTISTTRANSLIT" ) + out.m_sArtistTranslit = sParams[1]; + + else if( sValueName=="GENRE" ) + out.m_sGenre = sParams[1]; + + else if( sValueName=="CREDIT" ) + out.m_sCredit = sParams[1]; + + else if( sValueName=="BANNER" ) + out.m_sBannerFile = sParams[1]; + + else if( sValueName=="BACKGROUND" ) + out.m_sBackgroundFile = sParams[1]; + + // Save "#LYRICS" for later, so we can add an internal lyrics tag. + else if( sValueName=="LYRICSPATH" ) + out.m_sLyricsFile = sParams[1]; + + else if( sValueName=="CDTITLE" ) + out.m_sCDTitleFile = sParams[1]; + + else if( sValueName=="MUSIC" ) + out.m_sMusicFile = sParams[1]; + + else if( sValueName=="INSTRUMENTTRACK" ) + { + vector<RString> vs1; + split( sParams[1], ",", vs1 ); + FOREACH_CONST( RString, vs1, s ) + { + vector<RString> vs2; + split( *s, "=", vs2 ); + if( vs2.size() >= 2 ) + { + InstrumentTrack it = StringToInstrumentTrack( vs2[0] ); + if( it != InstrumentTrack_Invalid ) + out.m_sInstrumentTrackFile[it] = vs2[1]; + } + } + } + + else if( sValueName=="MUSICLENGTH" ) + { + continue; + } + + else if( sValueName=="LASTBEATHINT" ) + out.m_fSpecifiedLastBeat = StringToFloat( sParams[1] ); + + else if( sValueName=="MUSICBYTES" ) + ; /* ignore */ + + /* We calculate these. Some SMs in circulation have bogus values for + * these, so make sure we always calculate it ourself. */ + else if( sValueName=="FIRSTBEAT" ) + { + ; + } + else if( sValueName=="LASTBEAT" ) + { + ; } + else if( sValueName=="SONGFILENAME" ) + { + ; + } + else if( sValueName=="HASMUSIC" ) + { + ; + } + else if( sValueName=="HASBANNER" ) + { + ; + } + + else if( sValueName=="SAMPLESTART" ) + out.m_fMusicSampleStartSeconds = HHMMSSToSeconds( sParams[1] ); + + else if( sValueName=="SAMPLELENGTH" ) + out.m_fMusicSampleLengthSeconds = HHMMSSToSeconds( sParams[1] ); + + // SamplePath is used when the song has a separate preview clip. -aj + //else if( sValueName=="SAMPLEPATH" ) + //out.m_sMusicSamplePath = sParams[1]; + + else if( sValueName=="DISPLAYBPM" ) + { + // #DISPLAYBPM:[xxx][xxx:xxx]|[*]; + if( sParams[1] == "*" ) + out.m_DisplayBPMType = Song::DISPLAY_RANDOM; + else + { + out.m_DisplayBPMType = Song::DISPLAY_SPECIFIED; + out.m_fSpecifiedBPMMin = StringToFloat( sParams[1] ); + if( sParams[2].empty() ) + out.m_fSpecifiedBPMMax = out.m_fSpecifiedBPMMin; + else + out.m_fSpecifiedBPMMax = StringToFloat( sParams[2] ); + } + } + + else if( sValueName=="SELECTABLE" ) + { + if(!stricmp(sParams[1],"YES")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + else if(!stricmp(sParams[1],"NO")) + out.m_SelectionDisplay = out.SHOW_NEVER; + // ROULETTE from 3.9. It was removed since UnlockManager can serve + // the same purpose somehow. This, of course, assumes you're using + // unlocks. -aj + else if(!stricmp(sParams[1],"ROULETTE")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + /* The following two cases are just fixes to make sure simfiles that + * used 3.9+ features are not excluded here */ + else if(!stricmp(sParams[1],"ES") || !stricmp(sParams[1],"OMES")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + else if( atoi(sParams[1]) > 0 ) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + else + LOG->UserLog( "Song file", sPath, "has an unknown #SELECTABLE value, \"%s\"; ignored.", sParams[1].c_str() ); + } + + else if( sValueName.Left(strlen("BGCHANGES"))=="BGCHANGES" || sValueName=="ANIMATIONS" ) + { + BackgroundLayer iLayer = BACKGROUND_LAYER_1; + if( sscanf(sValueName, "BGCHANGES%d", &*ConvertValue<int>(&iLayer)) == 1 ) + enum_add(iLayer, -1); // #BGCHANGES2 = BACKGROUND_LAYER_2 + + bool bValid = iLayer>=0 && iLayer<NUM_BackgroundLayer; + if( !bValid ) + { + LOG->UserLog( "Song file", sPath, "has a #BGCHANGES tag \"%s\" that is out of range.", sValueName.c_str() ); + } + else + { + vector<RString> aBGChangeExpressions; + split( sParams[1], ",", aBGChangeExpressions ); + + for( unsigned b=0; b<aBGChangeExpressions.size(); b++ ) + { + BackgroundChange change; + if( LoadFromBGChangesString( change, aBGChangeExpressions[b] ) ) + out.AddBackgroundChange( iLayer, change ); + } + } + } + + else if( sValueName=="FGCHANGES" ) + { + vector<RString> aFGChangeExpressions; + split( sParams[1], ",", aFGChangeExpressions ); + + for( unsigned b=0; b<aFGChangeExpressions.size(); b++ ) + { + BackgroundChange change; + if( LoadFromBGChangesString( change, aFGChangeExpressions[b] ) ) + out.AddForegroundChange( change ); + } + } + + else if( sValueName=="KEYSOUNDS" ) + { + split( sParams[1], ",", out.m_vsKeysoundFile ); + } + + // Attacks loaded from file + else if( sValueName=="ATTACKS" ) + { + // Build the RString vector here so we can write it to file again later + for( unsigned s=1; s < sParams.params.size(); ++s ) + out.m_sAttackString.push_back( sParams[s] ); + + Attack attack; + float end = -9999; + + for( unsigned j=1; j < sParams.params.size(); ++j ) + { + vector<RString> sBits; + split( sParams[j], "=", sBits, false ); + + // Need an identifer and a value for this to work + if( sBits.size() < 2 ) + continue; + + TrimLeft( sBits[0] ); + TrimRight( sBits[0] ); + + if( !sBits[0].CompareNoCase("TIME") ) + attack.fStartSecond = strtof( sBits[1], NULL ); + else if( !sBits[0].CompareNoCase("LEN") ) + attack.fSecsRemaining = strtof( sBits[1], NULL ); + else if( !sBits[0].CompareNoCase("END") ) + end = strtof( sBits[1], NULL ); + else if( !sBits[0].CompareNoCase("MODS") ) + { + attack.sModifiers = sBits[1]; + + if( end != -9999 ) + { + attack.fSecsRemaining = end - attack.fStartSecond; + end = -9999; + } + + if( attack.fSecsRemaining < 0.0f ) + attack.fSecsRemaining = 0.0f; + + out.m_Attacks.push_back( attack ); + } + } + } + + else if( sValueName=="NOTES" || sValueName=="NOTES2" ) + { + if( iNumParams < 7 ) + { + LOG->UserLog( "Song file", sPath, "has %d fields in a #NOTES tag, but should have at least 7.", iNumParams ); + continue; + } + + Steps* pNewNotes = new Steps; + LoadFromSMATokens( + sParams[1], + sParams[2], + sParams[3], + sParams[4], + sParams[5], + sParams[6], + *pNewNotes ); + + out.AddSteps( pNewNotes ); + } + /* + * We used to check for timing data in this section. That has + * since been moved to a dedicated function. + */ + else if( sValueName=="OFFSET" || sValueName=="BPMS" || sValueName=="STOPS" || sValueName=="FREEZES" || sValueName=="DELAYS" || sValueName=="TIMESIGNATURES" || sValueName=="LEADTRACK" || sValueName=="TICKCOUNTS" ) + ; + else + LOG->UserLog( "Song file", sPath, "has an unexpected value named \"%s\".", sValueName.c_str() ); + } + + return true; +} + +void SMALoader::GetApplicableFiles( const RString &sPath, vector<RString> &out ) +{ + GetDirListing( sPath + RString("*.sma"), out ); +} + +bool SMALoader::LoadTimingFromFile( const RString &fn, TimingData &out ) +{ + MsdFile msd; + if( !msd.ReadFile( fn, true ) ) // unescape + { + LOG->UserLog( "Song file", fn, "couldn't be loaded: %s", msd.GetError().c_str() ); + return false; + } + + out.m_sFile = fn; + LoadTimingFromSMAFile( msd, out ); + return true; +} + +void SMALoader::LoadTimingFromSMAFile( const MsdFile &msd, TimingData &out ) +{ + out.m_fBeat0OffsetInSeconds = 0; + out.m_BPMSegments.clear(); + out.m_StopSegments.clear(); + out.m_WarpSegments.clear(); + out.m_vTimeSignatureSegments.clear(); + + vector<WarpSegment> arrayWarpsFromNegativeBPMs; + //vector<WarpSegment> arrayWarpsFromNegativeStops; + int rowsPerMeasure = 0; + bool encountered = false; + + for( unsigned i=0; i<msd.GetNumValues(); i++ ) + { + const MsdFile::value_t &sParams = msd.GetValue(i); + RString sValueName = sParams[0]; + sValueName.MakeUpper(); + + if( sValueName=="ROWSPERBEAT") + { + if( encountered ) + { + break; + } + encountered = true; + rowsPerMeasure = atoi( sParams[1] ); + } + else if( sValueName=="BEATSPERMEASURE" ) + { + TimeSignatureSegment new_seg; + new_seg.m_iStartRow = 0; + new_seg.m_iNumerator = atoi( sParams[1] ); + new_seg.m_iDenominator = 4; + out.AddTimeSignatureSegment( new_seg ); + } + else if( sValueName=="OFFSET" ) + { + out.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); + } + else if( sValueName=="STOPS" ) + { + vector<RString> arrayFreezeExpressions; + split( sParams[1], ",", arrayFreezeExpressions ); + + for( unsigned f=0; f<arrayFreezeExpressions.size(); f++ ) + { + vector<RString> arrayFreezeValues; + split( arrayFreezeExpressions[f], "=", arrayFreezeValues ); + if( arrayFreezeValues.size() != 2 ) + { + // XXX: Hard to tell which file caused this. + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayFreezeExpressions[f].c_str() ); + continue; + } + + float fFreezeBeat = 0; + RString beat = arrayFreezeValues[0]; + if( beat.Right(0).MakeUpper() == "R" ) + { + beat = beat.Left(beat.size()-1); + fFreezeBeat = StringToFloat( beat ) / rowsPerMeasure; + } + else + { + fFreezeBeat = StringToFloat(beat); + } + + //float fFreezeBeat = StringToFloat( arrayBPMChangeValues[0] ); + const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); + StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); + // XXX: Remove Negatives Bug? + new_seg.m_iStartRow = BeatToNoteRow(fFreezeBeat); + new_seg.m_fStopSeconds = fFreezeSeconds; + + if(fFreezeSeconds > 0.0f) + { + // LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + out.AddStopSegment( new_seg ); + } + else + { + // negative stops (hi JS!) -aj + if( PREFSMAN->m_bQuirksMode ) + { + // LOG->Trace( "Adding a negative freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + out.AddStopSegment( new_seg ); + } + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid stop at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); + } + } + } + + else if( sValueName=="BPMS" ) + { + vector<RString> arrayBPMChangeExpressions; + split( sParams[1], ",", arrayBPMChangeExpressions ); + + for( unsigned b=0; b<arrayBPMChangeExpressions.size(); b++ ) + { + vector<RString> arrayBPMChangeValues; + split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues ); + // XXX: Hard to tell which file caused this. + if( arrayBPMChangeValues.size() != 2 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() ); + continue; + } + + float fBeat = 0; + RString beat = arrayBPMChangeValues[0]; + if( beat.Right(0).MakeUpper() == "R" ) + { + beat = beat.Left(beat.size()-1); + fBeat = StringToFloat( beat ) / rowsPerMeasure; + } + else + { + fBeat = StringToFloat(beat); + } + + //float fBeat = StringToFloat( arrayBPMChangeValues[0] ); + const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); + // XXX: Remove Negatives Bug? + BPMSegment new_seg; + new_seg.m_iStartRow = BeatToNoteRow(fBeat); + new_seg.SetBPM( fNewBPM ); + + // convert negative BPMs into Warp segments + if( fNewBPM < 0.0f ) + { + vector<RString> arrayNextBPMChangeValues; + // get next bpm in sequence + if((b+1) < arrayBPMChangeExpressions.size()) + { + split( arrayBPMChangeExpressions[b+1], "=", arrayNextBPMChangeValues ); + const float fNextPositiveBeat = StringToFloat( arrayNextBPMChangeValues[0] ); + const float fNextPositiveBPM = StringToFloat( arrayNextBPMChangeValues[1] ); + + // tJumpPos = (tPosBPS-abs(negBPS)) + (gPosBPMPosition - fNegPosition) + float fDeltaBeat = ((fNextPositiveBPM/60.0f)-abs(fNewBPM/60.0f)) + (fNextPositiveBeat-fBeat); + //float fWarpLengthBeats = fNextPositiveBeat + fDeltaBeat; + WarpSegment wsTemp(BeatToNoteRow(fBeat),fDeltaBeat); + arrayWarpsFromNegativeBPMs.push_back(wsTemp); + + /* + LOG->Trace( ssprintf("==NotesLoSM negbpm==\nfnextposbeat = %f, fnextposbpm = %f,\nfdelta = %f, fwarpto = %f", + fNextPositiveBeat, + fNextPositiveBPM, + fDeltaBeat, + fWarpToBeat + ) ); + */ + /* + LOG->Trace( ssprintf("==Negative/Subtractive BPM in NotesLoader==\nNegBPM has noterow = %i, BPM = %f\nNextBPM @ noterow %i\nDelta value = %i noterows\nThis warp will have us end up at noterow %i", + BeatToNoteRow(fBeat), fNewBPM, + BeatToNoteRow(fNextPositiveBeat), + BeatToNoteRow(fDeltaBeat), + BeatToNoteRow(fWarpToBeat)) + ); + */ + //float fDeltaBeat = ((fNextPositiveBPM/60.0f)-abs(fNewBPM/60.0f)) + (fNextPositiveBeat-fBeat); + /* + LOG->Trace( ssprintf("==NotesLoader Delta as NoteRows==\nfDeltaBeat = %f (beat)\nfDeltaBeat = (NextBPMSeg %f - abs(fBPS %f)) + (nextStartRow %i - thisRow %i)", + fDeltaBeat,(fNextPositiveBPM/60.0f),abs(fNewBPM/60.0f),BeatToNoteRow(fNextPositiveBeat),BeatToNoteRow(fBeat)) + ); + */ + + out.AddBPMSegment( new_seg ); + + continue; + } + else + { + // last BPM is a negative one? ugh. -aj (MAX_NOTE_ROW exists btw) + out.AddBPMSegment( new_seg ); + } + } + + if(fNewBPM > 0.0f) + out.AddBPMSegment( new_seg ); + else + { + out.m_bHasNegativeBpms = true; + // only add Negative BPMs in quirks mode -aj + if( PREFSMAN->m_bQuirksMode ) + out.AddBPMSegment( new_seg ); + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid BPM change at beat %f, BPM %f.", fBeat, fNewBPM ); + } + } + } + + + // Note: Even though it is possible to have Negative BPMs and Stops in + // a song along with Warps, we should not support files that contain + // both styles of warp tricks (Negatives vs. #WARPS). + // If Warps have been populated from Negative BPMs, then go through that + // instead of using the data in the Warps tag. This should be above, + // but it breaks compiling so... + if(arrayWarpsFromNegativeBPMs.size() > 0) + { + // zomg we already have some warps... + for( unsigned j=0; j<arrayWarpsFromNegativeBPMs.size(); j++ ) + { + out.AddWarpSegment( arrayWarpsFromNegativeBPMs[j] ); + } + } + // warp sorting will need to take place. + //sort(out.m_WarpSegments.begin(), out.m_WarpSegments.end()); + } +} + +bool SMALoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ) +{ + LOG->Trace( "SMALoader::LoadEditFromFile(%s)", sEditFilePath.c_str() ); + + int iBytes = FILEMAN->GetFileSizeInBytes( sEditFilePath ); + if( iBytes > MAX_EDIT_STEPS_SIZE_BYTES ) + { + LOG->UserLog( "Edit file", sEditFilePath, "is unreasonably large. It won't be loaded." ); + return false; + } + + MsdFile msd; + if( !msd.ReadFile( sEditFilePath, true ) ) // unescape + { + LOG->UserLog( "Edit file", sEditFilePath, "couldn't be opened: %s", msd.GetError().c_str() ); + return false; + } + + return LoadEditFromMsd( msd, sEditFilePath, slot, bAddStepsToSong ); +} + +bool SMALoader::LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot ) +{ + MsdFile msd; + msd.ReadFromString( sBuffer, true ); // unescape + return LoadEditFromMsd( msd, sEditFilePath, slot, true ); +} + +bool SMALoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ) +{ + Song* pSong = NULL; + + for( unsigned i=0; i<msd.GetNumValues(); i++ ) + { + int iNumParams = msd.GetNumParams(i); + const MsdFile::value_t &sParams = msd.GetValue(i); + RString sValueName = sParams[0]; + sValueName.MakeUpper(); + + // handle the data + if( sValueName=="SONG" ) + { + if( pSong ) + { + LOG->UserLog( "Edit file", sEditFilePath, "has more than one #SONG tag." ); + return false; + } + + RString sSongFullTitle = sParams[1]; + sSongFullTitle.Replace( '\\', '/' ); + + pSong = SONGMAN->FindSong( sSongFullTitle ); + if( pSong == NULL ) + { + LOG->UserLog( "Edit file", sEditFilePath, "requires a song \"%s\" that isn't present.", sSongFullTitle.c_str() ); + return false; + } + + if( pSong->GetNumStepsLoadedFromProfile(slot) >= MAX_EDITS_PER_SONG_PER_PROFILE ) + { + LOG->UserLog( "Song file", sSongFullTitle, "already has the maximum number of edits allowed for ProfileSlotP%d.", slot+1 ); + return false; + } + } + + else if( sValueName=="NOTES" ) + { + if( pSong == NULL ) + { + LOG->UserLog( "Edit file", sEditFilePath, "doesn't have a #SONG tag preceeding the first #NOTES tag." ); + return false; + } + + if( iNumParams < 7 ) + { + LOG->UserLog( "Edit file", sEditFilePath, "has %d fields in a #NOTES tag, but should have at least 7.", iNumParams ); + continue; + } + + if( !bAddStepsToSong ) + return true; + + Steps* pNewNotes = new Steps; + LoadFromSMATokens( + sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6], + *pNewNotes); + + pNewNotes->SetLoadedFromProfile( slot ); + pNewNotes->SetDifficulty( Difficulty_Edit ); + pNewNotes->SetFilename( sEditFilePath ); + + if( pSong->IsEditAlreadyLoaded(pNewNotes) ) + { + LOG->UserLog( "Edit file", sEditFilePath, "is a duplicate of another edit that was already loaded." ); + SAFE_DELETE( pNewNotes ); + return false; + } + + pSong->AddSteps( pNewNotes ); + return true; // Only allow one Steps per edit file! + } + else + { + LOG->UserLog( "Edit file", sEditFilePath, "has an unexpected value \"%s\".", sValueName.c_str() ); + } + } + + return true; +} + +bool SMALoader::LoadFromBGChangesString( BackgroundChange &change, + const RString &sBGChangeExpression ) +{ + return SMLoader::LoadFromBGChangesString(change, sBGChangeExpression); +} + +/** + * @file + * @author Aldo Fregoso, Jason Felds (c) 2009-2011 + * @section LICENSE + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/NotesLoaderSMA.h b/src/NotesLoaderSMA.h index 0fceb3977d..0ae30c5a48 100644 --- a/src/NotesLoaderSMA.h +++ b/src/NotesLoaderSMA.h @@ -1,63 +1,63 @@ -#ifndef NOTES_LOADER_SMA_H -#define NOTES_LOADER_SMA_H - -#include "GameConstantsAndTypes.h" -#include "BackgroundUtil.h" - -class MsdFile; -class Song; -class Steps; -class TimingData; - -/** @brief Reads a Song from a .SMA file. */ -namespace SMALoader -{ - void LoadFromSMATokens( RString sStepsType, - RString sDescription, - RString sDifficulty, - RString sMeter, - RString sRadarValues, - RString sNoteData, - Steps &out ); - - bool LoadFromDir( const RString &sPath, Song &out ); - void TidyUpData( Song &song, bool bFromCache ); - - bool LoadFromSMAFile( const RString &sPath, Song &out ); - void GetApplicableFiles( const RString &sPath, vector<RString> &out ); - bool LoadTimingFromFile( const RString &fn, TimingData &out ); - void LoadTimingFromSMAFile( const MsdFile &msd, TimingData &out ); - bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); - bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot ); - bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); - bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression ); -}; - -#endif - -/** - * @file - * @author Aldo Fregoso, Jason Felds (c) 2009-2011 - * @section LICENSE - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +#ifndef NOTES_LOADER_SMA_H +#define NOTES_LOADER_SMA_H + +#include "GameConstantsAndTypes.h" +#include "BackgroundUtil.h" + +class MsdFile; +class Song; +class Steps; +class TimingData; + +/** @brief Reads a Song from a .SMA file. */ +namespace SMALoader +{ + void LoadFromSMATokens( RString sStepsType, + RString sDescription, + RString sDifficulty, + RString sMeter, + RString sRadarValues, + RString sNoteData, + Steps &out ); + + bool LoadFromDir( const RString &sPath, Song &out ); + void TidyUpData( Song &song, bool bFromCache ); + + bool LoadFromSMAFile( const RString &sPath, Song &out ); + void GetApplicableFiles( const RString &sPath, vector<RString> &out ); + bool LoadTimingFromFile( const RString &fn, TimingData &out ); + void LoadTimingFromSMAFile( const MsdFile &msd, TimingData &out ); + bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); + bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot ); + bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); + bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression ); +}; + +#endif + +/** + * @file + * @author Aldo Fregoso, Jason Felds (c) 2009-2011 + * @section LICENSE + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/NotesLoaderSSC.cpp b/src/NotesLoaderSSC.cpp index 7c84d9809f..232753b9d4 100644 --- a/src/NotesLoaderSSC.cpp +++ b/src/NotesLoaderSSC.cpp @@ -1,1260 +1,1260 @@ -#include "global.h" -#include "NotesLoaderSSC.h" -#include "BackgroundUtil.h" -#include "GameManager.h" -#include "MsdFile.h" // No JSON here. -#include "NoteTypes.h" -#include "NotesLoaderSM.h" // For loading SM style edits. -#include "RageFileManager.h" -#include "RageLog.h" -#include "RageUtil.h" -#include "Song.h" -#include "SongManager.h" -#include "Steps.h" -#include "PrefsManager.h" - -/** - * @brief A custom .edit file can only be so big before we have to reject it. - */ -const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60 KB - -/** - * @brief Attempt to load any background changes in use by this song. - * - * This code is right now copied from NotesLoaderSM. There may be a time - * when we add to this code, or perhaps just refactor it properly. - * @param change a reference to the background change. - * @param sBGChangeExpression a reference to the list of changes to be made. - * @return its success or failure. - */ -bool LoadFromBGSSCChangesString( BackgroundChange &change, const RString &sBGChangeExpression ) -{ - vector<RString> aBGChangeValues; - split( sBGChangeExpression, "=", aBGChangeValues, false ); - - aBGChangeValues.resize( min((int)aBGChangeValues.size(),11) ); - - switch( aBGChangeValues.size() ) - { - case 11: - change.m_def.m_sColor2 = aBGChangeValues[10]; - change.m_def.m_sColor2.Replace( '^', ',' ); - change.m_def.m_sColor2 = RageColor::NormalizeColorString( change.m_def.m_sColor2 ); - // fall through - case 10: - change.m_def.m_sColor1 = aBGChangeValues[9]; - change.m_def.m_sColor1.Replace( '^', ',' ); - change.m_def.m_sColor1 = RageColor::NormalizeColorString( change.m_def.m_sColor1 ); - // fall through - case 9: - change.m_sTransition = aBGChangeValues[8]; - // fall through - case 8: - change.m_def.m_sFile2 = aBGChangeValues[7]; - // fall through - case 7: - change.m_def.m_sEffect = aBGChangeValues[6]; - // fall through - case 6: - // param 7 overrides this. - // Backward compatibility: - if( change.m_def.m_sEffect.empty() ) - { - bool bLoop = atoi( aBGChangeValues[5] ) != 0; - if( !bLoop ) - change.m_def.m_sEffect = SBE_StretchNoLoop; - } - // fall through - case 5: - // param 7 overrides this. - // Backward compatibility: - if( change.m_def.m_sEffect.empty() ) - { - bool bRewindMovie = atoi( aBGChangeValues[4] ) != 0; - if( bRewindMovie ) - change.m_def.m_sEffect = SBE_StretchRewind; - } - // fall through - case 4: - // param 9 overrides this. - // Backward compatibility: - if( change.m_sTransition.empty() ) - change.m_sTransition = (atoi( aBGChangeValues[3] ) != 0) ? "CrossFade" : ""; - // fall through - case 3: - change.m_fRate = StringToFloat( aBGChangeValues[2] ); - // fall through - case 2: - change.m_def.m_sFile1 = aBGChangeValues[1]; - // fall through - case 1: - change.m_fStartBeat = StringToFloat( aBGChangeValues[0] ); - // fall through - } - - return aBGChangeValues.size() >= 2; -} - -bool SSCLoader::LoadFromDir( const RString &sPath, Song &out ) -{ - vector<RString> aFileNames; - GetApplicableFiles( sPath, aFileNames ); - - if( aFileNames.size() > 1 ) - { - LOG->UserLog( "Song", sPath, "has more than one SSC file. Only one SSC file is allowed per song." ); - return false; - } - - ASSERT( aFileNames.size() == 1 ); // Ensure one was found entirely. - - return LoadFromSSCFile( sPath + aFileNames[0], out ); -} - -bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache ) -{ - LOG->Trace( "Song::LoadFromSSCFile(%s)", sPath.c_str() ); - - MsdFile msd; - if( !msd.ReadFile( sPath, true ) ) - { - LOG->UserLog( "Song file", sPath, "couldn't be opened: %s", msd.GetError().c_str() ); - return false; - } - - out.m_Timing.m_sFile = sPath; // songs still have their fallback timing. - - int state = GETTING_SONG_INFO; - const unsigned values = msd.GetNumValues(); - Steps* pNewNotes; - - for( unsigned i = 0; i < values; i++ ) - { - const MsdFile::value_t &sParams = msd.GetValue(i); - RString sValueName = sParams[0]; - sValueName.MakeUpper(); - - switch (state) - { - case GETTING_SONG_INFO: - { - if( sValueName=="VERSION" ) - { - out.m_fVersion = StringToFloat( sParams[1] ); - } - - else if( sValueName=="TITLE" ) - { - out.m_sMainTitle = sParams[1]; - } - - else if( sValueName=="SUBTITLE" ) - { - out.m_sSubTitle = sParams[1]; - } - - else if( sValueName=="ARTIST" ) - { - out.m_sArtist = sParams[1]; - } - - else if( sValueName=="TITLETRANSLIT" ) - { - out.m_sMainTitleTranslit = sParams[1]; - } - - else if( sValueName=="SUBTITLETRANSLIT" ) - { - out.m_sSubTitleTranslit = sParams[1]; - } - - else if( sValueName=="ARTISTTRANSLIT" ) - { - out.m_sArtistTranslit = sParams[1]; - } - - else if( sValueName=="GENRE" ) - { - out.m_sGenre = sParams[1]; - } - - else if( sValueName=="CREDIT" ) - { - out.m_sCredit = sParams[1]; - } - - else if( sValueName=="BANNER" ) - { - out.m_sBannerFile = sParams[1]; - } - - else if( sValueName=="BACKGROUND" ) - { - out.m_sBackgroundFile = sParams[1]; - } - - else if( sValueName=="LYRICSPATH" ) - { - out.m_sLyricsFile = sParams[1]; - } - - else if( sValueName=="CDTITLE" ) - { - out.m_sCDTitleFile = sParams[1]; - } - - else if( sValueName=="MUSIC" ) - { - out.m_sMusicFile = sParams[1]; - } - - else if( sValueName=="INSTRUMENTTRACK" ) - { - vector<RString> vs1; - split( sParams[1], ",", vs1 ); - FOREACH_CONST( RString, vs1, s ) - { - vector<RString> vs2; - split( *s, "=", vs2 ); - if( vs2.size() >= 2 ) - { - InstrumentTrack it = StringToInstrumentTrack( vs2[0] ); - if( it != InstrumentTrack_Invalid ) - out.m_sInstrumentTrackFile[it] = vs2[1]; - } - } - } - - else if( sValueName=="MUSICLENGTH" ) - { - if( !bFromCache ) - continue; - out.m_fMusicLengthSeconds = StringToFloat( sParams[1] ); - } - - else if( sValueName=="LASTBEATHINT" ) - { - out.m_fSpecifiedLastBeat = StringToFloat( sParams[1] ); - } - - else if( sValueName=="MUSICBYTES" ) - { - ; // ignore - } - - else if( sValueName=="SAMPLESTART" ) - { - out.m_fMusicSampleStartSeconds = HHMMSSToSeconds( sParams[1] ); - } - - else if( sValueName=="SAMPLELENGTH" ) - { - out.m_fMusicSampleLengthSeconds = HHMMSSToSeconds( sParams[1] ); - } - - else if( sValueName=="DISPLAYBPM" ) - { - // #DISPLAYBPM:[xxx][xxx:xxx]|[*]; - if( sParams[1] == "*" ) - out.m_DisplayBPMType = Song::DISPLAY_RANDOM; - else - { - out.m_DisplayBPMType = Song::DISPLAY_SPECIFIED; - out.m_fSpecifiedBPMMin = StringToFloat( sParams[1] ); - if( sParams[2].empty() ) - out.m_fSpecifiedBPMMax = out.m_fSpecifiedBPMMin; - else - out.m_fSpecifiedBPMMax = StringToFloat( sParams[2] ); - } - } - - else if( sValueName=="SELECTABLE" ) - { - if(!stricmp(sParams[1],"YES")) - out.m_SelectionDisplay = out.SHOW_ALWAYS; - else if(!stricmp(sParams[1],"NO")) - out.m_SelectionDisplay = out.SHOW_NEVER; - // ROULETTE from 3.9 is no longer in use. - else if(!stricmp(sParams[1],"ROULETTE")) - out.m_SelectionDisplay = out.SHOW_ALWAYS; - /* The following two cases are just fixes to make sure simfiles that - * used 3.9+ features are not excluded here */ - else if(!stricmp(sParams[1],"ES") || !stricmp(sParams[1],"OMES")) - out.m_SelectionDisplay = out.SHOW_ALWAYS; - else if( atoi(sParams[1]) > 0 ) - out.m_SelectionDisplay = out.SHOW_ALWAYS; - else - LOG->UserLog( "Song file", sPath, "has an unknown #SELECTABLE value, \"%s\"; ignored.", sParams[1].c_str() ); - } - - else if( sValueName.Left(strlen("BGCHANGES"))=="BGCHANGES" || sValueName=="ANIMATIONS" ) - { - BackgroundLayer iLayer = BACKGROUND_LAYER_1; - if( sscanf(sValueName, "BGCHANGES%d", &*ConvertValue<int>(&iLayer)) == 1 ) - enum_add(iLayer, -1); // #BGCHANGES2 = BACKGROUND_LAYER_2 - - bool bValid = iLayer>=0 && iLayer<NUM_BackgroundLayer; - if( !bValid ) - { - LOG->UserLog( "Song file", sPath, "has a #BGCHANGES tag \"%s\" that is out of range.", sValueName.c_str() ); - } - else - { - vector<RString> aBGChangeExpressions; - split( sParams[1], ",", aBGChangeExpressions ); - - for( unsigned b=0; b<aBGChangeExpressions.size(); b++ ) - { - BackgroundChange change; - if( LoadFromBGSSCChangesString( change, aBGChangeExpressions[b] ) ) - out.AddBackgroundChange( iLayer, change ); - } - } - } - - else if( sValueName=="FGCHANGES" ) - { - vector<RString> aFGChangeExpressions; - split( sParams[1], ",", aFGChangeExpressions ); - - for( unsigned b=0; b<aFGChangeExpressions.size(); b++ ) - { - BackgroundChange change; - if( LoadFromBGSSCChangesString( change, aFGChangeExpressions[b] ) ) - out.AddForegroundChange( change ); - } - } - - else if( sValueName=="KEYSOUNDS" ) - { - split( sParams[1], ",", out.m_vsKeysoundFile ); - } - - // Attacks loaded from file - else if( sValueName=="ATTACKS" ) - { - // Build the RString vector here so we can write it to file again later - for( unsigned s=1; s < sParams.params.size(); ++s ) - out.m_sAttackString.push_back( sParams[s] ); - - Attack attack; - float end = -9999; - - for( unsigned j=1; j < sParams.params.size(); ++j ) - { - vector<RString> sBits; - split( sParams[j], "=", sBits, false ); - - // Need an identifer and a value for this to work - if( sBits.size() < 2 ) - continue; - - TrimLeft( sBits[0] ); - TrimRight( sBits[0] ); - - if( !sBits[0].CompareNoCase("TIME") ) - attack.fStartSecond = strtof( sBits[1], NULL ); - else if( !sBits[0].CompareNoCase("LEN") ) - attack.fSecsRemaining = strtof( sBits[1], NULL ); - else if( !sBits[0].CompareNoCase("END") ) - end = strtof( sBits[1], NULL ); - else if( !sBits[0].CompareNoCase("MODS") ) - { - attack.sModifiers = sBits[1]; - - if( end != -9999 ) - { - attack.fSecsRemaining = end - attack.fStartSecond; - end = -9999; - } - - if( attack.fSecsRemaining < 0.0f ) - attack.fSecsRemaining = 0.0f; - - out.m_Attacks.push_back( attack ); - } - } - } - - else if( sValueName=="OFFSET" ) - { - out.m_Timing.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); - } - /* Below are the song based timings that should only be used - * if the steps do not have their own timing. */ - else if( sValueName=="STOPS" ) - { - vector<RString> arrayFreezeExpressions; - split( sParams[1], ",", arrayFreezeExpressions ); - - for( unsigned f=0; f<arrayFreezeExpressions.size(); f++ ) - { - vector<RString> arrayFreezeValues; - split( arrayFreezeExpressions[f], "=", arrayFreezeValues ); - if( arrayFreezeValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayFreezeExpressions[f].c_str() ); - continue; - } - - const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] ); - const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); - StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); - - if(fFreezeSeconds > 0.0f) - { - // LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); - out.m_Timing.AddStopSegment( new_seg ); - } - else - { - // negative stops (hi JS!) -aj - if( PREFSMAN->m_bQuirksMode ) - { - // LOG->Trace( "Adding a negative freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); - out.m_Timing.AddStopSegment( new_seg ); - } - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid stop at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); - } - } - } - else if( sValueName=="DELAYS" ) - { - vector<RString> arrayDelayExpressions; - split( sParams[1], ",", arrayDelayExpressions ); - - for( unsigned f=0; f<arrayDelayExpressions.size(); f++ ) - { - vector<RString> arrayDelayValues; - split( arrayDelayExpressions[f], "=", arrayDelayValues ); - if( arrayDelayValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayDelayExpressions[f].c_str() ); - continue; - } - - const float fFreezeBeat = StringToFloat( arrayDelayValues[0] ); - const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] ); - - StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds, true ); - - // LOG->Trace( "Adding a delay segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); - - if(fFreezeSeconds > 0.0f) - out.m_Timing.AddStopSegment( new_seg ); - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); - } - } - - else if( sValueName=="BPMS" ) - { - vector<RString> arrayBPMChangeExpressions; - split( sParams[1], ",", arrayBPMChangeExpressions ); - - for( unsigned b=0; b<arrayBPMChangeExpressions.size(); b++ ) - { - vector<RString> arrayBPMChangeValues; - split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues ); - // XXX: Hard to tell which file caused this. - if( arrayBPMChangeValues.size() != 2 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() ); - continue; - } - - const float fBeat = StringToFloat( arrayBPMChangeValues[0] ); - const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); - - if(fNewBPM > 0.0f) - out.m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); - else - { - out.m_Timing.m_bHasNegativeBpms = true; - // only add Negative BPMs in quirks mode -aj - if( PREFSMAN->m_bQuirksMode ) - out.m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid BPM change at beat %f, BPM %f.", fBeat, fNewBPM ); - } - } - } - - else if( sValueName=="TIMESIGNATURES" ) - { - vector<RString> vs1; - split( sParams[1], ",", vs1 ); - - FOREACH_CONST( RString, vs1, s1 ) - { - vector<RString> vs2; - split( *s1, "=", vs2 ); - - if( vs2.size() < 3 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with %i values.", (int)vs2.size() ); - continue; - } - - const float fBeat = StringToFloat( vs2[0] ); - - TimeSignatureSegment seg; - seg.m_iStartRow = BeatToNoteRow(fBeat); - seg.m_iNumerator = atoi( vs2[1] ); - seg.m_iDenominator = atoi( vs2[2] ); - - if( fBeat < 0 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f.", fBeat ); - continue; - } - - if( seg.m_iNumerator < 1 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iNumerator %i.", fBeat, seg.m_iNumerator ); - continue; - } - - if( seg.m_iDenominator < 1 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iDenominator %i.", fBeat, seg.m_iDenominator ); - continue; - } - - out.m_Timing.AddTimeSignatureSegment( seg ); - } - } - - else if( sValueName=="TICKCOUNTS" ) - { - vector<RString> arrayTickcountExpressions; - split( sParams[1], ",", arrayTickcountExpressions ); - - for( unsigned f=0; f<arrayTickcountExpressions.size(); f++ ) - { - vector<RString> arrayTickcountValues; - split( arrayTickcountExpressions[f], "=", arrayTickcountValues ); - if( arrayTickcountValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayTickcountExpressions[f].c_str() ); - continue; - } - - const float fTickcountBeat = StringToFloat( arrayTickcountValues[0] ); - const int iTicks = atoi( arrayTickcountValues[1] ); - TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks ); - - if(iTicks >= 1 && iTicks <= ROWS_PER_BEAT ) // Constants - { - // LOG->Trace( "Adding a tickcount segment: beat: %f, ticks = %d", fTickcountBeat, iTicks ); - out.m_Timing.AddTickcountSegment( new_seg ); - } - else - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid tickcount at beat %f, ticks %d.", fTickcountBeat, iTicks ); - } - } - } - - else if( sValueName=="COMBOS" ) - { - vector<RString> arrayComboExpressions; - split( sParams[1], ",", arrayComboExpressions ); - - for( unsigned f=0; f<arrayComboExpressions.size(); f++ ) - { - vector<RString> arrayComboValues; - split( arrayComboExpressions[f], "=", arrayComboValues ); - if( arrayComboValues.size() != 2 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayComboExpressions[f].c_str() ); - continue; - } - const float fComboBeat = StringToFloat( arrayComboValues[0] ); - const int iCombos = atoi( arrayComboValues[1] ); - ComboSegment new_seg( BeatToNoteRow( fComboBeat ), iCombos ); - out.m_Timing.AddComboSegment( new_seg ); - } - } - - /* The following are cache tags. Never fill their values - * directly: only from the cached version. */ - else if( sValueName=="FIRSTBEAT" ) - { - if( bFromCache ) - out.m_fFirstBeat = StringToFloat( sParams[1] ); - } - - else if( sValueName=="LASTBEAT" ) - { - if( bFromCache ) - out.m_fLastBeat = StringToFloat( sParams[1] ); - } - - else if( sValueName=="SONGFILENAME" ) - { - if( bFromCache ) - out.m_sSongFileName = sParams[1]; - } - - else if( sValueName=="HASMUSIC" ) - { - if( bFromCache ) - out.m_bHasMusic = atoi( sParams[1] ) != 0; - } - - else if( sValueName=="HASBANNER" ) - { - if( bFromCache ) - out.m_bHasBanner = atoi( sParams[1] ) != 0; - } - - // This tag will get us to the next section. - else if( sValueName=="NOTEDATA" ) - { - state = GETTING_STEP_INFO; - pNewNotes = new Steps; - } - break; - } - case GETTING_STEP_INFO: - { - if( sValueName=="STEPSTYPE" ) - { - pNewNotes->m_StepsType = GAMEMAN->StringToStepsType( sParams[1] ); - } - - else if( sValueName=="CHARTSTYLE" ) - { - pNewNotes->SetChartStyle( sParams[1] ); - } - - else if( sValueName=="DESCRIPTION" ) - { - pNewNotes->SetDescription( sParams[1] ); - } - - else if( sValueName=="DIFFICULTY" ) - { - pNewNotes->SetDifficulty( DwiCompatibleStringToDifficulty( sParams[1] ) ); - } - - else if( sValueName=="METER" ) - { - pNewNotes->SetMeter( atoi( sParams[1] ) ); - } - - else if( sValueName=="RADARVALUES" ) - { - vector<RString> saValues; - split( sParams[1], ",", saValues, true ); - - int categories = NUM_RadarCategory; - if( out.m_fVersion < VERSION_RADAR_FAKE ) - categories -= 1; - - if( saValues.size() == (unsigned)categories * NUM_PLAYERS ) - { - RadarValues v[NUM_PLAYERS]; - FOREACH_PlayerNumber( pn ) - { - // Can't use the foreach anymore due to flexible radar lines. - for( RadarCategory rc = (RadarCategory)0; rc < categories; - enum_add<RadarCategory>( rc, +1 ) ) - { - v[pn][rc] = StringToFloat( saValues[pn*categories + rc] ); - } - } - pNewNotes->SetCachedRadarValues( v ); - } - } - - else if( sValueName=="CREDIT" ) - { - pNewNotes->SetCredit( sParams[1] ); - } - - else if( sValueName=="NOTES" || sValueName=="NOTES2" ) - { - state = GETTING_SONG_INFO; - //pNewNotes->m_Timing = out.m_Timing; - pNewNotes->SetSMNoteData( sParams[1] ); - pNewNotes->TidyUpData(); - out.AddSteps( pNewNotes ); - } - - else if( sValueName=="BPMS" ) - { - /* - state = GETTING_STEP_TIMING_INFO; - vector<RString> arrayBPMChangeExpressions; - split( sParams[1], ",", arrayBPMChangeExpressions ); - - for( unsigned b=0; b<arrayBPMChangeExpressions.size(); b++ ) - { - vector<RString> arrayBPMChangeValues; - split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues ); - // XXX: Hard to tell which file caused this. - if( arrayBPMChangeValues.size() != 2 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() ); - continue; - } - - const float fBeat = StringToFloat( arrayBPMChangeValues[0] ); - const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); - - if(fNewBPM > 0.0f) - pNewNotes->m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); - else - { - pNewNotes->m_Timing.m_bHasNegativeBpms = true; - // only add Negative BPMs in quirks mode -aj - if( PREFSMAN->m_bQuirksMode ) - pNewNotes->m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid BPM change at beat %f, BPM %f.", fBeat, fNewBPM ); - } - } - */ - } - break; - } - case GETTING_STEP_TIMING_INFO: - { - if( sValueName=="STOPS" ) - { - /* - vector<RString> arrayFreezeExpressions; - split( sParams[1], ",", arrayFreezeExpressions ); - - for( unsigned f=0; f<arrayFreezeExpressions.size(); f++ ) - { - vector<RString> arrayFreezeValues; - split( arrayFreezeExpressions[f], "=", arrayFreezeValues ); - if( arrayFreezeValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayFreezeExpressions[f].c_str() ); - continue; - } - - const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] ); - const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); - StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); - - if(fFreezeSeconds > 0.0f) - { - // LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); - pNewNotes->m_Timing.AddStopSegment( new_seg ); - } - else - { - // negative stops (hi JS!) -aj - if( PREFSMAN->m_bQuirksMode ) - { - // LOG->Trace( "Adding a negative freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); - pNewNotes->m_Timing.AddStopSegment( new_seg ); - } - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid stop at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); - } - } - */ - } - else if( sValueName=="DELAYS" ) - { - /* - vector<RString> arrayDelayExpressions; - split( sParams[1], ",", arrayDelayExpressions ); - - for( unsigned f=0; f<arrayDelayExpressions.size(); f++ ) - { - vector<RString> arrayDelayValues; - split( arrayDelayExpressions[f], "=", arrayDelayValues ); - if( arrayDelayValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayDelayExpressions[f].c_str() ); - continue; - } - - const float fFreezeBeat = StringToFloat( arrayDelayValues[0] ); - const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] ); - - StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds, true ); - - // LOG->Trace( "Adding a delay segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); - - if(fFreezeSeconds > 0.0f) - pNewNotes->m_Timing.AddStopSegment( new_seg ); - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); - } - */ - } - else if( sValueName=="TIMESIGNATURES" ) - { - /* - vector<RString> vs1; - split( sParams[1], ",", vs1 ); - - FOREACH_CONST( RString, vs1, s1 ) - { - vector<RString> vs2; - split( *s1, "=", vs2 ); - - if( vs2.size() < 3 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with %i values.", (int)vs2.size() ); - continue; - } - - const float fBeat = StringToFloat( vs2[0] ); - - TimeSignatureSegment seg; - seg.m_iStartRow = BeatToNoteRow(fBeat); - seg.m_iNumerator = atoi( vs2[1] ); - seg.m_iDenominator = atoi( vs2[2] ); - - if( fBeat < 0 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f.", fBeat ); - continue; - } - - if( seg.m_iNumerator < 1 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iNumerator %i.", fBeat, seg.m_iNumerator ); - continue; - } - - if( seg.m_iDenominator < 1 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iDenominator %i.", fBeat, seg.m_iDenominator ); - continue; - } - - pNewNotes->m_Timing.AddTimeSignatureSegment( seg ); - } - */ - } - - else if( sValueName=="TICKCOUNTS" ) - { - /* - vector<RString> arrayTickcountExpressions; - split( sParams[1], ",", arrayTickcountExpressions ); - - for( unsigned f=0; f<arrayTickcountExpressions.size(); f++ ) - { - vector<RString> arrayTickcountValues; - split( arrayTickcountExpressions[f], "=", arrayTickcountValues ); - if( arrayTickcountValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayTickcountExpressions[f].c_str() ); - continue; - } - - const float fTickcountBeat = StringToFloat( arrayTickcountValues[0] ); - const int iTicks = atoi( arrayTickcountValues[1] ); - TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks ); - - if(iTicks >= 1 && iTicks <= ROWS_PER_BEAT ) // Constants - { - // LOG->Trace( "Adding a tickcount segment: beat: %f, ticks = %d", fTickcountBeat, iTicks ); - pNewNotes->m_Timing.AddTickcountSegment( new_seg ); - } - else - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid tickcount at beat %f, ticks %d.", fTickcountBeat, iTicks ); - } - } - */ - } - else if( sValueName=="COMBOS" ) - { - /* - vector<RString> arrayComboExpressions; - split( sParams[1], ",", arrayComboExpressions ); - - for( unsigned f=0; f<arrayComboExpressions.size(); f++ ) - { - vector<RString> arrayComboValues; - split( arrayComboExpressions[f], "=", arrayComboValues ); - if( arrayComboValues.size() != 2 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayComboExpressions[f].c_str() ); - continue; - } - const float fComboBeat = StringToFloat( arrayComboValues[0] ); - const int iCombos = atoi( arrayComboValues[1] ); - ComboSegment new_seg( BeatToNoteRow( fComboBeat ), iCombos ); - pNewNotes->m_Timing.AddComboSegment( new_seg ); - } - */ - } - else if( sValueName=="ATTACKS" ) - { - // TODO: Look into Step attacks vs Song Attacks. -Wolfman2000 - /* - // Build the RString vector here so we can write it to file again later - for( unsigned s=1; s < sParams.params.size(); ++s ) - out.m_sAttackString.push_back( sParams[s] ); - - Attack attack; - float end = -9999; - - for( unsigned j=1; j < sParams.params.size(); ++j ) - { - vector<RString> sBits; - split( sParams[j], "=", sBits, false ); - - // Need an identifer and a value for this to work - if( sBits.size() < 2 ) - continue; - - TrimLeft( sBits[0] ); - TrimRight( sBits[0] ); - - if( !sBits[0].CompareNoCase("TIME") ) - attack.fStartSecond = strtof( sBits[1], NULL ); - else if( !sBits[0].CompareNoCase("LEN") ) - attack.fSecsRemaining = strtof( sBits[1], NULL ); - else if( !sBits[0].CompareNoCase("END") ) - end = strtof( sBits[1], NULL ); - else if( !sBits[0].CompareNoCase("MODS") ) - { - attack.sModifiers = sBits[1]; - - if( end != -9999 ) - { - attack.fSecsRemaining = end - attack.fStartSecond; - end = -9999; - } - - if( attack.fSecsRemaining < 0.0f ) - attack.fSecsRemaining = 0.0f; - - out.m_Attacks.push_back( attack ); - } - } - */ - } - else if( sValueName=="OFFSET" ) - {/* - pNewNotes->m_Timing.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); - */ - } - - else if( sValueName=="NOTES" ) - { - state = GETTING_SONG_INFO; - // pNewNotes->m_Timing.m_fBeat0OffsetInSeconds = out.m_Timing.m_fBeat0OffsetInSeconds; - pNewNotes->SetSMNoteData( sParams[1] ); - pNewNotes->TidyUpData(); - out.AddSteps( pNewNotes ); - } - break; - } - } - } - out.m_fVersion = STEPFILE_VERSION_NUMBER; - return true; -} - -void SSCLoader::GetApplicableFiles( const RString &sPath, vector<RString> &out ) -{ - GetDirListing( sPath + RString("*.ssc"), out ); -} - -bool SSCLoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ) -{ - LOG->Trace( "SSCLoader::LoadEditFromFile(%s)", sEditFilePath.c_str() ); - - int iBytes = FILEMAN->GetFileSizeInBytes( sEditFilePath ); - if( iBytes > MAX_EDIT_STEPS_SIZE_BYTES ) - { - LOG->UserLog( "Edit file", sEditFilePath, "is unreasonably large. It won't be loaded." ); - return false; - } - - MsdFile msd; - if( !msd.ReadFile( sEditFilePath, true ) ) // unescape - { - LOG->UserLog( "Edit file", sEditFilePath, "couldn't be opened: %s", msd.GetError().c_str() ); - return false; - } - - return LoadEditFromMsd( msd, sEditFilePath, slot, bAddStepsToSong ); -} - -bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ) -{ - Song* pSong = NULL; - Steps* pNewNotes; - bool bSSCFormat = false; - - for( unsigned i=0; i<msd.GetNumValues(); i++ ) - { - int iNumParams = msd.GetNumParams(i); - const MsdFile::value_t &sParams = msd.GetValue(i); - RString sValueName = sParams[0]; - sValueName.MakeUpper(); - - // handle the data - if( sValueName=="SONG" ) - { - if( pSong ) - { - LOG->UserLog( "Edit file", sEditFilePath, "has more than one #SONG tag." ); - return false; - } - - RString sSongFullTitle = sParams[1]; - sSongFullTitle.Replace( '\\', '/' ); - - pSong = SONGMAN->FindSong( sSongFullTitle ); - if( pSong == NULL ) - { - LOG->UserLog( "Edit file", sEditFilePath, "requires a song \"%s\" that isn't present.", sSongFullTitle.c_str() ); - return false; - } - - if( pSong->GetNumStepsLoadedFromProfile(slot) >= MAX_EDITS_PER_SONG_PER_PROFILE ) - { - LOG->UserLog( "Song file", sSongFullTitle, "already has the maximum number of edits allowed for ProfileSlotP%d.", slot+1 ); - return false; - } - } - - else if( sValueName=="NOTEDATA" ) - { - pNewNotes = new Steps; - bSSCFormat = true; - } - if( sValueName=="STEPSTYPE" ) - { - pNewNotes->m_StepsType = GAMEMAN->StringToStepsType( sParams[1] ); - bSSCFormat = true; - } - - else if( sValueName=="CHARTSTYLE" ) - { - pNewNotes->SetChartStyle( sParams[1] ); - bSSCFormat = true; - } - - else if( sValueName=="DESCRIPTION" ) - { - pNewNotes->SetDescription( sParams[1] ); - bSSCFormat = true; - } - - else if( sValueName=="DIFFICULTY" ) - { - pNewNotes->SetDifficulty( DwiCompatibleStringToDifficulty( sParams[1] ) ); - bSSCFormat = true; - } - - else if( sValueName=="METER" ) - { - pNewNotes->SetMeter( atoi( sParams[1] ) ); - bSSCFormat = true; - } - - else if( sValueName=="RADARVALUES" ) - { - vector<RString> saValues; - split( sParams[1], ",", saValues, true ); - if( saValues.size() == NUM_RadarCategory * NUM_PLAYERS ) - { - RadarValues v[NUM_PLAYERS]; - FOREACH_PlayerNumber( pn ) - FOREACH_ENUM( RadarCategory, rc ) - v[pn][rc] = StringToFloat( saValues[pn*NUM_RadarCategory + rc] ); - pNewNotes->SetCachedRadarValues( v ); - } - bSSCFormat = true; - } - - else if( sValueName=="CREDIT" ) - { - pNewNotes->SetCredit( sParams[1] ); - bSSCFormat = true; - } - - // TimingData for Steps isn't set yet, but still prepare for it. - else if( sValueName=="BPMS" ) - { - bSSCFormat = true; - } - else if( sValueName=="STOPS" ) - { - bSSCFormat = true; - } - else if( sValueName=="DELAYS" ) - { - bSSCFormat = true; - } - else if( sValueName=="TIMESIGNATURES" ) - { - bSSCFormat = true; - } - else if( sValueName=="TICKCOUNTS" ) - { - bSSCFormat = true; - } - else if( sValueName=="COMBOS" ) - { - bSSCFormat = true; - } - - else if( sValueName=="NOTES" ) - { - if( pSong == NULL ) - { - LOG->UserLog( "Edit file", sEditFilePath, "doesn't have a #SONG tag preceeding the first #NOTES tag." ); - return false; - } - - if ( !bSSCFormat && iNumParams < 7 ) - { - LOG->UserLog( "Edit file", sEditFilePath, "has %d fields in a #NOTES tag, but should have at least 7.", iNumParams ); - continue; - } - - if( !bAddStepsToSong ) - return true; - - if( bSSCFormat ) - { - pNewNotes->SetSMNoteData( sParams[1] ); - pNewNotes->TidyUpData(); - pSong->AddSteps( pNewNotes ); - } - else - { - pNewNotes = new Steps; - SMLoader::LoadFromSMTokens( - sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6], - *pNewNotes); - } - - pNewNotes->SetLoadedFromProfile( slot ); - pNewNotes->SetDifficulty( Difficulty_Edit ); - pNewNotes->SetFilename( sEditFilePath ); - - if( pSong->IsEditAlreadyLoaded(pNewNotes) ) - { - LOG->UserLog( "Edit file", sEditFilePath, "is a duplicate of another edit that was already loaded." ); - SAFE_DELETE( pNewNotes ); - return false; - } - - pSong->AddSteps( pNewNotes ); - return true; // Only allow one Steps per edit file! - } - else - { - LOG->UserLog( "Edit file", sEditFilePath, "has an unexpected value \"%s\".", sValueName.c_str() ); - } - } - - //return true; - // only load a SSC edit if it passes the checks. -aj - return bSSCFormat; -} - -void SSCLoader::TidyUpData( Song &song, bool bFromCache ) -{ - /* - * Hack: if the song has any changes at all (so it won't use a random BGA) - * and doesn't end with "-nosongbg-", add a song background BGC. Remove - * "-nosongbg-" if it exists. - * - * This way, songs that were created earlier, when we added the song BG - * at the end by default, will still behave as expected; all new songs will - * have to add an explicit song BG tag if they want it. This is really a - * formatting hack only; nothing outside of SMLoader ever sees "-nosongbg-". - */ - vector<BackgroundChange> &bg = song.GetBackgroundChanges(BACKGROUND_LAYER_1); - if( !bg.empty() ) - { - /* BGChanges have been sorted. On the odd chance that a BGChange exists - * with a very high beat, search the whole list. */ - bool bHasNoSongBgTag = false; - - for( unsigned i = 0; !bHasNoSongBgTag && i < bg.size(); ++i ) - { - if( !bg[i].m_def.m_sFile1.CompareNoCase(NO_SONG_BG_FILE) ) - { - bg.erase( bg.begin()+i ); - bHasNoSongBgTag = true; - } - } - - // If there's no -nosongbg- tag, add the song BG. - if( !bHasNoSongBgTag ) do - { - /* If we're loading cache, -nosongbg- should always be in there. We - * must not call IsAFile(song.GetBackgroundPath()) when loading cache. */ - if( bFromCache ) - break; - - /* If BGChanges already exist after the last beat, don't add the - * background in the middle. */ - if( !bg.empty() && bg.back().m_fStartBeat-0.0001f >= song.m_fLastBeat ) - break; - - // If the last BGA is already the song BGA, don't add a duplicate. - if( !bg.empty() && !bg.back().m_def.m_sFile1.CompareNoCase(song.m_sBackgroundFile) ) - break; - - if( !IsAFile( song.GetBackgroundPath() ) ) - break; - - bg.push_back( BackgroundChange(song.m_fLastBeat,song.m_sBackgroundFile) ); - } while(0); - } -} - -/* - * (c) 2011 Jason Felds - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +#include "global.h" +#include "NotesLoaderSSC.h" +#include "BackgroundUtil.h" +#include "GameManager.h" +#include "MsdFile.h" // No JSON here. +#include "NoteTypes.h" +#include "NotesLoaderSM.h" // For loading SM style edits. +#include "RageFileManager.h" +#include "RageLog.h" +#include "RageUtil.h" +#include "Song.h" +#include "SongManager.h" +#include "Steps.h" +#include "PrefsManager.h" + +/** + * @brief A custom .edit file can only be so big before we have to reject it. + */ +const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60 KB + +/** + * @brief Attempt to load any background changes in use by this song. + * + * This code is right now copied from NotesLoaderSM. There may be a time + * when we add to this code, or perhaps just refactor it properly. + * @param change a reference to the background change. + * @param sBGChangeExpression a reference to the list of changes to be made. + * @return its success or failure. + */ +bool LoadFromBGSSCChangesString( BackgroundChange &change, const RString &sBGChangeExpression ) +{ + vector<RString> aBGChangeValues; + split( sBGChangeExpression, "=", aBGChangeValues, false ); + + aBGChangeValues.resize( min((int)aBGChangeValues.size(),11) ); + + switch( aBGChangeValues.size() ) + { + case 11: + change.m_def.m_sColor2 = aBGChangeValues[10]; + change.m_def.m_sColor2.Replace( '^', ',' ); + change.m_def.m_sColor2 = RageColor::NormalizeColorString( change.m_def.m_sColor2 ); + // fall through + case 10: + change.m_def.m_sColor1 = aBGChangeValues[9]; + change.m_def.m_sColor1.Replace( '^', ',' ); + change.m_def.m_sColor1 = RageColor::NormalizeColorString( change.m_def.m_sColor1 ); + // fall through + case 9: + change.m_sTransition = aBGChangeValues[8]; + // fall through + case 8: + change.m_def.m_sFile2 = aBGChangeValues[7]; + // fall through + case 7: + change.m_def.m_sEffect = aBGChangeValues[6]; + // fall through + case 6: + // param 7 overrides this. + // Backward compatibility: + if( change.m_def.m_sEffect.empty() ) + { + bool bLoop = atoi( aBGChangeValues[5] ) != 0; + if( !bLoop ) + change.m_def.m_sEffect = SBE_StretchNoLoop; + } + // fall through + case 5: + // param 7 overrides this. + // Backward compatibility: + if( change.m_def.m_sEffect.empty() ) + { + bool bRewindMovie = atoi( aBGChangeValues[4] ) != 0; + if( bRewindMovie ) + change.m_def.m_sEffect = SBE_StretchRewind; + } + // fall through + case 4: + // param 9 overrides this. + // Backward compatibility: + if( change.m_sTransition.empty() ) + change.m_sTransition = (atoi( aBGChangeValues[3] ) != 0) ? "CrossFade" : ""; + // fall through + case 3: + change.m_fRate = StringToFloat( aBGChangeValues[2] ); + // fall through + case 2: + change.m_def.m_sFile1 = aBGChangeValues[1]; + // fall through + case 1: + change.m_fStartBeat = StringToFloat( aBGChangeValues[0] ); + // fall through + } + + return aBGChangeValues.size() >= 2; +} + +bool SSCLoader::LoadFromDir( const RString &sPath, Song &out ) +{ + vector<RString> aFileNames; + GetApplicableFiles( sPath, aFileNames ); + + if( aFileNames.size() > 1 ) + { + LOG->UserLog( "Song", sPath, "has more than one SSC file. Only one SSC file is allowed per song." ); + return false; + } + + ASSERT( aFileNames.size() == 1 ); // Ensure one was found entirely. + + return LoadFromSSCFile( sPath + aFileNames[0], out ); +} + +bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache ) +{ + LOG->Trace( "Song::LoadFromSSCFile(%s)", sPath.c_str() ); + + MsdFile msd; + if( !msd.ReadFile( sPath, true ) ) + { + LOG->UserLog( "Song file", sPath, "couldn't be opened: %s", msd.GetError().c_str() ); + return false; + } + + out.m_Timing.m_sFile = sPath; // songs still have their fallback timing. + + int state = GETTING_SONG_INFO; + const unsigned values = msd.GetNumValues(); + Steps* pNewNotes; + + for( unsigned i = 0; i < values; i++ ) + { + const MsdFile::value_t &sParams = msd.GetValue(i); + RString sValueName = sParams[0]; + sValueName.MakeUpper(); + + switch (state) + { + case GETTING_SONG_INFO: + { + if( sValueName=="VERSION" ) + { + out.m_fVersion = StringToFloat( sParams[1] ); + } + + else if( sValueName=="TITLE" ) + { + out.m_sMainTitle = sParams[1]; + } + + else if( sValueName=="SUBTITLE" ) + { + out.m_sSubTitle = sParams[1]; + } + + else if( sValueName=="ARTIST" ) + { + out.m_sArtist = sParams[1]; + } + + else if( sValueName=="TITLETRANSLIT" ) + { + out.m_sMainTitleTranslit = sParams[1]; + } + + else if( sValueName=="SUBTITLETRANSLIT" ) + { + out.m_sSubTitleTranslit = sParams[1]; + } + + else if( sValueName=="ARTISTTRANSLIT" ) + { + out.m_sArtistTranslit = sParams[1]; + } + + else if( sValueName=="GENRE" ) + { + out.m_sGenre = sParams[1]; + } + + else if( sValueName=="CREDIT" ) + { + out.m_sCredit = sParams[1]; + } + + else if( sValueName=="BANNER" ) + { + out.m_sBannerFile = sParams[1]; + } + + else if( sValueName=="BACKGROUND" ) + { + out.m_sBackgroundFile = sParams[1]; + } + + else if( sValueName=="LYRICSPATH" ) + { + out.m_sLyricsFile = sParams[1]; + } + + else if( sValueName=="CDTITLE" ) + { + out.m_sCDTitleFile = sParams[1]; + } + + else if( sValueName=="MUSIC" ) + { + out.m_sMusicFile = sParams[1]; + } + + else if( sValueName=="INSTRUMENTTRACK" ) + { + vector<RString> vs1; + split( sParams[1], ",", vs1 ); + FOREACH_CONST( RString, vs1, s ) + { + vector<RString> vs2; + split( *s, "=", vs2 ); + if( vs2.size() >= 2 ) + { + InstrumentTrack it = StringToInstrumentTrack( vs2[0] ); + if( it != InstrumentTrack_Invalid ) + out.m_sInstrumentTrackFile[it] = vs2[1]; + } + } + } + + else if( sValueName=="MUSICLENGTH" ) + { + if( !bFromCache ) + continue; + out.m_fMusicLengthSeconds = StringToFloat( sParams[1] ); + } + + else if( sValueName=="LASTBEATHINT" ) + { + out.m_fSpecifiedLastBeat = StringToFloat( sParams[1] ); + } + + else if( sValueName=="MUSICBYTES" ) + { + ; // ignore + } + + else if( sValueName=="SAMPLESTART" ) + { + out.m_fMusicSampleStartSeconds = HHMMSSToSeconds( sParams[1] ); + } + + else if( sValueName=="SAMPLELENGTH" ) + { + out.m_fMusicSampleLengthSeconds = HHMMSSToSeconds( sParams[1] ); + } + + else if( sValueName=="DISPLAYBPM" ) + { + // #DISPLAYBPM:[xxx][xxx:xxx]|[*]; + if( sParams[1] == "*" ) + out.m_DisplayBPMType = Song::DISPLAY_RANDOM; + else + { + out.m_DisplayBPMType = Song::DISPLAY_SPECIFIED; + out.m_fSpecifiedBPMMin = StringToFloat( sParams[1] ); + if( sParams[2].empty() ) + out.m_fSpecifiedBPMMax = out.m_fSpecifiedBPMMin; + else + out.m_fSpecifiedBPMMax = StringToFloat( sParams[2] ); + } + } + + else if( sValueName=="SELECTABLE" ) + { + if(!stricmp(sParams[1],"YES")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + else if(!stricmp(sParams[1],"NO")) + out.m_SelectionDisplay = out.SHOW_NEVER; + // ROULETTE from 3.9 is no longer in use. + else if(!stricmp(sParams[1],"ROULETTE")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + /* The following two cases are just fixes to make sure simfiles that + * used 3.9+ features are not excluded here */ + else if(!stricmp(sParams[1],"ES") || !stricmp(sParams[1],"OMES")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + else if( atoi(sParams[1]) > 0 ) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + else + LOG->UserLog( "Song file", sPath, "has an unknown #SELECTABLE value, \"%s\"; ignored.", sParams[1].c_str() ); + } + + else if( sValueName.Left(strlen("BGCHANGES"))=="BGCHANGES" || sValueName=="ANIMATIONS" ) + { + BackgroundLayer iLayer = BACKGROUND_LAYER_1; + if( sscanf(sValueName, "BGCHANGES%d", &*ConvertValue<int>(&iLayer)) == 1 ) + enum_add(iLayer, -1); // #BGCHANGES2 = BACKGROUND_LAYER_2 + + bool bValid = iLayer>=0 && iLayer<NUM_BackgroundLayer; + if( !bValid ) + { + LOG->UserLog( "Song file", sPath, "has a #BGCHANGES tag \"%s\" that is out of range.", sValueName.c_str() ); + } + else + { + vector<RString> aBGChangeExpressions; + split( sParams[1], ",", aBGChangeExpressions ); + + for( unsigned b=0; b<aBGChangeExpressions.size(); b++ ) + { + BackgroundChange change; + if( LoadFromBGSSCChangesString( change, aBGChangeExpressions[b] ) ) + out.AddBackgroundChange( iLayer, change ); + } + } + } + + else if( sValueName=="FGCHANGES" ) + { + vector<RString> aFGChangeExpressions; + split( sParams[1], ",", aFGChangeExpressions ); + + for( unsigned b=0; b<aFGChangeExpressions.size(); b++ ) + { + BackgroundChange change; + if( LoadFromBGSSCChangesString( change, aFGChangeExpressions[b] ) ) + out.AddForegroundChange( change ); + } + } + + else if( sValueName=="KEYSOUNDS" ) + { + split( sParams[1], ",", out.m_vsKeysoundFile ); + } + + // Attacks loaded from file + else if( sValueName=="ATTACKS" ) + { + // Build the RString vector here so we can write it to file again later + for( unsigned s=1; s < sParams.params.size(); ++s ) + out.m_sAttackString.push_back( sParams[s] ); + + Attack attack; + float end = -9999; + + for( unsigned j=1; j < sParams.params.size(); ++j ) + { + vector<RString> sBits; + split( sParams[j], "=", sBits, false ); + + // Need an identifer and a value for this to work + if( sBits.size() < 2 ) + continue; + + TrimLeft( sBits[0] ); + TrimRight( sBits[0] ); + + if( !sBits[0].CompareNoCase("TIME") ) + attack.fStartSecond = strtof( sBits[1], NULL ); + else if( !sBits[0].CompareNoCase("LEN") ) + attack.fSecsRemaining = strtof( sBits[1], NULL ); + else if( !sBits[0].CompareNoCase("END") ) + end = strtof( sBits[1], NULL ); + else if( !sBits[0].CompareNoCase("MODS") ) + { + attack.sModifiers = sBits[1]; + + if( end != -9999 ) + { + attack.fSecsRemaining = end - attack.fStartSecond; + end = -9999; + } + + if( attack.fSecsRemaining < 0.0f ) + attack.fSecsRemaining = 0.0f; + + out.m_Attacks.push_back( attack ); + } + } + } + + else if( sValueName=="OFFSET" ) + { + out.m_Timing.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); + } + /* Below are the song based timings that should only be used + * if the steps do not have their own timing. */ + else if( sValueName=="STOPS" ) + { + vector<RString> arrayFreezeExpressions; + split( sParams[1], ",", arrayFreezeExpressions ); + + for( unsigned f=0; f<arrayFreezeExpressions.size(); f++ ) + { + vector<RString> arrayFreezeValues; + split( arrayFreezeExpressions[f], "=", arrayFreezeValues ); + if( arrayFreezeValues.size() != 2 ) + { + // XXX: Hard to tell which file caused this. + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayFreezeExpressions[f].c_str() ); + continue; + } + + const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] ); + const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); + StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); + + if(fFreezeSeconds > 0.0f) + { + // LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + out.m_Timing.AddStopSegment( new_seg ); + } + else + { + // negative stops (hi JS!) -aj + if( PREFSMAN->m_bQuirksMode ) + { + // LOG->Trace( "Adding a negative freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + out.m_Timing.AddStopSegment( new_seg ); + } + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid stop at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); + } + } + } + else if( sValueName=="DELAYS" ) + { + vector<RString> arrayDelayExpressions; + split( sParams[1], ",", arrayDelayExpressions ); + + for( unsigned f=0; f<arrayDelayExpressions.size(); f++ ) + { + vector<RString> arrayDelayValues; + split( arrayDelayExpressions[f], "=", arrayDelayValues ); + if( arrayDelayValues.size() != 2 ) + { + // XXX: Hard to tell which file caused this. + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayDelayExpressions[f].c_str() ); + continue; + } + + const float fFreezeBeat = StringToFloat( arrayDelayValues[0] ); + const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] ); + + StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds, true ); + + // LOG->Trace( "Adding a delay segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + + if(fFreezeSeconds > 0.0f) + out.m_Timing.AddStopSegment( new_seg ); + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); + } + } + + else if( sValueName=="BPMS" ) + { + vector<RString> arrayBPMChangeExpressions; + split( sParams[1], ",", arrayBPMChangeExpressions ); + + for( unsigned b=0; b<arrayBPMChangeExpressions.size(); b++ ) + { + vector<RString> arrayBPMChangeValues; + split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues ); + // XXX: Hard to tell which file caused this. + if( arrayBPMChangeValues.size() != 2 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() ); + continue; + } + + const float fBeat = StringToFloat( arrayBPMChangeValues[0] ); + const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); + + if(fNewBPM > 0.0f) + out.m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); + else + { + out.m_Timing.m_bHasNegativeBpms = true; + // only add Negative BPMs in quirks mode -aj + if( PREFSMAN->m_bQuirksMode ) + out.m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid BPM change at beat %f, BPM %f.", fBeat, fNewBPM ); + } + } + } + + else if( sValueName=="TIMESIGNATURES" ) + { + vector<RString> vs1; + split( sParams[1], ",", vs1 ); + + FOREACH_CONST( RString, vs1, s1 ) + { + vector<RString> vs2; + split( *s1, "=", vs2 ); + + if( vs2.size() < 3 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with %i values.", (int)vs2.size() ); + continue; + } + + const float fBeat = StringToFloat( vs2[0] ); + + TimeSignatureSegment seg; + seg.m_iStartRow = BeatToNoteRow(fBeat); + seg.m_iNumerator = atoi( vs2[1] ); + seg.m_iDenominator = atoi( vs2[2] ); + + if( fBeat < 0 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f.", fBeat ); + continue; + } + + if( seg.m_iNumerator < 1 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iNumerator %i.", fBeat, seg.m_iNumerator ); + continue; + } + + if( seg.m_iDenominator < 1 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iDenominator %i.", fBeat, seg.m_iDenominator ); + continue; + } + + out.m_Timing.AddTimeSignatureSegment( seg ); + } + } + + else if( sValueName=="TICKCOUNTS" ) + { + vector<RString> arrayTickcountExpressions; + split( sParams[1], ",", arrayTickcountExpressions ); + + for( unsigned f=0; f<arrayTickcountExpressions.size(); f++ ) + { + vector<RString> arrayTickcountValues; + split( arrayTickcountExpressions[f], "=", arrayTickcountValues ); + if( arrayTickcountValues.size() != 2 ) + { + // XXX: Hard to tell which file caused this. + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayTickcountExpressions[f].c_str() ); + continue; + } + + const float fTickcountBeat = StringToFloat( arrayTickcountValues[0] ); + const int iTicks = atoi( arrayTickcountValues[1] ); + TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks ); + + if(iTicks >= 1 && iTicks <= ROWS_PER_BEAT ) // Constants + { + // LOG->Trace( "Adding a tickcount segment: beat: %f, ticks = %d", fTickcountBeat, iTicks ); + out.m_Timing.AddTickcountSegment( new_seg ); + } + else + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid tickcount at beat %f, ticks %d.", fTickcountBeat, iTicks ); + } + } + } + + else if( sValueName=="COMBOS" ) + { + vector<RString> arrayComboExpressions; + split( sParams[1], ",", arrayComboExpressions ); + + for( unsigned f=0; f<arrayComboExpressions.size(); f++ ) + { + vector<RString> arrayComboValues; + split( arrayComboExpressions[f], "=", arrayComboValues ); + if( arrayComboValues.size() != 2 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayComboExpressions[f].c_str() ); + continue; + } + const float fComboBeat = StringToFloat( arrayComboValues[0] ); + const int iCombos = atoi( arrayComboValues[1] ); + ComboSegment new_seg( BeatToNoteRow( fComboBeat ), iCombos ); + out.m_Timing.AddComboSegment( new_seg ); + } + } + + /* The following are cache tags. Never fill their values + * directly: only from the cached version. */ + else if( sValueName=="FIRSTBEAT" ) + { + if( bFromCache ) + out.m_fFirstBeat = StringToFloat( sParams[1] ); + } + + else if( sValueName=="LASTBEAT" ) + { + if( bFromCache ) + out.m_fLastBeat = StringToFloat( sParams[1] ); + } + + else if( sValueName=="SONGFILENAME" ) + { + if( bFromCache ) + out.m_sSongFileName = sParams[1]; + } + + else if( sValueName=="HASMUSIC" ) + { + if( bFromCache ) + out.m_bHasMusic = atoi( sParams[1] ) != 0; + } + + else if( sValueName=="HASBANNER" ) + { + if( bFromCache ) + out.m_bHasBanner = atoi( sParams[1] ) != 0; + } + + // This tag will get us to the next section. + else if( sValueName=="NOTEDATA" ) + { + state = GETTING_STEP_INFO; + pNewNotes = new Steps; + } + break; + } + case GETTING_STEP_INFO: + { + if( sValueName=="STEPSTYPE" ) + { + pNewNotes->m_StepsType = GAMEMAN->StringToStepsType( sParams[1] ); + } + + else if( sValueName=="CHARTSTYLE" ) + { + pNewNotes->SetChartStyle( sParams[1] ); + } + + else if( sValueName=="DESCRIPTION" ) + { + pNewNotes->SetDescription( sParams[1] ); + } + + else if( sValueName=="DIFFICULTY" ) + { + pNewNotes->SetDifficulty( DwiCompatibleStringToDifficulty( sParams[1] ) ); + } + + else if( sValueName=="METER" ) + { + pNewNotes->SetMeter( atoi( sParams[1] ) ); + } + + else if( sValueName=="RADARVALUES" ) + { + vector<RString> saValues; + split( sParams[1], ",", saValues, true ); + + int categories = NUM_RadarCategory; + if( out.m_fVersion < VERSION_RADAR_FAKE ) + categories -= 1; + + if( saValues.size() == (unsigned)categories * NUM_PLAYERS ) + { + RadarValues v[NUM_PLAYERS]; + FOREACH_PlayerNumber( pn ) + { + // Can't use the foreach anymore due to flexible radar lines. + for( RadarCategory rc = (RadarCategory)0; rc < categories; + enum_add<RadarCategory>( rc, +1 ) ) + { + v[pn][rc] = StringToFloat( saValues[pn*categories + rc] ); + } + } + pNewNotes->SetCachedRadarValues( v ); + } + } + + else if( sValueName=="CREDIT" ) + { + pNewNotes->SetCredit( sParams[1] ); + } + + else if( sValueName=="NOTES" || sValueName=="NOTES2" ) + { + state = GETTING_SONG_INFO; + //pNewNotes->m_Timing = out.m_Timing; + pNewNotes->SetSMNoteData( sParams[1] ); + pNewNotes->TidyUpData(); + out.AddSteps( pNewNotes ); + } + + else if( sValueName=="BPMS" ) + { + /* + state = GETTING_STEP_TIMING_INFO; + vector<RString> arrayBPMChangeExpressions; + split( sParams[1], ",", arrayBPMChangeExpressions ); + + for( unsigned b=0; b<arrayBPMChangeExpressions.size(); b++ ) + { + vector<RString> arrayBPMChangeValues; + split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues ); + // XXX: Hard to tell which file caused this. + if( arrayBPMChangeValues.size() != 2 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() ); + continue; + } + + const float fBeat = StringToFloat( arrayBPMChangeValues[0] ); + const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); + + if(fNewBPM > 0.0f) + pNewNotes->m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); + else + { + pNewNotes->m_Timing.m_bHasNegativeBpms = true; + // only add Negative BPMs in quirks mode -aj + if( PREFSMAN->m_bQuirksMode ) + pNewNotes->m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid BPM change at beat %f, BPM %f.", fBeat, fNewBPM ); + } + } + */ + } + break; + } + case GETTING_STEP_TIMING_INFO: + { + if( sValueName=="STOPS" ) + { + /* + vector<RString> arrayFreezeExpressions; + split( sParams[1], ",", arrayFreezeExpressions ); + + for( unsigned f=0; f<arrayFreezeExpressions.size(); f++ ) + { + vector<RString> arrayFreezeValues; + split( arrayFreezeExpressions[f], "=", arrayFreezeValues ); + if( arrayFreezeValues.size() != 2 ) + { + // XXX: Hard to tell which file caused this. + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayFreezeExpressions[f].c_str() ); + continue; + } + + const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] ); + const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); + StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); + + if(fFreezeSeconds > 0.0f) + { + // LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + pNewNotes->m_Timing.AddStopSegment( new_seg ); + } + else + { + // negative stops (hi JS!) -aj + if( PREFSMAN->m_bQuirksMode ) + { + // LOG->Trace( "Adding a negative freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + pNewNotes->m_Timing.AddStopSegment( new_seg ); + } + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid stop at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); + } + } + */ + } + else if( sValueName=="DELAYS" ) + { + /* + vector<RString> arrayDelayExpressions; + split( sParams[1], ",", arrayDelayExpressions ); + + for( unsigned f=0; f<arrayDelayExpressions.size(); f++ ) + { + vector<RString> arrayDelayValues; + split( arrayDelayExpressions[f], "=", arrayDelayValues ); + if( arrayDelayValues.size() != 2 ) + { + // XXX: Hard to tell which file caused this. + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayDelayExpressions[f].c_str() ); + continue; + } + + const float fFreezeBeat = StringToFloat( arrayDelayValues[0] ); + const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] ); + + StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds, true ); + + // LOG->Trace( "Adding a delay segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + + if(fFreezeSeconds > 0.0f) + pNewNotes->m_Timing.AddStopSegment( new_seg ); + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); + } + */ + } + else if( sValueName=="TIMESIGNATURES" ) + { + /* + vector<RString> vs1; + split( sParams[1], ",", vs1 ); + + FOREACH_CONST( RString, vs1, s1 ) + { + vector<RString> vs2; + split( *s1, "=", vs2 ); + + if( vs2.size() < 3 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with %i values.", (int)vs2.size() ); + continue; + } + + const float fBeat = StringToFloat( vs2[0] ); + + TimeSignatureSegment seg; + seg.m_iStartRow = BeatToNoteRow(fBeat); + seg.m_iNumerator = atoi( vs2[1] ); + seg.m_iDenominator = atoi( vs2[2] ); + + if( fBeat < 0 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f.", fBeat ); + continue; + } + + if( seg.m_iNumerator < 1 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iNumerator %i.", fBeat, seg.m_iNumerator ); + continue; + } + + if( seg.m_iDenominator < 1 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iDenominator %i.", fBeat, seg.m_iDenominator ); + continue; + } + + pNewNotes->m_Timing.AddTimeSignatureSegment( seg ); + } + */ + } + + else if( sValueName=="TICKCOUNTS" ) + { + /* + vector<RString> arrayTickcountExpressions; + split( sParams[1], ",", arrayTickcountExpressions ); + + for( unsigned f=0; f<arrayTickcountExpressions.size(); f++ ) + { + vector<RString> arrayTickcountValues; + split( arrayTickcountExpressions[f], "=", arrayTickcountValues ); + if( arrayTickcountValues.size() != 2 ) + { + // XXX: Hard to tell which file caused this. + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayTickcountExpressions[f].c_str() ); + continue; + } + + const float fTickcountBeat = StringToFloat( arrayTickcountValues[0] ); + const int iTicks = atoi( arrayTickcountValues[1] ); + TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks ); + + if(iTicks >= 1 && iTicks <= ROWS_PER_BEAT ) // Constants + { + // LOG->Trace( "Adding a tickcount segment: beat: %f, ticks = %d", fTickcountBeat, iTicks ); + pNewNotes->m_Timing.AddTickcountSegment( new_seg ); + } + else + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid tickcount at beat %f, ticks %d.", fTickcountBeat, iTicks ); + } + } + */ + } + else if( sValueName=="COMBOS" ) + { + /* + vector<RString> arrayComboExpressions; + split( sParams[1], ",", arrayComboExpressions ); + + for( unsigned f=0; f<arrayComboExpressions.size(); f++ ) + { + vector<RString> arrayComboValues; + split( arrayComboExpressions[f], "=", arrayComboValues ); + if( arrayComboValues.size() != 2 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayComboExpressions[f].c_str() ); + continue; + } + const float fComboBeat = StringToFloat( arrayComboValues[0] ); + const int iCombos = atoi( arrayComboValues[1] ); + ComboSegment new_seg( BeatToNoteRow( fComboBeat ), iCombos ); + pNewNotes->m_Timing.AddComboSegment( new_seg ); + } + */ + } + else if( sValueName=="ATTACKS" ) + { + // TODO: Look into Step attacks vs Song Attacks. -Wolfman2000 + /* + // Build the RString vector here so we can write it to file again later + for( unsigned s=1; s < sParams.params.size(); ++s ) + out.m_sAttackString.push_back( sParams[s] ); + + Attack attack; + float end = -9999; + + for( unsigned j=1; j < sParams.params.size(); ++j ) + { + vector<RString> sBits; + split( sParams[j], "=", sBits, false ); + + // Need an identifer and a value for this to work + if( sBits.size() < 2 ) + continue; + + TrimLeft( sBits[0] ); + TrimRight( sBits[0] ); + + if( !sBits[0].CompareNoCase("TIME") ) + attack.fStartSecond = strtof( sBits[1], NULL ); + else if( !sBits[0].CompareNoCase("LEN") ) + attack.fSecsRemaining = strtof( sBits[1], NULL ); + else if( !sBits[0].CompareNoCase("END") ) + end = strtof( sBits[1], NULL ); + else if( !sBits[0].CompareNoCase("MODS") ) + { + attack.sModifiers = sBits[1]; + + if( end != -9999 ) + { + attack.fSecsRemaining = end - attack.fStartSecond; + end = -9999; + } + + if( attack.fSecsRemaining < 0.0f ) + attack.fSecsRemaining = 0.0f; + + out.m_Attacks.push_back( attack ); + } + } + */ + } + else if( sValueName=="OFFSET" ) + {/* + pNewNotes->m_Timing.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); + */ + } + + else if( sValueName=="NOTES" ) + { + state = GETTING_SONG_INFO; + // pNewNotes->m_Timing.m_fBeat0OffsetInSeconds = out.m_Timing.m_fBeat0OffsetInSeconds; + pNewNotes->SetSMNoteData( sParams[1] ); + pNewNotes->TidyUpData(); + out.AddSteps( pNewNotes ); + } + break; + } + } + } + out.m_fVersion = STEPFILE_VERSION_NUMBER; + return true; +} + +void SSCLoader::GetApplicableFiles( const RString &sPath, vector<RString> &out ) +{ + GetDirListing( sPath + RString("*.ssc"), out ); +} + +bool SSCLoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ) +{ + LOG->Trace( "SSCLoader::LoadEditFromFile(%s)", sEditFilePath.c_str() ); + + int iBytes = FILEMAN->GetFileSizeInBytes( sEditFilePath ); + if( iBytes > MAX_EDIT_STEPS_SIZE_BYTES ) + { + LOG->UserLog( "Edit file", sEditFilePath, "is unreasonably large. It won't be loaded." ); + return false; + } + + MsdFile msd; + if( !msd.ReadFile( sEditFilePath, true ) ) // unescape + { + LOG->UserLog( "Edit file", sEditFilePath, "couldn't be opened: %s", msd.GetError().c_str() ); + return false; + } + + return LoadEditFromMsd( msd, sEditFilePath, slot, bAddStepsToSong ); +} + +bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ) +{ + Song* pSong = NULL; + Steps* pNewNotes; + bool bSSCFormat = false; + + for( unsigned i=0; i<msd.GetNumValues(); i++ ) + { + int iNumParams = msd.GetNumParams(i); + const MsdFile::value_t &sParams = msd.GetValue(i); + RString sValueName = sParams[0]; + sValueName.MakeUpper(); + + // handle the data + if( sValueName=="SONG" ) + { + if( pSong ) + { + LOG->UserLog( "Edit file", sEditFilePath, "has more than one #SONG tag." ); + return false; + } + + RString sSongFullTitle = sParams[1]; + sSongFullTitle.Replace( '\\', '/' ); + + pSong = SONGMAN->FindSong( sSongFullTitle ); + if( pSong == NULL ) + { + LOG->UserLog( "Edit file", sEditFilePath, "requires a song \"%s\" that isn't present.", sSongFullTitle.c_str() ); + return false; + } + + if( pSong->GetNumStepsLoadedFromProfile(slot) >= MAX_EDITS_PER_SONG_PER_PROFILE ) + { + LOG->UserLog( "Song file", sSongFullTitle, "already has the maximum number of edits allowed for ProfileSlotP%d.", slot+1 ); + return false; + } + } + + else if( sValueName=="NOTEDATA" ) + { + pNewNotes = new Steps; + bSSCFormat = true; + } + if( sValueName=="STEPSTYPE" ) + { + pNewNotes->m_StepsType = GAMEMAN->StringToStepsType( sParams[1] ); + bSSCFormat = true; + } + + else if( sValueName=="CHARTSTYLE" ) + { + pNewNotes->SetChartStyle( sParams[1] ); + bSSCFormat = true; + } + + else if( sValueName=="DESCRIPTION" ) + { + pNewNotes->SetDescription( sParams[1] ); + bSSCFormat = true; + } + + else if( sValueName=="DIFFICULTY" ) + { + pNewNotes->SetDifficulty( DwiCompatibleStringToDifficulty( sParams[1] ) ); + bSSCFormat = true; + } + + else if( sValueName=="METER" ) + { + pNewNotes->SetMeter( atoi( sParams[1] ) ); + bSSCFormat = true; + } + + else if( sValueName=="RADARVALUES" ) + { + vector<RString> saValues; + split( sParams[1], ",", saValues, true ); + if( saValues.size() == NUM_RadarCategory * NUM_PLAYERS ) + { + RadarValues v[NUM_PLAYERS]; + FOREACH_PlayerNumber( pn ) + FOREACH_ENUM( RadarCategory, rc ) + v[pn][rc] = StringToFloat( saValues[pn*NUM_RadarCategory + rc] ); + pNewNotes->SetCachedRadarValues( v ); + } + bSSCFormat = true; + } + + else if( sValueName=="CREDIT" ) + { + pNewNotes->SetCredit( sParams[1] ); + bSSCFormat = true; + } + + // TimingData for Steps isn't set yet, but still prepare for it. + else if( sValueName=="BPMS" ) + { + bSSCFormat = true; + } + else if( sValueName=="STOPS" ) + { + bSSCFormat = true; + } + else if( sValueName=="DELAYS" ) + { + bSSCFormat = true; + } + else if( sValueName=="TIMESIGNATURES" ) + { + bSSCFormat = true; + } + else if( sValueName=="TICKCOUNTS" ) + { + bSSCFormat = true; + } + else if( sValueName=="COMBOS" ) + { + bSSCFormat = true; + } + + else if( sValueName=="NOTES" ) + { + if( pSong == NULL ) + { + LOG->UserLog( "Edit file", sEditFilePath, "doesn't have a #SONG tag preceeding the first #NOTES tag." ); + return false; + } + + if ( !bSSCFormat && iNumParams < 7 ) + { + LOG->UserLog( "Edit file", sEditFilePath, "has %d fields in a #NOTES tag, but should have at least 7.", iNumParams ); + continue; + } + + if( !bAddStepsToSong ) + return true; + + if( bSSCFormat ) + { + pNewNotes->SetSMNoteData( sParams[1] ); + pNewNotes->TidyUpData(); + pSong->AddSteps( pNewNotes ); + } + else + { + pNewNotes = new Steps; + SMLoader::LoadFromSMTokens( + sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6], + *pNewNotes); + } + + pNewNotes->SetLoadedFromProfile( slot ); + pNewNotes->SetDifficulty( Difficulty_Edit ); + pNewNotes->SetFilename( sEditFilePath ); + + if( pSong->IsEditAlreadyLoaded(pNewNotes) ) + { + LOG->UserLog( "Edit file", sEditFilePath, "is a duplicate of another edit that was already loaded." ); + SAFE_DELETE( pNewNotes ); + return false; + } + + pSong->AddSteps( pNewNotes ); + return true; // Only allow one Steps per edit file! + } + else + { + LOG->UserLog( "Edit file", sEditFilePath, "has an unexpected value \"%s\".", sValueName.c_str() ); + } + } + + //return true; + // only load a SSC edit if it passes the checks. -aj + return bSSCFormat; +} + +void SSCLoader::TidyUpData( Song &song, bool bFromCache ) +{ + /* + * Hack: if the song has any changes at all (so it won't use a random BGA) + * and doesn't end with "-nosongbg-", add a song background BGC. Remove + * "-nosongbg-" if it exists. + * + * This way, songs that were created earlier, when we added the song BG + * at the end by default, will still behave as expected; all new songs will + * have to add an explicit song BG tag if they want it. This is really a + * formatting hack only; nothing outside of SMLoader ever sees "-nosongbg-". + */ + vector<BackgroundChange> &bg = song.GetBackgroundChanges(BACKGROUND_LAYER_1); + if( !bg.empty() ) + { + /* BGChanges have been sorted. On the odd chance that a BGChange exists + * with a very high beat, search the whole list. */ + bool bHasNoSongBgTag = false; + + for( unsigned i = 0; !bHasNoSongBgTag && i < bg.size(); ++i ) + { + if( !bg[i].m_def.m_sFile1.CompareNoCase(NO_SONG_BG_FILE) ) + { + bg.erase( bg.begin()+i ); + bHasNoSongBgTag = true; + } + } + + // If there's no -nosongbg- tag, add the song BG. + if( !bHasNoSongBgTag ) do + { + /* If we're loading cache, -nosongbg- should always be in there. We + * must not call IsAFile(song.GetBackgroundPath()) when loading cache. */ + if( bFromCache ) + break; + + /* If BGChanges already exist after the last beat, don't add the + * background in the middle. */ + if( !bg.empty() && bg.back().m_fStartBeat-0.0001f >= song.m_fLastBeat ) + break; + + // If the last BGA is already the song BGA, don't add a duplicate. + if( !bg.empty() && !bg.back().m_def.m_sFile1.CompareNoCase(song.m_sBackgroundFile) ) + break; + + if( !IsAFile( song.GetBackgroundPath() ) ) + break; + + bg.push_back( BackgroundChange(song.m_fLastBeat,song.m_sBackgroundFile) ); + } while(0); + } +} + +/* + * (c) 2011 Jason Felds + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/NotesLoaderSSC.h b/src/NotesLoaderSSC.h index ae8f00bc9c..f16aa68377 100644 --- a/src/NotesLoaderSSC.h +++ b/src/NotesLoaderSSC.h @@ -1,103 +1,103 @@ -/** @brief SSCLoader - Reads a Song and its Steps from a .SSC file. */ -#ifndef NotesLoaderSSC_H -#define NotesLoaderSSC_H - -#include "GameConstantsAndTypes.h" - -class MsdFile; -class Song; -class Steps; -class TimingData; - -/** - * @brief The various states while parsing a .ssc file. - */ -enum SSCLoadingStates -{ - GETTING_SONG_INFO, /**< Retrieving song information. */ - GETTING_STEP_INFO, /**< Retrieving step information. */ - GETTING_STEP_TIMING_INFO, /**< Retrieving a step's individual timing information. */ - GETTING_NOTE_INFO, /**< Retrieving the specific notes. This state may be deprecated. */ - NUM_SSCLoadingStates /**< The number of states used. */ -}; - -const float VERSION_RADAR_FAKE = 0.53f; - -/** - * @brief The SSCLoader handles all of the parsing needed for .ssc files. - */ -namespace SSCLoader -{ - /** - * @brief Attempt to load a song from a specified path. - * @param sPath a const reference to the path on the hard drive to check. - * @param out a reference to the Song that will retrieve the song information. - * @return its success or failure. - */ - bool LoadFromDir( const RString &sPath, Song &out ); - /** - * @brief Attempt to load the specified ssc file. - * @param sPath a const reference to the path on the hard drive to check. - * @param out a reference to the Song that will retrieve the song information. - * @param bFromCache a check to see if we are getting certain information from the cache file. - * @return its success or failure. - */ - bool LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache = false ); - /** - * @brief Retrieve the list of .ssc files. - * @param sPath a const reference to the path on the hard drive to check. - * @param out a vector of files found in the path. - */ - void GetApplicableFiles( const RString &sPath, vector<RString> &out ); - /** - * @brief Attempt to load an edit from the hard drive. - * @param sEditFilePath a path on the hard drive to check. - * @param slot the Profile of the user with the edit. - * @param bAddStepsToSong a flag to determine if we add the edit steps to the song file. - * @return its success or failure. - */ - bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); - /** - * @brief Attempt to parse the edit file in question. - * @param msd the edit file itself. - * @param sEditFilePath a const reference to a path on the hard drive to check. - * @param slot the Profile of the user with the edit. - * @param bAddStepsToSong a flag to determine if we add the edit steps to the song file. - * @return its success or failure. - */ - bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); - /** - * @brief Perform some cleanup on the loaded song. - * @param song a reference to the song that may need cleaning up. - * @param bFromCache a flag to determine if this song is loaded from a cache file. - */ - void TidyUpData( Song &song, bool bFromCache ); -} -#endif -/** - * @file - * @author Jason Felds (c) 2011 - * - * @section LICENSE - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +/** @brief SSCLoader - Reads a Song and its Steps from a .SSC file. */ +#ifndef NotesLoaderSSC_H +#define NotesLoaderSSC_H + +#include "GameConstantsAndTypes.h" + +class MsdFile; +class Song; +class Steps; +class TimingData; + +/** + * @brief The various states while parsing a .ssc file. + */ +enum SSCLoadingStates +{ + GETTING_SONG_INFO, /**< Retrieving song information. */ + GETTING_STEP_INFO, /**< Retrieving step information. */ + GETTING_STEP_TIMING_INFO, /**< Retrieving a step's individual timing information. */ + GETTING_NOTE_INFO, /**< Retrieving the specific notes. This state may be deprecated. */ + NUM_SSCLoadingStates /**< The number of states used. */ +}; + +const float VERSION_RADAR_FAKE = 0.53f; + +/** + * @brief The SSCLoader handles all of the parsing needed for .ssc files. + */ +namespace SSCLoader +{ + /** + * @brief Attempt to load a song from a specified path. + * @param sPath a const reference to the path on the hard drive to check. + * @param out a reference to the Song that will retrieve the song information. + * @return its success or failure. + */ + bool LoadFromDir( const RString &sPath, Song &out ); + /** + * @brief Attempt to load the specified ssc file. + * @param sPath a const reference to the path on the hard drive to check. + * @param out a reference to the Song that will retrieve the song information. + * @param bFromCache a check to see if we are getting certain information from the cache file. + * @return its success or failure. + */ + bool LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache = false ); + /** + * @brief Retrieve the list of .ssc files. + * @param sPath a const reference to the path on the hard drive to check. + * @param out a vector of files found in the path. + */ + void GetApplicableFiles( const RString &sPath, vector<RString> &out ); + /** + * @brief Attempt to load an edit from the hard drive. + * @param sEditFilePath a path on the hard drive to check. + * @param slot the Profile of the user with the edit. + * @param bAddStepsToSong a flag to determine if we add the edit steps to the song file. + * @return its success or failure. + */ + bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); + /** + * @brief Attempt to parse the edit file in question. + * @param msd the edit file itself. + * @param sEditFilePath a const reference to a path on the hard drive to check. + * @param slot the Profile of the user with the edit. + * @param bAddStepsToSong a flag to determine if we add the edit steps to the song file. + * @return its success or failure. + */ + bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); + /** + * @brief Perform some cleanup on the loaded song. + * @param song a reference to the song that may need cleaning up. + * @param bFromCache a flag to determine if this song is loaded from a cache file. + */ + void TidyUpData( Song &song, bool bFromCache ); +} +#endif +/** + * @file + * @author Jason Felds (c) 2011 + * + * @section LICENSE + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/RageFileManager_ReadAhead.h b/src/RageFileManager_ReadAhead.h index 7e42687cc5..def476c457 100644 --- a/src/RageFileManager_ReadAhead.h +++ b/src/RageFileManager_ReadAhead.h @@ -1,46 +1,46 @@ -#ifndef RAGE_FILE_MANAGER_READAHEAD_H -#define RAGE_FILE_MANAGER_READAHEAD_H - -#include "RageFileBasic.h" -/** @brief Utilities for reading the RageFiles. */ -namespace RageFileManagerReadAhead -{ - void Init(); - void Shutdown(); - - // Nonblockingly read ahead iBytes in pFile, starting at the current file position. - void ReadAhead( RageFileBasic *pFile, int iBytes ); - - /* Discard iBytes of kernel cache, starting at the current file position plus - * iRelativePosition (which may be negative). */ - void DiscardCache( RageFileBasic *pFile, int iRelativePosition, int iBytes ); - - void CacheHintStreaming( RageFileBasic *pFile ); -}; - -#endif - -/* - * Copyright (c) 2010 Glenn Maynard - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +#ifndef RAGE_FILE_MANAGER_READAHEAD_H +#define RAGE_FILE_MANAGER_READAHEAD_H + +#include "RageFileBasic.h" +/** @brief Utilities for reading the RageFiles. */ +namespace RageFileManagerReadAhead +{ + void Init(); + void Shutdown(); + + // Nonblockingly read ahead iBytes in pFile, starting at the current file position. + void ReadAhead( RageFileBasic *pFile, int iBytes ); + + /* Discard iBytes of kernel cache, starting at the current file position plus + * iRelativePosition (which may be negative). */ + void DiscardCache( RageFileBasic *pFile, int iRelativePosition, int iBytes ); + + void CacheHintStreaming( RageFileBasic *pFile ); +}; + +#endif + +/* + * Copyright (c) 2010 Glenn Maynard + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/RageSurface_Load_PNG.cpp b/src/RageSurface_Load_PNG.cpp index dd7014bf15..a9b7c8d43d 100644 --- a/src/RageSurface_Load_PNG.cpp +++ b/src/RageSurface_Load_PNG.cpp @@ -1,318 +1,318 @@ -#include "global.h" -#include "RageSurface_Load_PNG.h" -#include "RageUtil.h" -#include "RageLog.h" -#include "RageFile.h" -#include "RageSurface.h" - - -#if defined(_WINDOWS) || defined(_XBOX) -# include "libpng/include/png.h" -# if defined(_MSC_VER) -# if defined(_XBOX) -# pragma comment(lib, "libpng/lib/xboxlibpng.lib") -# else -# pragma comment(lib, "libpng/lib/libpng.lib") -# endif -# pragma warning(disable: 4611) /* interaction between '_setjmp' and C++ object destruction is non-portable */ -# endif // _MSC_VER -#else -# include <png.h> -#endif - -#if defined(_XBOX) -# include <malloc.h> // for alloca -# include "archutils/Xbox/VirtualMemory.h" -#endif - -namespace -{ -void RageFile_png_read( png_struct *png, png_byte *p, png_size_t size ) -{ - CHECKPOINT; - RageFile *f = (RageFile *) png_get_io_ptr(png); - - int got = f->Read( p, size ); - if( got == -1 ) - { - /* png_error will call PNG_Error, which will longjmp. If we just pass - * GetError().c_str() to it, a temporary may be created; since control - * never returns here, it may never be destructed and we could leak. */ - static char error[256]; - strncpy( error, f->GetError(), sizeof(error) ); - error[sizeof(error)-1] = 0; - png_error( png, error ); - } - else if( got != (int) size ) - png_error( png, "Unexpected EOF" ); -} - -struct error_info -{ - char *err; - const char *fn; -}; - -void PNG_Error( png_struct *png, const char *error ) -{ - CHECKPOINT; - error_info *info = (error_info *) png_get_error_ptr(png); - strncpy( info->err, error, 1024 ); - info->err[1023] = 0; - LOG->Trace( "loading \"%s\": err: %s", info->fn, info->err ); - longjmp( png_jmpbuf(png), 1 ); -} - -void PNG_Warning( png_struct *png, const char *warning ) -{ - CHECKPOINT; - error_info *info = (error_info *) png_get_io_ptr(png); - LOG->Trace( "loading \"%s\": warning: %s", info->fn, warning ); -} - -/* Since libpng forces us to use longjmp (gross!), this function shouldn't create any C++ - * objects, and needs to watch out for memleaks. */ -static RageSurface *RageSurface_Load_PNG( RageFile *f, const char *fn, char errorbuf[1024], bool bHeaderOnly ) -{ - error_info error; - error.err = errorbuf; - error.fn = fn; - - png_struct *png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning ); - -#if defined(XBOX) - while(png == NULL) - { - if(!vmem_Manager.DecommitLRU()) - break; - - png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning ); - } -#endif - - if( png == NULL ) - { - sprintf( errorbuf, "creating png_create_read_struct failed"); - return NULL; - } - - png_info *info_ptr = png_create_info_struct(png); - if( info_ptr == NULL ) - { - png_destroy_read_struct( &png, NULL, NULL ); - sprintf( errorbuf, "creating png_create_info_struct failed"); - return NULL; - } - - RageSurface *volatile img = NULL; - CHECKPOINT; - if( setjmp(png_jmpbuf(png) )) - { - png_destroy_read_struct( &png, &info_ptr, NULL ); - delete img; - return NULL; - } - CHECKPOINT; - - png_set_read_fn( png, f, RageFile_png_read ); - - png_read_info( png, info_ptr ); - - png_uint_32 width, height; - int bit_depth, color_type; - png_get_IHDR( png, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL ); - - /* If bHeaderOnly is true, don't allocate the pixel storage space or decompress - * the image. Just return an empty surface with only the width and height set. */ - if( bHeaderOnly ) - { - CHECKPOINT; - img = CreateSurfaceFrom( width, height, 32, 0, 0, 0, 0, NULL, width*4 ); - png_destroy_read_struct( &png, &info_ptr, NULL ); - - return img; - } - - - CHECKPOINT; - png_set_strip_16(png); /* 16bit->8bit */ - png_set_packing( png ); /* 1,2,4 bit->8 bit */ - - /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ - if( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 ) - png_set_expand_gray_1_2_4_to_8( png ); - - /* These are set for type == PALETTE. */ - RageSurfaceColor colors[256]; - int iColorKey = -1; - - /* We import three types of files: paletted, RGBX and RGBA. The only difference - * between RGBX and RGBA is that RGBX won't set the alpha mask, so it's easier - * to tell later on that there's no alpha (without actually having to do a pixel scan). */ - enum { PALETTE, RGBX, RGBA } type; - switch( color_type ) - { - case PNG_COLOR_TYPE_GRAY: - /* Fake PNG_COLOR_TYPE_GRAY. */ - for( int i = 0; i < 256; ++i ) - { - colors[i].r = colors[i].g = colors[i].b = (int8_t) i; - colors[i].a = 0xFF; - } - - type = PALETTE; - break; - - case PNG_COLOR_TYPE_GRAY_ALPHA: - type = RGBA; - png_set_gray_to_rgb( png ); - break; - case PNG_COLOR_TYPE_PALETTE: - type = PALETTE; - break; - case PNG_COLOR_TYPE_RGB: - type = RGBX; - break; - case PNG_COLOR_TYPE_RGB_ALPHA: - type = RGBA; - break; - default: - FAIL_M(ssprintf( "%i", color_type) ); - } - - CHECKPOINT; - if( color_type == PNG_COLOR_TYPE_GRAY ) - { - png_color_16 *trans; - if( png_get_tRNS( png, info_ptr, NULL, NULL, &trans ) == PNG_INFO_tRNS ) - iColorKey = trans->gray; - } - else if( color_type == PNG_COLOR_TYPE_PALETTE ) - { - int num_palette; - png_color *palette; - int ret = png_get_PLTE( png, info_ptr, &palette, &num_palette ); - ASSERT( ret == PNG_INFO_PLTE ); - - png_byte *trans = NULL; - int num_trans = 0; - png_get_tRNS( png, info_ptr, &trans, &num_trans, NULL ); - - for( int i = 0; i < num_palette; ++i ) - { - colors[i].r = palette[i].red; - colors[i].g = palette[i].green; - colors[i].b = palette[i].blue; - colors[i].a = 0xFF; - if( i < num_trans ) - colors[i].a = trans[i]; - } - } - else - { - /* If we have RGB image and tRNS, it's a color key. Just convert it to RGBA. */ - if( png_get_valid(png, info_ptr, PNG_INFO_tRNS) ) - { - /* We don't care about RGB color keys; just convert them to alpha. */ - png_set_tRNS_to_alpha( png ); - type = RGBA; - } - - /* RGB->RGBX */ - png_set_filler( png, 0xff, PNG_FILLER_AFTER ); - } - - png_set_interlace_handling( png ); - - CHECKPOINT; - png_read_update_info( png, info_ptr ); - - switch( type ) - { - case PALETTE: - img = CreateSurface( width, height, 8, 0, 0, 0, 0 ); - memcpy( img->fmt.palette->colors, colors, 256*sizeof(RageSurfaceColor) ); - - if( iColorKey != -1 ) - img->format->palette->colors[ iColorKey ].a = 0; - - break; - case RGBX: - case RGBA: - img = CreateSurface( width, height, 32, - Swap32BE( 0xFF000000 ), - Swap32BE( 0x00FF0000 ), - Swap32BE( 0x0000FF00 ), - Swap32BE( type == RGBA? 0x000000FF:0x00000000 ) ); - break; - default: - FAIL_M(ssprintf( "%i", type) ); - } - ASSERT( img ); - - /* alloca to prevent memleaks if libpng longjmps us */ - png_byte **row_pointers = (png_byte **) alloca( sizeof(png_byte*) * height ); - CHECKPOINT_M( ssprintf("%p",row_pointers) ); - - for( unsigned y = 0; y < height; ++y ) - { - png_byte *p = (png_byte *) img->pixels; - row_pointers[y] = p + img->pitch*y; - } - - CHECKPOINT; - png_read_image( png, row_pointers ); - - CHECKPOINT; - png_read_end( png, info_ptr ); - png_destroy_read_struct( &png, &info_ptr, NULL ); - - return img; -} - -}; - -RageSurfaceUtils::OpenResult RageSurface_Load_PNG( const RString &sPath, RageSurface *&ret, bool bHeaderOnly, RString &error ) -{ - RageFile f; - if( !f.Open( sPath ) ) - { - error = f.GetError(); - return RageSurfaceUtils::OPEN_FATAL_ERROR; - } - - char errorbuf[1024]; - ret = RageSurface_Load_PNG( &f, sPath, errorbuf, bHeaderOnly ); - if( ret == NULL ) - { - error = errorbuf; - return RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT; // XXX - } - - return RageSurfaceUtils::OPEN_OK; -} - -/* - * (c) 2004 Glenn Maynard - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +#include "global.h" +#include "RageSurface_Load_PNG.h" +#include "RageUtil.h" +#include "RageLog.h" +#include "RageFile.h" +#include "RageSurface.h" + + +#if defined(_WINDOWS) || defined(_XBOX) +# include "libpng/include/png.h" +# if defined(_MSC_VER) +# if defined(_XBOX) +# pragma comment(lib, "libpng/lib/xboxlibpng.lib") +# else +# pragma comment(lib, "libpng/lib/libpng.lib") +# endif +# pragma warning(disable: 4611) /* interaction between '_setjmp' and C++ object destruction is non-portable */ +# endif // _MSC_VER +#else +# include <png.h> +#endif + +#if defined(_XBOX) +# include <malloc.h> // for alloca +# include "archutils/Xbox/VirtualMemory.h" +#endif + +namespace +{ +void RageFile_png_read( png_struct *png, png_byte *p, png_size_t size ) +{ + CHECKPOINT; + RageFile *f = (RageFile *) png_get_io_ptr(png); + + int got = f->Read( p, size ); + if( got == -1 ) + { + /* png_error will call PNG_Error, which will longjmp. If we just pass + * GetError().c_str() to it, a temporary may be created; since control + * never returns here, it may never be destructed and we could leak. */ + static char error[256]; + strncpy( error, f->GetError(), sizeof(error) ); + error[sizeof(error)-1] = 0; + png_error( png, error ); + } + else if( got != (int) size ) + png_error( png, "Unexpected EOF" ); +} + +struct error_info +{ + char *err; + const char *fn; +}; + +void PNG_Error( png_struct *png, const char *error ) +{ + CHECKPOINT; + error_info *info = (error_info *) png_get_error_ptr(png); + strncpy( info->err, error, 1024 ); + info->err[1023] = 0; + LOG->Trace( "loading \"%s\": err: %s", info->fn, info->err ); + longjmp( png_jmpbuf(png), 1 ); +} + +void PNG_Warning( png_struct *png, const char *warning ) +{ + CHECKPOINT; + error_info *info = (error_info *) png_get_io_ptr(png); + LOG->Trace( "loading \"%s\": warning: %s", info->fn, warning ); +} + +/* Since libpng forces us to use longjmp (gross!), this function shouldn't create any C++ + * objects, and needs to watch out for memleaks. */ +static RageSurface *RageSurface_Load_PNG( RageFile *f, const char *fn, char errorbuf[1024], bool bHeaderOnly ) +{ + error_info error; + error.err = errorbuf; + error.fn = fn; + + png_struct *png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning ); + +#if defined(XBOX) + while(png == NULL) + { + if(!vmem_Manager.DecommitLRU()) + break; + + png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning ); + } +#endif + + if( png == NULL ) + { + sprintf( errorbuf, "creating png_create_read_struct failed"); + return NULL; + } + + png_info *info_ptr = png_create_info_struct(png); + if( info_ptr == NULL ) + { + png_destroy_read_struct( &png, NULL, NULL ); + sprintf( errorbuf, "creating png_create_info_struct failed"); + return NULL; + } + + RageSurface *volatile img = NULL; + CHECKPOINT; + if( setjmp(png_jmpbuf(png) )) + { + png_destroy_read_struct( &png, &info_ptr, NULL ); + delete img; + return NULL; + } + CHECKPOINT; + + png_set_read_fn( png, f, RageFile_png_read ); + + png_read_info( png, info_ptr ); + + png_uint_32 width, height; + int bit_depth, color_type; + png_get_IHDR( png, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL ); + + /* If bHeaderOnly is true, don't allocate the pixel storage space or decompress + * the image. Just return an empty surface with only the width and height set. */ + if( bHeaderOnly ) + { + CHECKPOINT; + img = CreateSurfaceFrom( width, height, 32, 0, 0, 0, 0, NULL, width*4 ); + png_destroy_read_struct( &png, &info_ptr, NULL ); + + return img; + } + + + CHECKPOINT; + png_set_strip_16(png); /* 16bit->8bit */ + png_set_packing( png ); /* 1,2,4 bit->8 bit */ + + /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ + if( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 ) + png_set_expand_gray_1_2_4_to_8( png ); + + /* These are set for type == PALETTE. */ + RageSurfaceColor colors[256]; + int iColorKey = -1; + + /* We import three types of files: paletted, RGBX and RGBA. The only difference + * between RGBX and RGBA is that RGBX won't set the alpha mask, so it's easier + * to tell later on that there's no alpha (without actually having to do a pixel scan). */ + enum { PALETTE, RGBX, RGBA } type; + switch( color_type ) + { + case PNG_COLOR_TYPE_GRAY: + /* Fake PNG_COLOR_TYPE_GRAY. */ + for( int i = 0; i < 256; ++i ) + { + colors[i].r = colors[i].g = colors[i].b = (int8_t) i; + colors[i].a = 0xFF; + } + + type = PALETTE; + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + type = RGBA; + png_set_gray_to_rgb( png ); + break; + case PNG_COLOR_TYPE_PALETTE: + type = PALETTE; + break; + case PNG_COLOR_TYPE_RGB: + type = RGBX; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + type = RGBA; + break; + default: + FAIL_M(ssprintf( "%i", color_type) ); + } + + CHECKPOINT; + if( color_type == PNG_COLOR_TYPE_GRAY ) + { + png_color_16 *trans; + if( png_get_tRNS( png, info_ptr, NULL, NULL, &trans ) == PNG_INFO_tRNS ) + iColorKey = trans->gray; + } + else if( color_type == PNG_COLOR_TYPE_PALETTE ) + { + int num_palette; + png_color *palette; + int ret = png_get_PLTE( png, info_ptr, &palette, &num_palette ); + ASSERT( ret == PNG_INFO_PLTE ); + + png_byte *trans = NULL; + int num_trans = 0; + png_get_tRNS( png, info_ptr, &trans, &num_trans, NULL ); + + for( int i = 0; i < num_palette; ++i ) + { + colors[i].r = palette[i].red; + colors[i].g = palette[i].green; + colors[i].b = palette[i].blue; + colors[i].a = 0xFF; + if( i < num_trans ) + colors[i].a = trans[i]; + } + } + else + { + /* If we have RGB image and tRNS, it's a color key. Just convert it to RGBA. */ + if( png_get_valid(png, info_ptr, PNG_INFO_tRNS) ) + { + /* We don't care about RGB color keys; just convert them to alpha. */ + png_set_tRNS_to_alpha( png ); + type = RGBA; + } + + /* RGB->RGBX */ + png_set_filler( png, 0xff, PNG_FILLER_AFTER ); + } + + png_set_interlace_handling( png ); + + CHECKPOINT; + png_read_update_info( png, info_ptr ); + + switch( type ) + { + case PALETTE: + img = CreateSurface( width, height, 8, 0, 0, 0, 0 ); + memcpy( img->fmt.palette->colors, colors, 256*sizeof(RageSurfaceColor) ); + + if( iColorKey != -1 ) + img->format->palette->colors[ iColorKey ].a = 0; + + break; + case RGBX: + case RGBA: + img = CreateSurface( width, height, 32, + Swap32BE( 0xFF000000 ), + Swap32BE( 0x00FF0000 ), + Swap32BE( 0x0000FF00 ), + Swap32BE( type == RGBA? 0x000000FF:0x00000000 ) ); + break; + default: + FAIL_M(ssprintf( "%i", type) ); + } + ASSERT( img ); + + /* alloca to prevent memleaks if libpng longjmps us */ + png_byte **row_pointers = (png_byte **) alloca( sizeof(png_byte*) * height ); + CHECKPOINT_M( ssprintf("%p",row_pointers) ); + + for( unsigned y = 0; y < height; ++y ) + { + png_byte *p = (png_byte *) img->pixels; + row_pointers[y] = p + img->pitch*y; + } + + CHECKPOINT; + png_read_image( png, row_pointers ); + + CHECKPOINT; + png_read_end( png, info_ptr ); + png_destroy_read_struct( &png, &info_ptr, NULL ); + + return img; +} + +}; + +RageSurfaceUtils::OpenResult RageSurface_Load_PNG( const RString &sPath, RageSurface *&ret, bool bHeaderOnly, RString &error ) +{ + RageFile f; + if( !f.Open( sPath ) ) + { + error = f.GetError(); + return RageSurfaceUtils::OPEN_FATAL_ERROR; + } + + char errorbuf[1024]; + ret = RageSurface_Load_PNG( &f, sPath, errorbuf, bHeaderOnly ); + if( ret == NULL ) + { + error = errorbuf; + return RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT; // XXX + } + + return RageSurfaceUtils::OPEN_OK; +} + +/* + * (c) 2004 Glenn Maynard + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/RageSurface_Save_PNG.cpp b/src/RageSurface_Save_PNG.cpp index f971760fbd..98b681527d 100644 --- a/src/RageSurface_Save_PNG.cpp +++ b/src/RageSurface_Save_PNG.cpp @@ -1,168 +1,168 @@ -#include "global.h" -#include "RageSurface_Save_PNG.h" -#include "RageSurface.h" -#include "RageSurfaceUtils.h" -#include "RageFile.h" -#include "RageLog.h" -#include "RageUtil.h" - -#if defined(WINDOWS) || defined(_XBOX) -#include "libpng/include/png.h" -#if defined(_MSC_VER) -# if defined(_XBOX) -# pragma comment(lib, "libpng/lib/xboxlibpng.lib") -# else -# pragma comment(lib, "libpng/lib/libpng.lib") -# endif -#pragma warning(disable: 4611) /* interaction between '_setjmp' and C++ object destruction is non-portable */ -#endif -#else -#include <png.h> -#endif - -static void SafePngError( png_struct *pPng, const RString &sStr ) -{ - /* png_error will call PNG_Error, which will longjmp. If we just pass - * GetError().c_str() to it, a temporary may be created; since control - * never returns, it may never be destructed and leak. */ - static char error[256]; - strncpy( error, sStr, sizeof(error) ); - error[sizeof(error)-1] = 0; - png_error( pPng, error ); -} - -static void RageFile_png_write( png_struct *pPng, png_byte *pData, png_size_t iSize ) -{ - RageFile *pFile = (RageFile *) png_get_io_ptr(pPng); - - int iGot = pFile->Write( pData, iSize ); - if( iGot == -1 ) - SafePngError( pPng, pFile->GetError() ); -} - -static void RageFile_png_flush( png_struct *pPng ) -{ - RageFile *pFile = (RageFile *) png_get_io_ptr(pPng); - - int iGot = pFile->Flush(); - if( iGot == -1 ) - SafePngError( pPng, pFile->GetError() ); -} - -struct error_info -{ - char *szErr; -}; - -static void PNG_Error( png_struct *pPng, const char *szError ) -{ - error_info *pInfo = (error_info *) png_get_error_ptr(pPng); - strncpy( pInfo->szErr, szError, 1024 ); - pInfo->szErr[1023] = 0; - longjmp( png_jmpbuf(pPng), 1 ); -} - -static void PNG_Warning( png_struct *png, const char *warning ) -{ - LOG->Trace( "saving PNG: warning: %s", warning ); -} - -/* Since libpng forces us to use longjmp, this function shouldn't create any C++ - * objects, and needs to watch out for memleaks. */ -static bool RageSurface_Save_PNG( RageFile &f, char szErrorbuf[1024], RageSurface *pImgIn ) -{ - bool bAlpha = pImgIn->format->Amask != 0; - RageSurface *pImg; - bool bDeleteImg = RageSurfaceUtils::ConvertSurface( pImgIn, pImg, pImgIn->w, pImgIn->h, 32, - Swap32BE( 0xFF000000 ), - Swap32BE( 0x00FF0000 ), - Swap32BE( 0x0000FF00 ), - Swap32BE( 0x000000FF ) ); - if( !bDeleteImg ) - pImg = pImgIn; - - error_info error; - error.szErr = szErrorbuf; - - png_struct *pPng = png_create_write_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning ); - if( pPng == NULL ) - { - sprintf( szErrorbuf, "creating png_create_write_struct failed"); - return false; - } - - png_info *pInfo = png_create_info_struct(pPng); - if( pInfo == NULL ) - { - png_destroy_read_struct( &pPng, NULL, NULL ); - if( bDeleteImg ) - delete pImg; - sprintf( szErrorbuf, "creating png_create_info_struct failed"); - return false; - } - - if( setjmp(png_jmpbuf(pPng)) ) - { - png_destroy_read_struct( &pPng, &pInfo, NULL ); - return false; - } - - png_set_write_fn( pPng, &f, RageFile_png_write, RageFile_png_flush ); - png_set_compression_level( pPng, 1 ); - - png_set_IHDR( pPng, pInfo, pImg->w, pImg->h, 8, bAlpha? PNG_COLOR_TYPE_RGBA:PNG_COLOR_TYPE_RGB, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE ); - - png_write_info( pPng, pInfo ); - png_set_filler( pPng, 0, PNG_FILLER_AFTER ); - - png_byte *pixels = (png_byte *) pImg->pixels; - for( int y = 0; y < pImg->h; y++ ) - png_write_row( pPng, pixels + pImg->pitch*y ); - - png_write_end( pPng, pInfo ); - png_destroy_write_struct( &pPng, &pInfo ); - - /* Free the converted image. */ - if( bDeleteImg ) - delete pImg; - - return true; -} - -bool RageSurfaceUtils::SavePNG( RageSurface *pImg, RageFile &f, RString &sError ) -{ - char szErrorBuf[1024]; - if( !RageSurface_Save_PNG(f, szErrorBuf, pImg) ) - { - sError = szErrorBuf; - return false; - } - - return true; -} - -/* - * (c) 2004-2006 Glenn Maynard - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +#include "global.h" +#include "RageSurface_Save_PNG.h" +#include "RageSurface.h" +#include "RageSurfaceUtils.h" +#include "RageFile.h" +#include "RageLog.h" +#include "RageUtil.h" + +#if defined(WINDOWS) || defined(_XBOX) +#include "libpng/include/png.h" +#if defined(_MSC_VER) +# if defined(_XBOX) +# pragma comment(lib, "libpng/lib/xboxlibpng.lib") +# else +# pragma comment(lib, "libpng/lib/libpng.lib") +# endif +#pragma warning(disable: 4611) /* interaction between '_setjmp' and C++ object destruction is non-portable */ +#endif +#else +#include <png.h> +#endif + +static void SafePngError( png_struct *pPng, const RString &sStr ) +{ + /* png_error will call PNG_Error, which will longjmp. If we just pass + * GetError().c_str() to it, a temporary may be created; since control + * never returns, it may never be destructed and leak. */ + static char error[256]; + strncpy( error, sStr, sizeof(error) ); + error[sizeof(error)-1] = 0; + png_error( pPng, error ); +} + +static void RageFile_png_write( png_struct *pPng, png_byte *pData, png_size_t iSize ) +{ + RageFile *pFile = (RageFile *) png_get_io_ptr(pPng); + + int iGot = pFile->Write( pData, iSize ); + if( iGot == -1 ) + SafePngError( pPng, pFile->GetError() ); +} + +static void RageFile_png_flush( png_struct *pPng ) +{ + RageFile *pFile = (RageFile *) png_get_io_ptr(pPng); + + int iGot = pFile->Flush(); + if( iGot == -1 ) + SafePngError( pPng, pFile->GetError() ); +} + +struct error_info +{ + char *szErr; +}; + +static void PNG_Error( png_struct *pPng, const char *szError ) +{ + error_info *pInfo = (error_info *) png_get_error_ptr(pPng); + strncpy( pInfo->szErr, szError, 1024 ); + pInfo->szErr[1023] = 0; + longjmp( png_jmpbuf(pPng), 1 ); +} + +static void PNG_Warning( png_struct *png, const char *warning ) +{ + LOG->Trace( "saving PNG: warning: %s", warning ); +} + +/* Since libpng forces us to use longjmp, this function shouldn't create any C++ + * objects, and needs to watch out for memleaks. */ +static bool RageSurface_Save_PNG( RageFile &f, char szErrorbuf[1024], RageSurface *pImgIn ) +{ + bool bAlpha = pImgIn->format->Amask != 0; + RageSurface *pImg; + bool bDeleteImg = RageSurfaceUtils::ConvertSurface( pImgIn, pImg, pImgIn->w, pImgIn->h, 32, + Swap32BE( 0xFF000000 ), + Swap32BE( 0x00FF0000 ), + Swap32BE( 0x0000FF00 ), + Swap32BE( 0x000000FF ) ); + if( !bDeleteImg ) + pImg = pImgIn; + + error_info error; + error.szErr = szErrorbuf; + + png_struct *pPng = png_create_write_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning ); + if( pPng == NULL ) + { + sprintf( szErrorbuf, "creating png_create_write_struct failed"); + return false; + } + + png_info *pInfo = png_create_info_struct(pPng); + if( pInfo == NULL ) + { + png_destroy_read_struct( &pPng, NULL, NULL ); + if( bDeleteImg ) + delete pImg; + sprintf( szErrorbuf, "creating png_create_info_struct failed"); + return false; + } + + if( setjmp(png_jmpbuf(pPng)) ) + { + png_destroy_read_struct( &pPng, &pInfo, NULL ); + return false; + } + + png_set_write_fn( pPng, &f, RageFile_png_write, RageFile_png_flush ); + png_set_compression_level( pPng, 1 ); + + png_set_IHDR( pPng, pInfo, pImg->w, pImg->h, 8, bAlpha? PNG_COLOR_TYPE_RGBA:PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE ); + + png_write_info( pPng, pInfo ); + png_set_filler( pPng, 0, PNG_FILLER_AFTER ); + + png_byte *pixels = (png_byte *) pImg->pixels; + for( int y = 0; y < pImg->h; y++ ) + png_write_row( pPng, pixels + pImg->pitch*y ); + + png_write_end( pPng, pInfo ); + png_destroy_write_struct( &pPng, &pInfo ); + + /* Free the converted image. */ + if( bDeleteImg ) + delete pImg; + + return true; +} + +bool RageSurfaceUtils::SavePNG( RageSurface *pImg, RageFile &f, RString &sError ) +{ + char szErrorBuf[1024]; + if( !RageSurface_Save_PNG(f, szErrorBuf, pImg) ) + { + sError = szErrorBuf; + return false; + } + + return true; +} + +/* + * (c) 2004-2006 Glenn Maynard + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/arch/InputHandler/InputHandler_Linux_Event.cpp b/src/arch/InputHandler/InputHandler_Linux_Event.cpp index 6c944f9a29..9fdcb473ee 100644 --- a/src/arch/InputHandler/InputHandler_Linux_Event.cpp +++ b/src/arch/InputHandler/InputHandler_Linux_Event.cpp @@ -1,447 +1,447 @@ -#include "global.h" -#include "InputHandler_Linux_Event.h" -#include "RageLog.h" -#include "RageUtil.h" - -#include <unistd.h> -#include <fcntl.h> - -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <linux/input.h> - -REGISTER_INPUT_HANDLER_CLASS2( Event, Linux_Event ); - -bool InputHandler_Linux_Event::m_bFoundAnyJoysticks; - -static RString BustypeToString( int iBus ) -{ - switch( iBus ) - { -// case BUS_ADB: -// case BUS_AMIGA: return "amiga input"; - case BUS_BLUETOOTH: return "Bluetooth"; - case BUS_GAMEPORT: return "gameport"; -// case BUS_HIL: -// case BUS_HOST: -// case BUS_I2C: - case BUS_I8042: return "keyboard"; - case BUS_ISA: return "ISA"; - case BUS_ISAPNP: return "ISAPNP"; - case BUS_PARPORT: return "parallel port"; - case BUS_PCI: return "PCI"; - case BUS_RS232: return "serial port"; - case BUS_USB: return "USB"; - case BUS_XTKBD: return "XT keyboard"; - default: return ssprintf("unknown bus %x", iBus); - } -} - -struct EventDevice -{ - EventDevice(); - ~EventDevice(); - bool Open( RString sFile, InputDevice dev ); - bool IsOpen() const { return m_iFD != -1; } - void Close() - { - if( m_iFD != -1 ) - close( m_iFD ); - m_iFD = -1; - } - - int m_iFD; - RString m_sPath; - RString m_sName; - InputDevice m_Dev; - - int aiAbsMin[ABS_MAX]; - int aiAbsMax[ABS_MAX]; - DeviceButton aiAbsMappingHigh[ABS_MAX]; - DeviceButton aiAbsMappingLow[ABS_MAX]; -}; - -static vector<EventDevice *> g_apEventDevices; - -/* Return true if the numbered event device exists. sysfs may not always be - * there; return false if we don't know. */ -static bool EventDeviceExists( int iNum ) -{ - RString sDir = ssprintf( "/sys/class" ); - struct stat st; - if( stat(sDir, &st) == -1 ) - return true; - - RString sFile = ssprintf( "/sys/class/input/event%i", iNum ); - return stat(sFile, &st) == 0; -} - -static bool BitIsSet( const uint8_t *pArray, uint32_t iBit ) -{ - return !!(pArray[iBit/8] & (1<<(iBit%8))); -} - -EventDevice::EventDevice() -{ - m_iFD = -1; -} - -bool EventDevice::Open( RString sFile, InputDevice dev ) -{ - m_sPath = sFile; - m_Dev = dev; - m_iFD = open( sFile, O_RDWR ); - if( m_iFD == -1 ) - { - if( errno == ENODEV ) - return false; - - if( !EventDeviceExists(m_iFD) ) - return false; - - LOG->Warn( "Error opening %s: %s", sFile.c_str(), strerror(errno) ); - return false; - } - - static bool bLogged = false; - if( !bLogged ) - { - bLogged = true; - int iVersion; - if( ioctl(m_iFD, EVIOCGVERSION, &iVersion) == -1 ) - LOG->Warn( "ioctl(EVIOCGVERSION): %s", strerror(errno) ); - else - LOG->Info( "Event driver: v%i.%i.%i", (iVersion >> 16) & 0xFF, (iVersion >> 8) & 0xFF, iVersion & 0xFF ); - } - - char szName[1024]; - if( ioctl(m_iFD, EVIOCGNAME(sizeof(szName)), szName) == -1 ) - { - LOG->Warn( "ioctl(EVIOCGNAME): %s", strerror(errno) ); - - m_sName = "(unknown)"; - } - else - { - m_sName = szName; - } - - input_id DevInfo; - if( ioctl(m_iFD, EVIOCGID, &DevInfo) == -1 ) - { - LOG->Warn( "ioctl(EVIOCGID): %s", strerror(errno) ); - } - else - { - LOG->Info( "Input device: %s: %s device, ID %04x:%04x, version %x: %s", sFile.c_str(), - BustypeToString(DevInfo.bustype).c_str(), DevInfo.vendor, DevInfo.product, - DevInfo.version, m_sName.c_str() ); - } - - uint8_t iABSMask[ABS_MAX/8 + 1]; - memset( iABSMask, 0, sizeof(iABSMask) ); - if( ioctl(m_iFD, EVIOCGBIT(EV_ABS, sizeof(iABSMask)), iABSMask) < 0 ) - LOG->Warn( "ioctl(EVIOCGBIT(EV_ABS)): %s", strerror(errno) ); - - if( !BitIsSet(iABSMask, ABS_X) && !BitIsSet(iABSMask, ABS_THROTTLE) && !BitIsSet(iABSMask, ABS_WHEEL) ) - { - LOG->Info( " Not a joystick; ignored" ); - Close(); - return false; - } - - uint8_t iKeyMask[KEY_MAX/8 + 1]; - memset( iKeyMask, 0, sizeof(iKeyMask) ); - if( ioctl(m_iFD, EVIOCGBIT(EV_KEY, sizeof(iKeyMask)), iKeyMask) < 0 ) - LOG->Warn( "ioctl(EVIOCGBIT(EV_KEY)): %s", strerror(errno) ); - - uint8_t iEventTypes[EV_MAX/8]; - memset( iEventTypes, 0, sizeof(iEventTypes) ); - if( ioctl(m_iFD, EVIOCGBIT(0, EV_MAX), iEventTypes) == -1 ) - LOG->Warn( "ioctl(EV_MAX): %s", strerror(errno) ); - - { - vector<RString> setEventTypes; - - if( BitIsSet(iEventTypes, EV_SYN) ) setEventTypes.push_back( "syn" ); - if( BitIsSet(iEventTypes, EV_KEY) ) setEventTypes.push_back( "key" ); - if( BitIsSet(iEventTypes, EV_REL) ) setEventTypes.push_back( "rel" ); - if( BitIsSet(iEventTypes, EV_ABS) ) setEventTypes.push_back( "abs" ); - if( BitIsSet(iEventTypes, EV_MSC) ) setEventTypes.push_back( "misc" ); - if( BitIsSet(iEventTypes, EV_SW) ) setEventTypes.push_back( "sw" ); - if( BitIsSet(iEventTypes, EV_LED) ) setEventTypes.push_back( "led" ); - if( BitIsSet(iEventTypes, EV_SND) ) setEventTypes.push_back( "snd" ); - if( BitIsSet(iEventTypes, EV_REP) ) setEventTypes.push_back( "rep" ); - if( BitIsSet(iEventTypes, EV_FF) ) setEventTypes.push_back( "ff" ); - if( BitIsSet(iEventTypes, EV_PWR) ) setEventTypes.push_back( "pwr" ); - if( BitIsSet(iEventTypes, EV_FF_STATUS) ) setEventTypes.push_back( "ff_status" ); - - LOG->Info( " Event types: %s", join(", ", setEventTypes).c_str() ); - } - - int iTotalKeys = 0; - for( int i = 0; i < KEY_MAX; ++i ) - { - if( !BitIsSet(iKeyMask, i) ) - continue; - ++iTotalKeys; - } - - int iTotalAxes = 0; - const DeviceButton iExtraAxes[] = { JOY_LEFT_2, JOY_UP_2, JOY_AUX_1, JOY_AUX_3 }; - int iNextExtraAxis = 0; - for( int i = 0; i < ABS_MAX; ++i ) - { - if( !BitIsSet(iABSMask, i) ) - continue; - struct input_absinfo absinfo; - if( ioctl(m_iFD, EVIOCGABS(i), &absinfo) < 0 ) - { - LOG->Warn( "ioctl(EVIOCGABS): %s", strerror(errno) ); - continue; - } - - //LOG->Info( " Axis %i: min: %i; max: %i; fuzz: %i; flat: %i", - // i, absinfo.minimum, absinfo.maximum, absinfo.fuzz, absinfo.flat ); - aiAbsMin[i] = absinfo.minimum; - aiAbsMax[i] = absinfo.maximum; - aiAbsMappingHigh[i] = enum_add2(JOY_RIGHT, 2*i); - aiAbsMappingLow[i] = enum_add2(JOY_LEFT, 2*i); - - if( i == ABS_X ) - { - aiAbsMappingHigh[i] = JOY_RIGHT; - aiAbsMappingLow[i] = JOY_LEFT; - } - else if( i == ABS_Y ) - { - aiAbsMappingHigh[i] = JOY_DOWN; - aiAbsMappingLow[i] = JOY_UP; - } - else if( i == ABS_Z ) - { - aiAbsMappingHigh[i] = JOY_Z_DOWN; - aiAbsMappingLow[i] = JOY_Z_UP; - } - else if( i == ABS_RX ) - { - aiAbsMappingHigh[i] = JOY_ROT_RIGHT; - aiAbsMappingLow[i] = JOY_ROT_LEFT; - } - else if( i == ABS_RY ) - { - aiAbsMappingHigh[i] = JOY_ROT_DOWN; - aiAbsMappingLow[i] = JOY_ROT_UP; - } - else if( i == ABS_RZ ) - { - aiAbsMappingHigh[i] = JOY_ROT_Z_DOWN; - aiAbsMappingLow[i] = JOY_ROT_Z_UP; - } - else if( i == ABS_HAT0X ) - { - aiAbsMappingHigh[i] = JOY_HAT_RIGHT; - aiAbsMappingLow[i] = JOY_HAT_LEFT; - } - else if( i == ABS_HAT0Y ) - { - aiAbsMappingHigh[i] = JOY_HAT_UP; - aiAbsMappingLow[i] = JOY_HAT_DOWN; - } - else - { - if( iNextExtraAxis < (int) ARRAYLEN(iExtraAxes) ) - { - aiAbsMappingLow[i] = iExtraAxes[iNextExtraAxis]; - aiAbsMappingHigh[i] = enum_add2( aiAbsMappingLow[i], 1 ); - ++iNextExtraAxis; - } - } - - ++iTotalAxes; - } - LOG->Info( " Total keys: %i; total axes: %i", iTotalKeys, iTotalAxes ); - - return true; -} - -EventDevice::~EventDevice() -{ - Close(); -} - -InputHandler_Linux_Event::InputHandler_Linux_Event() -{ - if( InputHandler_Linux_Event::m_bFoundAnyJoysticks ) - { - LOG->Trace( "InputHandler_Linux_Event disabled (joystick driver already loaded)" ); - return; - } - - /* Permission problems are likely. We want to warn about them only if there's actually - * an underlying device, but if we can't open the device, the only way we can tell if - * there'd be anything there is sysfs. That won't always be there. */ - m_bFoundAnyJoysticks = false; - InputDevice NextDevice = DEVICE_JOY1; - for( int i = 0; i < 64; ++i ) - { - RString sFile = ssprintf( "/dev/input/event%i", i ); - - g_apEventDevices.push_back( new EventDevice ); - EventDevice *pDev = g_apEventDevices.back(); - if( !pDev->Open(sFile, NextDevice) ) - { - delete pDev; - g_apEventDevices.pop_back(); - continue; - } - - NextDevice = enum_add2(NextDevice, 1); - m_bFoundAnyJoysticks = true; - } - - m_bShutdown = false; - - if( m_bFoundAnyJoysticks ) - { - m_InputThread.SetName( "Event input thread" ); - m_InputThread.Create( InputThread_Start, this ); - - /* We loaded joysticks, so disable joydev. */ - } -} - -InputHandler_Linux_Event::~InputHandler_Linux_Event() -{ - if( m_InputThread.IsCreated() ) - { - m_bShutdown = true; - LOG->Trace( "Shutting down joystick thread ..." ); - m_InputThread.Wait(); - LOG->Trace( "Joystick thread shut down." ); - } - - for( int i = 0; i < (int) g_apEventDevices.size(); ++i ) - delete g_apEventDevices[i]; - g_apEventDevices.clear(); -} - -int InputHandler_Linux_Event::InputThread_Start( void *p ) -{ - ((InputHandler_Linux_Event *) p)->InputThread(); - return 0; -} - -void InputHandler_Linux_Event::InputThread() -{ - while( !m_bShutdown ) - { - fd_set fdset; - FD_ZERO( &fdset ); - int iMaxFD = -1; - - for( int i = 0; i < (int) g_apEventDevices.size(); ++i ) - { - int iFD = g_apEventDevices[i]->m_iFD; - if( !g_apEventDevices[i]->IsOpen() ) - continue; - - FD_SET( iFD, &fdset ); - iMaxFD = max( iMaxFD, iFD ); - } - - if( iMaxFD == -1 ) - break; - - struct timeval zero = {0,100000}; - if( select(iMaxFD+1, &fdset, NULL, NULL, &zero) <= 0 ) - continue; - RageTimer now; - - for( int i = 0; i < (int) g_apEventDevices.size(); ++i ) - { - if( !g_apEventDevices[i]->IsOpen() ) - continue; - - if( !FD_ISSET(g_apEventDevices[i]->m_iFD, &fdset) ) - continue; - - input_event event; - int ret = read( g_apEventDevices[i]->m_iFD, &event, sizeof(event) ); - if( ret == -1 ) - { - LOG->Warn( "Error reading from %s: %s; disabled", g_apEventDevices[i]->m_sPath.c_str(), strerror(errno) ); - g_apEventDevices[i]->Close(); - continue; - } - - if( ret != sizeof(event) ) - { - LOG->Warn("Unexpected packet (size %i != %i) from joystick %i; disabled", ret, (int)sizeof(event), i); - g_apEventDevices[i]->Close(); - continue; - } - - switch (event.type) { - case EV_KEY: { - int iNum = event.code; - // In 2.6.11 using an EMS USB2, the event number for P1 Tri (the first button) - // is being reported as 32 instead of 0. Correct for this. - wrap( iNum, 32 ); // max number of joystick buttons. Make this a constant? - ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, enum_add2(JOY_BUTTON_1, iNum), event.value != 0, now) ); - break; - } - - case EV_ABS: { - ASSERT_M( event.code < ABS_MAX, ssprintf("%i", event.code) ); - DeviceButton neg = g_apEventDevices[i]->aiAbsMappingLow[event.code]; - DeviceButton pos = g_apEventDevices[i]->aiAbsMappingHigh[event.code]; - - float l = SCALE( int(event.value), (float) g_apEventDevices[i]->aiAbsMin[i], (float) g_apEventDevices[i]->aiAbsMax[i], -1.0f, 1.0f ); - ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, neg, max(-l,0), now) ); - ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, pos, max(+l,0), now) ); - break; - } - } - - } - - } - - InputHandler::UpdateTimer(); -} - -void InputHandler_Linux_Event::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevicesOut ) -{ - for( unsigned i = 0; i < g_apEventDevices.size(); ++i ) - { - EventDevice *pDev = g_apEventDevices[i]; - vDevicesOut.push_back( InputDeviceInfo(pDev->m_Dev, pDev->m_sName) ); - } -} - -/* - * (c) 2003-2008 Glenn Maynard - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +#include "global.h" +#include "InputHandler_Linux_Event.h" +#include "RageLog.h" +#include "RageUtil.h" + +#include <unistd.h> +#include <fcntl.h> + +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <linux/input.h> + +REGISTER_INPUT_HANDLER_CLASS2( Event, Linux_Event ); + +bool InputHandler_Linux_Event::m_bFoundAnyJoysticks; + +static RString BustypeToString( int iBus ) +{ + switch( iBus ) + { +// case BUS_ADB: +// case BUS_AMIGA: return "amiga input"; + case BUS_BLUETOOTH: return "Bluetooth"; + case BUS_GAMEPORT: return "gameport"; +// case BUS_HIL: +// case BUS_HOST: +// case BUS_I2C: + case BUS_I8042: return "keyboard"; + case BUS_ISA: return "ISA"; + case BUS_ISAPNP: return "ISAPNP"; + case BUS_PARPORT: return "parallel port"; + case BUS_PCI: return "PCI"; + case BUS_RS232: return "serial port"; + case BUS_USB: return "USB"; + case BUS_XTKBD: return "XT keyboard"; + default: return ssprintf("unknown bus %x", iBus); + } +} + +struct EventDevice +{ + EventDevice(); + ~EventDevice(); + bool Open( RString sFile, InputDevice dev ); + bool IsOpen() const { return m_iFD != -1; } + void Close() + { + if( m_iFD != -1 ) + close( m_iFD ); + m_iFD = -1; + } + + int m_iFD; + RString m_sPath; + RString m_sName; + InputDevice m_Dev; + + int aiAbsMin[ABS_MAX]; + int aiAbsMax[ABS_MAX]; + DeviceButton aiAbsMappingHigh[ABS_MAX]; + DeviceButton aiAbsMappingLow[ABS_MAX]; +}; + +static vector<EventDevice *> g_apEventDevices; + +/* Return true if the numbered event device exists. sysfs may not always be + * there; return false if we don't know. */ +static bool EventDeviceExists( int iNum ) +{ + RString sDir = ssprintf( "/sys/class" ); + struct stat st; + if( stat(sDir, &st) == -1 ) + return true; + + RString sFile = ssprintf( "/sys/class/input/event%i", iNum ); + return stat(sFile, &st) == 0; +} + +static bool BitIsSet( const uint8_t *pArray, uint32_t iBit ) +{ + return !!(pArray[iBit/8] & (1<<(iBit%8))); +} + +EventDevice::EventDevice() +{ + m_iFD = -1; +} + +bool EventDevice::Open( RString sFile, InputDevice dev ) +{ + m_sPath = sFile; + m_Dev = dev; + m_iFD = open( sFile, O_RDWR ); + if( m_iFD == -1 ) + { + if( errno == ENODEV ) + return false; + + if( !EventDeviceExists(m_iFD) ) + return false; + + LOG->Warn( "Error opening %s: %s", sFile.c_str(), strerror(errno) ); + return false; + } + + static bool bLogged = false; + if( !bLogged ) + { + bLogged = true; + int iVersion; + if( ioctl(m_iFD, EVIOCGVERSION, &iVersion) == -1 ) + LOG->Warn( "ioctl(EVIOCGVERSION): %s", strerror(errno) ); + else + LOG->Info( "Event driver: v%i.%i.%i", (iVersion >> 16) & 0xFF, (iVersion >> 8) & 0xFF, iVersion & 0xFF ); + } + + char szName[1024]; + if( ioctl(m_iFD, EVIOCGNAME(sizeof(szName)), szName) == -1 ) + { + LOG->Warn( "ioctl(EVIOCGNAME): %s", strerror(errno) ); + + m_sName = "(unknown)"; + } + else + { + m_sName = szName; + } + + input_id DevInfo; + if( ioctl(m_iFD, EVIOCGID, &DevInfo) == -1 ) + { + LOG->Warn( "ioctl(EVIOCGID): %s", strerror(errno) ); + } + else + { + LOG->Info( "Input device: %s: %s device, ID %04x:%04x, version %x: %s", sFile.c_str(), + BustypeToString(DevInfo.bustype).c_str(), DevInfo.vendor, DevInfo.product, + DevInfo.version, m_sName.c_str() ); + } + + uint8_t iABSMask[ABS_MAX/8 + 1]; + memset( iABSMask, 0, sizeof(iABSMask) ); + if( ioctl(m_iFD, EVIOCGBIT(EV_ABS, sizeof(iABSMask)), iABSMask) < 0 ) + LOG->Warn( "ioctl(EVIOCGBIT(EV_ABS)): %s", strerror(errno) ); + + if( !BitIsSet(iABSMask, ABS_X) && !BitIsSet(iABSMask, ABS_THROTTLE) && !BitIsSet(iABSMask, ABS_WHEEL) ) + { + LOG->Info( " Not a joystick; ignored" ); + Close(); + return false; + } + + uint8_t iKeyMask[KEY_MAX/8 + 1]; + memset( iKeyMask, 0, sizeof(iKeyMask) ); + if( ioctl(m_iFD, EVIOCGBIT(EV_KEY, sizeof(iKeyMask)), iKeyMask) < 0 ) + LOG->Warn( "ioctl(EVIOCGBIT(EV_KEY)): %s", strerror(errno) ); + + uint8_t iEventTypes[EV_MAX/8]; + memset( iEventTypes, 0, sizeof(iEventTypes) ); + if( ioctl(m_iFD, EVIOCGBIT(0, EV_MAX), iEventTypes) == -1 ) + LOG->Warn( "ioctl(EV_MAX): %s", strerror(errno) ); + + { + vector<RString> setEventTypes; + + if( BitIsSet(iEventTypes, EV_SYN) ) setEventTypes.push_back( "syn" ); + if( BitIsSet(iEventTypes, EV_KEY) ) setEventTypes.push_back( "key" ); + if( BitIsSet(iEventTypes, EV_REL) ) setEventTypes.push_back( "rel" ); + if( BitIsSet(iEventTypes, EV_ABS) ) setEventTypes.push_back( "abs" ); + if( BitIsSet(iEventTypes, EV_MSC) ) setEventTypes.push_back( "misc" ); + if( BitIsSet(iEventTypes, EV_SW) ) setEventTypes.push_back( "sw" ); + if( BitIsSet(iEventTypes, EV_LED) ) setEventTypes.push_back( "led" ); + if( BitIsSet(iEventTypes, EV_SND) ) setEventTypes.push_back( "snd" ); + if( BitIsSet(iEventTypes, EV_REP) ) setEventTypes.push_back( "rep" ); + if( BitIsSet(iEventTypes, EV_FF) ) setEventTypes.push_back( "ff" ); + if( BitIsSet(iEventTypes, EV_PWR) ) setEventTypes.push_back( "pwr" ); + if( BitIsSet(iEventTypes, EV_FF_STATUS) ) setEventTypes.push_back( "ff_status" ); + + LOG->Info( " Event types: %s", join(", ", setEventTypes).c_str() ); + } + + int iTotalKeys = 0; + for( int i = 0; i < KEY_MAX; ++i ) + { + if( !BitIsSet(iKeyMask, i) ) + continue; + ++iTotalKeys; + } + + int iTotalAxes = 0; + const DeviceButton iExtraAxes[] = { JOY_LEFT_2, JOY_UP_2, JOY_AUX_1, JOY_AUX_3 }; + int iNextExtraAxis = 0; + for( int i = 0; i < ABS_MAX; ++i ) + { + if( !BitIsSet(iABSMask, i) ) + continue; + struct input_absinfo absinfo; + if( ioctl(m_iFD, EVIOCGABS(i), &absinfo) < 0 ) + { + LOG->Warn( "ioctl(EVIOCGABS): %s", strerror(errno) ); + continue; + } + + //LOG->Info( " Axis %i: min: %i; max: %i; fuzz: %i; flat: %i", + // i, absinfo.minimum, absinfo.maximum, absinfo.fuzz, absinfo.flat ); + aiAbsMin[i] = absinfo.minimum; + aiAbsMax[i] = absinfo.maximum; + aiAbsMappingHigh[i] = enum_add2(JOY_RIGHT, 2*i); + aiAbsMappingLow[i] = enum_add2(JOY_LEFT, 2*i); + + if( i == ABS_X ) + { + aiAbsMappingHigh[i] = JOY_RIGHT; + aiAbsMappingLow[i] = JOY_LEFT; + } + else if( i == ABS_Y ) + { + aiAbsMappingHigh[i] = JOY_DOWN; + aiAbsMappingLow[i] = JOY_UP; + } + else if( i == ABS_Z ) + { + aiAbsMappingHigh[i] = JOY_Z_DOWN; + aiAbsMappingLow[i] = JOY_Z_UP; + } + else if( i == ABS_RX ) + { + aiAbsMappingHigh[i] = JOY_ROT_RIGHT; + aiAbsMappingLow[i] = JOY_ROT_LEFT; + } + else if( i == ABS_RY ) + { + aiAbsMappingHigh[i] = JOY_ROT_DOWN; + aiAbsMappingLow[i] = JOY_ROT_UP; + } + else if( i == ABS_RZ ) + { + aiAbsMappingHigh[i] = JOY_ROT_Z_DOWN; + aiAbsMappingLow[i] = JOY_ROT_Z_UP; + } + else if( i == ABS_HAT0X ) + { + aiAbsMappingHigh[i] = JOY_HAT_RIGHT; + aiAbsMappingLow[i] = JOY_HAT_LEFT; + } + else if( i == ABS_HAT0Y ) + { + aiAbsMappingHigh[i] = JOY_HAT_UP; + aiAbsMappingLow[i] = JOY_HAT_DOWN; + } + else + { + if( iNextExtraAxis < (int) ARRAYLEN(iExtraAxes) ) + { + aiAbsMappingLow[i] = iExtraAxes[iNextExtraAxis]; + aiAbsMappingHigh[i] = enum_add2( aiAbsMappingLow[i], 1 ); + ++iNextExtraAxis; + } + } + + ++iTotalAxes; + } + LOG->Info( " Total keys: %i; total axes: %i", iTotalKeys, iTotalAxes ); + + return true; +} + +EventDevice::~EventDevice() +{ + Close(); +} + +InputHandler_Linux_Event::InputHandler_Linux_Event() +{ + if( InputHandler_Linux_Event::m_bFoundAnyJoysticks ) + { + LOG->Trace( "InputHandler_Linux_Event disabled (joystick driver already loaded)" ); + return; + } + + /* Permission problems are likely. We want to warn about them only if there's actually + * an underlying device, but if we can't open the device, the only way we can tell if + * there'd be anything there is sysfs. That won't always be there. */ + m_bFoundAnyJoysticks = false; + InputDevice NextDevice = DEVICE_JOY1; + for( int i = 0; i < 64; ++i ) + { + RString sFile = ssprintf( "/dev/input/event%i", i ); + + g_apEventDevices.push_back( new EventDevice ); + EventDevice *pDev = g_apEventDevices.back(); + if( !pDev->Open(sFile, NextDevice) ) + { + delete pDev; + g_apEventDevices.pop_back(); + continue; + } + + NextDevice = enum_add2(NextDevice, 1); + m_bFoundAnyJoysticks = true; + } + + m_bShutdown = false; + + if( m_bFoundAnyJoysticks ) + { + m_InputThread.SetName( "Event input thread" ); + m_InputThread.Create( InputThread_Start, this ); + + /* We loaded joysticks, so disable joydev. */ + } +} + +InputHandler_Linux_Event::~InputHandler_Linux_Event() +{ + if( m_InputThread.IsCreated() ) + { + m_bShutdown = true; + LOG->Trace( "Shutting down joystick thread ..." ); + m_InputThread.Wait(); + LOG->Trace( "Joystick thread shut down." ); + } + + for( int i = 0; i < (int) g_apEventDevices.size(); ++i ) + delete g_apEventDevices[i]; + g_apEventDevices.clear(); +} + +int InputHandler_Linux_Event::InputThread_Start( void *p ) +{ + ((InputHandler_Linux_Event *) p)->InputThread(); + return 0; +} + +void InputHandler_Linux_Event::InputThread() +{ + while( !m_bShutdown ) + { + fd_set fdset; + FD_ZERO( &fdset ); + int iMaxFD = -1; + + for( int i = 0; i < (int) g_apEventDevices.size(); ++i ) + { + int iFD = g_apEventDevices[i]->m_iFD; + if( !g_apEventDevices[i]->IsOpen() ) + continue; + + FD_SET( iFD, &fdset ); + iMaxFD = max( iMaxFD, iFD ); + } + + if( iMaxFD == -1 ) + break; + + struct timeval zero = {0,100000}; + if( select(iMaxFD+1, &fdset, NULL, NULL, &zero) <= 0 ) + continue; + RageTimer now; + + for( int i = 0; i < (int) g_apEventDevices.size(); ++i ) + { + if( !g_apEventDevices[i]->IsOpen() ) + continue; + + if( !FD_ISSET(g_apEventDevices[i]->m_iFD, &fdset) ) + continue; + + input_event event; + int ret = read( g_apEventDevices[i]->m_iFD, &event, sizeof(event) ); + if( ret == -1 ) + { + LOG->Warn( "Error reading from %s: %s; disabled", g_apEventDevices[i]->m_sPath.c_str(), strerror(errno) ); + g_apEventDevices[i]->Close(); + continue; + } + + if( ret != sizeof(event) ) + { + LOG->Warn("Unexpected packet (size %i != %i) from joystick %i; disabled", ret, (int)sizeof(event), i); + g_apEventDevices[i]->Close(); + continue; + } + + switch (event.type) { + case EV_KEY: { + int iNum = event.code; + // In 2.6.11 using an EMS USB2, the event number for P1 Tri (the first button) + // is being reported as 32 instead of 0. Correct for this. + wrap( iNum, 32 ); // max number of joystick buttons. Make this a constant? + ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, enum_add2(JOY_BUTTON_1, iNum), event.value != 0, now) ); + break; + } + + case EV_ABS: { + ASSERT_M( event.code < ABS_MAX, ssprintf("%i", event.code) ); + DeviceButton neg = g_apEventDevices[i]->aiAbsMappingLow[event.code]; + DeviceButton pos = g_apEventDevices[i]->aiAbsMappingHigh[event.code]; + + float l = SCALE( int(event.value), (float) g_apEventDevices[i]->aiAbsMin[i], (float) g_apEventDevices[i]->aiAbsMax[i], -1.0f, 1.0f ); + ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, neg, max(-l,0), now) ); + ButtonPressed( DeviceInput(g_apEventDevices[i]->m_Dev, pos, max(+l,0), now) ); + break; + } + } + + } + + } + + InputHandler::UpdateTimer(); +} + +void InputHandler_Linux_Event::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevicesOut ) +{ + for( unsigned i = 0; i < g_apEventDevices.size(); ++i ) + { + EventDevice *pDev = g_apEventDevices[i]; + vDevicesOut.push_back( InputDeviceInfo(pDev->m_Dev, pDev->m_sName) ); + } +} + +/* + * (c) 2003-2008 Glenn Maynard + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/arch/InputHandler/InputHandler_Linux_Joystick.cpp b/src/arch/InputHandler/InputHandler_Linux_Joystick.cpp index 2fc7392d0c..92a0f58929 100644 --- a/src/arch/InputHandler/InputHandler_Linux_Joystick.cpp +++ b/src/arch/InputHandler/InputHandler_Linux_Joystick.cpp @@ -1,227 +1,227 @@ -#include "global.h" -#include "InputHandler_Linux_Joystick.h" -#include "InputHandler_Linux_Event.h" // for m_bFoundAnyJoysticks -#include "RageLog.h" -#include "RageUtil.h" - -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> - -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <linux/joystick.h> - -#include <set> - -REGISTER_INPUT_HANDLER_CLASS2( Joystick, Linux_Joystick ); - -static const char *Paths[InputHandler_Linux_Joystick::NUM_JOYSTICKS] = -{ - "/dev/js0", - "/dev/js1", - "/dev/input/js0", - "/dev/input/js1", -}; - -InputHandler_Linux_Joystick::InputHandler_Linux_Joystick() -{ - LOG->Trace( "InputHandler_Linux_Joystick::InputHandler_Linux_Joystick" ); - for(int i = 0; i < NUM_JOYSTICKS; ++i) - fds[i] = -1; - - if( InputHandler_Linux_Event::m_bFoundAnyJoysticks ) - { - LOG->Trace( "InputHandler_Linux_Joystick disabled (joystick driver already loaded)" ); - return; - } - - /* We check both eg. /dev/js0 and /dev/input/js0. If both exist, they're probably - * the same device; keep track of device IDs so we don't open the same joystick - * twice. */ - set< pair<int,int> > devices; - bool bFoundAnyJoysticks = false; - - for(int i = 0; i < NUM_JOYSTICKS; ++i) - { - struct stat st; - if( stat( Paths[i], &st ) == -1 ) - { - if( errno != ENOENT ) - LOG->Warn( "Couldn't stat %s: %s", Paths[i], strerror(errno) ); - continue; - } - - if( !S_ISCHR( st.st_mode ) ) - { - LOG->Warn( "Ignoring %s: not a character device", Paths[i] ); - continue; - } - - pair<int,int> dev( major(st.st_rdev), minor(st.st_rdev) ); - if( devices.find(dev) != devices.end() ) - continue; /* dupe */ - devices.insert( dev ); - - fds[i] = open( Paths[i], O_RDONLY ); - - if(fds[i] != -1) - { - char szName[1024]; - ZERO( szName ); - if( ioctl(fds[i], JSIOCGNAME(sizeof(szName)), szName) < 0 ) - m_sDescription[i] = ssprintf( "Unknown joystick at %s", Paths[i] ); - else - m_sDescription[i] = szName; - - LOG->Info("Opened %s", Paths[i]); - bFoundAnyJoysticks = true; - } - } - - m_bShutdown = false; - - if( bFoundAnyJoysticks ) - { - m_InputThread.SetName( "Joystick thread" ); - m_InputThread.Create( InputThread_Start, this ); - InputHandler_Linux_Event::m_bFoundAnyJoysticks = true; - } -} - -InputHandler_Linux_Joystick::~InputHandler_Linux_Joystick() -{ - if( m_InputThread.IsCreated() ) - { - m_bShutdown = true; - LOG->Trace( "Shutting down joystick thread ..." ); - m_InputThread.Wait(); - LOG->Trace( "Joystick thread shut down." ); - } - - for(int i = 0; i < NUM_JOYSTICKS; ++i) - if(fds[i] != -1) close(fds[i]); -} - -int InputHandler_Linux_Joystick::InputThread_Start( void *p ) -{ - ((InputHandler_Linux_Joystick *) p)->InputThread(); - return 0; -} - -void InputHandler_Linux_Joystick::InputThread() -{ - while( !m_bShutdown ) - { - fd_set fdset; - FD_ZERO(&fdset); - int max_fd = -1; - - for(int i = 0; i < NUM_JOYSTICKS; ++i) - { - if (fds[i] < 0) - continue; - - FD_SET(fds[i], &fdset); - max_fd = max(max_fd, fds[i]); - } - - if(max_fd == -1) - break; - - struct timeval zero = {0,100000}; - if( select(max_fd+1, &fdset, NULL, NULL, &zero) <= 0 ) - continue; - RageTimer now; - - printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"); - for(int i = 0; i < NUM_JOYSTICKS; ++i) - { - if( fds[i] == -1 ) - continue; - - if(!FD_ISSET(fds[i], &fdset)) - continue; - - js_event event; - int ret = read(fds[i], &event, sizeof(event)); - if(ret != sizeof(event)) - { - LOG->Warn("Unexpected packet (size %i != %i) from joystick %i; disabled", ret, (int)sizeof(event), i); - close(fds[i]); - fds[i] = -1; - continue; - } - - InputDevice id = InputDevice(DEVICE_JOY1 + i); - - event.type &= ~JS_EVENT_INIT; - switch (event.type) { - case JS_EVENT_BUTTON: { - int iNum = event.number; - // In 2.6.11 using an EMS USB2, the event number for P1 Tri (the first button) - // is being reported as 32 instead of 0. Correct for this. - wrap( iNum, 32 ); // max number of joystick buttons. Make this a constant? - ButtonPressed( DeviceInput(id, enum_add2(JOY_BUTTON_1, iNum), event.value, now) ); - break; - } - - case JS_EVENT_AXIS: { - DeviceButton neg = enum_add2(JOY_LEFT, 2*event.number); - DeviceButton pos = enum_add2(JOY_RIGHT, 2*event.number); - float l = SCALE( int(event.value), 0.0f, 32767, 0.0f, 1.0f ); - ButtonPressed( DeviceInput(id, neg, max(-l,0), now) ); - ButtonPressed( DeviceInput(id, pos, max(+l,0), now) ); - break; - } - - default: - LOG->Warn("Unexpected packet (type %i) from joystick %i; disabled", event.type, i); - close(fds[i]); - fds[i] = -1; - continue; - } - - } - - } - - InputHandler::UpdateTimer(); -} - -void InputHandler_Linux_Joystick::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevicesOut ) -{ - for(int i = 0; i < NUM_JOYSTICKS; ++i) - { - if (fds[i] < 0) - continue; - - vDevicesOut.push_back( InputDeviceInfo(InputDevice(DEVICE_JOY1+i), m_sDescription[i]) ); - } -} - -/* - * (c) 2003-2004 Glenn Maynard - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +#include "global.h" +#include "InputHandler_Linux_Joystick.h" +#include "InputHandler_Linux_Event.h" // for m_bFoundAnyJoysticks +#include "RageLog.h" +#include "RageUtil.h" + +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> + +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <linux/joystick.h> + +#include <set> + +REGISTER_INPUT_HANDLER_CLASS2( Joystick, Linux_Joystick ); + +static const char *Paths[InputHandler_Linux_Joystick::NUM_JOYSTICKS] = +{ + "/dev/js0", + "/dev/js1", + "/dev/input/js0", + "/dev/input/js1", +}; + +InputHandler_Linux_Joystick::InputHandler_Linux_Joystick() +{ + LOG->Trace( "InputHandler_Linux_Joystick::InputHandler_Linux_Joystick" ); + for(int i = 0; i < NUM_JOYSTICKS; ++i) + fds[i] = -1; + + if( InputHandler_Linux_Event::m_bFoundAnyJoysticks ) + { + LOG->Trace( "InputHandler_Linux_Joystick disabled (joystick driver already loaded)" ); + return; + } + + /* We check both eg. /dev/js0 and /dev/input/js0. If both exist, they're probably + * the same device; keep track of device IDs so we don't open the same joystick + * twice. */ + set< pair<int,int> > devices; + bool bFoundAnyJoysticks = false; + + for(int i = 0; i < NUM_JOYSTICKS; ++i) + { + struct stat st; + if( stat( Paths[i], &st ) == -1 ) + { + if( errno != ENOENT ) + LOG->Warn( "Couldn't stat %s: %s", Paths[i], strerror(errno) ); + continue; + } + + if( !S_ISCHR( st.st_mode ) ) + { + LOG->Warn( "Ignoring %s: not a character device", Paths[i] ); + continue; + } + + pair<int,int> dev( major(st.st_rdev), minor(st.st_rdev) ); + if( devices.find(dev) != devices.end() ) + continue; /* dupe */ + devices.insert( dev ); + + fds[i] = open( Paths[i], O_RDONLY ); + + if(fds[i] != -1) + { + char szName[1024]; + ZERO( szName ); + if( ioctl(fds[i], JSIOCGNAME(sizeof(szName)), szName) < 0 ) + m_sDescription[i] = ssprintf( "Unknown joystick at %s", Paths[i] ); + else + m_sDescription[i] = szName; + + LOG->Info("Opened %s", Paths[i]); + bFoundAnyJoysticks = true; + } + } + + m_bShutdown = false; + + if( bFoundAnyJoysticks ) + { + m_InputThread.SetName( "Joystick thread" ); + m_InputThread.Create( InputThread_Start, this ); + InputHandler_Linux_Event::m_bFoundAnyJoysticks = true; + } +} + +InputHandler_Linux_Joystick::~InputHandler_Linux_Joystick() +{ + if( m_InputThread.IsCreated() ) + { + m_bShutdown = true; + LOG->Trace( "Shutting down joystick thread ..." ); + m_InputThread.Wait(); + LOG->Trace( "Joystick thread shut down." ); + } + + for(int i = 0; i < NUM_JOYSTICKS; ++i) + if(fds[i] != -1) close(fds[i]); +} + +int InputHandler_Linux_Joystick::InputThread_Start( void *p ) +{ + ((InputHandler_Linux_Joystick *) p)->InputThread(); + return 0; +} + +void InputHandler_Linux_Joystick::InputThread() +{ + while( !m_bShutdown ) + { + fd_set fdset; + FD_ZERO(&fdset); + int max_fd = -1; + + for(int i = 0; i < NUM_JOYSTICKS; ++i) + { + if (fds[i] < 0) + continue; + + FD_SET(fds[i], &fdset); + max_fd = max(max_fd, fds[i]); + } + + if(max_fd == -1) + break; + + struct timeval zero = {0,100000}; + if( select(max_fd+1, &fdset, NULL, NULL, &zero) <= 0 ) + continue; + RageTimer now; + + printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"); + for(int i = 0; i < NUM_JOYSTICKS; ++i) + { + if( fds[i] == -1 ) + continue; + + if(!FD_ISSET(fds[i], &fdset)) + continue; + + js_event event; + int ret = read(fds[i], &event, sizeof(event)); + if(ret != sizeof(event)) + { + LOG->Warn("Unexpected packet (size %i != %i) from joystick %i; disabled", ret, (int)sizeof(event), i); + close(fds[i]); + fds[i] = -1; + continue; + } + + InputDevice id = InputDevice(DEVICE_JOY1 + i); + + event.type &= ~JS_EVENT_INIT; + switch (event.type) { + case JS_EVENT_BUTTON: { + int iNum = event.number; + // In 2.6.11 using an EMS USB2, the event number for P1 Tri (the first button) + // is being reported as 32 instead of 0. Correct for this. + wrap( iNum, 32 ); // max number of joystick buttons. Make this a constant? + ButtonPressed( DeviceInput(id, enum_add2(JOY_BUTTON_1, iNum), event.value, now) ); + break; + } + + case JS_EVENT_AXIS: { + DeviceButton neg = enum_add2(JOY_LEFT, 2*event.number); + DeviceButton pos = enum_add2(JOY_RIGHT, 2*event.number); + float l = SCALE( int(event.value), 0.0f, 32767, 0.0f, 1.0f ); + ButtonPressed( DeviceInput(id, neg, max(-l,0), now) ); + ButtonPressed( DeviceInput(id, pos, max(+l,0), now) ); + break; + } + + default: + LOG->Warn("Unexpected packet (type %i) from joystick %i; disabled", event.type, i); + close(fds[i]); + fds[i] = -1; + continue; + } + + } + + } + + InputHandler::UpdateTimer(); +} + +void InputHandler_Linux_Joystick::GetDevicesAndDescriptions( vector<InputDeviceInfo>& vDevicesOut ) +{ + for(int i = 0; i < NUM_JOYSTICKS; ++i) + { + if (fds[i] < 0) + continue; + + vDevicesOut.push_back( InputDeviceInfo(InputDevice(DEVICE_JOY1+i), m_sDescription[i]) ); + } +} + +/* + * (c) 2003-2004 Glenn Maynard + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/arch/LowLevelWindow/LowLevelWindow_X11.cpp b/src/arch/LowLevelWindow/LowLevelWindow_X11.cpp index 4311776ffe..91a6b7af9d 100644 --- a/src/arch/LowLevelWindow/LowLevelWindow_X11.cpp +++ b/src/arch/LowLevelWindow/LowLevelWindow_X11.cpp @@ -1,568 +1,568 @@ -#include "global.h" -#include "LowLevelWindow_X11.h" -#include "RageLog.h" -#include "RageException.h" -#include "archutils/Unix/X11Helper.h" -#include "PrefsManager.h" // XXX -#include "RageDisplay.h" // VideoModeParams -#include "DisplayResolutions.h" -#include "LocalizedString.h" - -#include "RageDisplay_OGL_Helpers.h" -using namespace RageDisplay_OGL_Helpers; -using namespace X11Helper; - -#include <stack> -#include <math.h> // ceil() -#define GLX_GLXEXT_PROTOTYPES -#include <GL/glx.h> // All sorts of stuff... -#include <X11/Xlib.h> -#include <X11/Xatom.h> -#include <X11/extensions/Xrandr.h> - -#if defined(HAVE_LIBXTST) -#include <X11/extensions/XTest.h> -#endif - -static GLXContext g_pContext = NULL; -static GLXContext g_pBackgroundContext = NULL; -static Window g_AltWindow = None; -static Rotation g_OldRotation; -static int g_iOldSize; -XRRScreenConfiguration *g_pScreenConfig = NULL; - -static LocalizedString FAILED_CONNECTION_XSERVER( "LowLevelWindow_X11", "Failed to establish a connection with the X server" ); -LowLevelWindow_X11::LowLevelWindow_X11() -{ - if( !OpenXConnection() ) - RageException::Throw( "%s", FAILED_CONNECTION_XSERVER.GetValue().c_str() ); - - const int iScreen = DefaultScreen( Dpy ); - int iXServerVersion = XVendorRelease( Dpy ); /* eg. 40201001 */ - int iMajor = iXServerVersion / 10000000; iXServerVersion %= 10000000; - int iMinor = iXServerVersion / 100000; iXServerVersion %= 100000; - int iRevision = iXServerVersion / 1000; iXServerVersion %= 1000; - int iPatch = iXServerVersion; - - - LOG->Info( "Display: %s (screen %i)", DisplayString(Dpy), iScreen ); - LOG->Info( "X server vendor: %s [%i.%i.%i.%i]", XServerVendor( Dpy ), iMajor, iMinor, iRevision, iPatch ); - LOG->Info( "Server GLX vendor: %s [%s]", glXQueryServerString( Dpy, iScreen, GLX_VENDOR ), glXQueryServerString( Dpy, iScreen, GLX_VERSION ) ); - LOG->Info( "Client GLX vendor: %s [%s]", glXGetClientString( Dpy, GLX_VENDOR ), glXGetClientString( Dpy, GLX_VERSION ) ); - m_bWasWindowed = true; - g_pScreenConfig = XRRGetScreenInfo( Dpy, RootWindow(Dpy, DefaultScreen(Dpy)) ); - g_iOldSize = XRRConfigCurrentConfiguration( g_pScreenConfig, &g_OldRotation ); -} - -LowLevelWindow_X11::~LowLevelWindow_X11() -{ - // Reset the display - if( !m_bWasWindowed ) - { - XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), g_iOldSize, g_OldRotation, CurrentTime ); - - XUngrabKeyboard( Dpy, CurrentTime ); - } - if( g_pContext ) - { - glXDestroyContext( Dpy, g_pContext ); - g_pContext = NULL; - } - if( g_pBackgroundContext ) - { - glXDestroyContext( Dpy, g_pBackgroundContext ); - g_pBackgroundContext = NULL; - } - XRRFreeScreenConfigInfo( g_pScreenConfig ); - g_pScreenConfig = NULL; - - XDestroyWindow( Dpy, Win ); - Win = None; - XDestroyWindow( Dpy, g_AltWindow ); - g_AltWindow = None; - CloseXConnection(); -} - -void *LowLevelWindow_X11::GetProcAddress( RString s ) -{ - // XXX: We should check whether glXGetProcAddress or - // glXGetProcAddressARB is available, and go by that, instead of - // assuming like this. - return (void*) glXGetProcAddressARB( (const GLubyte*) s.c_str() ); -} - -RString LowLevelWindow_X11::TryVideoMode( const VideoModeParams &p, bool &bNewDeviceOut ) -{ -#if defined(UNIX) - /* nVidia cards: - * - * This only works the first time we set up a window; after that, the - * drivers appear to cache the value, so you have to actually restart - * the program to change it again. - */ - static char buf[128]; - strcpy( buf, "__GL_SYNC_TO_VBLANK=" ); - strcat( buf, p.vsync?"1":"0" ); - putenv( buf ); -#endif - - if( g_pContext == NULL || p.bpp != CurrentParams.bpp || m_bWasWindowed != p.windowed ) - { - // Different depth, or we didn't make a window before. New context. - bNewDeviceOut = true; - - int visAttribs[32]; - int i = 0; - ASSERT( p.bpp == 16 || p.bpp == 32 ); - - if( p.bpp == 32 ) - { - visAttribs[i++] = GLX_RED_SIZE; visAttribs[i++] = 8; - visAttribs[i++] = GLX_GREEN_SIZE; visAttribs[i++] = 8; - visAttribs[i++] = GLX_BLUE_SIZE; visAttribs[i++] = 8; - } - else - { - visAttribs[i++] = GLX_RED_SIZE; visAttribs[i++] = 5; - visAttribs[i++] = GLX_GREEN_SIZE; visAttribs[i++] = 6; - visAttribs[i++] = GLX_BLUE_SIZE; visAttribs[i++] = 5; - } - - visAttribs[i++] = GLX_DEPTH_SIZE; visAttribs[i++] = 16; - visAttribs[i++] = GLX_RGBA; - visAttribs[i++] = GLX_DOUBLEBUFFER; - - visAttribs[i++] = None; - - XVisualInfo *xvi = glXChooseVisual( Dpy, DefaultScreen(Dpy), visAttribs ); - if( xvi == NULL ) - return "No visual available for that depth."; - - // I get strange behavior if I add override redirect after creating the window. - // So, let's recreate the window when changing that state. - if( !MakeWindow(Win, xvi->screen, xvi->depth, xvi->visual, p.width, p.height, !p.windowed) ) - return "Failed to create the window."; - - if( !MakeWindow(g_AltWindow, xvi->screen, xvi->depth, xvi->visual, p.width, p.height, !p.windowed) ) - FAIL_M( "Failed to create the alt window." ); // Should this be fatal? - - char *szWindowTitle = const_cast<char *>( p.sWindowTitle.c_str() ); - XChangeProperty( Dpy, Win, XA_WM_NAME, XA_STRING, 8, PropModeReplace, - reinterpret_cast<unsigned char*>(szWindowTitle), strlen(szWindowTitle) ); - - if( g_pContext ) - glXDestroyContext( Dpy, g_pContext ); - if( g_pBackgroundContext ) - glXDestroyContext( Dpy, g_pBackgroundContext ); - g_pContext = glXCreateContext( Dpy, xvi, NULL, True ); - g_pBackgroundContext = glXCreateContext( Dpy, xvi, g_pContext, True ); - - glXMakeCurrent( Dpy, Win, g_pContext ); - - XWindowAttributes winAttrib; - XGetWindowAttributes( Dpy, Win, &winAttrib ); - XSelectInput( Dpy, Win, winAttrib.your_event_mask | StructureNotifyMask ); - XMapWindow( Dpy, Win ); - - // XXX: Why do we need to wait for the MapNotify event? - while( true ) - { - XEvent event; - XMaskEvent( Dpy, StructureNotifyMask, &event ); - if( event.type == MapNotify ) - break; - } - XSelectInput( Dpy, Win, winAttrib.your_event_mask ); - - } - else - { - // We're remodeling the existing window, and not touching the context. - bNewDeviceOut = false; - } - - if( !p.windowed ) - { - if( m_bWasWindowed ) - { - // If the user changed the resolution while StepMania was windowed we overwrite the resolution to restore with it at exit. - g_iOldSize = XRRConfigCurrentConfiguration( g_pScreenConfig, &g_OldRotation ); - m_bWasWindowed = false; - } - - // Find a matching mode. - int iSizesXct; - XRRScreenSize *pSizesX = XRRSizes( Dpy, DefaultScreen(Dpy), &iSizesXct ); - ASSERT_M( iSizesXct != 0, "Couldn't get resolution list from X server" ); - - int iSizeMatch = -1; - - for( int i = 0; i < iSizesXct; ++i ) - { - if( pSizesX[i].width == p.width && pSizesX[i].height == p.height ) - { - iSizeMatch = i; - break; - } - } - - // Set this mode. - // XXX: This doesn't handle if the config has changed since we queried it (see man Xrandr) - XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), iSizeMatch, 1, CurrentTime ); - - // Move the window to the corner that the screen focuses in on. - XMoveWindow( Dpy, Win, 0, 0 ); - - XRaiseWindow( Dpy, Win ); - - // We want to prevent the WM from catching anything that comes from the keyboard. - // We should do this every time on fullscreen and not only we entering from windowed mode because we could lost focus at resolution change and that will leave the user input locked. - XGrabKeyboard( Dpy, Win, True, GrabModeAsync, GrabModeAsync, CurrentTime ); - } - else - { - if( !m_bWasWindowed ) - { - XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), g_iOldSize, g_OldRotation, CurrentTime ); - // In windowed mode, we actually want the WM to function normally. - // Release any previous grab. - XUngrabKeyboard( Dpy, CurrentTime ); - m_bWasWindowed = true; - } - } - int rate = XRRConfigCurrentRate( g_pScreenConfig ); - - // Make a window fixed size, don't let resize it or maximize it. - // Do this before resizing the window so that pane-style WMs (Ion, - // ratpoison) don't resize us back inappropriately. - { - XSizeHints hints; - - hints.flags = PMinSize|PMaxSize|PWinGravity; - hints.min_width = hints.max_width = p.width; - hints.min_height = hints.max_height = p.height; - hints.win_gravity = CenterGravity; - - XSetWMNormalHints( Dpy, Win, &hints ); - } - - // Workaround for metacity and compiz, if the window have the same resolution or higher than the screen - // it gets automaximized even when the window is set to don't let do it. - // This happens changing from fullscreen to window mode and our screen resolution is bigger. - { - XEvent xev; - Atom wm_state = XInternAtom(Dpy, "_NET_WM_STATE", False); - Atom maximized_vert = XInternAtom(Dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False); - Atom maximized_horz = XInternAtom(Dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False); - - memset(&xev, 0, sizeof(xev)); - xev.type = ClientMessage; - xev.xclient.window = Win; - xev.xclient.message_type = wm_state; - xev.xclient.format = 32; - xev.xclient.data.l[0] = 1; - xev.xclient.data.l[1] = maximized_vert; - xev.xclient.data.l[2] = 0; - - XSendEvent(Dpy, DefaultRootWindow(Dpy), False, SubstructureNotifyMask, &xev); - xev.xclient.data.l[1] = maximized_horz; - XSendEvent(Dpy, DefaultRootWindow(Dpy), False, SubstructureNotifyMask, &xev); - - // This one is needed for compiz, if the window reaches out of bounds of the screen it becames destroyed, only the window, the program is left running. - XMoveWindow( Dpy, Win, 0, 0 ); - } - - // Resize the window. - XResizeWindow( Dpy, Win, p.width, p.height ); - - CurrentParams = p; - CurrentParams.rate = rate; - return ""; // Success -} - -void LowLevelWindow_X11::LogDebugInformation() const -{ - LOG->Info( "Direct rendering: %s", glXIsDirect( Dpy, glXGetCurrentContext() )? "yes":"no" ); -} - -bool LowLevelWindow_X11::IsSoftwareRenderer( RString &sError ) -{ - if( glXIsDirect( Dpy, glXGetCurrentContext() ) ) - return false; - - sError = "Direct rendering is not available."; - return true; -} - -void LowLevelWindow_X11::SwapBuffers() -{ - glXSwapBuffers( Dpy, Win ); - - if( PREFSMAN->m_bDisableScreenSaver ) - { - // Disable the screensaver. -#if defined(HAVE_LIBXTST) - // This causes flicker. - // XForceScreenSaver( Dpy, ScreenSaverReset ); - - /* Instead, send a null relative mouse motion, to trick X into thinking - * there has been user activity. - * - * This also handles XScreenSaver; XForceScreenSaver only handles the - * internal X11 screen blanker. - * - * This will delay the X blanker, DPMS and XScreenSaver from activating, - * and will disable the blanker and XScreenSaver if they're already active - * (unless XSS is locked). For some reason, it doesn't un-blank DPMS if - * it's already active. - */ - - XLockDisplay( Dpy ); - - int event_base, error_base, major, minor; - if( XTestQueryExtension( Dpy, &event_base, &error_base, &major, &minor ) ) - { - XTestFakeRelativeMotionEvent( Dpy, 0, 0, 0 ); - XSync( Dpy, False ); - } - - XUnlockDisplay( Dpy ); -#endif - } -} - -void LowLevelWindow_X11::GetDisplayResolutions( DisplayResolutions &out ) const -{ - int iSizesXct; - XRRScreenSize *pSizesX = XRRSizes( Dpy, DefaultScreen( Dpy ), &iSizesXct ); - ASSERT_M( iSizesXct != 0, "Couldn't get resolution list from X server" ); - - for( int i = 0; i < iSizesXct; ++i ) - { - DisplayResolution res = { pSizesX[i].width, pSizesX[i].height, true }; - out.insert( res ); - } -} - -bool LowLevelWindow_X11::SupportsThreadedRendering() -{ - return g_pBackgroundContext != NULL; -} - -class RenderTarget_X11: public RenderTarget -{ -public: - RenderTarget_X11( LowLevelWindow_X11 *pWind ); - ~RenderTarget_X11(); - - void Create( const RenderTargetParam ¶m, int &iTextureWidthOut, int &iTextureHeightOut ); - unsigned GetTexture() const { return m_iTexHandle; } - void StartRenderingTo(); - void FinishRenderingTo(); - - // Copying from the Pbuffer to the texture flips Y. - virtual bool InvertY() const { return true; } - -private: - int m_iWidth, m_iHeight; - LowLevelWindow_X11 *m_pWind; - GLXPbuffer m_iPbuffer; - GLXContext m_pPbufferContext; - unsigned int m_iTexHandle; - - GLXContext m_pOldContext; - GLXDrawable m_pOldDrawable; -}; - -RenderTarget_X11::RenderTarget_X11( LowLevelWindow_X11 *pWind ) -{ - m_pWind = pWind; - m_iPbuffer = 0; - m_pPbufferContext = NULL; - m_iTexHandle = 0; - m_pOldContext = NULL; - m_pOldDrawable = 0; -} - -RenderTarget_X11::~RenderTarget_X11() -{ - if( m_pPbufferContext ) - glXDestroyContext( Dpy, m_pPbufferContext ); - if( m_iPbuffer ) - glXDestroyPbuffer( Dpy, m_iPbuffer ); - if( m_iTexHandle ) - glDeleteTextures( 1, reinterpret_cast<GLuint*>(&m_iTexHandle) ); -} - -/* Note that although the texture size may need to be a power of 2, the Pbuffer - * does not. */ -void RenderTarget_X11::Create( const RenderTargetParam ¶m, int &iTextureWidthOut, int &iTextureHeightOut ) -{ - //ASSERT( param.iWidth == power_of_two(param.iWidth) && param.iHeight == power_of_two(param.iHeight) ); - - m_iWidth = param.iWidth; - m_iHeight = param.iHeight; - - int pConfigAttribs[] = - { - GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, - GLX_RENDER_TYPE, GLX_RGBA_BIT, - - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_ALPHA_SIZE, param.bWithAlpha? 8:GLX_DONT_CARE, - - GLX_DOUBLEBUFFER, False, - GLX_DEPTH_SIZE, param.bWithDepthBuffer? 16:GLX_DONT_CARE, - None - }; - int iConfigs; - GLXFBConfig *pConfigs = glXChooseFBConfig( Dpy, DefaultScreen(Dpy), pConfigAttribs, &iConfigs ); - ASSERT( pConfigs ); - - const int pPbufferAttribs[] = - { - GLX_PBUFFER_WIDTH, param.iWidth, - GLX_PBUFFER_HEIGHT, param.iHeight, - None - }; - - for( int i = 0; i < iConfigs; ++i ) - { - m_iPbuffer = glXCreatePbuffer( Dpy, pConfigs[i], pPbufferAttribs ); - if( m_iPbuffer == 0 ) - continue; - - XVisualInfo *pVisual = glXGetVisualFromFBConfig( Dpy, pConfigs[i] ); - m_pPbufferContext = glXCreateContext( Dpy, pVisual, g_pContext, True ); - ASSERT( m_pPbufferContext ); - XFree( pVisual ); - break; - } - - ASSERT( m_iPbuffer ); - - // allocate OpenGL texture resource - glGenTextures( 1, reinterpret_cast<GLuint*>(&m_iTexHandle) ); - glBindTexture( GL_TEXTURE_2D, m_iTexHandle ); - - LOG->Trace( "n %i, %ix%i", m_iTexHandle, param.iWidth, param.iHeight ); - while( glGetError() != GL_NO_ERROR ) - ; - - int iTextureWidth = power_of_two( param.iWidth ); - int iTextureHeight = power_of_two( param.iHeight ); - iTextureWidthOut = iTextureWidth; - iTextureHeightOut = iTextureHeight; - - glTexImage2D( GL_TEXTURE_2D, 0, param.bWithAlpha? GL_RGBA8:GL_RGB8, - iTextureWidth, iTextureHeight, 0, param.bWithAlpha? GL_RGBA:GL_RGB, GL_UNSIGNED_BYTE, NULL ); - GLenum error = glGetError(); - ASSERT_M( error == GL_NO_ERROR, GLToString(error) ); - - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); -} - -void RenderTarget_X11::StartRenderingTo() -{ - m_pOldContext = glXGetCurrentContext(); - m_pOldDrawable = glXGetCurrentDrawable(); - glXMakeCurrent( Dpy, m_iPbuffer, m_pPbufferContext ); - - glViewport( 0, 0, m_iWidth, m_iHeight ); -} - -void RenderTarget_X11::FinishRenderingTo() -{ - glFlush(); - - glBindTexture( GL_TEXTURE_2D, m_iTexHandle ); - - while( glGetError() != GL_NO_ERROR ) - ; - - glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_iWidth, m_iHeight ); - - GLenum error = glGetError(); - ASSERT_M( error == GL_NO_ERROR, GLToString(error) ); - - glBindTexture( GL_TEXTURE_2D, 0 ); - - glXMakeCurrent( Dpy, m_pOldDrawable, m_pOldContext ); - m_pOldContext = NULL; - m_pOldDrawable = 0; - -} - -bool LowLevelWindow_X11::SupportsRenderToTexture() const -{ - // Server must support pbuffers: - const int iScreen = DefaultScreen( Dpy ); - float fVersion = strtof( glXQueryServerString(Dpy, iScreen, GLX_VERSION), NULL ); - if( fVersion < 1.3f ) - return false; - - return true; -} - -RenderTarget *LowLevelWindow_X11::CreateRenderTarget() -{ - return new RenderTarget_X11( this ); -} - -void LowLevelWindow_X11::BeginConcurrentRenderingMainThread() -{ - /* Move the main thread, which is going to be loading textures, etc. but - * not rendering, to an undisplayed window. This results in smoother - * rendering. */ - bool b = glXMakeCurrent( Dpy, g_AltWindow, g_pContext ); - ASSERT(b); -} - -void LowLevelWindow_X11::EndConcurrentRenderingMainThread() -{ - bool b = glXMakeCurrent( Dpy, Win, g_pContext ); - ASSERT(b); -} - -void LowLevelWindow_X11::BeginConcurrentRendering() -{ - bool b = glXMakeCurrent( Dpy, Win, g_pBackgroundContext ); - ASSERT(b); -} - -void LowLevelWindow_X11::EndConcurrentRendering() -{ - bool b = glXMakeCurrent( Dpy, None, NULL ); - ASSERT(b); -} - -/* - * (c) 2005 Ben Anderson - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +#include "global.h" +#include "LowLevelWindow_X11.h" +#include "RageLog.h" +#include "RageException.h" +#include "archutils/Unix/X11Helper.h" +#include "PrefsManager.h" // XXX +#include "RageDisplay.h" // VideoModeParams +#include "DisplayResolutions.h" +#include "LocalizedString.h" + +#include "RageDisplay_OGL_Helpers.h" +using namespace RageDisplay_OGL_Helpers; +using namespace X11Helper; + +#include <stack> +#include <math.h> // ceil() +#define GLX_GLXEXT_PROTOTYPES +#include <GL/glx.h> // All sorts of stuff... +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/extensions/Xrandr.h> + +#if defined(HAVE_LIBXTST) +#include <X11/extensions/XTest.h> +#endif + +static GLXContext g_pContext = NULL; +static GLXContext g_pBackgroundContext = NULL; +static Window g_AltWindow = None; +static Rotation g_OldRotation; +static int g_iOldSize; +XRRScreenConfiguration *g_pScreenConfig = NULL; + +static LocalizedString FAILED_CONNECTION_XSERVER( "LowLevelWindow_X11", "Failed to establish a connection with the X server" ); +LowLevelWindow_X11::LowLevelWindow_X11() +{ + if( !OpenXConnection() ) + RageException::Throw( "%s", FAILED_CONNECTION_XSERVER.GetValue().c_str() ); + + const int iScreen = DefaultScreen( Dpy ); + int iXServerVersion = XVendorRelease( Dpy ); /* eg. 40201001 */ + int iMajor = iXServerVersion / 10000000; iXServerVersion %= 10000000; + int iMinor = iXServerVersion / 100000; iXServerVersion %= 100000; + int iRevision = iXServerVersion / 1000; iXServerVersion %= 1000; + int iPatch = iXServerVersion; + + + LOG->Info( "Display: %s (screen %i)", DisplayString(Dpy), iScreen ); + LOG->Info( "X server vendor: %s [%i.%i.%i.%i]", XServerVendor( Dpy ), iMajor, iMinor, iRevision, iPatch ); + LOG->Info( "Server GLX vendor: %s [%s]", glXQueryServerString( Dpy, iScreen, GLX_VENDOR ), glXQueryServerString( Dpy, iScreen, GLX_VERSION ) ); + LOG->Info( "Client GLX vendor: %s [%s]", glXGetClientString( Dpy, GLX_VENDOR ), glXGetClientString( Dpy, GLX_VERSION ) ); + m_bWasWindowed = true; + g_pScreenConfig = XRRGetScreenInfo( Dpy, RootWindow(Dpy, DefaultScreen(Dpy)) ); + g_iOldSize = XRRConfigCurrentConfiguration( g_pScreenConfig, &g_OldRotation ); +} + +LowLevelWindow_X11::~LowLevelWindow_X11() +{ + // Reset the display + if( !m_bWasWindowed ) + { + XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), g_iOldSize, g_OldRotation, CurrentTime ); + + XUngrabKeyboard( Dpy, CurrentTime ); + } + if( g_pContext ) + { + glXDestroyContext( Dpy, g_pContext ); + g_pContext = NULL; + } + if( g_pBackgroundContext ) + { + glXDestroyContext( Dpy, g_pBackgroundContext ); + g_pBackgroundContext = NULL; + } + XRRFreeScreenConfigInfo( g_pScreenConfig ); + g_pScreenConfig = NULL; + + XDestroyWindow( Dpy, Win ); + Win = None; + XDestroyWindow( Dpy, g_AltWindow ); + g_AltWindow = None; + CloseXConnection(); +} + +void *LowLevelWindow_X11::GetProcAddress( RString s ) +{ + // XXX: We should check whether glXGetProcAddress or + // glXGetProcAddressARB is available, and go by that, instead of + // assuming like this. + return (void*) glXGetProcAddressARB( (const GLubyte*) s.c_str() ); +} + +RString LowLevelWindow_X11::TryVideoMode( const VideoModeParams &p, bool &bNewDeviceOut ) +{ +#if defined(UNIX) + /* nVidia cards: + * + * This only works the first time we set up a window; after that, the + * drivers appear to cache the value, so you have to actually restart + * the program to change it again. + */ + static char buf[128]; + strcpy( buf, "__GL_SYNC_TO_VBLANK=" ); + strcat( buf, p.vsync?"1":"0" ); + putenv( buf ); +#endif + + if( g_pContext == NULL || p.bpp != CurrentParams.bpp || m_bWasWindowed != p.windowed ) + { + // Different depth, or we didn't make a window before. New context. + bNewDeviceOut = true; + + int visAttribs[32]; + int i = 0; + ASSERT( p.bpp == 16 || p.bpp == 32 ); + + if( p.bpp == 32 ) + { + visAttribs[i++] = GLX_RED_SIZE; visAttribs[i++] = 8; + visAttribs[i++] = GLX_GREEN_SIZE; visAttribs[i++] = 8; + visAttribs[i++] = GLX_BLUE_SIZE; visAttribs[i++] = 8; + } + else + { + visAttribs[i++] = GLX_RED_SIZE; visAttribs[i++] = 5; + visAttribs[i++] = GLX_GREEN_SIZE; visAttribs[i++] = 6; + visAttribs[i++] = GLX_BLUE_SIZE; visAttribs[i++] = 5; + } + + visAttribs[i++] = GLX_DEPTH_SIZE; visAttribs[i++] = 16; + visAttribs[i++] = GLX_RGBA; + visAttribs[i++] = GLX_DOUBLEBUFFER; + + visAttribs[i++] = None; + + XVisualInfo *xvi = glXChooseVisual( Dpy, DefaultScreen(Dpy), visAttribs ); + if( xvi == NULL ) + return "No visual available for that depth."; + + // I get strange behavior if I add override redirect after creating the window. + // So, let's recreate the window when changing that state. + if( !MakeWindow(Win, xvi->screen, xvi->depth, xvi->visual, p.width, p.height, !p.windowed) ) + return "Failed to create the window."; + + if( !MakeWindow(g_AltWindow, xvi->screen, xvi->depth, xvi->visual, p.width, p.height, !p.windowed) ) + FAIL_M( "Failed to create the alt window." ); // Should this be fatal? + + char *szWindowTitle = const_cast<char *>( p.sWindowTitle.c_str() ); + XChangeProperty( Dpy, Win, XA_WM_NAME, XA_STRING, 8, PropModeReplace, + reinterpret_cast<unsigned char*>(szWindowTitle), strlen(szWindowTitle) ); + + if( g_pContext ) + glXDestroyContext( Dpy, g_pContext ); + if( g_pBackgroundContext ) + glXDestroyContext( Dpy, g_pBackgroundContext ); + g_pContext = glXCreateContext( Dpy, xvi, NULL, True ); + g_pBackgroundContext = glXCreateContext( Dpy, xvi, g_pContext, True ); + + glXMakeCurrent( Dpy, Win, g_pContext ); + + XWindowAttributes winAttrib; + XGetWindowAttributes( Dpy, Win, &winAttrib ); + XSelectInput( Dpy, Win, winAttrib.your_event_mask | StructureNotifyMask ); + XMapWindow( Dpy, Win ); + + // XXX: Why do we need to wait for the MapNotify event? + while( true ) + { + XEvent event; + XMaskEvent( Dpy, StructureNotifyMask, &event ); + if( event.type == MapNotify ) + break; + } + XSelectInput( Dpy, Win, winAttrib.your_event_mask ); + + } + else + { + // We're remodeling the existing window, and not touching the context. + bNewDeviceOut = false; + } + + if( !p.windowed ) + { + if( m_bWasWindowed ) + { + // If the user changed the resolution while StepMania was windowed we overwrite the resolution to restore with it at exit. + g_iOldSize = XRRConfigCurrentConfiguration( g_pScreenConfig, &g_OldRotation ); + m_bWasWindowed = false; + } + + // Find a matching mode. + int iSizesXct; + XRRScreenSize *pSizesX = XRRSizes( Dpy, DefaultScreen(Dpy), &iSizesXct ); + ASSERT_M( iSizesXct != 0, "Couldn't get resolution list from X server" ); + + int iSizeMatch = -1; + + for( int i = 0; i < iSizesXct; ++i ) + { + if( pSizesX[i].width == p.width && pSizesX[i].height == p.height ) + { + iSizeMatch = i; + break; + } + } + + // Set this mode. + // XXX: This doesn't handle if the config has changed since we queried it (see man Xrandr) + XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), iSizeMatch, 1, CurrentTime ); + + // Move the window to the corner that the screen focuses in on. + XMoveWindow( Dpy, Win, 0, 0 ); + + XRaiseWindow( Dpy, Win ); + + // We want to prevent the WM from catching anything that comes from the keyboard. + // We should do this every time on fullscreen and not only we entering from windowed mode because we could lost focus at resolution change and that will leave the user input locked. + XGrabKeyboard( Dpy, Win, True, GrabModeAsync, GrabModeAsync, CurrentTime ); + } + else + { + if( !m_bWasWindowed ) + { + XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), g_iOldSize, g_OldRotation, CurrentTime ); + // In windowed mode, we actually want the WM to function normally. + // Release any previous grab. + XUngrabKeyboard( Dpy, CurrentTime ); + m_bWasWindowed = true; + } + } + int rate = XRRConfigCurrentRate( g_pScreenConfig ); + + // Make a window fixed size, don't let resize it or maximize it. + // Do this before resizing the window so that pane-style WMs (Ion, + // ratpoison) don't resize us back inappropriately. + { + XSizeHints hints; + + hints.flags = PMinSize|PMaxSize|PWinGravity; + hints.min_width = hints.max_width = p.width; + hints.min_height = hints.max_height = p.height; + hints.win_gravity = CenterGravity; + + XSetWMNormalHints( Dpy, Win, &hints ); + } + + // Workaround for metacity and compiz, if the window have the same resolution or higher than the screen + // it gets automaximized even when the window is set to don't let do it. + // This happens changing from fullscreen to window mode and our screen resolution is bigger. + { + XEvent xev; + Atom wm_state = XInternAtom(Dpy, "_NET_WM_STATE", False); + Atom maximized_vert = XInternAtom(Dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False); + Atom maximized_horz = XInternAtom(Dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False); + + memset(&xev, 0, sizeof(xev)); + xev.type = ClientMessage; + xev.xclient.window = Win; + xev.xclient.message_type = wm_state; + xev.xclient.format = 32; + xev.xclient.data.l[0] = 1; + xev.xclient.data.l[1] = maximized_vert; + xev.xclient.data.l[2] = 0; + + XSendEvent(Dpy, DefaultRootWindow(Dpy), False, SubstructureNotifyMask, &xev); + xev.xclient.data.l[1] = maximized_horz; + XSendEvent(Dpy, DefaultRootWindow(Dpy), False, SubstructureNotifyMask, &xev); + + // This one is needed for compiz, if the window reaches out of bounds of the screen it becames destroyed, only the window, the program is left running. + XMoveWindow( Dpy, Win, 0, 0 ); + } + + // Resize the window. + XResizeWindow( Dpy, Win, p.width, p.height ); + + CurrentParams = p; + CurrentParams.rate = rate; + return ""; // Success +} + +void LowLevelWindow_X11::LogDebugInformation() const +{ + LOG->Info( "Direct rendering: %s", glXIsDirect( Dpy, glXGetCurrentContext() )? "yes":"no" ); +} + +bool LowLevelWindow_X11::IsSoftwareRenderer( RString &sError ) +{ + if( glXIsDirect( Dpy, glXGetCurrentContext() ) ) + return false; + + sError = "Direct rendering is not available."; + return true; +} + +void LowLevelWindow_X11::SwapBuffers() +{ + glXSwapBuffers( Dpy, Win ); + + if( PREFSMAN->m_bDisableScreenSaver ) + { + // Disable the screensaver. +#if defined(HAVE_LIBXTST) + // This causes flicker. + // XForceScreenSaver( Dpy, ScreenSaverReset ); + + /* Instead, send a null relative mouse motion, to trick X into thinking + * there has been user activity. + * + * This also handles XScreenSaver; XForceScreenSaver only handles the + * internal X11 screen blanker. + * + * This will delay the X blanker, DPMS and XScreenSaver from activating, + * and will disable the blanker and XScreenSaver if they're already active + * (unless XSS is locked). For some reason, it doesn't un-blank DPMS if + * it's already active. + */ + + XLockDisplay( Dpy ); + + int event_base, error_base, major, minor; + if( XTestQueryExtension( Dpy, &event_base, &error_base, &major, &minor ) ) + { + XTestFakeRelativeMotionEvent( Dpy, 0, 0, 0 ); + XSync( Dpy, False ); + } + + XUnlockDisplay( Dpy ); +#endif + } +} + +void LowLevelWindow_X11::GetDisplayResolutions( DisplayResolutions &out ) const +{ + int iSizesXct; + XRRScreenSize *pSizesX = XRRSizes( Dpy, DefaultScreen( Dpy ), &iSizesXct ); + ASSERT_M( iSizesXct != 0, "Couldn't get resolution list from X server" ); + + for( int i = 0; i < iSizesXct; ++i ) + { + DisplayResolution res = { pSizesX[i].width, pSizesX[i].height, true }; + out.insert( res ); + } +} + +bool LowLevelWindow_X11::SupportsThreadedRendering() +{ + return g_pBackgroundContext != NULL; +} + +class RenderTarget_X11: public RenderTarget +{ +public: + RenderTarget_X11( LowLevelWindow_X11 *pWind ); + ~RenderTarget_X11(); + + void Create( const RenderTargetParam ¶m, int &iTextureWidthOut, int &iTextureHeightOut ); + unsigned GetTexture() const { return m_iTexHandle; } + void StartRenderingTo(); + void FinishRenderingTo(); + + // Copying from the Pbuffer to the texture flips Y. + virtual bool InvertY() const { return true; } + +private: + int m_iWidth, m_iHeight; + LowLevelWindow_X11 *m_pWind; + GLXPbuffer m_iPbuffer; + GLXContext m_pPbufferContext; + unsigned int m_iTexHandle; + + GLXContext m_pOldContext; + GLXDrawable m_pOldDrawable; +}; + +RenderTarget_X11::RenderTarget_X11( LowLevelWindow_X11 *pWind ) +{ + m_pWind = pWind; + m_iPbuffer = 0; + m_pPbufferContext = NULL; + m_iTexHandle = 0; + m_pOldContext = NULL; + m_pOldDrawable = 0; +} + +RenderTarget_X11::~RenderTarget_X11() +{ + if( m_pPbufferContext ) + glXDestroyContext( Dpy, m_pPbufferContext ); + if( m_iPbuffer ) + glXDestroyPbuffer( Dpy, m_iPbuffer ); + if( m_iTexHandle ) + glDeleteTextures( 1, reinterpret_cast<GLuint*>(&m_iTexHandle) ); +} + +/* Note that although the texture size may need to be a power of 2, the Pbuffer + * does not. */ +void RenderTarget_X11::Create( const RenderTargetParam ¶m, int &iTextureWidthOut, int &iTextureHeightOut ) +{ + //ASSERT( param.iWidth == power_of_two(param.iWidth) && param.iHeight == power_of_two(param.iHeight) ); + + m_iWidth = param.iWidth; + m_iHeight = param.iHeight; + + int pConfigAttribs[] = + { + GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, param.bWithAlpha? 8:GLX_DONT_CARE, + + GLX_DOUBLEBUFFER, False, + GLX_DEPTH_SIZE, param.bWithDepthBuffer? 16:GLX_DONT_CARE, + None + }; + int iConfigs; + GLXFBConfig *pConfigs = glXChooseFBConfig( Dpy, DefaultScreen(Dpy), pConfigAttribs, &iConfigs ); + ASSERT( pConfigs ); + + const int pPbufferAttribs[] = + { + GLX_PBUFFER_WIDTH, param.iWidth, + GLX_PBUFFER_HEIGHT, param.iHeight, + None + }; + + for( int i = 0; i < iConfigs; ++i ) + { + m_iPbuffer = glXCreatePbuffer( Dpy, pConfigs[i], pPbufferAttribs ); + if( m_iPbuffer == 0 ) + continue; + + XVisualInfo *pVisual = glXGetVisualFromFBConfig( Dpy, pConfigs[i] ); + m_pPbufferContext = glXCreateContext( Dpy, pVisual, g_pContext, True ); + ASSERT( m_pPbufferContext ); + XFree( pVisual ); + break; + } + + ASSERT( m_iPbuffer ); + + // allocate OpenGL texture resource + glGenTextures( 1, reinterpret_cast<GLuint*>(&m_iTexHandle) ); + glBindTexture( GL_TEXTURE_2D, m_iTexHandle ); + + LOG->Trace( "n %i, %ix%i", m_iTexHandle, param.iWidth, param.iHeight ); + while( glGetError() != GL_NO_ERROR ) + ; + + int iTextureWidth = power_of_two( param.iWidth ); + int iTextureHeight = power_of_two( param.iHeight ); + iTextureWidthOut = iTextureWidth; + iTextureHeightOut = iTextureHeight; + + glTexImage2D( GL_TEXTURE_2D, 0, param.bWithAlpha? GL_RGBA8:GL_RGB8, + iTextureWidth, iTextureHeight, 0, param.bWithAlpha? GL_RGBA:GL_RGB, GL_UNSIGNED_BYTE, NULL ); + GLenum error = glGetError(); + ASSERT_M( error == GL_NO_ERROR, GLToString(error) ); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); +} + +void RenderTarget_X11::StartRenderingTo() +{ + m_pOldContext = glXGetCurrentContext(); + m_pOldDrawable = glXGetCurrentDrawable(); + glXMakeCurrent( Dpy, m_iPbuffer, m_pPbufferContext ); + + glViewport( 0, 0, m_iWidth, m_iHeight ); +} + +void RenderTarget_X11::FinishRenderingTo() +{ + glFlush(); + + glBindTexture( GL_TEXTURE_2D, m_iTexHandle ); + + while( glGetError() != GL_NO_ERROR ) + ; + + glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_iWidth, m_iHeight ); + + GLenum error = glGetError(); + ASSERT_M( error == GL_NO_ERROR, GLToString(error) ); + + glBindTexture( GL_TEXTURE_2D, 0 ); + + glXMakeCurrent( Dpy, m_pOldDrawable, m_pOldContext ); + m_pOldContext = NULL; + m_pOldDrawable = 0; + +} + +bool LowLevelWindow_X11::SupportsRenderToTexture() const +{ + // Server must support pbuffers: + const int iScreen = DefaultScreen( Dpy ); + float fVersion = strtof( glXQueryServerString(Dpy, iScreen, GLX_VERSION), NULL ); + if( fVersion < 1.3f ) + return false; + + return true; +} + +RenderTarget *LowLevelWindow_X11::CreateRenderTarget() +{ + return new RenderTarget_X11( this ); +} + +void LowLevelWindow_X11::BeginConcurrentRenderingMainThread() +{ + /* Move the main thread, which is going to be loading textures, etc. but + * not rendering, to an undisplayed window. This results in smoother + * rendering. */ + bool b = glXMakeCurrent( Dpy, g_AltWindow, g_pContext ); + ASSERT(b); +} + +void LowLevelWindow_X11::EndConcurrentRenderingMainThread() +{ + bool b = glXMakeCurrent( Dpy, Win, g_pContext ); + ASSERT(b); +} + +void LowLevelWindow_X11::BeginConcurrentRendering() +{ + bool b = glXMakeCurrent( Dpy, Win, g_pBackgroundContext ); + ASSERT(b); +} + +void LowLevelWindow_X11::EndConcurrentRendering() +{ + bool b = glXMakeCurrent( Dpy, None, NULL ); + ASSERT(b); +} + +/* + * (c) 2005 Ben Anderson + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/arch/MemoryCard/MemoryCardDriverThreaded_Linux.cpp b/src/arch/MemoryCard/MemoryCardDriverThreaded_Linux.cpp index 03445081ae..fdf5e31d99 100644 --- a/src/arch/MemoryCard/MemoryCardDriverThreaded_Linux.cpp +++ b/src/arch/MemoryCard/MemoryCardDriverThreaded_Linux.cpp @@ -1,392 +1,392 @@ -#include "global.h" -#include "MemoryCardDriverThreaded_Linux.h" -#include "RageLog.h" -#include "RageUtil.h" -#include "RageFile.h" -#include "RageTimer.h" - -#include <cerrno> -#include <fcntl.h> -#include <dirent.h> -#include <sys/types.h> -#include <sys/stat.h> - -bool MemoryCardDriverThreaded_Linux::TestWrite( UsbStorageDevice* pDevice ) -{ - if( access(pDevice->sOsMountDir, W_OK) == -1 ) - { - pDevice->SetError( "TestFailed" ); - return false; - } - - return true; -} - -static bool ExecuteCommand( const RString &sCommand ) -{ - LOG->Trace( "executing '%s'", sCommand.c_str() ); - int ret = system(sCommand); - LOG->Trace( "done executing '%s'", sCommand.c_str() ); - if( ret != 0 ) - { - RString sError = ssprintf("failed to execute '%s' with error %d", sCommand.c_str(), ret); - if( ret == -1 ) - sError += ssprintf(": %s", sCommand.c_str()); - LOG->Warn( "%s", sError.c_str() ); - } - return ret == 0; -} - -static bool ReadFile( const RString &sPath, RString &sBuf ) -{ - sBuf.clear(); - - int fd = open( sPath, O_RDONLY ); - if( fd == -1 ) - { - LOG->Warn( "Error opening \"%s\": %s", sPath.c_str(), strerror(errno) ); - return false; - } - - while(1) - { - char buf[1024]; - int iGot = read( fd, buf, sizeof(buf) ); - if( iGot == -1 ) - { - close(fd); - LOG->Warn( "Error reading \"%s\": %s", sPath.c_str(), strerror(errno) ); - return false; - } - - sBuf.append( buf, iGot ); - if( iGot < (int) sizeof(buf) ) - break; - } - - close(fd); - return true; -} - -static void GetFileList( const RString &sPath, vector<RString> &out ) -{ - out.clear(); - - DIR *dp = opendir( sPath ); - if( dp == NULL ) - return; // false; // XXX warn - - while( const struct dirent *ent = readdir(dp) ) - out.push_back( ent->d_name ); - - closedir( dp ); -} - -bool MemoryCardDriverThreaded_Linux::USBStorageDevicesChanged() -{ - RString sThisDevices; - - /* If a device is removed and reinserted, the inode of the /sys/block entry - * will change. */ - RString sDevicePath = "/sys/block/"; - - vector<RString> asDevices; - GetFileList( sDevicePath, asDevices ); - - for( unsigned i = 0; i < asDevices.size(); ++i ) - { - struct stat buf; - if( stat( sDevicePath + asDevices[i], &buf ) == -1 ) - continue; // XXX warn - - sThisDevices += ssprintf( "%i,", (int) buf.st_ino ); - } - - bool bChanged = sThisDevices != m_sLastDevices; - m_sLastDevices = sThisDevices; - if( bChanged ) - LOG->Trace( "Change in USB storage devices detected." ); - return bChanged; -} - -void MemoryCardDriverThreaded_Linux::GetUSBStorageDevices( vector<UsbStorageDevice>& vDevicesOut ) -{ - LOG->Trace( "GetUSBStorageDevices" ); - - vDevicesOut.clear(); - - { - vector<RString> asDevices; - RString sBlockDevicePath = "/sys/block/"; - GetFileList( sBlockDevicePath, asDevices ); - - for( unsigned i = 0; i < asDevices.size(); ++i ) - { - const RString &sDevice = asDevices[i]; - if( sDevice == "." || sDevice == ".." ) - continue; - - UsbStorageDevice usbd; - - RString sPath = sBlockDevicePath + sDevice + "/"; - usbd.sSysPath = sPath; - - /* Ignore non-removable devices. */ - RString sBuf; - if( !ReadFile( sPath + "removable", sBuf ) ) - continue; // already warned - if( atoi(sBuf) != 1 ) - continue; - - /* - * The kernel isn't exposing all of /sys atomically, so we end up missing - * the partition due to it not being shown yet. It won't show up until the - * kernel has scanned the partition table, which can take a variable amount - * of time, sometimes over a second. Watch for the "queue" sysfs directory, - * which is created after this, to tell when partition directories are created. - */ - RageTimer WaitUntil; - WaitUntil += 5; - RString sQueueFilePath = usbd.sSysPath + "queue"; - while(1) - { - if( WaitUntil.Ago() >= 0 ) - { - LOG->Warn( "Timed out waiting for %s", sQueueFilePath.c_str() ); - break; - } - - if( access(usbd.sSysPath, F_OK) == -1 ) - { - LOG->Warn( "Block directory %s went away while we were waiting for %s", - usbd.sSysPath.c_str(), sQueueFilePath.c_str() ); - break; - } - - if( access(sQueueFilePath, F_OK) != -1 ) - break; - - usleep(10000); - } - - /* If the first partition device exists, eg. /sys/block/uba/uba1, use it. */ - if( access(usbd.sSysPath + sDevice + "1", F_OK) != -1 ) - { - LOG->Trace("OK"); - usbd.sDevice = "/dev/" + sDevice + "1"; - } - else - { - LOG->Trace("error %s", strerror(errno)); - usbd.sDevice = "/dev/" + sDevice; - } - - /* - * sPath/device should be a symlink to the actual device. For USB - * devices, it looks like this: - * - * device -> ../../devices/pci0000:00/0000:00:02.1/usb2/2-1/2-1:1.0 - * - * "2-1" is "bus-port". - */ - char szLink[256]; - int iRet = readlink( sPath + "device", szLink, sizeof(szLink) ); - if( iRet == -1 ) - { - LOG->Warn( "readlink(\"%s\"): %s", (sPath + "device").c_str(), strerror(errno) ); - } - else - { - /* - * The full path looks like - * - * ../../devices/pci0000:00/0000:00:02.1/usb2/2-2/2-2.1/2-2.1:1.0 - * - * In newer kernels, it looks like: - * - * ../../../3-2.1:1.0 - * - * Each path element refers to a new hop in the chain. - * "usb2" = second USB host - * 2- second USB host, - * -2 port 1 on the host, - * .1 port 1 on an attached hub - * .2 ... port 2 on the next hub ... - * - * We want the bus number and the port of the last hop. The level is - * the number of hops. - */ - szLink[iRet] = 0; - vector<RString> asBits; - split( szLink, "/", asBits ); - - RString sHostPort = asBits[asBits.size()-1]; - if( !sHostPort.empty() ) - { - /* Strip off the endpoint information after the colon. */ - size_t pos = sHostPort.find(':'); - if( pos != string::npos ) - sHostPort.erase( pos ); - - /* sHostPort is eg. 2-2.1. */ - sHostPort.Replace( "-", "." ); - asBits.clear(); - split( sHostPort, ".", asBits ); - if( asBits.size() > 1 ) - { - usbd.iBus = atoi( asBits[0] ); - usbd.iPort = atoi( asBits[asBits.size()-1] ); - usbd.iLevel = asBits.size() - 1; - } - } - } - - if( ReadFile( sPath + "device/../idVendor", sBuf ) ) - sscanf( sBuf, "%x", &usbd.idVendor ); - - if( ReadFile( sPath + "device/../idProduct", sBuf ) ) - sscanf( sBuf, "%x", &usbd.idProduct ); - - if( ReadFile( sPath + "device/../serial", sBuf ) ) - { - usbd.sSerial = sBuf; - TrimRight( usbd.sSerial ); - } - if( ReadFile( sPath + "device/../product", sBuf ) ) - { - usbd.sProduct = sBuf; - TrimRight( usbd.sProduct ); - } - if( ReadFile( sPath + "device/../manufacturer", sBuf ) ) - { - usbd.sVendor = sBuf; - TrimRight( usbd.sVendor ); - } - - vDevicesOut.push_back( usbd ); - } - } - - { - // Find where each device is mounted. Output looks like: - - // /dev/sda1 /mnt/flash1 auto noauto,owner 0 0 - // /dev/sdb1 /mnt/flash2 auto noauto,owner 0 0 - // /dev/sdc1 /mnt/flash3 auto noauto,owner 0 0 - - RString fn = "/rootfs/etc/fstab"; - RageFile f; - if( !f.Open(fn) ) - { - LOG->Warn( "can't open '%s': %s", fn.c_str(), f.GetError().c_str() ); - return; - } - - RString sLine; - while( !f.AtEOF() ) - { - switch( f.GetLine(sLine) ) - { - case 0: continue; /* eof */ - case -1: - LOG->Warn( "error reading '%s': %s", fn.c_str(), f.GetError().c_str() ); - return; - } - - char szScsiDevice[1024]; - char szMountPoint[1024]; - int iRet = sscanf( sLine, "%s %s", szScsiDevice, szMountPoint ); - if( iRet != 2 ) - continue; // don't process this line - - - RString sMountPoint = szMountPoint; - TrimLeft( sMountPoint ); - TrimRight( sMountPoint ); - - // search for the mountpoint corresponding to the device - for( unsigned i=0; i<vDevicesOut.size(); i++ ) - { - UsbStorageDevice& usbd = vDevicesOut[i]; - if( usbd.sDevice == szScsiDevice ) // found our match - { - usbd.sOsMountDir = sMountPoint; - break; // stop looking for a match - } - } - } - } - - for( unsigned i=0; i<vDevicesOut.size(); i++ ) - { - UsbStorageDevice& usbd = vDevicesOut[i]; - LOG->Trace( " sDevice: %s, iBus: %d, iLevel: %d, iPort: %d, id: %04X:%04X, Vendor: '%s', Product: '%s', sSerial: \"%s\", sOsMountDir: %s", - usbd.sDevice.c_str(), usbd.iBus, usbd.iLevel, usbd.iPort, usbd.idVendor, usbd.idProduct, usbd.sVendor.c_str(), - usbd.sProduct.c_str(), usbd.sSerial.c_str(), usbd.sOsMountDir.c_str() ); - } - - /* Remove any devices that we couldn't find a mountpoint for. */ - for( unsigned i=0; i<vDevicesOut.size(); i++ ) - { - UsbStorageDevice& usbd = vDevicesOut[i]; - if( usbd.sOsMountDir.empty() ) - { - LOG->Trace( "Ignoring %s (couldn't find in /etc/fstab)", usbd.sDevice.c_str() ); - - vDevicesOut.erase( vDevicesOut.begin()+i ); - --i; - } - } - - LOG->Trace( "Done with GetUSBStorageDevices" ); -} - - -bool MemoryCardDriverThreaded_Linux::Mount( UsbStorageDevice* pDevice ) -{ - ASSERT( !pDevice->sDevice.empty() ); - - RString sCommand = "mount " + pDevice->sDevice; - bool bMountedSuccessfully = ExecuteCommand( sCommand ); - - return bMountedSuccessfully; -} - -void MemoryCardDriverThreaded_Linux::Unmount( UsbStorageDevice* pDevice ) -{ - if( pDevice->sDevice.empty() ) - return; - - /* Use umount -l, so we unmount the device even if it's in use. Open - * files remain usable, and the device (eg. /dev/sda) won't be reused - * by new devices until those are closed. Without this, if something - * causes the device to not unmount here, we'll never unmount it; that - * causes a device name leak, eventually running us out of mountpoints. */ - RString sCommand = "sync; umount -l \"" + pDevice->sDevice + "\""; - ExecuteCommand( sCommand ); -} - -/* - * (c) 2003-2005 Chris Danford, Glenn Maynard - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +#include "global.h" +#include "MemoryCardDriverThreaded_Linux.h" +#include "RageLog.h" +#include "RageUtil.h" +#include "RageFile.h" +#include "RageTimer.h" + +#include <cerrno> +#include <fcntl.h> +#include <dirent.h> +#include <sys/types.h> +#include <sys/stat.h> + +bool MemoryCardDriverThreaded_Linux::TestWrite( UsbStorageDevice* pDevice ) +{ + if( access(pDevice->sOsMountDir, W_OK) == -1 ) + { + pDevice->SetError( "TestFailed" ); + return false; + } + + return true; +} + +static bool ExecuteCommand( const RString &sCommand ) +{ + LOG->Trace( "executing '%s'", sCommand.c_str() ); + int ret = system(sCommand); + LOG->Trace( "done executing '%s'", sCommand.c_str() ); + if( ret != 0 ) + { + RString sError = ssprintf("failed to execute '%s' with error %d", sCommand.c_str(), ret); + if( ret == -1 ) + sError += ssprintf(": %s", sCommand.c_str()); + LOG->Warn( "%s", sError.c_str() ); + } + return ret == 0; +} + +static bool ReadFile( const RString &sPath, RString &sBuf ) +{ + sBuf.clear(); + + int fd = open( sPath, O_RDONLY ); + if( fd == -1 ) + { + LOG->Warn( "Error opening \"%s\": %s", sPath.c_str(), strerror(errno) ); + return false; + } + + while(1) + { + char buf[1024]; + int iGot = read( fd, buf, sizeof(buf) ); + if( iGot == -1 ) + { + close(fd); + LOG->Warn( "Error reading \"%s\": %s", sPath.c_str(), strerror(errno) ); + return false; + } + + sBuf.append( buf, iGot ); + if( iGot < (int) sizeof(buf) ) + break; + } + + close(fd); + return true; +} + +static void GetFileList( const RString &sPath, vector<RString> &out ) +{ + out.clear(); + + DIR *dp = opendir( sPath ); + if( dp == NULL ) + return; // false; // XXX warn + + while( const struct dirent *ent = readdir(dp) ) + out.push_back( ent->d_name ); + + closedir( dp ); +} + +bool MemoryCardDriverThreaded_Linux::USBStorageDevicesChanged() +{ + RString sThisDevices; + + /* If a device is removed and reinserted, the inode of the /sys/block entry + * will change. */ + RString sDevicePath = "/sys/block/"; + + vector<RString> asDevices; + GetFileList( sDevicePath, asDevices ); + + for( unsigned i = 0; i < asDevices.size(); ++i ) + { + struct stat buf; + if( stat( sDevicePath + asDevices[i], &buf ) == -1 ) + continue; // XXX warn + + sThisDevices += ssprintf( "%i,", (int) buf.st_ino ); + } + + bool bChanged = sThisDevices != m_sLastDevices; + m_sLastDevices = sThisDevices; + if( bChanged ) + LOG->Trace( "Change in USB storage devices detected." ); + return bChanged; +} + +void MemoryCardDriverThreaded_Linux::GetUSBStorageDevices( vector<UsbStorageDevice>& vDevicesOut ) +{ + LOG->Trace( "GetUSBStorageDevices" ); + + vDevicesOut.clear(); + + { + vector<RString> asDevices; + RString sBlockDevicePath = "/sys/block/"; + GetFileList( sBlockDevicePath, asDevices ); + + for( unsigned i = 0; i < asDevices.size(); ++i ) + { + const RString &sDevice = asDevices[i]; + if( sDevice == "." || sDevice == ".." ) + continue; + + UsbStorageDevice usbd; + + RString sPath = sBlockDevicePath + sDevice + "/"; + usbd.sSysPath = sPath; + + /* Ignore non-removable devices. */ + RString sBuf; + if( !ReadFile( sPath + "removable", sBuf ) ) + continue; // already warned + if( atoi(sBuf) != 1 ) + continue; + + /* + * The kernel isn't exposing all of /sys atomically, so we end up missing + * the partition due to it not being shown yet. It won't show up until the + * kernel has scanned the partition table, which can take a variable amount + * of time, sometimes over a second. Watch for the "queue" sysfs directory, + * which is created after this, to tell when partition directories are created. + */ + RageTimer WaitUntil; + WaitUntil += 5; + RString sQueueFilePath = usbd.sSysPath + "queue"; + while(1) + { + if( WaitUntil.Ago() >= 0 ) + { + LOG->Warn( "Timed out waiting for %s", sQueueFilePath.c_str() ); + break; + } + + if( access(usbd.sSysPath, F_OK) == -1 ) + { + LOG->Warn( "Block directory %s went away while we were waiting for %s", + usbd.sSysPath.c_str(), sQueueFilePath.c_str() ); + break; + } + + if( access(sQueueFilePath, F_OK) != -1 ) + break; + + usleep(10000); + } + + /* If the first partition device exists, eg. /sys/block/uba/uba1, use it. */ + if( access(usbd.sSysPath + sDevice + "1", F_OK) != -1 ) + { + LOG->Trace("OK"); + usbd.sDevice = "/dev/" + sDevice + "1"; + } + else + { + LOG->Trace("error %s", strerror(errno)); + usbd.sDevice = "/dev/" + sDevice; + } + + /* + * sPath/device should be a symlink to the actual device. For USB + * devices, it looks like this: + * + * device -> ../../devices/pci0000:00/0000:00:02.1/usb2/2-1/2-1:1.0 + * + * "2-1" is "bus-port". + */ + char szLink[256]; + int iRet = readlink( sPath + "device", szLink, sizeof(szLink) ); + if( iRet == -1 ) + { + LOG->Warn( "readlink(\"%s\"): %s", (sPath + "device").c_str(), strerror(errno) ); + } + else + { + /* + * The full path looks like + * + * ../../devices/pci0000:00/0000:00:02.1/usb2/2-2/2-2.1/2-2.1:1.0 + * + * In newer kernels, it looks like: + * + * ../../../3-2.1:1.0 + * + * Each path element refers to a new hop in the chain. + * "usb2" = second USB host + * 2- second USB host, + * -2 port 1 on the host, + * .1 port 1 on an attached hub + * .2 ... port 2 on the next hub ... + * + * We want the bus number and the port of the last hop. The level is + * the number of hops. + */ + szLink[iRet] = 0; + vector<RString> asBits; + split( szLink, "/", asBits ); + + RString sHostPort = asBits[asBits.size()-1]; + if( !sHostPort.empty() ) + { + /* Strip off the endpoint information after the colon. */ + size_t pos = sHostPort.find(':'); + if( pos != string::npos ) + sHostPort.erase( pos ); + + /* sHostPort is eg. 2-2.1. */ + sHostPort.Replace( "-", "." ); + asBits.clear(); + split( sHostPort, ".", asBits ); + if( asBits.size() > 1 ) + { + usbd.iBus = atoi( asBits[0] ); + usbd.iPort = atoi( asBits[asBits.size()-1] ); + usbd.iLevel = asBits.size() - 1; + } + } + } + + if( ReadFile( sPath + "device/../idVendor", sBuf ) ) + sscanf( sBuf, "%x", &usbd.idVendor ); + + if( ReadFile( sPath + "device/../idProduct", sBuf ) ) + sscanf( sBuf, "%x", &usbd.idProduct ); + + if( ReadFile( sPath + "device/../serial", sBuf ) ) + { + usbd.sSerial = sBuf; + TrimRight( usbd.sSerial ); + } + if( ReadFile( sPath + "device/../product", sBuf ) ) + { + usbd.sProduct = sBuf; + TrimRight( usbd.sProduct ); + } + if( ReadFile( sPath + "device/../manufacturer", sBuf ) ) + { + usbd.sVendor = sBuf; + TrimRight( usbd.sVendor ); + } + + vDevicesOut.push_back( usbd ); + } + } + + { + // Find where each device is mounted. Output looks like: + + // /dev/sda1 /mnt/flash1 auto noauto,owner 0 0 + // /dev/sdb1 /mnt/flash2 auto noauto,owner 0 0 + // /dev/sdc1 /mnt/flash3 auto noauto,owner 0 0 + + RString fn = "/rootfs/etc/fstab"; + RageFile f; + if( !f.Open(fn) ) + { + LOG->Warn( "can't open '%s': %s", fn.c_str(), f.GetError().c_str() ); + return; + } + + RString sLine; + while( !f.AtEOF() ) + { + switch( f.GetLine(sLine) ) + { + case 0: continue; /* eof */ + case -1: + LOG->Warn( "error reading '%s': %s", fn.c_str(), f.GetError().c_str() ); + return; + } + + char szScsiDevice[1024]; + char szMountPoint[1024]; + int iRet = sscanf( sLine, "%s %s", szScsiDevice, szMountPoint ); + if( iRet != 2 ) + continue; // don't process this line + + + RString sMountPoint = szMountPoint; + TrimLeft( sMountPoint ); + TrimRight( sMountPoint ); + + // search for the mountpoint corresponding to the device + for( unsigned i=0; i<vDevicesOut.size(); i++ ) + { + UsbStorageDevice& usbd = vDevicesOut[i]; + if( usbd.sDevice == szScsiDevice ) // found our match + { + usbd.sOsMountDir = sMountPoint; + break; // stop looking for a match + } + } + } + } + + for( unsigned i=0; i<vDevicesOut.size(); i++ ) + { + UsbStorageDevice& usbd = vDevicesOut[i]; + LOG->Trace( " sDevice: %s, iBus: %d, iLevel: %d, iPort: %d, id: %04X:%04X, Vendor: '%s', Product: '%s', sSerial: \"%s\", sOsMountDir: %s", + usbd.sDevice.c_str(), usbd.iBus, usbd.iLevel, usbd.iPort, usbd.idVendor, usbd.idProduct, usbd.sVendor.c_str(), + usbd.sProduct.c_str(), usbd.sSerial.c_str(), usbd.sOsMountDir.c_str() ); + } + + /* Remove any devices that we couldn't find a mountpoint for. */ + for( unsigned i=0; i<vDevicesOut.size(); i++ ) + { + UsbStorageDevice& usbd = vDevicesOut[i]; + if( usbd.sOsMountDir.empty() ) + { + LOG->Trace( "Ignoring %s (couldn't find in /etc/fstab)", usbd.sDevice.c_str() ); + + vDevicesOut.erase( vDevicesOut.begin()+i ); + --i; + } + } + + LOG->Trace( "Done with GetUSBStorageDevices" ); +} + + +bool MemoryCardDriverThreaded_Linux::Mount( UsbStorageDevice* pDevice ) +{ + ASSERT( !pDevice->sDevice.empty() ); + + RString sCommand = "mount " + pDevice->sDevice; + bool bMountedSuccessfully = ExecuteCommand( sCommand ); + + return bMountedSuccessfully; +} + +void MemoryCardDriverThreaded_Linux::Unmount( UsbStorageDevice* pDevice ) +{ + if( pDevice->sDevice.empty() ) + return; + + /* Use umount -l, so we unmount the device even if it's in use. Open + * files remain usable, and the device (eg. /dev/sda) won't be reused + * by new devices until those are closed. Without this, if something + * causes the device to not unmount here, we'll never unmount it; that + * causes a device name leak, eventually running us out of mountpoints. */ + RString sCommand = "sync; umount -l \"" + pDevice->sDevice + "\""; + ExecuteCommand( sCommand ); +} + +/* + * (c) 2003-2005 Chris Danford, Glenn Maynard + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/src/ffmpeg/include/ffmpeg/avcodec.h b/src/ffmpeg/include/ffmpeg/avcodec.h index ead4dc8dfe..4c5ef2763e 100644 --- a/src/ffmpeg/include/ffmpeg/avcodec.h +++ b/src/ffmpeg/include/ffmpeg/avcodec.h @@ -1,3073 +1,3073 @@ -/* - * copyright (c) 2001 Fabrice Bellard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVCODEC_H -#define AVCODEC_H - -/** - * @file avcodec.h - * external api header. - */ - - -#ifdef __cplusplus -extern "C" { -#endif - -#include "avutil.h" -#include <sys/types.h> /* size_t */ - -#define AV_STRINGIFY(s) AV_TOSTRING(s) -#define AV_TOSTRING(s) #s - -#define LIBAVCODEC_VERSION_INT ((51<<16)+(40<<8)+0) -#define LIBAVCODEC_VERSION 51.40.0 -#define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT - -#define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) - -#define AV_NOPTS_VALUE INT64_C(0x8000000000000000) -#define AV_TIME_BASE 1000000 -#define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE} - -enum CodecID { - CODEC_ID_NONE, - CODEC_ID_MPEG1VIDEO, - CODEC_ID_MPEG2VIDEO, /* prefered ID for MPEG Video 1 or 2 decoding */ - CODEC_ID_MPEG2VIDEO_XVMC, - CODEC_ID_H261, - CODEC_ID_H263, - CODEC_ID_RV10, - CODEC_ID_RV20, - CODEC_ID_MJPEG, - CODEC_ID_MJPEGB, - CODEC_ID_LJPEG, - CODEC_ID_SP5X, - CODEC_ID_JPEGLS, - CODEC_ID_MPEG4, - CODEC_ID_RAWVIDEO, - CODEC_ID_MSMPEG4V1, - CODEC_ID_MSMPEG4V2, - CODEC_ID_MSMPEG4V3, - CODEC_ID_WMV1, - CODEC_ID_WMV2, - CODEC_ID_H263P, - CODEC_ID_H263I, - CODEC_ID_FLV1, - CODEC_ID_SVQ1, - CODEC_ID_SVQ3, - CODEC_ID_DVVIDEO, - CODEC_ID_HUFFYUV, - CODEC_ID_CYUV, - CODEC_ID_H264, - CODEC_ID_INDEO3, - CODEC_ID_VP3, - CODEC_ID_THEORA, - CODEC_ID_ASV1, - CODEC_ID_ASV2, - CODEC_ID_FFV1, - CODEC_ID_4XM, - CODEC_ID_VCR1, - CODEC_ID_CLJR, - CODEC_ID_MDEC, - CODEC_ID_ROQ, - CODEC_ID_INTERPLAY_VIDEO, - CODEC_ID_XAN_WC3, - CODEC_ID_XAN_WC4, - CODEC_ID_RPZA, - CODEC_ID_CINEPAK, - CODEC_ID_WS_VQA, - CODEC_ID_MSRLE, - CODEC_ID_MSVIDEO1, - CODEC_ID_IDCIN, - CODEC_ID_8BPS, - CODEC_ID_SMC, - CODEC_ID_FLIC, - CODEC_ID_TRUEMOTION1, - CODEC_ID_VMDVIDEO, - CODEC_ID_MSZH, - CODEC_ID_ZLIB, - CODEC_ID_QTRLE, - CODEC_ID_SNOW, - CODEC_ID_TSCC, - CODEC_ID_ULTI, - CODEC_ID_QDRAW, - CODEC_ID_VIXL, - CODEC_ID_QPEG, - CODEC_ID_XVID, - CODEC_ID_PNG, - CODEC_ID_PPM, - CODEC_ID_PBM, - CODEC_ID_PGM, - CODEC_ID_PGMYUV, - CODEC_ID_PAM, - CODEC_ID_FFVHUFF, - CODEC_ID_RV30, - CODEC_ID_RV40, - CODEC_ID_VC1, - CODEC_ID_WMV3, - CODEC_ID_LOCO, - CODEC_ID_WNV1, - CODEC_ID_AASC, - CODEC_ID_INDEO2, - CODEC_ID_FRAPS, - CODEC_ID_TRUEMOTION2, - CODEC_ID_BMP, - CODEC_ID_CSCD, - CODEC_ID_MMVIDEO, - CODEC_ID_ZMBV, - CODEC_ID_AVS, - CODEC_ID_SMACKVIDEO, - CODEC_ID_NUV, - CODEC_ID_KMVC, - CODEC_ID_FLASHSV, - CODEC_ID_CAVS, - CODEC_ID_JPEG2000, - CODEC_ID_VMNC, - CODEC_ID_VP5, - CODEC_ID_VP6, - CODEC_ID_VP6F, - CODEC_ID_TARGA, - CODEC_ID_DSICINVIDEO, - CODEC_ID_TIERTEXSEQVIDEO, - CODEC_ID_TIFF, - CODEC_ID_GIF, - CODEC_ID_FFH264, - CODEC_ID_DXA, - CODEC_ID_DNXHD, - - /* various pcm "codecs" */ - CODEC_ID_PCM_S16LE= 0x10000, - CODEC_ID_PCM_S16BE, - CODEC_ID_PCM_U16LE, - CODEC_ID_PCM_U16BE, - CODEC_ID_PCM_S8, - CODEC_ID_PCM_U8, - CODEC_ID_PCM_MULAW, - CODEC_ID_PCM_ALAW, - CODEC_ID_PCM_S32LE, - CODEC_ID_PCM_S32BE, - CODEC_ID_PCM_U32LE, - CODEC_ID_PCM_U32BE, - CODEC_ID_PCM_S24LE, - CODEC_ID_PCM_S24BE, - CODEC_ID_PCM_U24LE, - CODEC_ID_PCM_U24BE, - CODEC_ID_PCM_S24DAUD, - - /* various adpcm codecs */ - CODEC_ID_ADPCM_IMA_QT= 0x11000, - CODEC_ID_ADPCM_IMA_WAV, - CODEC_ID_ADPCM_IMA_DK3, - CODEC_ID_ADPCM_IMA_DK4, - CODEC_ID_ADPCM_IMA_WS, - CODEC_ID_ADPCM_IMA_SMJPEG, - CODEC_ID_ADPCM_MS, - CODEC_ID_ADPCM_4XM, - CODEC_ID_ADPCM_XA, - CODEC_ID_ADPCM_ADX, - CODEC_ID_ADPCM_EA, - CODEC_ID_ADPCM_G726, - CODEC_ID_ADPCM_CT, - CODEC_ID_ADPCM_SWF, - CODEC_ID_ADPCM_YAMAHA, - CODEC_ID_ADPCM_SBPRO_4, - CODEC_ID_ADPCM_SBPRO_3, - CODEC_ID_ADPCM_SBPRO_2, - - /* AMR */ - CODEC_ID_AMR_NB= 0x12000, - CODEC_ID_AMR_WB, - - /* RealAudio codecs*/ - CODEC_ID_RA_144= 0x13000, - CODEC_ID_RA_288, - - /* various DPCM codecs */ - CODEC_ID_ROQ_DPCM= 0x14000, - CODEC_ID_INTERPLAY_DPCM, - CODEC_ID_XAN_DPCM, - CODEC_ID_SOL_DPCM, - - CODEC_ID_MP2= 0x15000, - CODEC_ID_MP3, /* prefered ID for MPEG Audio layer 1, 2 or3 decoding */ - CODEC_ID_AAC, -#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) - CODEC_ID_MPEG4AAC, -#endif - CODEC_ID_AC3, - CODEC_ID_DTS, - CODEC_ID_VORBIS, - CODEC_ID_DVAUDIO, - CODEC_ID_WMAV1, - CODEC_ID_WMAV2, - CODEC_ID_MACE3, - CODEC_ID_MACE6, - CODEC_ID_VMDAUDIO, - CODEC_ID_SONIC, - CODEC_ID_SONIC_LS, - CODEC_ID_FLAC, - CODEC_ID_MP3ADU, - CODEC_ID_MP3ON4, - CODEC_ID_SHORTEN, - CODEC_ID_ALAC, - CODEC_ID_WESTWOOD_SND1, - CODEC_ID_GSM, /* As in Berlin toast format */ - CODEC_ID_QDM2, - CODEC_ID_COOK, - CODEC_ID_TRUESPEECH, - CODEC_ID_TTA, - CODEC_ID_SMACKAUDIO, - CODEC_ID_QCELP, - CODEC_ID_WAVPACK, - CODEC_ID_DSICINAUDIO, - CODEC_ID_IMC, - CODEC_ID_MUSEPACK7, - CODEC_ID_MLP, - CODEC_ID_GSM_MS, /* As found in WAV */ - - /* subtitle codecs */ - CODEC_ID_DVD_SUBTITLE= 0x17000, - CODEC_ID_DVB_SUBTITLE, - - CODEC_ID_MPEG2TS= 0x20000, /* _FAKE_ codec to indicate a raw MPEG2 transport - stream (only used by libavformat) */ -}; - -#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) -/* CODEC_ID_MP3LAME is absolete */ -#define CODEC_ID_MP3LAME CODEC_ID_MP3 -#define CODEC_ID_MPEG4AAC CODEC_ID_AAC -#endif - -enum CodecType { - CODEC_TYPE_UNKNOWN = -1, - CODEC_TYPE_VIDEO, - CODEC_TYPE_AUDIO, - CODEC_TYPE_DATA, - CODEC_TYPE_SUBTITLE, - CODEC_TYPE_NB -}; - -/* currently unused, may be used if 24/32 bits samples ever supported */ -/* all in native endian */ -enum SampleFormat { - SAMPLE_FMT_NONE = -1, - SAMPLE_FMT_U8, ///< unsigned 8 bits - SAMPLE_FMT_S16, ///< signed 16 bits - SAMPLE_FMT_S24, ///< signed 24 bits - SAMPLE_FMT_S32, ///< signed 32 bits - SAMPLE_FMT_FLT, ///< float -}; - -/* in bytes */ -#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio - -/** - * Required number of additionally allocated bytes at the end of the input bitstream for decoding. - * this is mainly needed because some optimized bitstream readers read - * 32 or 64 bit at once and could read over the end<br> - * Note, if the first 23 bits of the additional bytes are not 0 then damaged - * MPEG bitstreams could cause overread and segfault - */ -#define FF_INPUT_BUFFER_PADDING_SIZE 8 - -/** - * minimum encoding buffer size. - * used to avoid some checks during header writing - */ -#define FF_MIN_BUFFER_SIZE 16384 - -/* motion estimation type, EPZS by default */ -enum Motion_Est_ID { - ME_ZERO = 1, - ME_FULL, - ME_LOG, - ME_PHODS, - ME_EPZS, - ME_X1, - ME_HEX, - ME_UMH, - ME_ITER, -}; - -enum AVDiscard{ -//we leave some space between them for extensions (drop some keyframes for intra only or drop just some bidir frames) - AVDISCARD_NONE =-16, ///< discard nothing - AVDISCARD_DEFAULT= 0, ///< discard useless packets like 0 size packets in avi - AVDISCARD_NONREF = 8, ///< discard all non reference - AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames - AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes - AVDISCARD_ALL = 48, ///< discard all -}; - -typedef struct RcOverride{ - int start_frame; - int end_frame; - int qscale; // if this is 0 then quality_factor will be used instead - float quality_factor; -} RcOverride; - -#define FF_MAX_B_FRAMES 16 - -/* encoding support - these flags can be passed in AVCodecContext.flags before initing - Note: not everything is supported yet. -*/ - -#define CODEC_FLAG_QSCALE 0x0002 ///< use fixed qscale -#define CODEC_FLAG_4MV 0x0004 ///< 4 MV per MB allowed / Advanced prediction for H263 -#define CODEC_FLAG_QPEL 0x0010 ///< use qpel MC -#define CODEC_FLAG_GMC 0x0020 ///< use GMC -#define CODEC_FLAG_MV0 0x0040 ///< always try a MB with MV=<0,0> -#define CODEC_FLAG_PART 0x0080 ///< use data partitioning -/* parent program guarantees that the input for b-frame containing streams is not written to - for at least s->max_b_frames+1 frames, if this is not set than the input will be copied */ -#define CODEC_FLAG_INPUT_PRESERVED 0x0100 -#define CODEC_FLAG_PASS1 0x0200 ///< use internal 2pass ratecontrol in first pass mode -#define CODEC_FLAG_PASS2 0x0400 ///< use internal 2pass ratecontrol in second pass mode -#define CODEC_FLAG_EXTERN_HUFF 0x1000 ///< use external huffman table (for mjpeg) -#define CODEC_FLAG_GRAY 0x2000 ///< only decode/encode grayscale -#define CODEC_FLAG_EMU_EDGE 0x4000///< don't draw edges -#define CODEC_FLAG_PSNR 0x8000 ///< error[?] variables will be set during encoding -#define CODEC_FLAG_TRUNCATED 0x00010000 /** input bitstream might be truncated at a random location instead - of only at frame boundaries */ -#define CODEC_FLAG_NORMALIZE_AQP 0x00020000 ///< normalize adaptive quantization -#define CODEC_FLAG_INTERLACED_DCT 0x00040000 ///< use interlaced dct -#define CODEC_FLAG_LOW_DELAY 0x00080000 ///< force low delay -#define CODEC_FLAG_ALT_SCAN 0x00100000 ///< use alternate scan -#define CODEC_FLAG_TRELLIS_QUANT 0x00200000 ///< use trellis quantization -#define CODEC_FLAG_GLOBAL_HEADER 0x00400000 ///< place global headers in extradata instead of every keyframe -#define CODEC_FLAG_BITEXACT 0x00800000 ///< use only bitexact stuff (except (i)dct) -/* Fx : Flag for h263+ extra options */ -#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) -#define CODEC_FLAG_H263P_AIC 0x01000000 ///< H263 Advanced intra coding / MPEG4 AC prediction (remove this) -#endif -#define CODEC_FLAG_AC_PRED 0x01000000 ///< H263 Advanced intra coding / MPEG4 AC prediction -#define CODEC_FLAG_H263P_UMV 0x02000000 ///< Unlimited motion vector -#define CODEC_FLAG_CBP_RD 0x04000000 ///< use rate distortion optimization for cbp -#define CODEC_FLAG_QP_RD 0x08000000 ///< use rate distortion optimization for qp selectioon -#define CODEC_FLAG_H263P_AIV 0x00000008 ///< H263 Alternative inter vlc -#define CODEC_FLAG_OBMC 0x00000001 ///< OBMC -#define CODEC_FLAG_LOOP_FILTER 0x00000800 ///< loop filter -#define CODEC_FLAG_H263P_SLICE_STRUCT 0x10000000 -#define CODEC_FLAG_INTERLACED_ME 0x20000000 ///< interlaced motion estimation -#define CODEC_FLAG_SVCD_SCAN_OFFSET 0x40000000 ///< will reserve space for SVCD scan offset user data -#define CODEC_FLAG_CLOSED_GOP ((int)0x80000000) -#define CODEC_FLAG2_FAST 0x00000001 ///< allow non spec compliant speedup tricks -#define CODEC_FLAG2_STRICT_GOP 0x00000002 ///< strictly enforce GOP size -#define CODEC_FLAG2_NO_OUTPUT 0x00000004 ///< skip bitstream encoding -#define CODEC_FLAG2_LOCAL_HEADER 0x00000008 ///< place global headers at every keyframe instead of in extradata -#define CODEC_FLAG2_BPYRAMID 0x00000010 ///< H.264 allow b-frames to be used as references -#define CODEC_FLAG2_WPRED 0x00000020 ///< H.264 weighted biprediction for b-frames -#define CODEC_FLAG2_MIXED_REFS 0x00000040 ///< H.264 one reference per partition, as opposed to one reference per macroblock -#define CODEC_FLAG2_8X8DCT 0x00000080 ///< H.264 high profile 8x8 transform -#define CODEC_FLAG2_FASTPSKIP 0x00000100 ///< H.264 fast pskip -#define CODEC_FLAG2_AUD 0x00000200 ///< H.264 access unit delimiters -#define CODEC_FLAG2_BRDO 0x00000400 ///< b-frame rate-distortion optimization -#define CODEC_FLAG2_INTRA_VLC 0x00000800 ///< use MPEG-2 intra VLC table -#define CODEC_FLAG2_MEMC_ONLY 0x00001000 ///< only do ME/MC (I frames -> ref, P frame -> ME+MC) -#define CODEC_FLAG2_DROP_FRAME_TIMECODE 0x00002000 ///< timecode is in drop frame format -#define CODEC_FLAG2_SKIP_RD 0x00004000 ///< RD optimal MB level residual skiping -#define CODEC_FLAG2_CHUNKS 0x00008000 ///< input bitstream might be truncated at a packet boundaries instead of only at frame boundaries -#define CODEC_FLAG2_NON_LINEAR_QUANT 0x00010000 ///< use MPEG-2 non linear quantizer - -/* Unsupported options : - * Syntax Arithmetic coding (SAC) - * Reference Picture Selection - * Independent Segment Decoding */ -/* /Fx */ -/* codec capabilities */ - -#define CODEC_CAP_DRAW_HORIZ_BAND 0x0001 ///< decoder can use draw_horiz_band callback -/** - * Codec uses get_buffer() for allocating buffers. - * direct rendering method 1 - */ -#define CODEC_CAP_DR1 0x0002 -/* if 'parse_only' field is true, then avcodec_parse_frame() can be - used */ -#define CODEC_CAP_PARSE_ONLY 0x0004 -#define CODEC_CAP_TRUNCATED 0x0008 -/* codec can export data for HW decoding (XvMC) */ -#define CODEC_CAP_HWACCEL 0x0010 -/** - * codec has a non zero delay and needs to be feeded with NULL at the end to get the delayed data. - * if this is not set, the codec is guaranteed to never be feeded with NULL data - */ -#define CODEC_CAP_DELAY 0x0020 -/** - * Codec can be fed a final frame with a smaller size. - * This can be used to prevent truncation of the last audio samples. - */ -#define CODEC_CAP_SMALL_LAST_FRAME 0x0040 - -//the following defines may change, don't expect compatibility if you use them -#define MB_TYPE_INTRA4x4 0x0001 -#define MB_TYPE_INTRA16x16 0x0002 //FIXME h264 specific -#define MB_TYPE_INTRA_PCM 0x0004 //FIXME h264 specific -#define MB_TYPE_16x16 0x0008 -#define MB_TYPE_16x8 0x0010 -#define MB_TYPE_8x16 0x0020 -#define MB_TYPE_8x8 0x0040 -#define MB_TYPE_INTERLACED 0x0080 -#define MB_TYPE_DIRECT2 0x0100 //FIXME -#define MB_TYPE_ACPRED 0x0200 -#define MB_TYPE_GMC 0x0400 -#define MB_TYPE_SKIP 0x0800 -#define MB_TYPE_P0L0 0x1000 -#define MB_TYPE_P1L0 0x2000 -#define MB_TYPE_P0L1 0x4000 -#define MB_TYPE_P1L1 0x8000 -#define MB_TYPE_L0 (MB_TYPE_P0L0 | MB_TYPE_P1L0) -#define MB_TYPE_L1 (MB_TYPE_P0L1 | MB_TYPE_P1L1) -#define MB_TYPE_L0L1 (MB_TYPE_L0 | MB_TYPE_L1) -#define MB_TYPE_QUANT 0x00010000 -#define MB_TYPE_CBP 0x00020000 -//Note bits 24-31 are reserved for codec specific use (h264 ref0, mpeg1 0mv, ...) - -/** - * Pan Scan area. - * this specifies the area which should be displayed. Note there may be multiple such areas for one frame - */ -typedef struct AVPanScan{ - /** - * id. - * - encoding: set by user. - * - decoding: set by lavc - */ - int id; - - /** - * width and height in 1/16 pel - * - encoding: set by user. - * - decoding: set by lavc - */ - int width; - int height; - - /** - * position of the top left corner in 1/16 pel for up to 3 fields/frames. - * - encoding: set by user. - * - decoding: set by lavc - */ - int16_t position[3][2]; -}AVPanScan; - -#define FF_COMMON_FRAME \ - /**\ - * pointer to the picture planes.\ - * this might be different from the first allocated byte\ - * - encoding: \ - * - decoding: \ - */\ - uint8_t *data[4];\ - int linesize[4];\ - /**\ - * pointer to the first allocated byte of the picture. can be used in get_buffer/release_buffer\ - * this isn't used by lavc unless the default get/release_buffer() is used\ - * - encoding: \ - * - decoding: \ - */\ - uint8_t *base[4];\ - /**\ - * 1 -> keyframe, 0-> not\ - * - encoding: set by lavc\ - * - decoding: set by lavc\ - */\ - int key_frame;\ -\ - /**\ - * picture type of the frame, see ?_TYPE below.\ - * - encoding: set by lavc for coded_picture (and set by user for input)\ - * - decoding: set by lavc\ - */\ - int pict_type;\ -\ - /**\ - * presentation timestamp in time_base units (time when frame should be shown to user)\ - * if AV_NOPTS_VALUE then frame_rate = 1/time_base will be assumed\ - * - encoding: MUST be set by user\ - * - decoding: set by lavc\ - */\ - int64_t pts;\ -\ - /**\ - * picture number in bitstream order.\ - * - encoding: set by\ - * - decoding: set by lavc\ - */\ - int coded_picture_number;\ - /**\ - * picture number in display order.\ - * - encoding: set by\ - * - decoding: set by lavc\ - */\ - int display_picture_number;\ -\ - /**\ - * quality (between 1 (good) and FF_LAMBDA_MAX (bad)) \ - * - encoding: set by lavc for coded_picture (and set by user for input)\ - * - decoding: set by lavc\ - */\ - int quality; \ -\ - /**\ - * buffer age (1->was last buffer and dint change, 2->..., ...).\ - * set to INT_MAX if the buffer has not been used yet \ - * - encoding: unused\ - * - decoding: MUST be set by get_buffer()\ - */\ - int age;\ -\ - /**\ - * is this picture used as reference\ - * - encoding: unused\ - * - decoding: set by lavc (before get_buffer() call))\ - */\ - int reference;\ -\ - /**\ - * QP table\ - * - encoding: unused\ - * - decoding: set by lavc\ - */\ - int8_t *qscale_table;\ - /**\ - * QP store stride\ - * - encoding: unused\ - * - decoding: set by lavc\ - */\ - int qstride;\ -\ - /**\ - * mbskip_table[mb]>=1 if MB didnt change\ - * stride= mb_width = (width+15)>>4\ - * - encoding: unused\ - * - decoding: set by lavc\ - */\ - uint8_t *mbskip_table;\ -\ - /**\ - * Motion vector table.\ - * @code\ - * example:\ - * int mv_sample_log2= 4 - motion_subsample_log2;\ - * int mb_width= (width+15)>>4;\ - * int mv_stride= (mb_width << mv_sample_log2) + 1;\ - * motion_val[direction][x + y*mv_stride][0->mv_x, 1->mv_y];\ - * @endcode\ - * - encoding: set by user\ - * - decoding: set by lavc\ - */\ - int16_t (*motion_val[2])[2];\ -\ - /**\ - * Macroblock type table\ - * mb_type_base + mb_width + 2\ - * - encoding: set by user\ - * - decoding: set by lavc\ - */\ - uint32_t *mb_type;\ -\ - /**\ - * log2 of the size of the block which a single vector in motion_val represents: \ - * (4->16x16, 3->8x8, 2-> 4x4, 1-> 2x2)\ - * - encoding: unused\ - * - decoding: set by lavc\ - */\ - uint8_t motion_subsample_log2;\ -\ - /**\ - * for some private data of the user\ - * - encoding: unused\ - * - decoding: set by user\ - */\ - void *opaque;\ -\ - /**\ - * error\ - * - encoding: set by lavc if flags&CODEC_FLAG_PSNR\ - * - decoding: unused\ - */\ - uint64_t error[4];\ -\ - /**\ - * type of the buffer (to keep track of who has to dealloc data[*])\ - * - encoding: set by the one who allocs it\ - * - decoding: set by the one who allocs it\ - * Note: user allocated (direct rendering) & internal buffers can not coexist currently\ - */\ - int type;\ - \ - /**\ - * when decoding, this signal how much the picture must be delayed.\ - * extra_delay = repeat_pict / (2*fps)\ - * - encoding: unused\ - * - decoding: set by lavc\ - */\ - int repeat_pict;\ - \ - /**\ - * \ - */\ - int qscale_type;\ - \ - /**\ - * The content of the picture is interlaced.\ - * - encoding: set by user\ - * - decoding: set by lavc (default 0)\ - */\ - int interlaced_frame;\ - \ - /**\ - * if the content is interlaced, is top field displayed first.\ - * - encoding: set by user\ - * - decoding: set by lavc\ - */\ - int top_field_first;\ - \ - /**\ - * Pan scan.\ - * - encoding: set by user\ - * - decoding: set by lavc\ - */\ - AVPanScan *pan_scan;\ - \ - /**\ - * tell user application that palette has changed from previous frame.\ - * - encoding: ??? (no palette-enabled encoder yet)\ - * - decoding: set by lavc (default 0)\ - */\ - int palette_has_changed;\ - \ - /**\ - * Codec suggestion on buffer type if != 0\ - * - encoding: unused\ - * - decoding: set by lavc (before get_buffer() call))\ - */\ - int buffer_hints;\ -\ - /**\ - * DCT coeffitients\ - * - encoding: unused\ - * - decoding: set by lavc\ - */\ - short *dct_coeff;\ -\ - /**\ - * Motion referece frame index\ - * - encoding: set by user\ - * - decoding: set by lavc\ - */\ - int8_t *ref_index[2]; - -#define FF_QSCALE_TYPE_MPEG1 0 -#define FF_QSCALE_TYPE_MPEG2 1 -#define FF_QSCALE_TYPE_H264 2 - -#define FF_BUFFER_TYPE_INTERNAL 1 -#define FF_BUFFER_TYPE_USER 2 ///< Direct rendering buffers (image is (de)allocated by user) -#define FF_BUFFER_TYPE_SHARED 4 ///< buffer from somewhere else, don't dealloc image (data/base), all other tables are not shared -#define FF_BUFFER_TYPE_COPY 8 ///< just a (modified) copy of some other buffer, don't dealloc anything - - -#define FF_I_TYPE 1 // Intra -#define FF_P_TYPE 2 // Predicted -#define FF_B_TYPE 3 // Bi-dir predicted -#define FF_S_TYPE 4 // S(GMC)-VOP MPEG4 -#define FF_SI_TYPE 5 -#define FF_SP_TYPE 6 - -#define FF_BUFFER_HINTS_VALID 0x01 // Buffer hints value is meaningful (if 0 ignore) -#define FF_BUFFER_HINTS_READABLE 0x02 // Codec will read from buffer -#define FF_BUFFER_HINTS_PRESERVE 0x04 // User must not alter buffer content -#define FF_BUFFER_HINTS_REUSABLE 0x08 // Codec will reuse the buffer (update) - -/** - * Audio Video Frame. - */ -typedef struct AVFrame { - FF_COMMON_FRAME -} AVFrame; - -#define DEFAULT_FRAME_RATE_BASE 1001000 - -/** - * main external api structure. - */ -typedef struct AVCodecContext { - /** - * Info on struct for av_log - * - set by avcodec_alloc_context - */ - AVClass *av_class; - /** - * the average bitrate. - * - encoding: set by user. unused for constant quantizer encoding - * - decoding: set by lavc. 0 or some bitrate if this info is available in the stream - */ - int bit_rate; - - /** - * number of bits the bitstream is allowed to diverge from the reference. - * the reference can be CBR (for CBR pass1) or VBR (for pass2) - * - encoding: set by user. unused for constant quantizer encoding - * - decoding: unused - */ - int bit_rate_tolerance; - - /** - * CODEC_FLAG_*. - * - encoding: set by user. - * - decoding: set by user. - */ - int flags; - - /** - * some codecs needs additionnal format info. It is stored here - * - encoding: set by user. - * - decoding: set by lavc. (FIXME is this ok?) - */ - int sub_id; - - /** - * motion estimation algorithm used for video coding. - * 1 (zero), 2 (full), 3 (log), 4 (phods), 5 (epzs), 6 (x1), 7 (hex), - * 8 (umh), 9 (iter) [7, 8 are x264 specific, 9 is snow specific] - * - encoding: MUST be set by user. - * - decoding: unused - */ - int me_method; - - /** - * some codecs need / can use extra-data like huffman tables. - * mjpeg: huffman tables - * rv10: additional flags - * mpeg4: global headers (they can be in the bitstream or here) - * the allocated memory should be FF_INPUT_BUFFER_PADDING_SIZE bytes larger - * then extradata_size to avoid prolems if its read with the bitstream reader - * the bytewise contents of extradata must not depend on the architecture or cpu endianness - * - encoding: set/allocated/freed by lavc. - * - decoding: set/allocated/freed by user. - */ - uint8_t *extradata; - int extradata_size; - - /** - * this is the fundamental unit of time (in seconds) in terms - * of which frame timestamps are represented. for fixed-fps content, - * timebase should be 1/framerate and timestamp increments should be - * identically 1. - * - encoding: MUST be set by user - * - decoding: set by lavc. - */ - AVRational time_base; - - /* video only */ - /** - * picture width / height. - * - encoding: MUST be set by user. - * - decoding: set by lavc. - * Note, for compatibility its possible to set this instead of - * coded_width/height before decoding - */ - int width, height; - -#define FF_ASPECT_EXTENDED 15 - - /** - * the number of pictures in a group of pitures, or 0 for intra_only. - * - encoding: set by user. - * - decoding: unused - */ - int gop_size; - - /** - * pixel format, see PIX_FMT_xxx. - * - encoding: set by user. - * - decoding: set by lavc. - */ - enum PixelFormat pix_fmt; - - /** - * Frame rate emulation. If not zero lower layer (i.e. format handler) - * has to read frames at native frame rate. - * - encoding: set by user. - * - decoding: unused. - */ - int rate_emu; - - /** - * if non NULL, 'draw_horiz_band' is called by the libavcodec - * decoder to draw an horizontal band. It improve cache usage. Not - * all codecs can do that. You must check the codec capabilities - * before - * - encoding: unused - * - decoding: set by user. - * @param height the height of the slice - * @param y the y position of the slice - * @param type 1->top field, 2->bottom field, 3->frame - * @param offset offset into the AVFrame.data from which the slice should be read - */ - void (*draw_horiz_band)(struct AVCodecContext *s, - const AVFrame *src, int offset[4], - int y, int type, int height); - - /* audio only */ - int sample_rate; ///< samples per sec - int channels; - - /** - * audio sample format. - * - encoding: set by user. - * - decoding: set by lavc. - */ - enum SampleFormat sample_fmt; ///< sample format, currenly unused - - /* the following data should not be initialized */ - /** - * samples per packet. initialized when calling 'init' - */ - int frame_size; - int frame_number; ///< audio or video frame number - int real_pict_num; ///< returns the real picture number of previous encoded frame - - /** - * number of frames the decoded output will be delayed relative to - * the encoded input. - * - encoding: set by lavc. - * - decoding: unused - */ - int delay; - - /* - encoding parameters */ - float qcompress; ///< amount of qscale change between easy & hard scenes (0.0-1.0) - float qblur; ///< amount of qscale smoothing over time (0.0-1.0) - - /** - * minimum quantizer. - * - encoding: set by user. - * - decoding: unused - */ - int qmin; - - /** - * maximum quantizer. - * - encoding: set by user. - * - decoding: unused - */ - int qmax; - - /** - * maximum quantizer difference between frames. - * - encoding: set by user. - * - decoding: unused - */ - int max_qdiff; - - /** - * maximum number of b frames between non b frames. - * note: the output will be delayed by max_b_frames+1 relative to the input - * - encoding: set by user. - * - decoding: unused - */ - int max_b_frames; - - /** - * qscale factor between ip and b frames. - * - encoding: set by user. - * - decoding: unused - */ - float b_quant_factor; - - /** obsolete FIXME remove */ - int rc_strategy; -#define FF_RC_STRATEGY_XVID 1 - - int b_frame_strategy; - - /** - * hurry up amount. - * - encoding: unused - * - decoding: set by user. 1-> skip b frames, 2-> skip idct/dequant too, 5-> skip everything except header - * @deprecated Deprecated in favor of skip_idct and skip_frame. - */ - int hurry_up; - - struct AVCodec *codec; - - void *priv_data; - -#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) - /* unused, FIXME remove*/ - int rtp_mode; -#endif - - int rtp_payload_size; /* The size of the RTP payload: the coder will */ - /* do it's best to deliver a chunk with size */ - /* below rtp_payload_size, the chunk will start */ - /* with a start code on some codecs like H.263 */ - /* This doesn't take account of any particular */ - /* headers inside the transmited RTP payload */ - - - /* The RTP callback: This function is called */ - /* every time the encoder has a packet to send */ - /* Depends on the encoder if the data starts */ - /* with a Start Code (it should) H.263 does. */ - /* mb_nb contains the number of macroblocks */ - /* encoded in the RTP payload */ - void (*rtp_callback)(struct AVCodecContext *avctx, void *data, int size, int mb_nb); - - /* statistics, used for 2-pass encoding */ - int mv_bits; - int header_bits; - int i_tex_bits; - int p_tex_bits; - int i_count; - int p_count; - int skip_count; - int misc_bits; - - /** - * number of bits used for the previously encoded frame. - * - encoding: set by lavc - * - decoding: unused - */ - int frame_bits; - - /** - * private data of the user, can be used to carry app specific stuff. - * - encoding: set by user - * - decoding: set by user - */ - void *opaque; - - char codec_name[32]; - enum CodecType codec_type; /* see CODEC_TYPE_xxx */ - enum CodecID codec_id; /* see CODEC_ID_xxx */ - - /** - * fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). - * this is used to workaround some encoder bugs - * - encoding: set by user, if not then the default based on codec_id will be used - * - decoding: set by user, will be converted to upper case by lavc during init - */ - unsigned int codec_tag; - - /** - * workaround bugs in encoders which sometimes cannot be detected automatically. - * - encoding: set by user - * - decoding: set by user - */ - int workaround_bugs; -#define FF_BUG_AUTODETECT 1 ///< autodetection -#define FF_BUG_OLD_MSMPEG4 2 -#define FF_BUG_XVID_ILACE 4 -#define FF_BUG_UMP4 8 -#define FF_BUG_NO_PADDING 16 -#define FF_BUG_AMV 32 -#define FF_BUG_AC_VLC 0 ///< will be removed, libavcodec can now handle these non compliant files by default -#define FF_BUG_QPEL_CHROMA 64 -#define FF_BUG_STD_QPEL 128 -#define FF_BUG_QPEL_CHROMA2 256 -#define FF_BUG_DIRECT_BLOCKSIZE 512 -#define FF_BUG_EDGE 1024 -#define FF_BUG_HPEL_CHROMA 2048 -#define FF_BUG_DC_CLIP 4096 -#define FF_BUG_MS 8192 ///< workaround various bugs in microsofts broken decoders -//#define FF_BUG_FAKE_SCALABILITY 16 //autodetection should work 100% - - /** - * luma single coeff elimination threshold. - * - encoding: set by user - * - decoding: unused - */ - int luma_elim_threshold; - - /** - * chroma single coeff elimination threshold. - * - encoding: set by user - * - decoding: unused - */ - int chroma_elim_threshold; - - /** - * strictly follow the std (MPEG4, ...). - * - encoding: set by user - * - decoding: unused - */ - int strict_std_compliance; -#define FF_COMPLIANCE_VERY_STRICT 2 ///< strictly conform to a older more strict version of the spec or reference software -#define FF_COMPLIANCE_STRICT 1 ///< strictly conform to all the things in the spec no matter what consequences -#define FF_COMPLIANCE_NORMAL 0 -#define FF_COMPLIANCE_INOFFICIAL -1 ///< allow inofficial extensions -#define FF_COMPLIANCE_EXPERIMENTAL -2 ///< allow non standarized experimental things - - /** - * qscale offset between ip and b frames. - * if > 0 then the last p frame quantizer will be used (q= lastp_q*factor+offset) - * if < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset) - * - encoding: set by user. - * - decoding: unused - */ - float b_quant_offset; - - /** - * error resilience higher values will detect more errors but may missdetect - * some more or less valid parts as errors. - * - encoding: unused - * - decoding: set by user - */ - int error_resilience; -#define FF_ER_CAREFUL 1 -#define FF_ER_COMPLIANT 2 -#define FF_ER_AGGRESSIVE 3 -#define FF_ER_VERY_AGGRESSIVE 4 - - /** - * called at the beginning of each frame to get a buffer for it. - * if pic.reference is set then the frame will be read later by lavc - * avcodec_align_dimensions() should be used to find the required width and - * height, as they normally need to be rounded up to the next multiple of 16 - * - encoding: unused - * - decoding: set by lavc, user can override - */ - int (*get_buffer)(struct AVCodecContext *c, AVFrame *pic); - - /** - * called to release buffers which where allocated with get_buffer. - * a released buffer can be reused in get_buffer() - * pic.data[*] must be set to NULL - * - encoding: unused - * - decoding: set by lavc, user can override - */ - void (*release_buffer)(struct AVCodecContext *c, AVFrame *pic); - - /** - * if 1 the stream has a 1 frame delay during decoding. - * - encoding: set by lavc - * - decoding: set by lavc - */ - int has_b_frames; - - /** - * number of bytes per packet if constant and known or 0 - * used by some WAV based audio codecs - */ - int block_align; - - int parse_only; /* - decoding only: if true, only parsing is done - (function avcodec_parse_frame()). The frame - data is returned. Only MPEG codecs support this now. */ - - /** - * 0-> h263 quant 1-> mpeg quant. - * - encoding: set by user. - * - decoding: unused - */ - int mpeg_quant; - - /** - * pass1 encoding statistics output buffer. - * - encoding: set by lavc - * - decoding: unused - */ - char *stats_out; - - /** - * pass2 encoding statistics input buffer. - * concatenated stuff from stats_out of pass1 should be placed here - * - encoding: allocated/set/freed by user - * - decoding: unused - */ - char *stats_in; - - /** - * ratecontrol qmin qmax limiting method. - * 0-> clipping, 1-> use a nice continous function to limit qscale wthin qmin/qmax - * - encoding: set by user. - * - decoding: unused - */ - float rc_qsquish; - - float rc_qmod_amp; - int rc_qmod_freq; - - /** - * ratecontrol override, see RcOverride. - * - encoding: allocated/set/freed by user. - * - decoding: unused - */ - RcOverride *rc_override; - int rc_override_count; - - /** - * rate control equation. - * - encoding: set by user - * - decoding: unused - */ - char *rc_eq; - - /** - * maximum bitrate. - * - encoding: set by user. - * - decoding: unused - */ - int rc_max_rate; - - /** - * minimum bitrate. - * - encoding: set by user. - * - decoding: unused - */ - int rc_min_rate; - - /** - * decoder bitstream buffer size. - * - encoding: set by user. - * - decoding: unused - */ - int rc_buffer_size; - float rc_buffer_aggressivity; - - /** - * qscale factor between p and i frames. - * if > 0 then the last p frame quantizer will be used (q= lastp_q*factor+offset) - * if < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset) - * - encoding: set by user. - * - decoding: unused - */ - float i_quant_factor; - - /** - * qscale offset between p and i frames. - * - encoding: set by user. - * - decoding: unused - */ - float i_quant_offset; - - /** - * initial complexity for pass1 ratecontrol. - * - encoding: set by user. - * - decoding: unused - */ - float rc_initial_cplx; - - /** - * dct algorithm, see FF_DCT_* below. - * - encoding: set by user - * - decoding: unused - */ - int dct_algo; -#define FF_DCT_AUTO 0 -#define FF_DCT_FASTINT 1 -#define FF_DCT_INT 2 -#define FF_DCT_MMX 3 -#define FF_DCT_MLIB 4 -#define FF_DCT_ALTIVEC 5 -#define FF_DCT_FAAN 6 - - /** - * luminance masking (0-> disabled). - * - encoding: set by user - * - decoding: unused - */ - float lumi_masking; - - /** - * temporary complexity masking (0-> disabled). - * - encoding: set by user - * - decoding: unused - */ - float temporal_cplx_masking; - - /** - * spatial complexity masking (0-> disabled). - * - encoding: set by user - * - decoding: unused - */ - float spatial_cplx_masking; - - /** - * p block masking (0-> disabled). - * - encoding: set by user - * - decoding: unused - */ - float p_masking; - - /** - * darkness masking (0-> disabled). - * - encoding: set by user - * - decoding: unused - */ - float dark_masking; - - - /* for binary compatibility */ - int unused; - - /** - * idct algorithm, see FF_IDCT_* below. - * - encoding: set by user - * - decoding: set by user - */ - int idct_algo; -#define FF_IDCT_AUTO 0 -#define FF_IDCT_INT 1 -#define FF_IDCT_SIMPLE 2 -#define FF_IDCT_SIMPLEMMX 3 -#define FF_IDCT_LIBMPEG2MMX 4 -#define FF_IDCT_PS2 5 -#define FF_IDCT_MLIB 6 -#define FF_IDCT_ARM 7 -#define FF_IDCT_ALTIVEC 8 -#define FF_IDCT_SH4 9 -#define FF_IDCT_SIMPLEARM 10 -#define FF_IDCT_H264 11 -#define FF_IDCT_VP3 12 -#define FF_IDCT_IPP 13 -#define FF_IDCT_XVIDMMX 14 -#define FF_IDCT_CAVS 15 -#define FF_IDCT_SIMPLEARMV5TE 16 -#define FF_IDCT_SIMPLEARMV6 17 - - /** - * slice count. - * - encoding: set by lavc - * - decoding: set by user (or 0) - */ - int slice_count; - /** - * slice offsets in the frame in bytes. - * - encoding: set/allocated by lavc - * - decoding: set/allocated by user (or NULL) - */ - int *slice_offset; - - /** - * error concealment flags. - * - encoding: unused - * - decoding: set by user - */ - int error_concealment; -#define FF_EC_GUESS_MVS 1 -#define FF_EC_DEBLOCK 2 - - /** - * dsp_mask could be add used to disable unwanted CPU features - * CPU features (i.e. MMX, SSE. ...) - * - * with FORCE flag you may instead enable given CPU features - * (Dangerous: usable in case of misdetection, improper usage however will - * result into program crash) - */ - unsigned dsp_mask; -#define FF_MM_FORCE 0x80000000 /* force usage of selected flags (OR) */ - /* lower 16 bits - CPU features */ -#ifdef HAVE_MMX -#define FF_MM_MMX 0x0001 /* standard MMX */ -#define FF_MM_3DNOW 0x0004 /* AMD 3DNOW */ -#define FF_MM_MMXEXT 0x0002 /* SSE integer functions or AMD MMX ext */ -#define FF_MM_SSE 0x0008 /* SSE functions */ -#define FF_MM_SSE2 0x0010 /* PIV SSE2 functions */ -#define FF_MM_3DNOWEXT 0x0020 /* AMD 3DNowExt */ -#endif /* HAVE_MMX */ -#ifdef HAVE_IWMMXT -#define FF_MM_IWMMXT 0x0100 /* XScale IWMMXT */ -#endif /* HAVE_IWMMXT */ - - /** - * bits per sample/pixel from the demuxer (needed for huffyuv). - * - encoding: set by lavc - * - decoding: set by user - */ - int bits_per_sample; - - /** - * prediction method (needed for huffyuv). - * - encoding: set by user - * - decoding: unused - */ - int prediction_method; -#define FF_PRED_LEFT 0 -#define FF_PRED_PLANE 1 -#define FF_PRED_MEDIAN 2 - - /** - * sample aspect ratio (0 if unknown). - * numerator and denominator must be relative prime and smaller then 256 for some video standards - * - encoding: set by user. - * - decoding: set by lavc. - */ - AVRational sample_aspect_ratio; - - /** - * the picture in the bitstream. - * - encoding: set by lavc - * - decoding: set by lavc - */ - AVFrame *coded_frame; - - /** - * debug. - * - encoding: set by user. - * - decoding: set by user. - */ - int debug; -#define FF_DEBUG_PICT_INFO 1 -#define FF_DEBUG_RC 2 -#define FF_DEBUG_BITSTREAM 4 -#define FF_DEBUG_MB_TYPE 8 -#define FF_DEBUG_QP 16 -#define FF_DEBUG_MV 32 -#define FF_DEBUG_DCT_COEFF 0x00000040 -#define FF_DEBUG_SKIP 0x00000080 -#define FF_DEBUG_STARTCODE 0x00000100 -#define FF_DEBUG_PTS 0x00000200 -#define FF_DEBUG_ER 0x00000400 -#define FF_DEBUG_MMCO 0x00000800 -#define FF_DEBUG_BUGS 0x00001000 -#define FF_DEBUG_VIS_QP 0x00002000 -#define FF_DEBUG_VIS_MB_TYPE 0x00004000 - - /** - * debug. - * - encoding: set by user. - * - decoding: set by user. - */ - int debug_mv; -#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames -#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames -#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames - - /** - * error. - * - encoding: set by lavc if flags&CODEC_FLAG_PSNR - * - decoding: unused - */ - uint64_t error[4]; - - /** - * minimum MB quantizer. - * - encoding: unused - * - decoding: unused - */ - int mb_qmin; - - /** - * maximum MB quantizer. - * - encoding: unused - * - decoding: unused - */ - int mb_qmax; - - /** - * motion estimation compare function. - * - encoding: set by user. - * - decoding: unused - */ - int me_cmp; - /** - * subpixel motion estimation compare function. - * - encoding: set by user. - * - decoding: unused - */ - int me_sub_cmp; - /** - * macroblock compare function (not supported yet). - * - encoding: set by user. - * - decoding: unused - */ - int mb_cmp; - /** - * interlaced dct compare function - * - encoding: set by user. - * - decoding: unused - */ - int ildct_cmp; -#define FF_CMP_SAD 0 -#define FF_CMP_SSE 1 -#define FF_CMP_SATD 2 -#define FF_CMP_DCT 3 -#define FF_CMP_PSNR 4 -#define FF_CMP_BIT 5 -#define FF_CMP_RD 6 -#define FF_CMP_ZERO 7 -#define FF_CMP_VSAD 8 -#define FF_CMP_VSSE 9 -#define FF_CMP_NSSE 10 -#define FF_CMP_W53 11 -#define FF_CMP_W97 12 -#define FF_CMP_DCTMAX 13 -#define FF_CMP_DCT264 14 -#define FF_CMP_CHROMA 256 - - /** - * ME diamond size & shape. - * - encoding: set by user. - * - decoding: unused - */ - int dia_size; - - /** - * amount of previous MV predictors (2a+1 x 2a+1 square). - * - encoding: set by user. - * - decoding: unused - */ - int last_predictor_count; - - /** - * pre pass for motion estimation. - * - encoding: set by user. - * - decoding: unused - */ - int pre_me; - - /** - * motion estimation pre pass compare function. - * - encoding: set by user. - * - decoding: unused - */ - int me_pre_cmp; - - /** - * ME pre pass diamond size & shape. - * - encoding: set by user. - * - decoding: unused - */ - int pre_dia_size; - - /** - * subpel ME quality. - * - encoding: set by user. - * - decoding: unused - */ - int me_subpel_quality; - - /** - * callback to negotiate the pixelFormat. - * @param fmt is the list of formats which are supported by the codec, - * its terminated by -1 as 0 is a valid format, the formats are ordered by quality - * the first is allways the native one - * @return the choosen format - * - encoding: unused - * - decoding: set by user, if not set then the native format will always be choosen - */ - enum PixelFormat (*get_format)(struct AVCodecContext *s, const enum PixelFormat * fmt); - - /** - * DTG active format information (additionnal aspect ratio - * information only used in DVB MPEG2 transport streams). 0 if - * not set. - * - * - encoding: unused. - * - decoding: set by decoder - */ - int dtg_active_format; -#define FF_DTG_AFD_SAME 8 -#define FF_DTG_AFD_4_3 9 -#define FF_DTG_AFD_16_9 10 -#define FF_DTG_AFD_14_9 11 -#define FF_DTG_AFD_4_3_SP_14_9 13 -#define FF_DTG_AFD_16_9_SP_14_9 14 -#define FF_DTG_AFD_SP_4_3 15 - - /** - * Maximum motion estimation search range in subpel units. - * if 0 then no limit - * - * - encoding: set by user. - * - decoding: unused. - */ - int me_range; - - /** - * intra quantizer bias. - * - encoding: set by user. - * - decoding: unused - */ - int intra_quant_bias; -#define FF_DEFAULT_QUANT_BIAS 999999 - - /** - * inter quantizer bias. - * - encoding: set by user. - * - decoding: unused - */ - int inter_quant_bias; - - /** - * color table ID. - * - encoding: unused. - * - decoding: which clrtable should be used for 8bit RGB images - * table have to be stored somewhere FIXME - */ - int color_table_id; - - /** - * internal_buffer count. - * Don't touch, used by lavc default_get_buffer() - */ - int internal_buffer_count; - - /** - * internal_buffers. - * Don't touch, used by lavc default_get_buffer() - */ - void *internal_buffer; - -#define FF_LAMBDA_SHIFT 7 -#define FF_LAMBDA_SCALE (1<<FF_LAMBDA_SHIFT) -#define FF_QP2LAMBDA 118 ///< factor to convert from H.263 QP to lambda -#define FF_LAMBDA_MAX (256*128-1) - -#define FF_QUALITY_SCALE FF_LAMBDA_SCALE //FIXME maybe remove - /** - * global quality for codecs which cannot change it per frame. - * this should be proportional to MPEG1/2/4 qscale. - * - encoding: set by user. - * - decoding: unused - */ - int global_quality; - -#define FF_CODER_TYPE_VLC 0 -#define FF_CODER_TYPE_AC 1 - /** - * coder type - * - encoding: set by user. - * - decoding: unused - */ - int coder_type; - - /** - * context model - * - encoding: set by user. - * - decoding: unused - */ - int context_model; -#if 0 - /** - * - * - encoding: unused - * - decoding: set by user. - */ - uint8_t * (*realloc)(struct AVCodecContext *s, uint8_t *buf, int buf_size); -#endif - - /** - * slice flags - * - encoding: unused - * - decoding: set by user. - */ - int slice_flags; -#define SLICE_FLAG_CODED_ORDER 0x0001 ///< draw_horiz_band() is called in coded order instead of display -#define SLICE_FLAG_ALLOW_FIELD 0x0002 ///< allow draw_horiz_band() with field slices (MPEG2 field pics) -#define SLICE_FLAG_ALLOW_PLANE 0x0004 ///< allow draw_horiz_band() with 1 component at a time (SVQ1) - - /** - * XVideo Motion Acceleration - * - encoding: forbidden - * - decoding: set by decoder - */ - int xvmc_acceleration; - - /** - * macroblock decision mode - * - encoding: set by user. - * - decoding: unused - */ - int mb_decision; -#define FF_MB_DECISION_SIMPLE 0 ///< uses mb_cmp -#define FF_MB_DECISION_BITS 1 ///< chooses the one which needs the fewest bits -#define FF_MB_DECISION_RD 2 ///< rate distoration - - /** - * custom intra quantization matrix - * - encoding: set by user, can be NULL - * - decoding: set by lavc - */ - uint16_t *intra_matrix; - - /** - * custom inter quantization matrix - * - encoding: set by user, can be NULL - * - decoding: set by lavc - */ - uint16_t *inter_matrix; - - /** - * fourcc from the AVI stream header (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). - * this is used to workaround some encoder bugs - * - encoding: unused - * - decoding: set by user, will be converted to upper case by lavc during init - */ - unsigned int stream_codec_tag; - - /** - * scene change detection threshold. - * 0 is default, larger means fewer detected scene changes - * - encoding: set by user. - * - decoding: unused - */ - int scenechange_threshold; - - /** - * minimum lagrange multipler - * - encoding: set by user. - * - decoding: unused - */ - int lmin; - - /** - * maximum lagrange multipler - * - encoding: set by user. - * - decoding: unused - */ - int lmax; - - /** - * Palette control structure - * - encoding: ??? (no palette-enabled encoder yet) - * - decoding: set by user. - */ - struct AVPaletteControl *palctrl; - - /** - * noise reduction strength - * - encoding: set by user. - * - decoding: unused - */ - int noise_reduction; - - /** - * called at the beginning of a frame to get cr buffer for it. - * buffer type (size, hints) must be the same. lavc won't check it. - * lavc will pass previous buffer in pic, function should return - * same buffer or new buffer with old frame "painted" into it. - * if pic.data[0] == NULL must behave like get_buffer(). - * - encoding: unused - * - decoding: set by lavc, user can override - */ - int (*reget_buffer)(struct AVCodecContext *c, AVFrame *pic); - - /** - * number of bits which should be loaded into the rc buffer before decoding starts - * - encoding: set by user. - * - decoding: unused - */ - int rc_initial_buffer_occupancy; - - /** - * - * - encoding: set by user. - * - decoding: unused - */ - int inter_threshold; - - /** - * CODEC_FLAG2_*. - * - encoding: set by user. - * - decoding: set by user. - */ - int flags2; - - /** - * simulates errors in the bitstream to test error concealment. - * - encoding: set by user. - * - decoding: unused. - */ - int error_rate; - - /** - * MP3 antialias algorithm, see FF_AA_* below. - * - encoding: unused - * - decoding: set by user - */ - int antialias_algo; -#define FF_AA_AUTO 0 -#define FF_AA_FASTINT 1 //not implemented yet -#define FF_AA_INT 2 -#define FF_AA_FLOAT 3 - /** - * Quantizer noise shaping. - * - encoding: set by user - * - decoding: unused - */ - int quantizer_noise_shaping; - - /** - * Thread count. - * is used to decide how many independent tasks should be passed to execute() - * - encoding: set by user - * - decoding: set by user - */ - int thread_count; - - /** - * the codec may call this to execute several independent things. it will return only after - * finishing all tasks, the user may replace this with some multithreaded implementation, the - * default implementation will execute the parts serially - * @param count the number of things to execute - * - encoding: set by lavc, user can override - * - decoding: set by lavc, user can override - */ - int (*execute)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg), void **arg2, int *ret, int count); - - /** - * Thread opaque. - * can be used by execute() to store some per AVCodecContext stuff. - * - encoding: set by execute() - * - decoding: set by execute() - */ - void *thread_opaque; - - /** - * Motion estimation threshold. under which no motion estimation is - * performed, but instead the user specified motion vectors are used - * - * - encoding: set by user - * - decoding: unused - */ - int me_threshold; - - /** - * Macroblock threshold. under which the user specified macroblock types will be used - * - encoding: set by user - * - decoding: unused - */ - int mb_threshold; - - /** - * precision of the intra dc coefficient - 8. - * - encoding: set by user - * - decoding: unused - */ - int intra_dc_precision; - - /** - * noise vs. sse weight for the nsse comparsion function. - * - encoding: set by user - * - decoding: unused - */ - int nsse_weight; - - /** - * number of macroblock rows at the top which are skipped. - * - encoding: unused - * - decoding: set by user - */ - int skip_top; - - /** - * number of macroblock rows at the bottom which are skipped. - * - encoding: unused - * - decoding: set by user - */ - int skip_bottom; - - /** - * profile - * - encoding: set by user - * - decoding: set by lavc - */ - int profile; -#define FF_PROFILE_UNKNOWN -99 - - /** - * level - * - encoding: set by user - * - decoding: set by lavc - */ - int level; -#define FF_LEVEL_UNKNOWN -99 - - /** - * low resolution decoding. 1-> 1/2 size, 2->1/4 size - * - encoding: unused - * - decoding: set by user - */ - int lowres; - - /** - * bitsream width / height. may be different from width/height if lowres - * or other things are used - * - encoding: unused - * - decoding: set by user before init if known, codec should override / dynamically change if needed - */ - int coded_width, coded_height; - - /** - * frame skip threshold - * - encoding: set by user - * - decoding: unused - */ - int frame_skip_threshold; - - /** - * frame skip factor - * - encoding: set by user - * - decoding: unused - */ - int frame_skip_factor; - - /** - * frame skip exponent - * - encoding: set by user - * - decoding: unused - */ - int frame_skip_exp; - - /** - * frame skip comparission function - * - encoding: set by user. - * - decoding: unused - */ - int frame_skip_cmp; - - /** - * border processing masking. raises the quantizer for mbs on the borders - * of the picture. - * - encoding: set by user - * - decoding: unused - */ - float border_masking; - - /** - * minimum MB lagrange multipler. - * - encoding: set by user. - * - decoding: unused - */ - int mb_lmin; - - /** - * maximum MB lagrange multipler. - * - encoding: set by user. - * - decoding: unused - */ - int mb_lmax; - - /** - * - * - encoding: set by user. - * - decoding: unused - */ - int me_penalty_compensation; - - /** - * - * - encoding: unused - * - decoding: set by user. - */ - enum AVDiscard skip_loop_filter; - - /** - * - * - encoding: unused - * - decoding: set by user. - */ - enum AVDiscard skip_idct; - - /** - * - * - encoding: unused - * - decoding: set by user. - */ - enum AVDiscard skip_frame; - - /** - * - * - encoding: set by user. - * - decoding: unused - */ - int bidir_refine; - - /** - * - * - encoding: set by user. - * - decoding: unused - */ - int brd_scale; - - /** - * constant rate factor - quality-based VBR - values ~correspond to qps - * - encoding: set by user. - * - decoding: unused - */ - float crf; - - /** - * constant quantization parameter rate control method - * - encoding: set by user. - * - decoding: unused - */ - int cqp; - - /** - * minimum gop size - * - encoding: set by user. - * - decoding: unused - */ - int keyint_min; - - /** - * number of reference frames - * - encoding: set by user. - * - decoding: unused - */ - int refs; - - /** - * chroma qp offset from luma - * - encoding: set by user. - * - decoding: unused - */ - int chromaoffset; - - /** - * influences how often b-frames are used - * - encoding: set by user. - * - decoding: unused - */ - int bframebias; - - /** - * trellis RD quantization - * - encoding: set by user. - * - decoding: unused - */ - int trellis; - - /** - * reduce fluctuations in qp (before curve compression) - * - encoding: set by user. - * - decoding: unused - */ - float complexityblur; - - /** - * in-loop deblocking filter alphac0 parameter - * alpha is in the range -6...6 - * - encoding: set by user. - * - decoding: unused - */ - int deblockalpha; - - /** - * in-loop deblocking filter beta parameter - * beta is in the range -6...6 - * - encoding: set by user. - * - decoding: unused - */ - int deblockbeta; - - /** - * macroblock subpartition sizes to consider - p8x8, p4x4, b8x8, i8x8, i4x4 - * - encoding: set by user. - * - decoding: unused - */ - int partitions; -#define X264_PART_I4X4 0x001 /* Analyse i4x4 */ -#define X264_PART_I8X8 0x002 /* Analyse i8x8 (requires 8x8 transform) */ -#define X264_PART_P8X8 0x010 /* Analyse p16x8, p8x16 and p8x8 */ -#define X264_PART_P4X4 0x020 /* Analyse p8x4, p4x8, p4x4 */ -#define X264_PART_B8X8 0x100 /* Analyse b16x8, b8x16 and b8x8 */ - - /** - * direct mv prediction mode - 0 (none), 1 (spatial), 2 (temporal) - * - encoding: set by user. - * - decoding: unused - */ - int directpred; - - /** - * audio cutoff bandwidth (0 means "automatic") . Currently used only by FAAC - * - encoding: set by user. - * - decoding: unused - */ - int cutoff; - - /** - * multiplied by qscale for each frame and added to scene_change_score - * - encoding: set by user. - * - decoding: unused - */ - int scenechange_factor; - - /** - * - * note: value depends upon the compare functin used for fullpel ME - * - encoding: set by user. - * - decoding: unused - */ - int mv0_threshold; - - /** - * adjusts sensitivity of b_frame_strategy 1 - * - encoding: set by user. - * - decoding: unused - */ - int b_sensitivity; - - /** - * - encoding: set by user. - * - decoding: unused - */ - int compression_level; -#define FF_COMPRESSION_DEFAULT -1 - - /** - * sets whether to use LPC mode - used by FLAC encoder - * - encoding: set by user. - * - decoding: unused. - */ - int use_lpc; - - /** - * LPC coefficient precision - used by FLAC encoder - * - encoding: set by user. - * - decoding: unused. - */ - int lpc_coeff_precision; - - /** - * - encoding: set by user. - * - decoding: unused. - */ - int min_prediction_order; - - /** - * - encoding: set by user. - * - decoding: unused. - */ - int max_prediction_order; - - /** - * search method for selecting prediction order - * - encoding: set by user. - * - decoding: unused. - */ - int prediction_order_method; - - /** - * - encoding: set by user. - * - decoding: unused. - */ - int min_partition_order; - - /** - * - encoding: set by user. - * - decoding: unused. - */ - int max_partition_order; - - /** - * GOP timecode frame start number, in non drop frame format - * - encoding: set by user. - * - decoding: unused. - */ - int64_t timecode_frame_start; -} AVCodecContext; - -/** - * AVCodec. - */ -typedef struct AVCodec { - const char *name; - enum CodecType type; - enum CodecID id; - int priv_data_size; - int (*init)(AVCodecContext *); - int (*encode)(AVCodecContext *, uint8_t *buf, int buf_size, void *data); - int (*close)(AVCodecContext *); - int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, - uint8_t *buf, int buf_size); - int capabilities; - struct AVCodec *next; - void (*flush)(AVCodecContext *); - const AVRational *supported_framerates; ///array of supported framerates, or NULL if any, array is terminated by {0,0} - const enum PixelFormat *pix_fmts; ///array of supported pixel formats, or NULL if unknown, array is terminanted by -1 -} AVCodec; - -/** - * four components are given, that's all. - * the last component is alpha - */ -typedef struct AVPicture { - uint8_t *data[4]; - int linesize[4]; ///< number of bytes per line -} AVPicture; - -/** - * AVPaletteControl - * This structure defines a method for communicating palette changes - * between and demuxer and a decoder. - * this is totally broken, palette changes should be sent as AVPackets - */ -#define AVPALETTE_SIZE 1024 -#define AVPALETTE_COUNT 256 -typedef struct AVPaletteControl { - - /* demuxer sets this to 1 to indicate the palette has changed; - * decoder resets to 0 */ - int palette_changed; - - /* 4-byte ARGB palette entries, stored in native byte order; note that - * the individual palette components should be on a 8-bit scale; if - * the palette data comes from a IBM VGA native format, the component - * data is probably 6 bits in size and needs to be scaled */ - unsigned int palette[AVPALETTE_COUNT]; - -} AVPaletteControl attribute_deprecated; - -typedef struct AVSubtitleRect { - uint16_t x; - uint16_t y; - uint16_t w; - uint16_t h; - uint16_t nb_colors; - int linesize; - uint32_t *rgba_palette; - uint8_t *bitmap; -} AVSubtitleRect; - -typedef struct AVSubtitle { - uint16_t format; /* 0 = graphics */ - uint32_t start_display_time; /* relative to packet pts, in ms */ - uint32_t end_display_time; /* relative to packet pts, in ms */ - uint32_t num_rects; - AVSubtitleRect *rects; -} AVSubtitle; - -extern AVCodec ac3_encoder; -extern AVCodec amr_nb_encoder; -extern AVCodec amr_wb_encoder; -extern AVCodec asv1_encoder; -extern AVCodec asv2_encoder; -extern AVCodec bmp_encoder; -extern AVCodec dvvideo_encoder; -extern AVCodec faac_encoder; -extern AVCodec ffv1_encoder; -extern AVCodec ffvhuff_encoder; -extern AVCodec flac_encoder; -extern AVCodec flashsv_encoder; -extern AVCodec flv_encoder; -extern AVCodec gif_encoder; -extern AVCodec h261_encoder; -extern AVCodec h263_encoder; -extern AVCodec h263p_encoder; -extern AVCodec h264_encoder; -extern AVCodec huffyuv_encoder; -extern AVCodec jpegls_encoder; -extern AVCodec libgsm_encoder; -extern AVCodec libgsm_ms_encoder; -extern AVCodec libtheora_encoder; -extern AVCodec ljpeg_encoder; -extern AVCodec mdec_encoder; -extern AVCodec mjpeg_encoder; -extern AVCodec mp2_encoder; -extern AVCodec mp3lame_encoder; -extern AVCodec mpeg1video_encoder; -extern AVCodec mpeg2video_encoder; -extern AVCodec mpeg4_encoder; -extern AVCodec msmpeg4v1_encoder; -extern AVCodec msmpeg4v2_encoder; -extern AVCodec msmpeg4v3_encoder; -extern AVCodec oggvorbis_encoder; -extern AVCodec pam_encoder; -extern AVCodec pbm_encoder; -extern AVCodec pgm_encoder; -extern AVCodec pgmyuv_encoder; -extern AVCodec png_encoder; -extern AVCodec ppm_encoder; -extern AVCodec rv10_encoder; -extern AVCodec rv20_encoder; -extern AVCodec snow_encoder; -extern AVCodec sonic_encoder; -extern AVCodec sonic_ls_encoder; -extern AVCodec svq1_encoder; -extern AVCodec targa_encoder; -extern AVCodec vcr1_encoder; -extern AVCodec vorbis_encoder; -extern AVCodec wmav1_encoder; -extern AVCodec wmav2_encoder; -extern AVCodec wmv1_encoder; -extern AVCodec wmv2_encoder; -extern AVCodec x264_encoder; -extern AVCodec xvid_encoder; -extern AVCodec zlib_encoder; -extern AVCodec zmbv_encoder; - -extern AVCodec aac_decoder; -extern AVCodec aasc_decoder; -extern AVCodec alac_decoder; -extern AVCodec amr_nb_decoder; -extern AVCodec amr_wb_decoder; -extern AVCodec asv1_decoder; -extern AVCodec asv2_decoder; -extern AVCodec avs_decoder; -extern AVCodec bmp_decoder; -extern AVCodec cavs_decoder; -extern AVCodec cinepak_decoder; -extern AVCodec cljr_decoder; -extern AVCodec cook_decoder; -extern AVCodec cscd_decoder; -extern AVCodec cyuv_decoder; -extern AVCodec dca_decoder; -extern AVCodec dnxhd_decoder; -extern AVCodec dsicinaudio_decoder; -extern AVCodec dsicinvideo_decoder; -extern AVCodec dvvideo_decoder; -extern AVCodec dxa_decoder; -extern AVCodec eightbps_decoder; -extern AVCodec ffv1_decoder; -extern AVCodec ffvhuff_decoder; -extern AVCodec flac_decoder; -extern AVCodec flashsv_decoder; -extern AVCodec flic_decoder; -extern AVCodec flv_decoder; -extern AVCodec fourxm_decoder; -extern AVCodec fraps_decoder; -extern AVCodec gif_decoder; -extern AVCodec h261_decoder; -extern AVCodec h263_decoder; -extern AVCodec h263i_decoder; -extern AVCodec h264_decoder; -extern AVCodec huffyuv_decoder; -extern AVCodec idcin_decoder; -extern AVCodec imc_decoder; -extern AVCodec indeo2_decoder; -extern AVCodec indeo3_decoder; -extern AVCodec interplay_dpcm_decoder; -extern AVCodec interplay_video_decoder; -extern AVCodec kmvc_decoder; -extern AVCodec libgsm_decoder; -extern AVCodec libgsm_ms_decoder; -extern AVCodec loco_decoder; -extern AVCodec mace3_decoder; -extern AVCodec mace6_decoder; -extern AVCodec mdec_decoder; -extern AVCodec mjpeg_decoder; -extern AVCodec mjpegb_decoder; -extern AVCodec mmvideo_decoder; -extern AVCodec mp2_decoder; -extern AVCodec mp3_decoder; -extern AVCodec mp3adu_decoder; -extern AVCodec mp3on4_decoder; -extern AVCodec mpc7_decoder; -extern AVCodec mpeg1video_decoder; -extern AVCodec mpeg2video_decoder; -extern AVCodec mpeg4_decoder; -extern AVCodec mpeg4aac_decoder; -extern AVCodec mpeg_xvmc_decoder; -extern AVCodec mpegvideo_decoder; -extern AVCodec msmpeg4v1_decoder; -extern AVCodec msmpeg4v2_decoder; -extern AVCodec msmpeg4v3_decoder; -extern AVCodec msrle_decoder; -extern AVCodec msvideo1_decoder; -extern AVCodec mszh_decoder; -extern AVCodec nuv_decoder; -extern AVCodec oggvorbis_decoder; -extern AVCodec png_decoder; -extern AVCodec qdm2_decoder; -extern AVCodec qdraw_decoder; -extern AVCodec qpeg_decoder; -extern AVCodec qtrle_decoder; -extern AVCodec ra_144_decoder; -extern AVCodec ra_288_decoder; -extern AVCodec roq_decoder; -extern AVCodec roq_dpcm_decoder; -extern AVCodec rpza_decoder; -extern AVCodec rv10_decoder; -extern AVCodec rv20_decoder; -extern AVCodec rv30_decoder; -extern AVCodec rv40_decoder; -extern AVCodec shorten_decoder; -extern AVCodec smackaud_decoder; -extern AVCodec smacker_decoder; -extern AVCodec smc_decoder; -extern AVCodec snow_decoder; -extern AVCodec sol_dpcm_decoder; -extern AVCodec sonic_decoder; -extern AVCodec sp5x_decoder; -extern AVCodec svq1_decoder; -extern AVCodec svq3_decoder; -extern AVCodec targa_decoder; -extern AVCodec theora_decoder; -extern AVCodec tiertexseqvideo_decoder; -extern AVCodec tiff_decoder; -extern AVCodec truemotion1_decoder; -extern AVCodec truemotion2_decoder; -extern AVCodec truespeech_decoder; -extern AVCodec tscc_decoder; -extern AVCodec tta_decoder; -extern AVCodec ulti_decoder; -extern AVCodec vc1_decoder; -extern AVCodec vcr1_decoder; -extern AVCodec vmdaudio_decoder; -extern AVCodec vmdvideo_decoder; -extern AVCodec vmnc_decoder; -extern AVCodec vorbis_decoder; -extern AVCodec vp3_decoder; -extern AVCodec vp5_decoder; -extern AVCodec vp6_decoder; -extern AVCodec vp6f_decoder; -extern AVCodec vqa_decoder; -extern AVCodec wavpack_decoder; -extern AVCodec wmav1_decoder; -extern AVCodec wmav2_decoder; -extern AVCodec wmv1_decoder; -extern AVCodec wmv2_decoder; -extern AVCodec wmv3_decoder; -extern AVCodec wnv1_decoder; -extern AVCodec ws_snd1_decoder; -extern AVCodec xan_dpcm_decoder; -extern AVCodec xan_wc3_decoder; -extern AVCodec xl_decoder; -extern AVCodec zlib_decoder; -extern AVCodec zmbv_decoder; - -/* pcm codecs */ -#define PCM_CODEC(id, name) \ -extern AVCodec name ## _decoder; \ -extern AVCodec name ## _encoder - -PCM_CODEC(CODEC_ID_PCM_ALAW, pcm_alaw); -PCM_CODEC(CODEC_ID_PCM_MULAW, pcm_mulaw); -PCM_CODEC(CODEC_ID_PCM_S8, pcm_s8); -PCM_CODEC(CODEC_ID_PCM_S16BE, pcm_s16be); -PCM_CODEC(CODEC_ID_PCM_S16LE, pcm_s16le); -PCM_CODEC(CODEC_ID_PCM_S24BE, pcm_s24be); -PCM_CODEC(CODEC_ID_PCM_S24DAUD, pcm_s24daud); -PCM_CODEC(CODEC_ID_PCM_S24LE, pcm_s24le); -PCM_CODEC(CODEC_ID_PCM_S32BE, pcm_s32be); -PCM_CODEC(CODEC_ID_PCM_S32LE, pcm_s32le); -PCM_CODEC(CODEC_ID_PCM_U8, pcm_u8); -PCM_CODEC(CODEC_ID_PCM_U16BE, pcm_u16be); -PCM_CODEC(CODEC_ID_PCM_U16LE, pcm_u16le); -PCM_CODEC(CODEC_ID_PCM_U24BE, pcm_u24be); -PCM_CODEC(CODEC_ID_PCM_U24LE, pcm_u24le); -PCM_CODEC(CODEC_ID_PCM_U32BE, pcm_u32be); -PCM_CODEC(CODEC_ID_PCM_U32LE, pcm_u32le); - -/* adpcm codecs */ - -PCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm); -PCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx); -PCM_CODEC(CODEC_ID_ADPCM_CT, adpcm_ct); -PCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea); -PCM_CODEC(CODEC_ID_ADPCM_G726, adpcm_g726); -PCM_CODEC(CODEC_ID_ADPCM_IMA_DK3, adpcm_ima_dk3); -PCM_CODEC(CODEC_ID_ADPCM_IMA_DK4, adpcm_ima_dk4); -PCM_CODEC(CODEC_ID_ADPCM_IMA_QT, adpcm_ima_qt); -PCM_CODEC(CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav); -PCM_CODEC(CODEC_ID_ADPCM_IMA_WS, adpcm_ima_ws); -PCM_CODEC(CODEC_ID_ADPCM_MS, adpcm_ms); -PCM_CODEC(CODEC_ID_ADPCM_SBPRO_2, adpcm_sbpro_2); -PCM_CODEC(CODEC_ID_ADPCM_SBPRO_3, adpcm_sbpro_3); -PCM_CODEC(CODEC_ID_ADPCM_SBPRO_4, adpcm_sbpro_4); -PCM_CODEC(CODEC_ID_ADPCM_SMJPEG, adpcm_ima_smjpeg); -PCM_CODEC(CODEC_ID_ADPCM_SWF, adpcm_swf); -PCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa); -PCM_CODEC(CODEC_ID_ADPCM_YAMAHA, adpcm_yamaha); - -#undef PCM_CODEC - -/* dummy raw video codec */ -extern AVCodec rawvideo_decoder; -extern AVCodec rawvideo_encoder; - -/* the following codecs use external GPL libs */ -extern AVCodec dts_decoder; -extern AVCodec liba52_decoder; - -/* subtitles */ -extern AVCodec dvbsub_decoder; -extern AVCodec dvbsub_encoder; -extern AVCodec dvdsub_decoder; -extern AVCodec dvdsub_encoder; - -/* resample.c */ - -struct ReSampleContext; -struct AVResampleContext; - -typedef struct ReSampleContext ReSampleContext; - -ReSampleContext *audio_resample_init(int output_channels, int input_channels, - int output_rate, int input_rate); -int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples); -void audio_resample_close(ReSampleContext *s); - -struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff); -int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx); -void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance); -void av_resample_close(struct AVResampleContext *c); - -#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) -/* YUV420 format is assumed ! */ - -struct ImgReSampleContext attribute_deprecated; - -typedef struct ImgReSampleContext ImgReSampleContext attribute_deprecated; - -attribute_deprecated ImgReSampleContext *img_resample_init(int output_width, int output_height, - int input_width, int input_height); - -attribute_deprecated ImgReSampleContext *img_resample_full_init(int owidth, int oheight, - int iwidth, int iheight, - int topBand, int bottomBand, - int leftBand, int rightBand, - int padtop, int padbottom, - int padleft, int padright); - - -attribute_deprecated void img_resample(ImgReSampleContext *s, - AVPicture *output, const AVPicture *input); - -attribute_deprecated void img_resample_close(ImgReSampleContext *s); - -#endif - -/** - * Allocate memory for a picture. Call avpicture_free to free it. - * - * @param picture the picture to be filled in. - * @param pix_fmt the format of the picture. - * @param width the width of the picture. - * @param height the height of the picture. - * @return Zero if successful, a negative value if not. - */ -int avpicture_alloc(AVPicture *picture, int pix_fmt, int width, int height); - -/** - * Free a picture previously allocated by avpicture_alloc(). - * - * @param picture The AVPicture to be freed. - */ -void avpicture_free(AVPicture *picture); - -/** - * Fill in AVPicture's fields. - * The fields of the given AVPicture are filled in by using the 'ptr' address - * which points to the image data buffer. Depending on the specified picture - * format, one or multiple image data pointers and line sizes will be set. - * If a planar format is specified, several pointers will be set pointing to - * the different picture planes and the line sizes of the different planes - * will be stored in the lines_sizes array. - * - * @param picture AVPicture who's fields are to be filled in - * @param ptr Buffer which will contain or contains the actual image data - * @param pix_fmt The format in which the picture data is stored - * @param width The width of the image in pixels - * @param height The height of the image in pixels - * @return Size of the image data in bytes. - */ -int avpicture_fill(AVPicture *picture, uint8_t *ptr, - int pix_fmt, int width, int height); -int avpicture_layout(const AVPicture* src, int pix_fmt, int width, int height, - unsigned char *dest, int dest_size); - -/** - * Calculate the size in bytes that a picture of the given width and height - * would occupy if stored in the given picture format. - * - * @param pix_fmt The given picture format - * @param width The width of the image - * @param height The height of the image - * @return Image data size in bytes - */ -int avpicture_get_size(int pix_fmt, int width, int height); -void avcodec_get_chroma_sub_sample(int pix_fmt, int *h_shift, int *v_shift); -const char *avcodec_get_pix_fmt_name(int pix_fmt); -void avcodec_set_dimensions(AVCodecContext *s, int width, int height); -enum PixelFormat avcodec_get_pix_fmt(const char* name); -unsigned int avcodec_pix_fmt_to_codec_tag(enum PixelFormat p); - -#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */ -#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */ -#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */ -#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */ -#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */ -#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */ - -/** - * Computes what kind of losses will occur when converting from one specific - * pixel format to another. - * When converting from one pixel format to another, information loss may occur. - * For example, when converting from RGB24 to GRAY, the color information will - * be lost. Similarly, other losses occur when converting from some formats to - * other formats. These losses can involve loss of chroma, but also loss of - * resolution, loss of color depth, loss due to the color space conversion, loss - * of the alpha bits or loss due to color quantization. - * avcodec_get_fix_fmt_loss() informs you on the various types of losses which - * will occur when converting from one pixel format to another. - * - * @param[in] dst_pix_fmt Destination pixel format. - * @param[in] src_pix_fmt Source pixel format. - * @param[in] has_alpha Whether the source pixel format alpha channel is used. - * @return Combination of flags informing you what kind of losses will occur. - */ -int avcodec_get_pix_fmt_loss(int dst_pix_fmt, int src_pix_fmt, - int has_alpha); - -/** - * Finds the best pixel format to convert to given a certain source pixel - * format. When converting from one pixel format to another, information loss - * may occur. For example, when converting from RGB24 to GRAY, the color - * information will be lost. Similarly, other losses occur when converting from - * some formats to other formats. avcodec_find_best_pix_fmt() searches which of - * the given pixel formats should be used to undergo the least amount of losses. - * The pixel formats from which it choses one, are determined by the - * \p pix_fmt_mask parameter. - * - * @code - * src_pix_fmt = PIX_FMT_YUV420P; - * pix_fmt_mask = (1 << PIX_FMT_YUV422P) || (1 << PIX_FMT_RGB24); - * dst_pix_fmt = avcodec_find_best_pix_fmt(pix_fmt_mask, src_pix_fmt, alpha, &loss); - * @endcode - * - * @param[in] pix_fmt_mask Bitmask determining which pixel format to choose from. - * @param[in] src_pix_fmt Source pixel format. - * @param[in] has_alpha Whether the source pixel format alpha channel is used. - * @param[out] loss_ptr Combination of flags informing you what kind of losses will occur. - * @return The best pixel format to convert to or -1 if none was found. - */ -int avcodec_find_best_pix_fmt(int pix_fmt_mask, int src_pix_fmt, - int has_alpha, int *loss_ptr); - -#define FF_ALPHA_TRANSP 0x0001 /* image has some totally transparent pixels */ -#define FF_ALPHA_SEMI_TRANSP 0x0002 /* image has some transparent pixels */ - -/** - * Tell if an image really has transparent alpha values. - * @return ored mask of FF_ALPHA_xxx constants - */ -int img_get_alpha_info(const AVPicture *src, - int pix_fmt, int width, int height); - -#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) -/* convert among pixel formats */ -attribute_deprecated int img_convert(AVPicture *dst, int dst_pix_fmt, - const AVPicture *src, int pix_fmt, - int width, int height); -#endif - -/* deinterlace a picture */ -/* deinterlace - if not supported return -1 */ -int avpicture_deinterlace(AVPicture *dst, const AVPicture *src, - int pix_fmt, int width, int height); - -/* external high level API */ - -extern AVCodec *first_avcodec; - -/* returns LIBAVCODEC_VERSION_INT constant */ -unsigned avcodec_version(void); -/* returns LIBAVCODEC_BUILD constant */ -unsigned avcodec_build(void); - -/** - * Initializes libavcodec. - * - * @warning This function \e must be called before any other libavcodec - * function. - */ -void avcodec_init(void); - -void register_avcodec(AVCodec *format); - -/** - * Finds an encoder with a matching codec ID. - * - * @param id CodecID of the requested encoder. - * @return An encoder if one was found, NULL otherwise. - */ -AVCodec *avcodec_find_encoder(enum CodecID id); - -/** - * Finds an encoder with the specified name. - * - * @param name Name of the requested encoder. - * @return An encoder if one was found, NULL otherwise. - */ -AVCodec *avcodec_find_encoder_by_name(const char *name); - -/** - * Finds a decoder with a matching codec ID. - * - * @param id CodecID of the requested decoder. - * @return A decoder if one was found, NULL otherwise. - */ -AVCodec *avcodec_find_decoder(enum CodecID id); - -/** - * Finds an decoder with the specified name. - * - * @param name Name of the requested decoder. - * @return A decoder if one was found, NULL otherwise. - */ -AVCodec *avcodec_find_decoder_by_name(const char *name); -void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode); - -/** - * Sets the fields of the given AVCodecContext to default values. - * - * @param s The AVCodecContext of which the fields should be set to default values. - */ -void avcodec_get_context_defaults(AVCodecContext *s); - -/** THIS FUNCTION IS NOT YET PART OF THE PUBLIC API! - * we WILL change its arguments and name a few times! */ -void avcodec_get_context_defaults2(AVCodecContext *s, enum CodecType); - -/** - * Allocates an AVCodecContext and sets its fields to default values. The - * resulting struct can be deallocated by simply calling av_free(). - * - * @return An AVCodecContext filled with default values or NULL on failure. - * @see avcodec_get_context_defaults - */ -AVCodecContext *avcodec_alloc_context(void); - -/** THIS FUNCTION IS NOT YET PART OF THE PUBLIC API! - * we WILL change its arguments and name a few times! */ -AVCodecContext *avcodec_alloc_context2(enum CodecType); - -/** - * Sets the fields of the given AVFrame to default values. - * - * @param pic The AVFrame of which the fields should be set to default values. - */ -void avcodec_get_frame_defaults(AVFrame *pic); - -/** - * Allocates an AVFrame and sets its fields to default values. The resulting - * struct can be deallocated by simply calling av_free(). - * - * @return An AVFrame filled with default values or NULL on failure. - * @see avcodec_get_frame_defaults - */ -AVFrame *avcodec_alloc_frame(void); - -int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic); -void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic); -int avcodec_default_reget_buffer(AVCodecContext *s, AVFrame *pic); -void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height); - -/** - * Checks if the given dimension of a picture is valid, meaning that all - * bytes of the picture can be addressed with a signed int. - * - * @param[in] w Width of the picture. - * @param[in] h Height of the picture. - * @return Zero if valid, a negative value if invalid. - */ -int avcodec_check_dimensions(void *av_log_ctx, unsigned int w, unsigned int h); -enum PixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum PixelFormat * fmt); - -int avcodec_thread_init(AVCodecContext *s, int thread_count); -void avcodec_thread_free(AVCodecContext *s); -int avcodec_thread_execute(AVCodecContext *s, int (*func)(AVCodecContext *c2, void *arg2),void **arg, int *ret, int count); -int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2),void **arg, int *ret, int count); -//FIXME func typedef - -/** - * Initializes the AVCodecContext to use the given AVCodec. Prior to using this - * function the context has to be allocated. - * - * The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(), - * avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for - * retrieving a codec. - * - * @warning This function is not thread save! - * - * @code - * codec = avcodec_find_decoder(CODEC_ID_H264); - * if (!codec) - * exit(1); - * - * context = avcodec_alloc_context(); - * - * if (avcodec_open(context, codec) < 0) - * exit(1); - * @endcode - * - * @param avctx The context which will be setup to use the given codec. - * @param codec The codec to use within the context. - * @return Zero on success, a negative value on error. - * @see avcodec_alloc_context, avcodec_find_decoder, avcodec_find_encoder - */ -int avcodec_open(AVCodecContext *avctx, AVCodec *codec); - -/** - * @deprecated Use avcodec_decode_audio2() instead. - */ -attribute_deprecated int avcodec_decode_audio(AVCodecContext *avctx, int16_t *samples, - int *frame_size_ptr, - uint8_t *buf, int buf_size); - -/** - * Decodes an audio frame from \p buf into \p samples. - * The avcodec_decode_audio2() function decodes a frame of audio from the input - * buffer \p buf of size \p buf_size. To decode it, it makes use of the - * audiocodec which was coupled with \p avctx using avcodec_open(). The - * resulting decoded frame is stored in output buffer \p samples. If no frame - * could be decompressed, \p frame_size_ptr is zero. Otherwise, it is the - * decompressed frame size in \e bytes. - * - * @warning You \e must set \p frame_size_ptr to the allocated size of the - * output buffer before calling avcodec_decode_audio2(). - * - * @warning The input buffer must be \c FF_INPUT_BUFFER_PADDING_SIZE larger than - * the actual read bytes because some optimized bitstream readers read 32 or 64 - * bits at once and could read over the end. - * - * @warning The end of the input buffer \p buf should be set to 0 to ensure that - * no overreading happens for damaged MPEG streams. - * - * @note You might have to align the input buffer \p buf and output buffer \p - * samples. The alignment requirements depend on the CPU: on some CPUs it isn't - * necessary at all, on others it won't work at all if not aligned and on others - * it will work but it will have an impact on performance. In practice, the - * bitstream should have 4 byte alignment at minimum and all sample data should - * be 16 byte aligned unless the CPU doesn't need it (AltiVec and SSE do). If - * the linesize is not a multiple of 16 then there's no sense in aligning the - * start of the buffer to 16. - * - * @param avctx The codec context. - * @param[out] samples The output buffer. - * @param[in,out] frame_size_ptr The output buffer size in bytes. - * @param[in] buf The input buffer. - * @param[in] buf_size The input buffer size in bytes. - * @return On error a negative value is returned, otherwise the number of bytes - * used or zero if no frame could be decompressed. - */ -int avcodec_decode_audio2(AVCodecContext *avctx, int16_t *samples, - int *frame_size_ptr, - uint8_t *buf, int buf_size); - -/** - * Decodes a video frame from \p buf into \p picture. - * The avcodec_decode_video() function decodes a frame of video from the input - * buffer \p buf of size \p buf_size. To decode it, it makes use of the - * videocodec which was coupled with \p avctx using avcodec_open(). The - * resulting decoded frame is stored in \p picture. - * - * @warning The input buffer must be \c FF_INPUT_BUFFER_PADDING_SIZE larger than - * the actual read bytes because some optimized bitstream readers read 32 or 64 - * bits at once and could read over the end. - * - * @warning The end of the input buffer \p buf should be set to 0 to ensure that - * no overreading happens for damaged MPEG streams. - * - * @note You might have to align the input buffer \p buf and output buffer \p - * samples. The alignment requirements depend on the CPU: on some CPUs it isn't - * necessary at all, on others it won't work at all if not aligned and on others - * it will work but it will have an impact on performance. In practice, the - * bitstream should have 4 byte alignment at minimum and all sample data should - * be 16 byte aligned unless the CPU doesn't need it (AltiVec and SSE do). If - * the linesize is not a multiple of 16 then there's no sense in aligning the - * start of the buffer to 16. - * - * @param avctx The codec context. - * @param[out] picture The AVFrame in which the decoded video frame will be stored. - * @param[in] buf The input buffer. - * @param[in] buf_size The size of the input buffer in bytes. - * @param[in,out] got_picture_ptr Zero if no frame could be decompressed, otherwise, it is non zero. - * @return On error a negative value is returned, otherwise the number of bytes - * used or zero if no frame could be decompressed. - */ -int avcodec_decode_video(AVCodecContext *avctx, AVFrame *picture, - int *got_picture_ptr, - uint8_t *buf, int buf_size); - -/* decode a subtitle message. return -1 if error, otherwise return the - *number of bytes used. If no subtitle could be decompressed, - *got_sub_ptr is zero. Otherwise, the subtitle is stored in *sub. */ -int avcodec_decode_subtitle(AVCodecContext *avctx, AVSubtitle *sub, - int *got_sub_ptr, - const uint8_t *buf, int buf_size); -int avcodec_parse_frame(AVCodecContext *avctx, uint8_t **pdata, - int *data_size_ptr, - uint8_t *buf, int buf_size); - -/** - * Encodes an audio frame from \p samples into \p buf. - * The avcodec_encode_audio() function encodes a frame of audio from the input - * buffer \p samples. To encode it, it makes use of the audiocodec which was - * coupled with \p avctx using avcodec_open(). The resulting encoded frame is - * stored in output buffer \p buf. - * - * @note The output buffer should be at least \c FF_MIN_BUFFER_SIZE bytes large. - * - * @param avctx The codec context. - * @param[out] buf The output buffer. - * @param[in] buf_size The output buffer size. - * @param[in] samples The input buffer containing the samples. - * @return On error a negative value is returned, on succes zero or the number - * of bytes used from the input buffer. - */ -int avcodec_encode_audio(AVCodecContext *avctx, uint8_t *buf, int buf_size, - const short *samples); - -/** - * Encodes a video frame from \p pict into \p buf. - * The avcodec_encode_video() function encodes a frame of video from the input - * \p pict. To encode it, it makes use of the videocodec which was coupled with - * \p avctx using avcodec_open(). The resulting encoded bytes representing the - * frame are stored in the output buffer \p buf. The input picture should be - * stored using a specific format, namely \c avctx.pix_fmt. - * - * @param avctx The codec context. - * @param[out] buf The output buffer for the bitstream of encoded frame. - * @param[in] buf_size The size of the outputbuffer in bytes. - * @param[in] pict The input picture to encode. - * @return On error a negative value is returned, on success zero or the number - * of bytes used from the input buffer. - */ -int avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size, - const AVFrame *pict); -int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, - const AVSubtitle *sub); - -int avcodec_close(AVCodecContext *avctx); - -void avcodec_register_all(void); - -/** - * Flush buffers, should be called when seeking or when switching to a different stream. - */ -void avcodec_flush_buffers(AVCodecContext *avctx); - -void avcodec_default_free_buffers(AVCodecContext *s); - -/* misc useful functions */ - -/** - * Returns a single letter to describe the given picture type \p pict_type. - * - * @param[in] pict_type The picture type. - * @return A single character representing the picture type. - */ -char av_get_pict_type_char(int pict_type); - -/** - * Returns codec bits per sample. - * - * @param[in] codec_id The codec. - * @return Number of bits per sample or zero if unknown for the given codec. - */ -int av_get_bits_per_sample(enum CodecID codec_id); - -/* frame parsing */ -typedef struct AVCodecParserContext { - void *priv_data; - struct AVCodecParser *parser; - int64_t frame_offset; /* offset of the current frame */ - int64_t cur_offset; /* current offset - (incremented by each av_parser_parse()) */ - int64_t last_frame_offset; /* offset of the last frame */ - /* video info */ - int pict_type; /* XXX: put it back in AVCodecContext */ - int repeat_pict; /* XXX: put it back in AVCodecContext */ - int64_t pts; /* pts of the current frame */ - int64_t dts; /* dts of the current frame */ - - /* private data */ - int64_t last_pts; - int64_t last_dts; - int fetch_timestamp; - -#define AV_PARSER_PTS_NB 4 - int cur_frame_start_index; - int64_t cur_frame_offset[AV_PARSER_PTS_NB]; - int64_t cur_frame_pts[AV_PARSER_PTS_NB]; - int64_t cur_frame_dts[AV_PARSER_PTS_NB]; - - int flags; -#define PARSER_FLAG_COMPLETE_FRAMES 0x0001 -} AVCodecParserContext; - -typedef struct AVCodecParser { - int codec_ids[5]; /* several codec IDs are permitted */ - int priv_data_size; - int (*parser_init)(AVCodecParserContext *s); - int (*parser_parse)(AVCodecParserContext *s, - AVCodecContext *avctx, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size); - void (*parser_close)(AVCodecParserContext *s); - int (*split)(AVCodecContext *avctx, const uint8_t *buf, int buf_size); - struct AVCodecParser *next; -} AVCodecParser; - -extern AVCodecParser *av_first_parser; - -void av_register_codec_parser(AVCodecParser *parser); -AVCodecParserContext *av_parser_init(int codec_id); -int av_parser_parse(AVCodecParserContext *s, - AVCodecContext *avctx, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, - int64_t pts, int64_t dts); -int av_parser_change(AVCodecParserContext *s, - AVCodecContext *avctx, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, int keyframe); -void av_parser_close(AVCodecParserContext *s); - -extern AVCodecParser aac_parser; -extern AVCodecParser ac3_parser; -extern AVCodecParser cavsvideo_parser; -extern AVCodecParser dca_parser; -extern AVCodecParser dvbsub_parser; -extern AVCodecParser dvdsub_parser; -extern AVCodecParser h261_parser; -extern AVCodecParser h263_parser; -extern AVCodecParser h264_parser; -extern AVCodecParser mjpeg_parser; -extern AVCodecParser mpeg4video_parser; -extern AVCodecParser mpegaudio_parser; -extern AVCodecParser mpegvideo_parser; -extern AVCodecParser pnm_parser; -extern AVCodecParser vc1_parser; - - -typedef struct AVBitStreamFilterContext { - void *priv_data; - struct AVBitStreamFilter *filter; - AVCodecParserContext *parser; - struct AVBitStreamFilterContext *next; -} AVBitStreamFilterContext; - - -typedef struct AVBitStreamFilter { - const char *name; - int priv_data_size; - int (*filter)(AVBitStreamFilterContext *bsfc, - AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, int keyframe); - struct AVBitStreamFilter *next; -} AVBitStreamFilter; - -extern AVBitStreamFilter *av_first_bitstream_filter; - -void av_register_bitstream_filter(AVBitStreamFilter *bsf); -AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); -int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, - AVCodecContext *avctx, const char *args, - uint8_t **poutbuf, int *poutbuf_size, - const uint8_t *buf, int buf_size, int keyframe); -void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); - -extern AVBitStreamFilter dump_extradata_bsf; -extern AVBitStreamFilter remove_extradata_bsf; -extern AVBitStreamFilter noise_bsf; -extern AVBitStreamFilter mp3_header_compress_bsf; -extern AVBitStreamFilter mp3_header_decompress_bsf; -extern AVBitStreamFilter mjpega_dump_header_bsf; -extern AVBitStreamFilter imx_dump_header_bsf; - - -/* memory */ - -/** - * Reallocates the given block if it is not large enough, otherwise it - * does nothing. - * - * @see av_realloc - */ -void *av_fast_realloc(void *ptr, unsigned int *size, unsigned int min_size); - -/* for static data only */ - -/** - * Frees all static arrays and reset their pointers to 0. - * Call this function to release all statically allocated tables. - */ -attribute_deprecated void av_free_static(void); - -/** - * Allocation of static arrays. - * - * @warning Do not use for normal allocation. - * - * @param[in] size The amount of memory you need in bytes. - * @return Block of memory of the requested size. - */ -attribute_deprecated void *av_mallocz_static(unsigned int size); - -/** - * Copy image 'src' to 'dst'. - */ -void av_picture_copy(AVPicture *dst, const AVPicture *src, - int pix_fmt, int width, int height); - -/** - * Crop image top and left side - */ -int av_picture_crop(AVPicture *dst, const AVPicture *src, - int pix_fmt, int top_band, int left_band); - -/** - * Pad image - */ -int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width, int pix_fmt, - int padtop, int padbottom, int padleft, int padright, int *color); - -#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) -attribute_deprecated void img_copy(AVPicture *dst, const AVPicture *src, - int pix_fmt, int width, int height); - -attribute_deprecated int img_crop(AVPicture *dst, const AVPicture *src, - int pix_fmt, int top_band, int left_band); - -attribute_deprecated int img_pad(AVPicture *dst, const AVPicture *src, int height, int width, int pix_fmt, - int padtop, int padbottom, int padleft, int padright, int *color); -#endif - -extern unsigned int av_xiphlacing(unsigned char *s, unsigned int v); - -/* error handling */ -#if EINVAL > 0 -#define AVERROR(e) (-(e)) /**< returns a negative error code from a POSIX error code, to return from library functions. */ -#define AVUNERROR(e) (-(e)) /**< returns a POSIX error code from a library function error return value. */ -#else -/* some platforms have E* and errno already negated. */ -#define AVERROR(e) (e) -#define AVUNERROR(e) (e) -#endif -#define AVERROR_UNKNOWN AVERROR(EINVAL) /**< unknown error */ -#define AVERROR_IO AVERROR(EIO) /**< i/o error */ -#define AVERROR_NUMEXPECTED AVERROR(EDOM) /**< number syntax expected in filename */ -#define AVERROR_INVALIDDATA AVERROR(EINVAL) /**< invalid data found */ -#define AVERROR_NOMEM AVERROR(ENOMEM) /**< not enough memory */ -#define AVERROR_NOFMT AVERROR(EILSEQ) /**< unknown format */ -#define AVERROR_NOTSUPP AVERROR(ENOSYS) /**< operation not supported */ - -#ifdef __cplusplus -} -#endif - -#endif /* AVCODEC_H */ +/* + * copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_H +#define AVCODEC_H + +/** + * @file avcodec.h + * external api header. + */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#include "avutil.h" +#include <sys/types.h> /* size_t */ + +#define AV_STRINGIFY(s) AV_TOSTRING(s) +#define AV_TOSTRING(s) #s + +#define LIBAVCODEC_VERSION_INT ((51<<16)+(40<<8)+0) +#define LIBAVCODEC_VERSION 51.40.0 +#define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT + +#define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) + +#define AV_NOPTS_VALUE INT64_C(0x8000000000000000) +#define AV_TIME_BASE 1000000 +#define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE} + +enum CodecID { + CODEC_ID_NONE, + CODEC_ID_MPEG1VIDEO, + CODEC_ID_MPEG2VIDEO, /* prefered ID for MPEG Video 1 or 2 decoding */ + CODEC_ID_MPEG2VIDEO_XVMC, + CODEC_ID_H261, + CODEC_ID_H263, + CODEC_ID_RV10, + CODEC_ID_RV20, + CODEC_ID_MJPEG, + CODEC_ID_MJPEGB, + CODEC_ID_LJPEG, + CODEC_ID_SP5X, + CODEC_ID_JPEGLS, + CODEC_ID_MPEG4, + CODEC_ID_RAWVIDEO, + CODEC_ID_MSMPEG4V1, + CODEC_ID_MSMPEG4V2, + CODEC_ID_MSMPEG4V3, + CODEC_ID_WMV1, + CODEC_ID_WMV2, + CODEC_ID_H263P, + CODEC_ID_H263I, + CODEC_ID_FLV1, + CODEC_ID_SVQ1, + CODEC_ID_SVQ3, + CODEC_ID_DVVIDEO, + CODEC_ID_HUFFYUV, + CODEC_ID_CYUV, + CODEC_ID_H264, + CODEC_ID_INDEO3, + CODEC_ID_VP3, + CODEC_ID_THEORA, + CODEC_ID_ASV1, + CODEC_ID_ASV2, + CODEC_ID_FFV1, + CODEC_ID_4XM, + CODEC_ID_VCR1, + CODEC_ID_CLJR, + CODEC_ID_MDEC, + CODEC_ID_ROQ, + CODEC_ID_INTERPLAY_VIDEO, + CODEC_ID_XAN_WC3, + CODEC_ID_XAN_WC4, + CODEC_ID_RPZA, + CODEC_ID_CINEPAK, + CODEC_ID_WS_VQA, + CODEC_ID_MSRLE, + CODEC_ID_MSVIDEO1, + CODEC_ID_IDCIN, + CODEC_ID_8BPS, + CODEC_ID_SMC, + CODEC_ID_FLIC, + CODEC_ID_TRUEMOTION1, + CODEC_ID_VMDVIDEO, + CODEC_ID_MSZH, + CODEC_ID_ZLIB, + CODEC_ID_QTRLE, + CODEC_ID_SNOW, + CODEC_ID_TSCC, + CODEC_ID_ULTI, + CODEC_ID_QDRAW, + CODEC_ID_VIXL, + CODEC_ID_QPEG, + CODEC_ID_XVID, + CODEC_ID_PNG, + CODEC_ID_PPM, + CODEC_ID_PBM, + CODEC_ID_PGM, + CODEC_ID_PGMYUV, + CODEC_ID_PAM, + CODEC_ID_FFVHUFF, + CODEC_ID_RV30, + CODEC_ID_RV40, + CODEC_ID_VC1, + CODEC_ID_WMV3, + CODEC_ID_LOCO, + CODEC_ID_WNV1, + CODEC_ID_AASC, + CODEC_ID_INDEO2, + CODEC_ID_FRAPS, + CODEC_ID_TRUEMOTION2, + CODEC_ID_BMP, + CODEC_ID_CSCD, + CODEC_ID_MMVIDEO, + CODEC_ID_ZMBV, + CODEC_ID_AVS, + CODEC_ID_SMACKVIDEO, + CODEC_ID_NUV, + CODEC_ID_KMVC, + CODEC_ID_FLASHSV, + CODEC_ID_CAVS, + CODEC_ID_JPEG2000, + CODEC_ID_VMNC, + CODEC_ID_VP5, + CODEC_ID_VP6, + CODEC_ID_VP6F, + CODEC_ID_TARGA, + CODEC_ID_DSICINVIDEO, + CODEC_ID_TIERTEXSEQVIDEO, + CODEC_ID_TIFF, + CODEC_ID_GIF, + CODEC_ID_FFH264, + CODEC_ID_DXA, + CODEC_ID_DNXHD, + + /* various pcm "codecs" */ + CODEC_ID_PCM_S16LE= 0x10000, + CODEC_ID_PCM_S16BE, + CODEC_ID_PCM_U16LE, + CODEC_ID_PCM_U16BE, + CODEC_ID_PCM_S8, + CODEC_ID_PCM_U8, + CODEC_ID_PCM_MULAW, + CODEC_ID_PCM_ALAW, + CODEC_ID_PCM_S32LE, + CODEC_ID_PCM_S32BE, + CODEC_ID_PCM_U32LE, + CODEC_ID_PCM_U32BE, + CODEC_ID_PCM_S24LE, + CODEC_ID_PCM_S24BE, + CODEC_ID_PCM_U24LE, + CODEC_ID_PCM_U24BE, + CODEC_ID_PCM_S24DAUD, + + /* various adpcm codecs */ + CODEC_ID_ADPCM_IMA_QT= 0x11000, + CODEC_ID_ADPCM_IMA_WAV, + CODEC_ID_ADPCM_IMA_DK3, + CODEC_ID_ADPCM_IMA_DK4, + CODEC_ID_ADPCM_IMA_WS, + CODEC_ID_ADPCM_IMA_SMJPEG, + CODEC_ID_ADPCM_MS, + CODEC_ID_ADPCM_4XM, + CODEC_ID_ADPCM_XA, + CODEC_ID_ADPCM_ADX, + CODEC_ID_ADPCM_EA, + CODEC_ID_ADPCM_G726, + CODEC_ID_ADPCM_CT, + CODEC_ID_ADPCM_SWF, + CODEC_ID_ADPCM_YAMAHA, + CODEC_ID_ADPCM_SBPRO_4, + CODEC_ID_ADPCM_SBPRO_3, + CODEC_ID_ADPCM_SBPRO_2, + + /* AMR */ + CODEC_ID_AMR_NB= 0x12000, + CODEC_ID_AMR_WB, + + /* RealAudio codecs*/ + CODEC_ID_RA_144= 0x13000, + CODEC_ID_RA_288, + + /* various DPCM codecs */ + CODEC_ID_ROQ_DPCM= 0x14000, + CODEC_ID_INTERPLAY_DPCM, + CODEC_ID_XAN_DPCM, + CODEC_ID_SOL_DPCM, + + CODEC_ID_MP2= 0x15000, + CODEC_ID_MP3, /* prefered ID for MPEG Audio layer 1, 2 or3 decoding */ + CODEC_ID_AAC, +#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) + CODEC_ID_MPEG4AAC, +#endif + CODEC_ID_AC3, + CODEC_ID_DTS, + CODEC_ID_VORBIS, + CODEC_ID_DVAUDIO, + CODEC_ID_WMAV1, + CODEC_ID_WMAV2, + CODEC_ID_MACE3, + CODEC_ID_MACE6, + CODEC_ID_VMDAUDIO, + CODEC_ID_SONIC, + CODEC_ID_SONIC_LS, + CODEC_ID_FLAC, + CODEC_ID_MP3ADU, + CODEC_ID_MP3ON4, + CODEC_ID_SHORTEN, + CODEC_ID_ALAC, + CODEC_ID_WESTWOOD_SND1, + CODEC_ID_GSM, /* As in Berlin toast format */ + CODEC_ID_QDM2, + CODEC_ID_COOK, + CODEC_ID_TRUESPEECH, + CODEC_ID_TTA, + CODEC_ID_SMACKAUDIO, + CODEC_ID_QCELP, + CODEC_ID_WAVPACK, + CODEC_ID_DSICINAUDIO, + CODEC_ID_IMC, + CODEC_ID_MUSEPACK7, + CODEC_ID_MLP, + CODEC_ID_GSM_MS, /* As found in WAV */ + + /* subtitle codecs */ + CODEC_ID_DVD_SUBTITLE= 0x17000, + CODEC_ID_DVB_SUBTITLE, + + CODEC_ID_MPEG2TS= 0x20000, /* _FAKE_ codec to indicate a raw MPEG2 transport + stream (only used by libavformat) */ +}; + +#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) +/* CODEC_ID_MP3LAME is absolete */ +#define CODEC_ID_MP3LAME CODEC_ID_MP3 +#define CODEC_ID_MPEG4AAC CODEC_ID_AAC +#endif + +enum CodecType { + CODEC_TYPE_UNKNOWN = -1, + CODEC_TYPE_VIDEO, + CODEC_TYPE_AUDIO, + CODEC_TYPE_DATA, + CODEC_TYPE_SUBTITLE, + CODEC_TYPE_NB +}; + +/* currently unused, may be used if 24/32 bits samples ever supported */ +/* all in native endian */ +enum SampleFormat { + SAMPLE_FMT_NONE = -1, + SAMPLE_FMT_U8, ///< unsigned 8 bits + SAMPLE_FMT_S16, ///< signed 16 bits + SAMPLE_FMT_S24, ///< signed 24 bits + SAMPLE_FMT_S32, ///< signed 32 bits + SAMPLE_FMT_FLT, ///< float +}; + +/* in bytes */ +#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio + +/** + * Required number of additionally allocated bytes at the end of the input bitstream for decoding. + * this is mainly needed because some optimized bitstream readers read + * 32 or 64 bit at once and could read over the end<br> + * Note, if the first 23 bits of the additional bytes are not 0 then damaged + * MPEG bitstreams could cause overread and segfault + */ +#define FF_INPUT_BUFFER_PADDING_SIZE 8 + +/** + * minimum encoding buffer size. + * used to avoid some checks during header writing + */ +#define FF_MIN_BUFFER_SIZE 16384 + +/* motion estimation type, EPZS by default */ +enum Motion_Est_ID { + ME_ZERO = 1, + ME_FULL, + ME_LOG, + ME_PHODS, + ME_EPZS, + ME_X1, + ME_HEX, + ME_UMH, + ME_ITER, +}; + +enum AVDiscard{ +//we leave some space between them for extensions (drop some keyframes for intra only or drop just some bidir frames) + AVDISCARD_NONE =-16, ///< discard nothing + AVDISCARD_DEFAULT= 0, ///< discard useless packets like 0 size packets in avi + AVDISCARD_NONREF = 8, ///< discard all non reference + AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames + AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes + AVDISCARD_ALL = 48, ///< discard all +}; + +typedef struct RcOverride{ + int start_frame; + int end_frame; + int qscale; // if this is 0 then quality_factor will be used instead + float quality_factor; +} RcOverride; + +#define FF_MAX_B_FRAMES 16 + +/* encoding support + these flags can be passed in AVCodecContext.flags before initing + Note: not everything is supported yet. +*/ + +#define CODEC_FLAG_QSCALE 0x0002 ///< use fixed qscale +#define CODEC_FLAG_4MV 0x0004 ///< 4 MV per MB allowed / Advanced prediction for H263 +#define CODEC_FLAG_QPEL 0x0010 ///< use qpel MC +#define CODEC_FLAG_GMC 0x0020 ///< use GMC +#define CODEC_FLAG_MV0 0x0040 ///< always try a MB with MV=<0,0> +#define CODEC_FLAG_PART 0x0080 ///< use data partitioning +/* parent program guarantees that the input for b-frame containing streams is not written to + for at least s->max_b_frames+1 frames, if this is not set than the input will be copied */ +#define CODEC_FLAG_INPUT_PRESERVED 0x0100 +#define CODEC_FLAG_PASS1 0x0200 ///< use internal 2pass ratecontrol in first pass mode +#define CODEC_FLAG_PASS2 0x0400 ///< use internal 2pass ratecontrol in second pass mode +#define CODEC_FLAG_EXTERN_HUFF 0x1000 ///< use external huffman table (for mjpeg) +#define CODEC_FLAG_GRAY 0x2000 ///< only decode/encode grayscale +#define CODEC_FLAG_EMU_EDGE 0x4000///< don't draw edges +#define CODEC_FLAG_PSNR 0x8000 ///< error[?] variables will be set during encoding +#define CODEC_FLAG_TRUNCATED 0x00010000 /** input bitstream might be truncated at a random location instead + of only at frame boundaries */ +#define CODEC_FLAG_NORMALIZE_AQP 0x00020000 ///< normalize adaptive quantization +#define CODEC_FLAG_INTERLACED_DCT 0x00040000 ///< use interlaced dct +#define CODEC_FLAG_LOW_DELAY 0x00080000 ///< force low delay +#define CODEC_FLAG_ALT_SCAN 0x00100000 ///< use alternate scan +#define CODEC_FLAG_TRELLIS_QUANT 0x00200000 ///< use trellis quantization +#define CODEC_FLAG_GLOBAL_HEADER 0x00400000 ///< place global headers in extradata instead of every keyframe +#define CODEC_FLAG_BITEXACT 0x00800000 ///< use only bitexact stuff (except (i)dct) +/* Fx : Flag for h263+ extra options */ +#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) +#define CODEC_FLAG_H263P_AIC 0x01000000 ///< H263 Advanced intra coding / MPEG4 AC prediction (remove this) +#endif +#define CODEC_FLAG_AC_PRED 0x01000000 ///< H263 Advanced intra coding / MPEG4 AC prediction +#define CODEC_FLAG_H263P_UMV 0x02000000 ///< Unlimited motion vector +#define CODEC_FLAG_CBP_RD 0x04000000 ///< use rate distortion optimization for cbp +#define CODEC_FLAG_QP_RD 0x08000000 ///< use rate distortion optimization for qp selectioon +#define CODEC_FLAG_H263P_AIV 0x00000008 ///< H263 Alternative inter vlc +#define CODEC_FLAG_OBMC 0x00000001 ///< OBMC +#define CODEC_FLAG_LOOP_FILTER 0x00000800 ///< loop filter +#define CODEC_FLAG_H263P_SLICE_STRUCT 0x10000000 +#define CODEC_FLAG_INTERLACED_ME 0x20000000 ///< interlaced motion estimation +#define CODEC_FLAG_SVCD_SCAN_OFFSET 0x40000000 ///< will reserve space for SVCD scan offset user data +#define CODEC_FLAG_CLOSED_GOP ((int)0x80000000) +#define CODEC_FLAG2_FAST 0x00000001 ///< allow non spec compliant speedup tricks +#define CODEC_FLAG2_STRICT_GOP 0x00000002 ///< strictly enforce GOP size +#define CODEC_FLAG2_NO_OUTPUT 0x00000004 ///< skip bitstream encoding +#define CODEC_FLAG2_LOCAL_HEADER 0x00000008 ///< place global headers at every keyframe instead of in extradata +#define CODEC_FLAG2_BPYRAMID 0x00000010 ///< H.264 allow b-frames to be used as references +#define CODEC_FLAG2_WPRED 0x00000020 ///< H.264 weighted biprediction for b-frames +#define CODEC_FLAG2_MIXED_REFS 0x00000040 ///< H.264 one reference per partition, as opposed to one reference per macroblock +#define CODEC_FLAG2_8X8DCT 0x00000080 ///< H.264 high profile 8x8 transform +#define CODEC_FLAG2_FASTPSKIP 0x00000100 ///< H.264 fast pskip +#define CODEC_FLAG2_AUD 0x00000200 ///< H.264 access unit delimiters +#define CODEC_FLAG2_BRDO 0x00000400 ///< b-frame rate-distortion optimization +#define CODEC_FLAG2_INTRA_VLC 0x00000800 ///< use MPEG-2 intra VLC table +#define CODEC_FLAG2_MEMC_ONLY 0x00001000 ///< only do ME/MC (I frames -> ref, P frame -> ME+MC) +#define CODEC_FLAG2_DROP_FRAME_TIMECODE 0x00002000 ///< timecode is in drop frame format +#define CODEC_FLAG2_SKIP_RD 0x00004000 ///< RD optimal MB level residual skiping +#define CODEC_FLAG2_CHUNKS 0x00008000 ///< input bitstream might be truncated at a packet boundaries instead of only at frame boundaries +#define CODEC_FLAG2_NON_LINEAR_QUANT 0x00010000 ///< use MPEG-2 non linear quantizer + +/* Unsupported options : + * Syntax Arithmetic coding (SAC) + * Reference Picture Selection + * Independent Segment Decoding */ +/* /Fx */ +/* codec capabilities */ + +#define CODEC_CAP_DRAW_HORIZ_BAND 0x0001 ///< decoder can use draw_horiz_band callback +/** + * Codec uses get_buffer() for allocating buffers. + * direct rendering method 1 + */ +#define CODEC_CAP_DR1 0x0002 +/* if 'parse_only' field is true, then avcodec_parse_frame() can be + used */ +#define CODEC_CAP_PARSE_ONLY 0x0004 +#define CODEC_CAP_TRUNCATED 0x0008 +/* codec can export data for HW decoding (XvMC) */ +#define CODEC_CAP_HWACCEL 0x0010 +/** + * codec has a non zero delay and needs to be feeded with NULL at the end to get the delayed data. + * if this is not set, the codec is guaranteed to never be feeded with NULL data + */ +#define CODEC_CAP_DELAY 0x0020 +/** + * Codec can be fed a final frame with a smaller size. + * This can be used to prevent truncation of the last audio samples. + */ +#define CODEC_CAP_SMALL_LAST_FRAME 0x0040 + +//the following defines may change, don't expect compatibility if you use them +#define MB_TYPE_INTRA4x4 0x0001 +#define MB_TYPE_INTRA16x16 0x0002 //FIXME h264 specific +#define MB_TYPE_INTRA_PCM 0x0004 //FIXME h264 specific +#define MB_TYPE_16x16 0x0008 +#define MB_TYPE_16x8 0x0010 +#define MB_TYPE_8x16 0x0020 +#define MB_TYPE_8x8 0x0040 +#define MB_TYPE_INTERLACED 0x0080 +#define MB_TYPE_DIRECT2 0x0100 //FIXME +#define MB_TYPE_ACPRED 0x0200 +#define MB_TYPE_GMC 0x0400 +#define MB_TYPE_SKIP 0x0800 +#define MB_TYPE_P0L0 0x1000 +#define MB_TYPE_P1L0 0x2000 +#define MB_TYPE_P0L1 0x4000 +#define MB_TYPE_P1L1 0x8000 +#define MB_TYPE_L0 (MB_TYPE_P0L0 | MB_TYPE_P1L0) +#define MB_TYPE_L1 (MB_TYPE_P0L1 | MB_TYPE_P1L1) +#define MB_TYPE_L0L1 (MB_TYPE_L0 | MB_TYPE_L1) +#define MB_TYPE_QUANT 0x00010000 +#define MB_TYPE_CBP 0x00020000 +//Note bits 24-31 are reserved for codec specific use (h264 ref0, mpeg1 0mv, ...) + +/** + * Pan Scan area. + * this specifies the area which should be displayed. Note there may be multiple such areas for one frame + */ +typedef struct AVPanScan{ + /** + * id. + * - encoding: set by user. + * - decoding: set by lavc + */ + int id; + + /** + * width and height in 1/16 pel + * - encoding: set by user. + * - decoding: set by lavc + */ + int width; + int height; + + /** + * position of the top left corner in 1/16 pel for up to 3 fields/frames. + * - encoding: set by user. + * - decoding: set by lavc + */ + int16_t position[3][2]; +}AVPanScan; + +#define FF_COMMON_FRAME \ + /**\ + * pointer to the picture planes.\ + * this might be different from the first allocated byte\ + * - encoding: \ + * - decoding: \ + */\ + uint8_t *data[4];\ + int linesize[4];\ + /**\ + * pointer to the first allocated byte of the picture. can be used in get_buffer/release_buffer\ + * this isn't used by lavc unless the default get/release_buffer() is used\ + * - encoding: \ + * - decoding: \ + */\ + uint8_t *base[4];\ + /**\ + * 1 -> keyframe, 0-> not\ + * - encoding: set by lavc\ + * - decoding: set by lavc\ + */\ + int key_frame;\ +\ + /**\ + * picture type of the frame, see ?_TYPE below.\ + * - encoding: set by lavc for coded_picture (and set by user for input)\ + * - decoding: set by lavc\ + */\ + int pict_type;\ +\ + /**\ + * presentation timestamp in time_base units (time when frame should be shown to user)\ + * if AV_NOPTS_VALUE then frame_rate = 1/time_base will be assumed\ + * - encoding: MUST be set by user\ + * - decoding: set by lavc\ + */\ + int64_t pts;\ +\ + /**\ + * picture number in bitstream order.\ + * - encoding: set by\ + * - decoding: set by lavc\ + */\ + int coded_picture_number;\ + /**\ + * picture number in display order.\ + * - encoding: set by\ + * - decoding: set by lavc\ + */\ + int display_picture_number;\ +\ + /**\ + * quality (between 1 (good) and FF_LAMBDA_MAX (bad)) \ + * - encoding: set by lavc for coded_picture (and set by user for input)\ + * - decoding: set by lavc\ + */\ + int quality; \ +\ + /**\ + * buffer age (1->was last buffer and dint change, 2->..., ...).\ + * set to INT_MAX if the buffer has not been used yet \ + * - encoding: unused\ + * - decoding: MUST be set by get_buffer()\ + */\ + int age;\ +\ + /**\ + * is this picture used as reference\ + * - encoding: unused\ + * - decoding: set by lavc (before get_buffer() call))\ + */\ + int reference;\ +\ + /**\ + * QP table\ + * - encoding: unused\ + * - decoding: set by lavc\ + */\ + int8_t *qscale_table;\ + /**\ + * QP store stride\ + * - encoding: unused\ + * - decoding: set by lavc\ + */\ + int qstride;\ +\ + /**\ + * mbskip_table[mb]>=1 if MB didnt change\ + * stride= mb_width = (width+15)>>4\ + * - encoding: unused\ + * - decoding: set by lavc\ + */\ + uint8_t *mbskip_table;\ +\ + /**\ + * Motion vector table.\ + * @code\ + * example:\ + * int mv_sample_log2= 4 - motion_subsample_log2;\ + * int mb_width= (width+15)>>4;\ + * int mv_stride= (mb_width << mv_sample_log2) + 1;\ + * motion_val[direction][x + y*mv_stride][0->mv_x, 1->mv_y];\ + * @endcode\ + * - encoding: set by user\ + * - decoding: set by lavc\ + */\ + int16_t (*motion_val[2])[2];\ +\ + /**\ + * Macroblock type table\ + * mb_type_base + mb_width + 2\ + * - encoding: set by user\ + * - decoding: set by lavc\ + */\ + uint32_t *mb_type;\ +\ + /**\ + * log2 of the size of the block which a single vector in motion_val represents: \ + * (4->16x16, 3->8x8, 2-> 4x4, 1-> 2x2)\ + * - encoding: unused\ + * - decoding: set by lavc\ + */\ + uint8_t motion_subsample_log2;\ +\ + /**\ + * for some private data of the user\ + * - encoding: unused\ + * - decoding: set by user\ + */\ + void *opaque;\ +\ + /**\ + * error\ + * - encoding: set by lavc if flags&CODEC_FLAG_PSNR\ + * - decoding: unused\ + */\ + uint64_t error[4];\ +\ + /**\ + * type of the buffer (to keep track of who has to dealloc data[*])\ + * - encoding: set by the one who allocs it\ + * - decoding: set by the one who allocs it\ + * Note: user allocated (direct rendering) & internal buffers can not coexist currently\ + */\ + int type;\ + \ + /**\ + * when decoding, this signal how much the picture must be delayed.\ + * extra_delay = repeat_pict / (2*fps)\ + * - encoding: unused\ + * - decoding: set by lavc\ + */\ + int repeat_pict;\ + \ + /**\ + * \ + */\ + int qscale_type;\ + \ + /**\ + * The content of the picture is interlaced.\ + * - encoding: set by user\ + * - decoding: set by lavc (default 0)\ + */\ + int interlaced_frame;\ + \ + /**\ + * if the content is interlaced, is top field displayed first.\ + * - encoding: set by user\ + * - decoding: set by lavc\ + */\ + int top_field_first;\ + \ + /**\ + * Pan scan.\ + * - encoding: set by user\ + * - decoding: set by lavc\ + */\ + AVPanScan *pan_scan;\ + \ + /**\ + * tell user application that palette has changed from previous frame.\ + * - encoding: ??? (no palette-enabled encoder yet)\ + * - decoding: set by lavc (default 0)\ + */\ + int palette_has_changed;\ + \ + /**\ + * Codec suggestion on buffer type if != 0\ + * - encoding: unused\ + * - decoding: set by lavc (before get_buffer() call))\ + */\ + int buffer_hints;\ +\ + /**\ + * DCT coeffitients\ + * - encoding: unused\ + * - decoding: set by lavc\ + */\ + short *dct_coeff;\ +\ + /**\ + * Motion referece frame index\ + * - encoding: set by user\ + * - decoding: set by lavc\ + */\ + int8_t *ref_index[2]; + +#define FF_QSCALE_TYPE_MPEG1 0 +#define FF_QSCALE_TYPE_MPEG2 1 +#define FF_QSCALE_TYPE_H264 2 + +#define FF_BUFFER_TYPE_INTERNAL 1 +#define FF_BUFFER_TYPE_USER 2 ///< Direct rendering buffers (image is (de)allocated by user) +#define FF_BUFFER_TYPE_SHARED 4 ///< buffer from somewhere else, don't dealloc image (data/base), all other tables are not shared +#define FF_BUFFER_TYPE_COPY 8 ///< just a (modified) copy of some other buffer, don't dealloc anything + + +#define FF_I_TYPE 1 // Intra +#define FF_P_TYPE 2 // Predicted +#define FF_B_TYPE 3 // Bi-dir predicted +#define FF_S_TYPE 4 // S(GMC)-VOP MPEG4 +#define FF_SI_TYPE 5 +#define FF_SP_TYPE 6 + +#define FF_BUFFER_HINTS_VALID 0x01 // Buffer hints value is meaningful (if 0 ignore) +#define FF_BUFFER_HINTS_READABLE 0x02 // Codec will read from buffer +#define FF_BUFFER_HINTS_PRESERVE 0x04 // User must not alter buffer content +#define FF_BUFFER_HINTS_REUSABLE 0x08 // Codec will reuse the buffer (update) + +/** + * Audio Video Frame. + */ +typedef struct AVFrame { + FF_COMMON_FRAME +} AVFrame; + +#define DEFAULT_FRAME_RATE_BASE 1001000 + +/** + * main external api structure. + */ +typedef struct AVCodecContext { + /** + * Info on struct for av_log + * - set by avcodec_alloc_context + */ + AVClass *av_class; + /** + * the average bitrate. + * - encoding: set by user. unused for constant quantizer encoding + * - decoding: set by lavc. 0 or some bitrate if this info is available in the stream + */ + int bit_rate; + + /** + * number of bits the bitstream is allowed to diverge from the reference. + * the reference can be CBR (for CBR pass1) or VBR (for pass2) + * - encoding: set by user. unused for constant quantizer encoding + * - decoding: unused + */ + int bit_rate_tolerance; + + /** + * CODEC_FLAG_*. + * - encoding: set by user. + * - decoding: set by user. + */ + int flags; + + /** + * some codecs needs additionnal format info. It is stored here + * - encoding: set by user. + * - decoding: set by lavc. (FIXME is this ok?) + */ + int sub_id; + + /** + * motion estimation algorithm used for video coding. + * 1 (zero), 2 (full), 3 (log), 4 (phods), 5 (epzs), 6 (x1), 7 (hex), + * 8 (umh), 9 (iter) [7, 8 are x264 specific, 9 is snow specific] + * - encoding: MUST be set by user. + * - decoding: unused + */ + int me_method; + + /** + * some codecs need / can use extra-data like huffman tables. + * mjpeg: huffman tables + * rv10: additional flags + * mpeg4: global headers (they can be in the bitstream or here) + * the allocated memory should be FF_INPUT_BUFFER_PADDING_SIZE bytes larger + * then extradata_size to avoid prolems if its read with the bitstream reader + * the bytewise contents of extradata must not depend on the architecture or cpu endianness + * - encoding: set/allocated/freed by lavc. + * - decoding: set/allocated/freed by user. + */ + uint8_t *extradata; + int extradata_size; + + /** + * this is the fundamental unit of time (in seconds) in terms + * of which frame timestamps are represented. for fixed-fps content, + * timebase should be 1/framerate and timestamp increments should be + * identically 1. + * - encoding: MUST be set by user + * - decoding: set by lavc. + */ + AVRational time_base; + + /* video only */ + /** + * picture width / height. + * - encoding: MUST be set by user. + * - decoding: set by lavc. + * Note, for compatibility its possible to set this instead of + * coded_width/height before decoding + */ + int width, height; + +#define FF_ASPECT_EXTENDED 15 + + /** + * the number of pictures in a group of pitures, or 0 for intra_only. + * - encoding: set by user. + * - decoding: unused + */ + int gop_size; + + /** + * pixel format, see PIX_FMT_xxx. + * - encoding: set by user. + * - decoding: set by lavc. + */ + enum PixelFormat pix_fmt; + + /** + * Frame rate emulation. If not zero lower layer (i.e. format handler) + * has to read frames at native frame rate. + * - encoding: set by user. + * - decoding: unused. + */ + int rate_emu; + + /** + * if non NULL, 'draw_horiz_band' is called by the libavcodec + * decoder to draw an horizontal band. It improve cache usage. Not + * all codecs can do that. You must check the codec capabilities + * before + * - encoding: unused + * - decoding: set by user. + * @param height the height of the slice + * @param y the y position of the slice + * @param type 1->top field, 2->bottom field, 3->frame + * @param offset offset into the AVFrame.data from which the slice should be read + */ + void (*draw_horiz_band)(struct AVCodecContext *s, + const AVFrame *src, int offset[4], + int y, int type, int height); + + /* audio only */ + int sample_rate; ///< samples per sec + int channels; + + /** + * audio sample format. + * - encoding: set by user. + * - decoding: set by lavc. + */ + enum SampleFormat sample_fmt; ///< sample format, currenly unused + + /* the following data should not be initialized */ + /** + * samples per packet. initialized when calling 'init' + */ + int frame_size; + int frame_number; ///< audio or video frame number + int real_pict_num; ///< returns the real picture number of previous encoded frame + + /** + * number of frames the decoded output will be delayed relative to + * the encoded input. + * - encoding: set by lavc. + * - decoding: unused + */ + int delay; + + /* - encoding parameters */ + float qcompress; ///< amount of qscale change between easy & hard scenes (0.0-1.0) + float qblur; ///< amount of qscale smoothing over time (0.0-1.0) + + /** + * minimum quantizer. + * - encoding: set by user. + * - decoding: unused + */ + int qmin; + + /** + * maximum quantizer. + * - encoding: set by user. + * - decoding: unused + */ + int qmax; + + /** + * maximum quantizer difference between frames. + * - encoding: set by user. + * - decoding: unused + */ + int max_qdiff; + + /** + * maximum number of b frames between non b frames. + * note: the output will be delayed by max_b_frames+1 relative to the input + * - encoding: set by user. + * - decoding: unused + */ + int max_b_frames; + + /** + * qscale factor between ip and b frames. + * - encoding: set by user. + * - decoding: unused + */ + float b_quant_factor; + + /** obsolete FIXME remove */ + int rc_strategy; +#define FF_RC_STRATEGY_XVID 1 + + int b_frame_strategy; + + /** + * hurry up amount. + * - encoding: unused + * - decoding: set by user. 1-> skip b frames, 2-> skip idct/dequant too, 5-> skip everything except header + * @deprecated Deprecated in favor of skip_idct and skip_frame. + */ + int hurry_up; + + struct AVCodec *codec; + + void *priv_data; + +#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) + /* unused, FIXME remove*/ + int rtp_mode; +#endif + + int rtp_payload_size; /* The size of the RTP payload: the coder will */ + /* do it's best to deliver a chunk with size */ + /* below rtp_payload_size, the chunk will start */ + /* with a start code on some codecs like H.263 */ + /* This doesn't take account of any particular */ + /* headers inside the transmited RTP payload */ + + + /* The RTP callback: This function is called */ + /* every time the encoder has a packet to send */ + /* Depends on the encoder if the data starts */ + /* with a Start Code (it should) H.263 does. */ + /* mb_nb contains the number of macroblocks */ + /* encoded in the RTP payload */ + void (*rtp_callback)(struct AVCodecContext *avctx, void *data, int size, int mb_nb); + + /* statistics, used for 2-pass encoding */ + int mv_bits; + int header_bits; + int i_tex_bits; + int p_tex_bits; + int i_count; + int p_count; + int skip_count; + int misc_bits; + + /** + * number of bits used for the previously encoded frame. + * - encoding: set by lavc + * - decoding: unused + */ + int frame_bits; + + /** + * private data of the user, can be used to carry app specific stuff. + * - encoding: set by user + * - decoding: set by user + */ + void *opaque; + + char codec_name[32]; + enum CodecType codec_type; /* see CODEC_TYPE_xxx */ + enum CodecID codec_id; /* see CODEC_ID_xxx */ + + /** + * fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). + * this is used to workaround some encoder bugs + * - encoding: set by user, if not then the default based on codec_id will be used + * - decoding: set by user, will be converted to upper case by lavc during init + */ + unsigned int codec_tag; + + /** + * workaround bugs in encoders which sometimes cannot be detected automatically. + * - encoding: set by user + * - decoding: set by user + */ + int workaround_bugs; +#define FF_BUG_AUTODETECT 1 ///< autodetection +#define FF_BUG_OLD_MSMPEG4 2 +#define FF_BUG_XVID_ILACE 4 +#define FF_BUG_UMP4 8 +#define FF_BUG_NO_PADDING 16 +#define FF_BUG_AMV 32 +#define FF_BUG_AC_VLC 0 ///< will be removed, libavcodec can now handle these non compliant files by default +#define FF_BUG_QPEL_CHROMA 64 +#define FF_BUG_STD_QPEL 128 +#define FF_BUG_QPEL_CHROMA2 256 +#define FF_BUG_DIRECT_BLOCKSIZE 512 +#define FF_BUG_EDGE 1024 +#define FF_BUG_HPEL_CHROMA 2048 +#define FF_BUG_DC_CLIP 4096 +#define FF_BUG_MS 8192 ///< workaround various bugs in microsofts broken decoders +//#define FF_BUG_FAKE_SCALABILITY 16 //autodetection should work 100% + + /** + * luma single coeff elimination threshold. + * - encoding: set by user + * - decoding: unused + */ + int luma_elim_threshold; + + /** + * chroma single coeff elimination threshold. + * - encoding: set by user + * - decoding: unused + */ + int chroma_elim_threshold; + + /** + * strictly follow the std (MPEG4, ...). + * - encoding: set by user + * - decoding: unused + */ + int strict_std_compliance; +#define FF_COMPLIANCE_VERY_STRICT 2 ///< strictly conform to a older more strict version of the spec or reference software +#define FF_COMPLIANCE_STRICT 1 ///< strictly conform to all the things in the spec no matter what consequences +#define FF_COMPLIANCE_NORMAL 0 +#define FF_COMPLIANCE_INOFFICIAL -1 ///< allow inofficial extensions +#define FF_COMPLIANCE_EXPERIMENTAL -2 ///< allow non standarized experimental things + + /** + * qscale offset between ip and b frames. + * if > 0 then the last p frame quantizer will be used (q= lastp_q*factor+offset) + * if < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset) + * - encoding: set by user. + * - decoding: unused + */ + float b_quant_offset; + + /** + * error resilience higher values will detect more errors but may missdetect + * some more or less valid parts as errors. + * - encoding: unused + * - decoding: set by user + */ + int error_resilience; +#define FF_ER_CAREFUL 1 +#define FF_ER_COMPLIANT 2 +#define FF_ER_AGGRESSIVE 3 +#define FF_ER_VERY_AGGRESSIVE 4 + + /** + * called at the beginning of each frame to get a buffer for it. + * if pic.reference is set then the frame will be read later by lavc + * avcodec_align_dimensions() should be used to find the required width and + * height, as they normally need to be rounded up to the next multiple of 16 + * - encoding: unused + * - decoding: set by lavc, user can override + */ + int (*get_buffer)(struct AVCodecContext *c, AVFrame *pic); + + /** + * called to release buffers which where allocated with get_buffer. + * a released buffer can be reused in get_buffer() + * pic.data[*] must be set to NULL + * - encoding: unused + * - decoding: set by lavc, user can override + */ + void (*release_buffer)(struct AVCodecContext *c, AVFrame *pic); + + /** + * if 1 the stream has a 1 frame delay during decoding. + * - encoding: set by lavc + * - decoding: set by lavc + */ + int has_b_frames; + + /** + * number of bytes per packet if constant and known or 0 + * used by some WAV based audio codecs + */ + int block_align; + + int parse_only; /* - decoding only: if true, only parsing is done + (function avcodec_parse_frame()). The frame + data is returned. Only MPEG codecs support this now. */ + + /** + * 0-> h263 quant 1-> mpeg quant. + * - encoding: set by user. + * - decoding: unused + */ + int mpeg_quant; + + /** + * pass1 encoding statistics output buffer. + * - encoding: set by lavc + * - decoding: unused + */ + char *stats_out; + + /** + * pass2 encoding statistics input buffer. + * concatenated stuff from stats_out of pass1 should be placed here + * - encoding: allocated/set/freed by user + * - decoding: unused + */ + char *stats_in; + + /** + * ratecontrol qmin qmax limiting method. + * 0-> clipping, 1-> use a nice continous function to limit qscale wthin qmin/qmax + * - encoding: set by user. + * - decoding: unused + */ + float rc_qsquish; + + float rc_qmod_amp; + int rc_qmod_freq; + + /** + * ratecontrol override, see RcOverride. + * - encoding: allocated/set/freed by user. + * - decoding: unused + */ + RcOverride *rc_override; + int rc_override_count; + + /** + * rate control equation. + * - encoding: set by user + * - decoding: unused + */ + char *rc_eq; + + /** + * maximum bitrate. + * - encoding: set by user. + * - decoding: unused + */ + int rc_max_rate; + + /** + * minimum bitrate. + * - encoding: set by user. + * - decoding: unused + */ + int rc_min_rate; + + /** + * decoder bitstream buffer size. + * - encoding: set by user. + * - decoding: unused + */ + int rc_buffer_size; + float rc_buffer_aggressivity; + + /** + * qscale factor between p and i frames. + * if > 0 then the last p frame quantizer will be used (q= lastp_q*factor+offset) + * if < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset) + * - encoding: set by user. + * - decoding: unused + */ + float i_quant_factor; + + /** + * qscale offset between p and i frames. + * - encoding: set by user. + * - decoding: unused + */ + float i_quant_offset; + + /** + * initial complexity for pass1 ratecontrol. + * - encoding: set by user. + * - decoding: unused + */ + float rc_initial_cplx; + + /** + * dct algorithm, see FF_DCT_* below. + * - encoding: set by user + * - decoding: unused + */ + int dct_algo; +#define FF_DCT_AUTO 0 +#define FF_DCT_FASTINT 1 +#define FF_DCT_INT 2 +#define FF_DCT_MMX 3 +#define FF_DCT_MLIB 4 +#define FF_DCT_ALTIVEC 5 +#define FF_DCT_FAAN 6 + + /** + * luminance masking (0-> disabled). + * - encoding: set by user + * - decoding: unused + */ + float lumi_masking; + + /** + * temporary complexity masking (0-> disabled). + * - encoding: set by user + * - decoding: unused + */ + float temporal_cplx_masking; + + /** + * spatial complexity masking (0-> disabled). + * - encoding: set by user + * - decoding: unused + */ + float spatial_cplx_masking; + + /** + * p block masking (0-> disabled). + * - encoding: set by user + * - decoding: unused + */ + float p_masking; + + /** + * darkness masking (0-> disabled). + * - encoding: set by user + * - decoding: unused + */ + float dark_masking; + + + /* for binary compatibility */ + int unused; + + /** + * idct algorithm, see FF_IDCT_* below. + * - encoding: set by user + * - decoding: set by user + */ + int idct_algo; +#define FF_IDCT_AUTO 0 +#define FF_IDCT_INT 1 +#define FF_IDCT_SIMPLE 2 +#define FF_IDCT_SIMPLEMMX 3 +#define FF_IDCT_LIBMPEG2MMX 4 +#define FF_IDCT_PS2 5 +#define FF_IDCT_MLIB 6 +#define FF_IDCT_ARM 7 +#define FF_IDCT_ALTIVEC 8 +#define FF_IDCT_SH4 9 +#define FF_IDCT_SIMPLEARM 10 +#define FF_IDCT_H264 11 +#define FF_IDCT_VP3 12 +#define FF_IDCT_IPP 13 +#define FF_IDCT_XVIDMMX 14 +#define FF_IDCT_CAVS 15 +#define FF_IDCT_SIMPLEARMV5TE 16 +#define FF_IDCT_SIMPLEARMV6 17 + + /** + * slice count. + * - encoding: set by lavc + * - decoding: set by user (or 0) + */ + int slice_count; + /** + * slice offsets in the frame in bytes. + * - encoding: set/allocated by lavc + * - decoding: set/allocated by user (or NULL) + */ + int *slice_offset; + + /** + * error concealment flags. + * - encoding: unused + * - decoding: set by user + */ + int error_concealment; +#define FF_EC_GUESS_MVS 1 +#define FF_EC_DEBLOCK 2 + + /** + * dsp_mask could be add used to disable unwanted CPU features + * CPU features (i.e. MMX, SSE. ...) + * + * with FORCE flag you may instead enable given CPU features + * (Dangerous: usable in case of misdetection, improper usage however will + * result into program crash) + */ + unsigned dsp_mask; +#define FF_MM_FORCE 0x80000000 /* force usage of selected flags (OR) */ + /* lower 16 bits - CPU features */ +#ifdef HAVE_MMX +#define FF_MM_MMX 0x0001 /* standard MMX */ +#define FF_MM_3DNOW 0x0004 /* AMD 3DNOW */ +#define FF_MM_MMXEXT 0x0002 /* SSE integer functions or AMD MMX ext */ +#define FF_MM_SSE 0x0008 /* SSE functions */ +#define FF_MM_SSE2 0x0010 /* PIV SSE2 functions */ +#define FF_MM_3DNOWEXT 0x0020 /* AMD 3DNowExt */ +#endif /* HAVE_MMX */ +#ifdef HAVE_IWMMXT +#define FF_MM_IWMMXT 0x0100 /* XScale IWMMXT */ +#endif /* HAVE_IWMMXT */ + + /** + * bits per sample/pixel from the demuxer (needed for huffyuv). + * - encoding: set by lavc + * - decoding: set by user + */ + int bits_per_sample; + + /** + * prediction method (needed for huffyuv). + * - encoding: set by user + * - decoding: unused + */ + int prediction_method; +#define FF_PRED_LEFT 0 +#define FF_PRED_PLANE 1 +#define FF_PRED_MEDIAN 2 + + /** + * sample aspect ratio (0 if unknown). + * numerator and denominator must be relative prime and smaller then 256 for some video standards + * - encoding: set by user. + * - decoding: set by lavc. + */ + AVRational sample_aspect_ratio; + + /** + * the picture in the bitstream. + * - encoding: set by lavc + * - decoding: set by lavc + */ + AVFrame *coded_frame; + + /** + * debug. + * - encoding: set by user. + * - decoding: set by user. + */ + int debug; +#define FF_DEBUG_PICT_INFO 1 +#define FF_DEBUG_RC 2 +#define FF_DEBUG_BITSTREAM 4 +#define FF_DEBUG_MB_TYPE 8 +#define FF_DEBUG_QP 16 +#define FF_DEBUG_MV 32 +#define FF_DEBUG_DCT_COEFF 0x00000040 +#define FF_DEBUG_SKIP 0x00000080 +#define FF_DEBUG_STARTCODE 0x00000100 +#define FF_DEBUG_PTS 0x00000200 +#define FF_DEBUG_ER 0x00000400 +#define FF_DEBUG_MMCO 0x00000800 +#define FF_DEBUG_BUGS 0x00001000 +#define FF_DEBUG_VIS_QP 0x00002000 +#define FF_DEBUG_VIS_MB_TYPE 0x00004000 + + /** + * debug. + * - encoding: set by user. + * - decoding: set by user. + */ + int debug_mv; +#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames +#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames +#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames + + /** + * error. + * - encoding: set by lavc if flags&CODEC_FLAG_PSNR + * - decoding: unused + */ + uint64_t error[4]; + + /** + * minimum MB quantizer. + * - encoding: unused + * - decoding: unused + */ + int mb_qmin; + + /** + * maximum MB quantizer. + * - encoding: unused + * - decoding: unused + */ + int mb_qmax; + + /** + * motion estimation compare function. + * - encoding: set by user. + * - decoding: unused + */ + int me_cmp; + /** + * subpixel motion estimation compare function. + * - encoding: set by user. + * - decoding: unused + */ + int me_sub_cmp; + /** + * macroblock compare function (not supported yet). + * - encoding: set by user. + * - decoding: unused + */ + int mb_cmp; + /** + * interlaced dct compare function + * - encoding: set by user. + * - decoding: unused + */ + int ildct_cmp; +#define FF_CMP_SAD 0 +#define FF_CMP_SSE 1 +#define FF_CMP_SATD 2 +#define FF_CMP_DCT 3 +#define FF_CMP_PSNR 4 +#define FF_CMP_BIT 5 +#define FF_CMP_RD 6 +#define FF_CMP_ZERO 7 +#define FF_CMP_VSAD 8 +#define FF_CMP_VSSE 9 +#define FF_CMP_NSSE 10 +#define FF_CMP_W53 11 +#define FF_CMP_W97 12 +#define FF_CMP_DCTMAX 13 +#define FF_CMP_DCT264 14 +#define FF_CMP_CHROMA 256 + + /** + * ME diamond size & shape. + * - encoding: set by user. + * - decoding: unused + */ + int dia_size; + + /** + * amount of previous MV predictors (2a+1 x 2a+1 square). + * - encoding: set by user. + * - decoding: unused + */ + int last_predictor_count; + + /** + * pre pass for motion estimation. + * - encoding: set by user. + * - decoding: unused + */ + int pre_me; + + /** + * motion estimation pre pass compare function. + * - encoding: set by user. + * - decoding: unused + */ + int me_pre_cmp; + + /** + * ME pre pass diamond size & shape. + * - encoding: set by user. + * - decoding: unused + */ + int pre_dia_size; + + /** + * subpel ME quality. + * - encoding: set by user. + * - decoding: unused + */ + int me_subpel_quality; + + /** + * callback to negotiate the pixelFormat. + * @param fmt is the list of formats which are supported by the codec, + * its terminated by -1 as 0 is a valid format, the formats are ordered by quality + * the first is allways the native one + * @return the choosen format + * - encoding: unused + * - decoding: set by user, if not set then the native format will always be choosen + */ + enum PixelFormat (*get_format)(struct AVCodecContext *s, const enum PixelFormat * fmt); + + /** + * DTG active format information (additionnal aspect ratio + * information only used in DVB MPEG2 transport streams). 0 if + * not set. + * + * - encoding: unused. + * - decoding: set by decoder + */ + int dtg_active_format; +#define FF_DTG_AFD_SAME 8 +#define FF_DTG_AFD_4_3 9 +#define FF_DTG_AFD_16_9 10 +#define FF_DTG_AFD_14_9 11 +#define FF_DTG_AFD_4_3_SP_14_9 13 +#define FF_DTG_AFD_16_9_SP_14_9 14 +#define FF_DTG_AFD_SP_4_3 15 + + /** + * Maximum motion estimation search range in subpel units. + * if 0 then no limit + * + * - encoding: set by user. + * - decoding: unused. + */ + int me_range; + + /** + * intra quantizer bias. + * - encoding: set by user. + * - decoding: unused + */ + int intra_quant_bias; +#define FF_DEFAULT_QUANT_BIAS 999999 + + /** + * inter quantizer bias. + * - encoding: set by user. + * - decoding: unused + */ + int inter_quant_bias; + + /** + * color table ID. + * - encoding: unused. + * - decoding: which clrtable should be used for 8bit RGB images + * table have to be stored somewhere FIXME + */ + int color_table_id; + + /** + * internal_buffer count. + * Don't touch, used by lavc default_get_buffer() + */ + int internal_buffer_count; + + /** + * internal_buffers. + * Don't touch, used by lavc default_get_buffer() + */ + void *internal_buffer; + +#define FF_LAMBDA_SHIFT 7 +#define FF_LAMBDA_SCALE (1<<FF_LAMBDA_SHIFT) +#define FF_QP2LAMBDA 118 ///< factor to convert from H.263 QP to lambda +#define FF_LAMBDA_MAX (256*128-1) + +#define FF_QUALITY_SCALE FF_LAMBDA_SCALE //FIXME maybe remove + /** + * global quality for codecs which cannot change it per frame. + * this should be proportional to MPEG1/2/4 qscale. + * - encoding: set by user. + * - decoding: unused + */ + int global_quality; + +#define FF_CODER_TYPE_VLC 0 +#define FF_CODER_TYPE_AC 1 + /** + * coder type + * - encoding: set by user. + * - decoding: unused + */ + int coder_type; + + /** + * context model + * - encoding: set by user. + * - decoding: unused + */ + int context_model; +#if 0 + /** + * + * - encoding: unused + * - decoding: set by user. + */ + uint8_t * (*realloc)(struct AVCodecContext *s, uint8_t *buf, int buf_size); +#endif + + /** + * slice flags + * - encoding: unused + * - decoding: set by user. + */ + int slice_flags; +#define SLICE_FLAG_CODED_ORDER 0x0001 ///< draw_horiz_band() is called in coded order instead of display +#define SLICE_FLAG_ALLOW_FIELD 0x0002 ///< allow draw_horiz_band() with field slices (MPEG2 field pics) +#define SLICE_FLAG_ALLOW_PLANE 0x0004 ///< allow draw_horiz_band() with 1 component at a time (SVQ1) + + /** + * XVideo Motion Acceleration + * - encoding: forbidden + * - decoding: set by decoder + */ + int xvmc_acceleration; + + /** + * macroblock decision mode + * - encoding: set by user. + * - decoding: unused + */ + int mb_decision; +#define FF_MB_DECISION_SIMPLE 0 ///< uses mb_cmp +#define FF_MB_DECISION_BITS 1 ///< chooses the one which needs the fewest bits +#define FF_MB_DECISION_RD 2 ///< rate distoration + + /** + * custom intra quantization matrix + * - encoding: set by user, can be NULL + * - decoding: set by lavc + */ + uint16_t *intra_matrix; + + /** + * custom inter quantization matrix + * - encoding: set by user, can be NULL + * - decoding: set by lavc + */ + uint16_t *inter_matrix; + + /** + * fourcc from the AVI stream header (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). + * this is used to workaround some encoder bugs + * - encoding: unused + * - decoding: set by user, will be converted to upper case by lavc during init + */ + unsigned int stream_codec_tag; + + /** + * scene change detection threshold. + * 0 is default, larger means fewer detected scene changes + * - encoding: set by user. + * - decoding: unused + */ + int scenechange_threshold; + + /** + * minimum lagrange multipler + * - encoding: set by user. + * - decoding: unused + */ + int lmin; + + /** + * maximum lagrange multipler + * - encoding: set by user. + * - decoding: unused + */ + int lmax; + + /** + * Palette control structure + * - encoding: ??? (no palette-enabled encoder yet) + * - decoding: set by user. + */ + struct AVPaletteControl *palctrl; + + /** + * noise reduction strength + * - encoding: set by user. + * - decoding: unused + */ + int noise_reduction; + + /** + * called at the beginning of a frame to get cr buffer for it. + * buffer type (size, hints) must be the same. lavc won't check it. + * lavc will pass previous buffer in pic, function should return + * same buffer or new buffer with old frame "painted" into it. + * if pic.data[0] == NULL must behave like get_buffer(). + * - encoding: unused + * - decoding: set by lavc, user can override + */ + int (*reget_buffer)(struct AVCodecContext *c, AVFrame *pic); + + /** + * number of bits which should be loaded into the rc buffer before decoding starts + * - encoding: set by user. + * - decoding: unused + */ + int rc_initial_buffer_occupancy; + + /** + * + * - encoding: set by user. + * - decoding: unused + */ + int inter_threshold; + + /** + * CODEC_FLAG2_*. + * - encoding: set by user. + * - decoding: set by user. + */ + int flags2; + + /** + * simulates errors in the bitstream to test error concealment. + * - encoding: set by user. + * - decoding: unused. + */ + int error_rate; + + /** + * MP3 antialias algorithm, see FF_AA_* below. + * - encoding: unused + * - decoding: set by user + */ + int antialias_algo; +#define FF_AA_AUTO 0 +#define FF_AA_FASTINT 1 //not implemented yet +#define FF_AA_INT 2 +#define FF_AA_FLOAT 3 + /** + * Quantizer noise shaping. + * - encoding: set by user + * - decoding: unused + */ + int quantizer_noise_shaping; + + /** + * Thread count. + * is used to decide how many independent tasks should be passed to execute() + * - encoding: set by user + * - decoding: set by user + */ + int thread_count; + + /** + * the codec may call this to execute several independent things. it will return only after + * finishing all tasks, the user may replace this with some multithreaded implementation, the + * default implementation will execute the parts serially + * @param count the number of things to execute + * - encoding: set by lavc, user can override + * - decoding: set by lavc, user can override + */ + int (*execute)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg), void **arg2, int *ret, int count); + + /** + * Thread opaque. + * can be used by execute() to store some per AVCodecContext stuff. + * - encoding: set by execute() + * - decoding: set by execute() + */ + void *thread_opaque; + + /** + * Motion estimation threshold. under which no motion estimation is + * performed, but instead the user specified motion vectors are used + * + * - encoding: set by user + * - decoding: unused + */ + int me_threshold; + + /** + * Macroblock threshold. under which the user specified macroblock types will be used + * - encoding: set by user + * - decoding: unused + */ + int mb_threshold; + + /** + * precision of the intra dc coefficient - 8. + * - encoding: set by user + * - decoding: unused + */ + int intra_dc_precision; + + /** + * noise vs. sse weight for the nsse comparsion function. + * - encoding: set by user + * - decoding: unused + */ + int nsse_weight; + + /** + * number of macroblock rows at the top which are skipped. + * - encoding: unused + * - decoding: set by user + */ + int skip_top; + + /** + * number of macroblock rows at the bottom which are skipped. + * - encoding: unused + * - decoding: set by user + */ + int skip_bottom; + + /** + * profile + * - encoding: set by user + * - decoding: set by lavc + */ + int profile; +#define FF_PROFILE_UNKNOWN -99 + + /** + * level + * - encoding: set by user + * - decoding: set by lavc + */ + int level; +#define FF_LEVEL_UNKNOWN -99 + + /** + * low resolution decoding. 1-> 1/2 size, 2->1/4 size + * - encoding: unused + * - decoding: set by user + */ + int lowres; + + /** + * bitsream width / height. may be different from width/height if lowres + * or other things are used + * - encoding: unused + * - decoding: set by user before init if known, codec should override / dynamically change if needed + */ + int coded_width, coded_height; + + /** + * frame skip threshold + * - encoding: set by user + * - decoding: unused + */ + int frame_skip_threshold; + + /** + * frame skip factor + * - encoding: set by user + * - decoding: unused + */ + int frame_skip_factor; + + /** + * frame skip exponent + * - encoding: set by user + * - decoding: unused + */ + int frame_skip_exp; + + /** + * frame skip comparission function + * - encoding: set by user. + * - decoding: unused + */ + int frame_skip_cmp; + + /** + * border processing masking. raises the quantizer for mbs on the borders + * of the picture. + * - encoding: set by user + * - decoding: unused + */ + float border_masking; + + /** + * minimum MB lagrange multipler. + * - encoding: set by user. + * - decoding: unused + */ + int mb_lmin; + + /** + * maximum MB lagrange multipler. + * - encoding: set by user. + * - decoding: unused + */ + int mb_lmax; + + /** + * + * - encoding: set by user. + * - decoding: unused + */ + int me_penalty_compensation; + + /** + * + * - encoding: unused + * - decoding: set by user. + */ + enum AVDiscard skip_loop_filter; + + /** + * + * - encoding: unused + * - decoding: set by user. + */ + enum AVDiscard skip_idct; + + /** + * + * - encoding: unused + * - decoding: set by user. + */ + enum AVDiscard skip_frame; + + /** + * + * - encoding: set by user. + * - decoding: unused + */ + int bidir_refine; + + /** + * + * - encoding: set by user. + * - decoding: unused + */ + int brd_scale; + + /** + * constant rate factor - quality-based VBR - values ~correspond to qps + * - encoding: set by user. + * - decoding: unused + */ + float crf; + + /** + * constant quantization parameter rate control method + * - encoding: set by user. + * - decoding: unused + */ + int cqp; + + /** + * minimum gop size + * - encoding: set by user. + * - decoding: unused + */ + int keyint_min; + + /** + * number of reference frames + * - encoding: set by user. + * - decoding: unused + */ + int refs; + + /** + * chroma qp offset from luma + * - encoding: set by user. + * - decoding: unused + */ + int chromaoffset; + + /** + * influences how often b-frames are used + * - encoding: set by user. + * - decoding: unused + */ + int bframebias; + + /** + * trellis RD quantization + * - encoding: set by user. + * - decoding: unused + */ + int trellis; + + /** + * reduce fluctuations in qp (before curve compression) + * - encoding: set by user. + * - decoding: unused + */ + float complexityblur; + + /** + * in-loop deblocking filter alphac0 parameter + * alpha is in the range -6...6 + * - encoding: set by user. + * - decoding: unused + */ + int deblockalpha; + + /** + * in-loop deblocking filter beta parameter + * beta is in the range -6...6 + * - encoding: set by user. + * - decoding: unused + */ + int deblockbeta; + + /** + * macroblock subpartition sizes to consider - p8x8, p4x4, b8x8, i8x8, i4x4 + * - encoding: set by user. + * - decoding: unused + */ + int partitions; +#define X264_PART_I4X4 0x001 /* Analyse i4x4 */ +#define X264_PART_I8X8 0x002 /* Analyse i8x8 (requires 8x8 transform) */ +#define X264_PART_P8X8 0x010 /* Analyse p16x8, p8x16 and p8x8 */ +#define X264_PART_P4X4 0x020 /* Analyse p8x4, p4x8, p4x4 */ +#define X264_PART_B8X8 0x100 /* Analyse b16x8, b8x16 and b8x8 */ + + /** + * direct mv prediction mode - 0 (none), 1 (spatial), 2 (temporal) + * - encoding: set by user. + * - decoding: unused + */ + int directpred; + + /** + * audio cutoff bandwidth (0 means "automatic") . Currently used only by FAAC + * - encoding: set by user. + * - decoding: unused + */ + int cutoff; + + /** + * multiplied by qscale for each frame and added to scene_change_score + * - encoding: set by user. + * - decoding: unused + */ + int scenechange_factor; + + /** + * + * note: value depends upon the compare functin used for fullpel ME + * - encoding: set by user. + * - decoding: unused + */ + int mv0_threshold; + + /** + * adjusts sensitivity of b_frame_strategy 1 + * - encoding: set by user. + * - decoding: unused + */ + int b_sensitivity; + + /** + * - encoding: set by user. + * - decoding: unused + */ + int compression_level; +#define FF_COMPRESSION_DEFAULT -1 + + /** + * sets whether to use LPC mode - used by FLAC encoder + * - encoding: set by user. + * - decoding: unused. + */ + int use_lpc; + + /** + * LPC coefficient precision - used by FLAC encoder + * - encoding: set by user. + * - decoding: unused. + */ + int lpc_coeff_precision; + + /** + * - encoding: set by user. + * - decoding: unused. + */ + int min_prediction_order; + + /** + * - encoding: set by user. + * - decoding: unused. + */ + int max_prediction_order; + + /** + * search method for selecting prediction order + * - encoding: set by user. + * - decoding: unused. + */ + int prediction_order_method; + + /** + * - encoding: set by user. + * - decoding: unused. + */ + int min_partition_order; + + /** + * - encoding: set by user. + * - decoding: unused. + */ + int max_partition_order; + + /** + * GOP timecode frame start number, in non drop frame format + * - encoding: set by user. + * - decoding: unused. + */ + int64_t timecode_frame_start; +} AVCodecContext; + +/** + * AVCodec. + */ +typedef struct AVCodec { + const char *name; + enum CodecType type; + enum CodecID id; + int priv_data_size; + int (*init)(AVCodecContext *); + int (*encode)(AVCodecContext *, uint8_t *buf, int buf_size, void *data); + int (*close)(AVCodecContext *); + int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, + uint8_t *buf, int buf_size); + int capabilities; + struct AVCodec *next; + void (*flush)(AVCodecContext *); + const AVRational *supported_framerates; ///array of supported framerates, or NULL if any, array is terminated by {0,0} + const enum PixelFormat *pix_fmts; ///array of supported pixel formats, or NULL if unknown, array is terminanted by -1 +} AVCodec; + +/** + * four components are given, that's all. + * the last component is alpha + */ +typedef struct AVPicture { + uint8_t *data[4]; + int linesize[4]; ///< number of bytes per line +} AVPicture; + +/** + * AVPaletteControl + * This structure defines a method for communicating palette changes + * between and demuxer and a decoder. + * this is totally broken, palette changes should be sent as AVPackets + */ +#define AVPALETTE_SIZE 1024 +#define AVPALETTE_COUNT 256 +typedef struct AVPaletteControl { + + /* demuxer sets this to 1 to indicate the palette has changed; + * decoder resets to 0 */ + int palette_changed; + + /* 4-byte ARGB palette entries, stored in native byte order; note that + * the individual palette components should be on a 8-bit scale; if + * the palette data comes from a IBM VGA native format, the component + * data is probably 6 bits in size and needs to be scaled */ + unsigned int palette[AVPALETTE_COUNT]; + +} AVPaletteControl attribute_deprecated; + +typedef struct AVSubtitleRect { + uint16_t x; + uint16_t y; + uint16_t w; + uint16_t h; + uint16_t nb_colors; + int linesize; + uint32_t *rgba_palette; + uint8_t *bitmap; +} AVSubtitleRect; + +typedef struct AVSubtitle { + uint16_t format; /* 0 = graphics */ + uint32_t start_display_time; /* relative to packet pts, in ms */ + uint32_t end_display_time; /* relative to packet pts, in ms */ + uint32_t num_rects; + AVSubtitleRect *rects; +} AVSubtitle; + +extern AVCodec ac3_encoder; +extern AVCodec amr_nb_encoder; +extern AVCodec amr_wb_encoder; +extern AVCodec asv1_encoder; +extern AVCodec asv2_encoder; +extern AVCodec bmp_encoder; +extern AVCodec dvvideo_encoder; +extern AVCodec faac_encoder; +extern AVCodec ffv1_encoder; +extern AVCodec ffvhuff_encoder; +extern AVCodec flac_encoder; +extern AVCodec flashsv_encoder; +extern AVCodec flv_encoder; +extern AVCodec gif_encoder; +extern AVCodec h261_encoder; +extern AVCodec h263_encoder; +extern AVCodec h263p_encoder; +extern AVCodec h264_encoder; +extern AVCodec huffyuv_encoder; +extern AVCodec jpegls_encoder; +extern AVCodec libgsm_encoder; +extern AVCodec libgsm_ms_encoder; +extern AVCodec libtheora_encoder; +extern AVCodec ljpeg_encoder; +extern AVCodec mdec_encoder; +extern AVCodec mjpeg_encoder; +extern AVCodec mp2_encoder; +extern AVCodec mp3lame_encoder; +extern AVCodec mpeg1video_encoder; +extern AVCodec mpeg2video_encoder; +extern AVCodec mpeg4_encoder; +extern AVCodec msmpeg4v1_encoder; +extern AVCodec msmpeg4v2_encoder; +extern AVCodec msmpeg4v3_encoder; +extern AVCodec oggvorbis_encoder; +extern AVCodec pam_encoder; +extern AVCodec pbm_encoder; +extern AVCodec pgm_encoder; +extern AVCodec pgmyuv_encoder; +extern AVCodec png_encoder; +extern AVCodec ppm_encoder; +extern AVCodec rv10_encoder; +extern AVCodec rv20_encoder; +extern AVCodec snow_encoder; +extern AVCodec sonic_encoder; +extern AVCodec sonic_ls_encoder; +extern AVCodec svq1_encoder; +extern AVCodec targa_encoder; +extern AVCodec vcr1_encoder; +extern AVCodec vorbis_encoder; +extern AVCodec wmav1_encoder; +extern AVCodec wmav2_encoder; +extern AVCodec wmv1_encoder; +extern AVCodec wmv2_encoder; +extern AVCodec x264_encoder; +extern AVCodec xvid_encoder; +extern AVCodec zlib_encoder; +extern AVCodec zmbv_encoder; + +extern AVCodec aac_decoder; +extern AVCodec aasc_decoder; +extern AVCodec alac_decoder; +extern AVCodec amr_nb_decoder; +extern AVCodec amr_wb_decoder; +extern AVCodec asv1_decoder; +extern AVCodec asv2_decoder; +extern AVCodec avs_decoder; +extern AVCodec bmp_decoder; +extern AVCodec cavs_decoder; +extern AVCodec cinepak_decoder; +extern AVCodec cljr_decoder; +extern AVCodec cook_decoder; +extern AVCodec cscd_decoder; +extern AVCodec cyuv_decoder; +extern AVCodec dca_decoder; +extern AVCodec dnxhd_decoder; +extern AVCodec dsicinaudio_decoder; +extern AVCodec dsicinvideo_decoder; +extern AVCodec dvvideo_decoder; +extern AVCodec dxa_decoder; +extern AVCodec eightbps_decoder; +extern AVCodec ffv1_decoder; +extern AVCodec ffvhuff_decoder; +extern AVCodec flac_decoder; +extern AVCodec flashsv_decoder; +extern AVCodec flic_decoder; +extern AVCodec flv_decoder; +extern AVCodec fourxm_decoder; +extern AVCodec fraps_decoder; +extern AVCodec gif_decoder; +extern AVCodec h261_decoder; +extern AVCodec h263_decoder; +extern AVCodec h263i_decoder; +extern AVCodec h264_decoder; +extern AVCodec huffyuv_decoder; +extern AVCodec idcin_decoder; +extern AVCodec imc_decoder; +extern AVCodec indeo2_decoder; +extern AVCodec indeo3_decoder; +extern AVCodec interplay_dpcm_decoder; +extern AVCodec interplay_video_decoder; +extern AVCodec kmvc_decoder; +extern AVCodec libgsm_decoder; +extern AVCodec libgsm_ms_decoder; +extern AVCodec loco_decoder; +extern AVCodec mace3_decoder; +extern AVCodec mace6_decoder; +extern AVCodec mdec_decoder; +extern AVCodec mjpeg_decoder; +extern AVCodec mjpegb_decoder; +extern AVCodec mmvideo_decoder; +extern AVCodec mp2_decoder; +extern AVCodec mp3_decoder; +extern AVCodec mp3adu_decoder; +extern AVCodec mp3on4_decoder; +extern AVCodec mpc7_decoder; +extern AVCodec mpeg1video_decoder; +extern AVCodec mpeg2video_decoder; +extern AVCodec mpeg4_decoder; +extern AVCodec mpeg4aac_decoder; +extern AVCodec mpeg_xvmc_decoder; +extern AVCodec mpegvideo_decoder; +extern AVCodec msmpeg4v1_decoder; +extern AVCodec msmpeg4v2_decoder; +extern AVCodec msmpeg4v3_decoder; +extern AVCodec msrle_decoder; +extern AVCodec msvideo1_decoder; +extern AVCodec mszh_decoder; +extern AVCodec nuv_decoder; +extern AVCodec oggvorbis_decoder; +extern AVCodec png_decoder; +extern AVCodec qdm2_decoder; +extern AVCodec qdraw_decoder; +extern AVCodec qpeg_decoder; +extern AVCodec qtrle_decoder; +extern AVCodec ra_144_decoder; +extern AVCodec ra_288_decoder; +extern AVCodec roq_decoder; +extern AVCodec roq_dpcm_decoder; +extern AVCodec rpza_decoder; +extern AVCodec rv10_decoder; +extern AVCodec rv20_decoder; +extern AVCodec rv30_decoder; +extern AVCodec rv40_decoder; +extern AVCodec shorten_decoder; +extern AVCodec smackaud_decoder; +extern AVCodec smacker_decoder; +extern AVCodec smc_decoder; +extern AVCodec snow_decoder; +extern AVCodec sol_dpcm_decoder; +extern AVCodec sonic_decoder; +extern AVCodec sp5x_decoder; +extern AVCodec svq1_decoder; +extern AVCodec svq3_decoder; +extern AVCodec targa_decoder; +extern AVCodec theora_decoder; +extern AVCodec tiertexseqvideo_decoder; +extern AVCodec tiff_decoder; +extern AVCodec truemotion1_decoder; +extern AVCodec truemotion2_decoder; +extern AVCodec truespeech_decoder; +extern AVCodec tscc_decoder; +extern AVCodec tta_decoder; +extern AVCodec ulti_decoder; +extern AVCodec vc1_decoder; +extern AVCodec vcr1_decoder; +extern AVCodec vmdaudio_decoder; +extern AVCodec vmdvideo_decoder; +extern AVCodec vmnc_decoder; +extern AVCodec vorbis_decoder; +extern AVCodec vp3_decoder; +extern AVCodec vp5_decoder; +extern AVCodec vp6_decoder; +extern AVCodec vp6f_decoder; +extern AVCodec vqa_decoder; +extern AVCodec wavpack_decoder; +extern AVCodec wmav1_decoder; +extern AVCodec wmav2_decoder; +extern AVCodec wmv1_decoder; +extern AVCodec wmv2_decoder; +extern AVCodec wmv3_decoder; +extern AVCodec wnv1_decoder; +extern AVCodec ws_snd1_decoder; +extern AVCodec xan_dpcm_decoder; +extern AVCodec xan_wc3_decoder; +extern AVCodec xl_decoder; +extern AVCodec zlib_decoder; +extern AVCodec zmbv_decoder; + +/* pcm codecs */ +#define PCM_CODEC(id, name) \ +extern AVCodec name ## _decoder; \ +extern AVCodec name ## _encoder + +PCM_CODEC(CODEC_ID_PCM_ALAW, pcm_alaw); +PCM_CODEC(CODEC_ID_PCM_MULAW, pcm_mulaw); +PCM_CODEC(CODEC_ID_PCM_S8, pcm_s8); +PCM_CODEC(CODEC_ID_PCM_S16BE, pcm_s16be); +PCM_CODEC(CODEC_ID_PCM_S16LE, pcm_s16le); +PCM_CODEC(CODEC_ID_PCM_S24BE, pcm_s24be); +PCM_CODEC(CODEC_ID_PCM_S24DAUD, pcm_s24daud); +PCM_CODEC(CODEC_ID_PCM_S24LE, pcm_s24le); +PCM_CODEC(CODEC_ID_PCM_S32BE, pcm_s32be); +PCM_CODEC(CODEC_ID_PCM_S32LE, pcm_s32le); +PCM_CODEC(CODEC_ID_PCM_U8, pcm_u8); +PCM_CODEC(CODEC_ID_PCM_U16BE, pcm_u16be); +PCM_CODEC(CODEC_ID_PCM_U16LE, pcm_u16le); +PCM_CODEC(CODEC_ID_PCM_U24BE, pcm_u24be); +PCM_CODEC(CODEC_ID_PCM_U24LE, pcm_u24le); +PCM_CODEC(CODEC_ID_PCM_U32BE, pcm_u32be); +PCM_CODEC(CODEC_ID_PCM_U32LE, pcm_u32le); + +/* adpcm codecs */ + +PCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm); +PCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx); +PCM_CODEC(CODEC_ID_ADPCM_CT, adpcm_ct); +PCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea); +PCM_CODEC(CODEC_ID_ADPCM_G726, adpcm_g726); +PCM_CODEC(CODEC_ID_ADPCM_IMA_DK3, adpcm_ima_dk3); +PCM_CODEC(CODEC_ID_ADPCM_IMA_DK4, adpcm_ima_dk4); +PCM_CODEC(CODEC_ID_ADPCM_IMA_QT, adpcm_ima_qt); +PCM_CODEC(CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav); +PCM_CODEC(CODEC_ID_ADPCM_IMA_WS, adpcm_ima_ws); +PCM_CODEC(CODEC_ID_ADPCM_MS, adpcm_ms); +PCM_CODEC(CODEC_ID_ADPCM_SBPRO_2, adpcm_sbpro_2); +PCM_CODEC(CODEC_ID_ADPCM_SBPRO_3, adpcm_sbpro_3); +PCM_CODEC(CODEC_ID_ADPCM_SBPRO_4, adpcm_sbpro_4); +PCM_CODEC(CODEC_ID_ADPCM_SMJPEG, adpcm_ima_smjpeg); +PCM_CODEC(CODEC_ID_ADPCM_SWF, adpcm_swf); +PCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa); +PCM_CODEC(CODEC_ID_ADPCM_YAMAHA, adpcm_yamaha); + +#undef PCM_CODEC + +/* dummy raw video codec */ +extern AVCodec rawvideo_decoder; +extern AVCodec rawvideo_encoder; + +/* the following codecs use external GPL libs */ +extern AVCodec dts_decoder; +extern AVCodec liba52_decoder; + +/* subtitles */ +extern AVCodec dvbsub_decoder; +extern AVCodec dvbsub_encoder; +extern AVCodec dvdsub_decoder; +extern AVCodec dvdsub_encoder; + +/* resample.c */ + +struct ReSampleContext; +struct AVResampleContext; + +typedef struct ReSampleContext ReSampleContext; + +ReSampleContext *audio_resample_init(int output_channels, int input_channels, + int output_rate, int input_rate); +int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples); +void audio_resample_close(ReSampleContext *s); + +struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff); +int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx); +void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance); +void av_resample_close(struct AVResampleContext *c); + +#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) +/* YUV420 format is assumed ! */ + +struct ImgReSampleContext attribute_deprecated; + +typedef struct ImgReSampleContext ImgReSampleContext attribute_deprecated; + +attribute_deprecated ImgReSampleContext *img_resample_init(int output_width, int output_height, + int input_width, int input_height); + +attribute_deprecated ImgReSampleContext *img_resample_full_init(int owidth, int oheight, + int iwidth, int iheight, + int topBand, int bottomBand, + int leftBand, int rightBand, + int padtop, int padbottom, + int padleft, int padright); + + +attribute_deprecated void img_resample(ImgReSampleContext *s, + AVPicture *output, const AVPicture *input); + +attribute_deprecated void img_resample_close(ImgReSampleContext *s); + +#endif + +/** + * Allocate memory for a picture. Call avpicture_free to free it. + * + * @param picture the picture to be filled in. + * @param pix_fmt the format of the picture. + * @param width the width of the picture. + * @param height the height of the picture. + * @return Zero if successful, a negative value if not. + */ +int avpicture_alloc(AVPicture *picture, int pix_fmt, int width, int height); + +/** + * Free a picture previously allocated by avpicture_alloc(). + * + * @param picture The AVPicture to be freed. + */ +void avpicture_free(AVPicture *picture); + +/** + * Fill in AVPicture's fields. + * The fields of the given AVPicture are filled in by using the 'ptr' address + * which points to the image data buffer. Depending on the specified picture + * format, one or multiple image data pointers and line sizes will be set. + * If a planar format is specified, several pointers will be set pointing to + * the different picture planes and the line sizes of the different planes + * will be stored in the lines_sizes array. + * + * @param picture AVPicture who's fields are to be filled in + * @param ptr Buffer which will contain or contains the actual image data + * @param pix_fmt The format in which the picture data is stored + * @param width The width of the image in pixels + * @param height The height of the image in pixels + * @return Size of the image data in bytes. + */ +int avpicture_fill(AVPicture *picture, uint8_t *ptr, + int pix_fmt, int width, int height); +int avpicture_layout(const AVPicture* src, int pix_fmt, int width, int height, + unsigned char *dest, int dest_size); + +/** + * Calculate the size in bytes that a picture of the given width and height + * would occupy if stored in the given picture format. + * + * @param pix_fmt The given picture format + * @param width The width of the image + * @param height The height of the image + * @return Image data size in bytes + */ +int avpicture_get_size(int pix_fmt, int width, int height); +void avcodec_get_chroma_sub_sample(int pix_fmt, int *h_shift, int *v_shift); +const char *avcodec_get_pix_fmt_name(int pix_fmt); +void avcodec_set_dimensions(AVCodecContext *s, int width, int height); +enum PixelFormat avcodec_get_pix_fmt(const char* name); +unsigned int avcodec_pix_fmt_to_codec_tag(enum PixelFormat p); + +#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */ +#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */ +#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */ +#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */ +#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */ +#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */ + +/** + * Computes what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * avcodec_get_fix_fmt_loss() informs you on the various types of losses which + * will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt Destination pixel format. + * @param[in] src_pix_fmt Source pixel format. + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur. + */ +int avcodec_get_pix_fmt_loss(int dst_pix_fmt, int src_pix_fmt, + int has_alpha); + +/** + * Finds the best pixel format to convert to given a certain source pixel + * format. When converting from one pixel format to another, information loss + * may occur. For example, when converting from RGB24 to GRAY, the color + * information will be lost. Similarly, other losses occur when converting from + * some formats to other formats. avcodec_find_best_pix_fmt() searches which of + * the given pixel formats should be used to undergo the least amount of losses. + * The pixel formats from which it choses one, are determined by the + * \p pix_fmt_mask parameter. + * + * @code + * src_pix_fmt = PIX_FMT_YUV420P; + * pix_fmt_mask = (1 << PIX_FMT_YUV422P) || (1 << PIX_FMT_RGB24); + * dst_pix_fmt = avcodec_find_best_pix_fmt(pix_fmt_mask, src_pix_fmt, alpha, &loss); + * @endcode + * + * @param[in] pix_fmt_mask Bitmask determining which pixel format to choose from. + * @param[in] src_pix_fmt Source pixel format. + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @param[out] loss_ptr Combination of flags informing you what kind of losses will occur. + * @return The best pixel format to convert to or -1 if none was found. + */ +int avcodec_find_best_pix_fmt(int pix_fmt_mask, int src_pix_fmt, + int has_alpha, int *loss_ptr); + +#define FF_ALPHA_TRANSP 0x0001 /* image has some totally transparent pixels */ +#define FF_ALPHA_SEMI_TRANSP 0x0002 /* image has some transparent pixels */ + +/** + * Tell if an image really has transparent alpha values. + * @return ored mask of FF_ALPHA_xxx constants + */ +int img_get_alpha_info(const AVPicture *src, + int pix_fmt, int width, int height); + +#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) +/* convert among pixel formats */ +attribute_deprecated int img_convert(AVPicture *dst, int dst_pix_fmt, + const AVPicture *src, int pix_fmt, + int width, int height); +#endif + +/* deinterlace a picture */ +/* deinterlace - if not supported return -1 */ +int avpicture_deinterlace(AVPicture *dst, const AVPicture *src, + int pix_fmt, int width, int height); + +/* external high level API */ + +extern AVCodec *first_avcodec; + +/* returns LIBAVCODEC_VERSION_INT constant */ +unsigned avcodec_version(void); +/* returns LIBAVCODEC_BUILD constant */ +unsigned avcodec_build(void); + +/** + * Initializes libavcodec. + * + * @warning This function \e must be called before any other libavcodec + * function. + */ +void avcodec_init(void); + +void register_avcodec(AVCodec *format); + +/** + * Finds an encoder with a matching codec ID. + * + * @param id CodecID of the requested encoder. + * @return An encoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_encoder(enum CodecID id); + +/** + * Finds an encoder with the specified name. + * + * @param name Name of the requested encoder. + * @return An encoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_encoder_by_name(const char *name); + +/** + * Finds a decoder with a matching codec ID. + * + * @param id CodecID of the requested decoder. + * @return A decoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_decoder(enum CodecID id); + +/** + * Finds an decoder with the specified name. + * + * @param name Name of the requested decoder. + * @return A decoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_decoder_by_name(const char *name); +void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode); + +/** + * Sets the fields of the given AVCodecContext to default values. + * + * @param s The AVCodecContext of which the fields should be set to default values. + */ +void avcodec_get_context_defaults(AVCodecContext *s); + +/** THIS FUNCTION IS NOT YET PART OF THE PUBLIC API! + * we WILL change its arguments and name a few times! */ +void avcodec_get_context_defaults2(AVCodecContext *s, enum CodecType); + +/** + * Allocates an AVCodecContext and sets its fields to default values. The + * resulting struct can be deallocated by simply calling av_free(). + * + * @return An AVCodecContext filled with default values or NULL on failure. + * @see avcodec_get_context_defaults + */ +AVCodecContext *avcodec_alloc_context(void); + +/** THIS FUNCTION IS NOT YET PART OF THE PUBLIC API! + * we WILL change its arguments and name a few times! */ +AVCodecContext *avcodec_alloc_context2(enum CodecType); + +/** + * Sets the fields of the given AVFrame to default values. + * + * @param pic The AVFrame of which the fields should be set to default values. + */ +void avcodec_get_frame_defaults(AVFrame *pic); + +/** + * Allocates an AVFrame and sets its fields to default values. The resulting + * struct can be deallocated by simply calling av_free(). + * + * @return An AVFrame filled with default values or NULL on failure. + * @see avcodec_get_frame_defaults + */ +AVFrame *avcodec_alloc_frame(void); + +int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic); +void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic); +int avcodec_default_reget_buffer(AVCodecContext *s, AVFrame *pic); +void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height); + +/** + * Checks if the given dimension of a picture is valid, meaning that all + * bytes of the picture can be addressed with a signed int. + * + * @param[in] w Width of the picture. + * @param[in] h Height of the picture. + * @return Zero if valid, a negative value if invalid. + */ +int avcodec_check_dimensions(void *av_log_ctx, unsigned int w, unsigned int h); +enum PixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum PixelFormat * fmt); + +int avcodec_thread_init(AVCodecContext *s, int thread_count); +void avcodec_thread_free(AVCodecContext *s); +int avcodec_thread_execute(AVCodecContext *s, int (*func)(AVCodecContext *c2, void *arg2),void **arg, int *ret, int count); +int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2),void **arg, int *ret, int count); +//FIXME func typedef + +/** + * Initializes the AVCodecContext to use the given AVCodec. Prior to using this + * function the context has to be allocated. + * + * The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(), + * avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for + * retrieving a codec. + * + * @warning This function is not thread save! + * + * @code + * codec = avcodec_find_decoder(CODEC_ID_H264); + * if (!codec) + * exit(1); + * + * context = avcodec_alloc_context(); + * + * if (avcodec_open(context, codec) < 0) + * exit(1); + * @endcode + * + * @param avctx The context which will be setup to use the given codec. + * @param codec The codec to use within the context. + * @return Zero on success, a negative value on error. + * @see avcodec_alloc_context, avcodec_find_decoder, avcodec_find_encoder + */ +int avcodec_open(AVCodecContext *avctx, AVCodec *codec); + +/** + * @deprecated Use avcodec_decode_audio2() instead. + */ +attribute_deprecated int avcodec_decode_audio(AVCodecContext *avctx, int16_t *samples, + int *frame_size_ptr, + uint8_t *buf, int buf_size); + +/** + * Decodes an audio frame from \p buf into \p samples. + * The avcodec_decode_audio2() function decodes a frame of audio from the input + * buffer \p buf of size \p buf_size. To decode it, it makes use of the + * audiocodec which was coupled with \p avctx using avcodec_open(). The + * resulting decoded frame is stored in output buffer \p samples. If no frame + * could be decompressed, \p frame_size_ptr is zero. Otherwise, it is the + * decompressed frame size in \e bytes. + * + * @warning You \e must set \p frame_size_ptr to the allocated size of the + * output buffer before calling avcodec_decode_audio2(). + * + * @warning The input buffer must be \c FF_INPUT_BUFFER_PADDING_SIZE larger than + * the actual read bytes because some optimized bitstream readers read 32 or 64 + * bits at once and could read over the end. + * + * @warning The end of the input buffer \p buf should be set to 0 to ensure that + * no overreading happens for damaged MPEG streams. + * + * @note You might have to align the input buffer \p buf and output buffer \p + * samples. The alignment requirements depend on the CPU: on some CPUs it isn't + * necessary at all, on others it won't work at all if not aligned and on others + * it will work but it will have an impact on performance. In practice, the + * bitstream should have 4 byte alignment at minimum and all sample data should + * be 16 byte aligned unless the CPU doesn't need it (AltiVec and SSE do). If + * the linesize is not a multiple of 16 then there's no sense in aligning the + * start of the buffer to 16. + * + * @param avctx The codec context. + * @param[out] samples The output buffer. + * @param[in,out] frame_size_ptr The output buffer size in bytes. + * @param[in] buf The input buffer. + * @param[in] buf_size The input buffer size in bytes. + * @return On error a negative value is returned, otherwise the number of bytes + * used or zero if no frame could be decompressed. + */ +int avcodec_decode_audio2(AVCodecContext *avctx, int16_t *samples, + int *frame_size_ptr, + uint8_t *buf, int buf_size); + +/** + * Decodes a video frame from \p buf into \p picture. + * The avcodec_decode_video() function decodes a frame of video from the input + * buffer \p buf of size \p buf_size. To decode it, it makes use of the + * videocodec which was coupled with \p avctx using avcodec_open(). The + * resulting decoded frame is stored in \p picture. + * + * @warning The input buffer must be \c FF_INPUT_BUFFER_PADDING_SIZE larger than + * the actual read bytes because some optimized bitstream readers read 32 or 64 + * bits at once and could read over the end. + * + * @warning The end of the input buffer \p buf should be set to 0 to ensure that + * no overreading happens for damaged MPEG streams. + * + * @note You might have to align the input buffer \p buf and output buffer \p + * samples. The alignment requirements depend on the CPU: on some CPUs it isn't + * necessary at all, on others it won't work at all if not aligned and on others + * it will work but it will have an impact on performance. In practice, the + * bitstream should have 4 byte alignment at minimum and all sample data should + * be 16 byte aligned unless the CPU doesn't need it (AltiVec and SSE do). If + * the linesize is not a multiple of 16 then there's no sense in aligning the + * start of the buffer to 16. + * + * @param avctx The codec context. + * @param[out] picture The AVFrame in which the decoded video frame will be stored. + * @param[in] buf The input buffer. + * @param[in] buf_size The size of the input buffer in bytes. + * @param[in,out] got_picture_ptr Zero if no frame could be decompressed, otherwise, it is non zero. + * @return On error a negative value is returned, otherwise the number of bytes + * used or zero if no frame could be decompressed. + */ +int avcodec_decode_video(AVCodecContext *avctx, AVFrame *picture, + int *got_picture_ptr, + uint8_t *buf, int buf_size); + +/* decode a subtitle message. return -1 if error, otherwise return the + *number of bytes used. If no subtitle could be decompressed, + *got_sub_ptr is zero. Otherwise, the subtitle is stored in *sub. */ +int avcodec_decode_subtitle(AVCodecContext *avctx, AVSubtitle *sub, + int *got_sub_ptr, + const uint8_t *buf, int buf_size); +int avcodec_parse_frame(AVCodecContext *avctx, uint8_t **pdata, + int *data_size_ptr, + uint8_t *buf, int buf_size); + +/** + * Encodes an audio frame from \p samples into \p buf. + * The avcodec_encode_audio() function encodes a frame of audio from the input + * buffer \p samples. To encode it, it makes use of the audiocodec which was + * coupled with \p avctx using avcodec_open(). The resulting encoded frame is + * stored in output buffer \p buf. + * + * @note The output buffer should be at least \c FF_MIN_BUFFER_SIZE bytes large. + * + * @param avctx The codec context. + * @param[out] buf The output buffer. + * @param[in] buf_size The output buffer size. + * @param[in] samples The input buffer containing the samples. + * @return On error a negative value is returned, on succes zero or the number + * of bytes used from the input buffer. + */ +int avcodec_encode_audio(AVCodecContext *avctx, uint8_t *buf, int buf_size, + const short *samples); + +/** + * Encodes a video frame from \p pict into \p buf. + * The avcodec_encode_video() function encodes a frame of video from the input + * \p pict. To encode it, it makes use of the videocodec which was coupled with + * \p avctx using avcodec_open(). The resulting encoded bytes representing the + * frame are stored in the output buffer \p buf. The input picture should be + * stored using a specific format, namely \c avctx.pix_fmt. + * + * @param avctx The codec context. + * @param[out] buf The output buffer for the bitstream of encoded frame. + * @param[in] buf_size The size of the outputbuffer in bytes. + * @param[in] pict The input picture to encode. + * @return On error a negative value is returned, on success zero or the number + * of bytes used from the input buffer. + */ +int avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size, + const AVFrame *pict); +int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, + const AVSubtitle *sub); + +int avcodec_close(AVCodecContext *avctx); + +void avcodec_register_all(void); + +/** + * Flush buffers, should be called when seeking or when switching to a different stream. + */ +void avcodec_flush_buffers(AVCodecContext *avctx); + +void avcodec_default_free_buffers(AVCodecContext *s); + +/* misc useful functions */ + +/** + * Returns a single letter to describe the given picture type \p pict_type. + * + * @param[in] pict_type The picture type. + * @return A single character representing the picture type. + */ +char av_get_pict_type_char(int pict_type); + +/** + * Returns codec bits per sample. + * + * @param[in] codec_id The codec. + * @return Number of bits per sample or zero if unknown for the given codec. + */ +int av_get_bits_per_sample(enum CodecID codec_id); + +/* frame parsing */ +typedef struct AVCodecParserContext { + void *priv_data; + struct AVCodecParser *parser; + int64_t frame_offset; /* offset of the current frame */ + int64_t cur_offset; /* current offset + (incremented by each av_parser_parse()) */ + int64_t last_frame_offset; /* offset of the last frame */ + /* video info */ + int pict_type; /* XXX: put it back in AVCodecContext */ + int repeat_pict; /* XXX: put it back in AVCodecContext */ + int64_t pts; /* pts of the current frame */ + int64_t dts; /* dts of the current frame */ + + /* private data */ + int64_t last_pts; + int64_t last_dts; + int fetch_timestamp; + +#define AV_PARSER_PTS_NB 4 + int cur_frame_start_index; + int64_t cur_frame_offset[AV_PARSER_PTS_NB]; + int64_t cur_frame_pts[AV_PARSER_PTS_NB]; + int64_t cur_frame_dts[AV_PARSER_PTS_NB]; + + int flags; +#define PARSER_FLAG_COMPLETE_FRAMES 0x0001 +} AVCodecParserContext; + +typedef struct AVCodecParser { + int codec_ids[5]; /* several codec IDs are permitted */ + int priv_data_size; + int (*parser_init)(AVCodecParserContext *s); + int (*parser_parse)(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size); + void (*parser_close)(AVCodecParserContext *s); + int (*split)(AVCodecContext *avctx, const uint8_t *buf, int buf_size); + struct AVCodecParser *next; +} AVCodecParser; + +extern AVCodecParser *av_first_parser; + +void av_register_codec_parser(AVCodecParser *parser); +AVCodecParserContext *av_parser_init(int codec_id); +int av_parser_parse(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, + int64_t pts, int64_t dts); +int av_parser_change(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe); +void av_parser_close(AVCodecParserContext *s); + +extern AVCodecParser aac_parser; +extern AVCodecParser ac3_parser; +extern AVCodecParser cavsvideo_parser; +extern AVCodecParser dca_parser; +extern AVCodecParser dvbsub_parser; +extern AVCodecParser dvdsub_parser; +extern AVCodecParser h261_parser; +extern AVCodecParser h263_parser; +extern AVCodecParser h264_parser; +extern AVCodecParser mjpeg_parser; +extern AVCodecParser mpeg4video_parser; +extern AVCodecParser mpegaudio_parser; +extern AVCodecParser mpegvideo_parser; +extern AVCodecParser pnm_parser; +extern AVCodecParser vc1_parser; + + +typedef struct AVBitStreamFilterContext { + void *priv_data; + struct AVBitStreamFilter *filter; + AVCodecParserContext *parser; + struct AVBitStreamFilterContext *next; +} AVBitStreamFilterContext; + + +typedef struct AVBitStreamFilter { + const char *name; + int priv_data_size; + int (*filter)(AVBitStreamFilterContext *bsfc, + AVCodecContext *avctx, const char *args, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe); + struct AVBitStreamFilter *next; +} AVBitStreamFilter; + +extern AVBitStreamFilter *av_first_bitstream_filter; + +void av_register_bitstream_filter(AVBitStreamFilter *bsf); +AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); +int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, + AVCodecContext *avctx, const char *args, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe); +void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); + +extern AVBitStreamFilter dump_extradata_bsf; +extern AVBitStreamFilter remove_extradata_bsf; +extern AVBitStreamFilter noise_bsf; +extern AVBitStreamFilter mp3_header_compress_bsf; +extern AVBitStreamFilter mp3_header_decompress_bsf; +extern AVBitStreamFilter mjpega_dump_header_bsf; +extern AVBitStreamFilter imx_dump_header_bsf; + + +/* memory */ + +/** + * Reallocates the given block if it is not large enough, otherwise it + * does nothing. + * + * @see av_realloc + */ +void *av_fast_realloc(void *ptr, unsigned int *size, unsigned int min_size); + +/* for static data only */ + +/** + * Frees all static arrays and reset their pointers to 0. + * Call this function to release all statically allocated tables. + */ +attribute_deprecated void av_free_static(void); + +/** + * Allocation of static arrays. + * + * @warning Do not use for normal allocation. + * + * @param[in] size The amount of memory you need in bytes. + * @return Block of memory of the requested size. + */ +attribute_deprecated void *av_mallocz_static(unsigned int size); + +/** + * Copy image 'src' to 'dst'. + */ +void av_picture_copy(AVPicture *dst, const AVPicture *src, + int pix_fmt, int width, int height); + +/** + * Crop image top and left side + */ +int av_picture_crop(AVPicture *dst, const AVPicture *src, + int pix_fmt, int top_band, int left_band); + +/** + * Pad image + */ +int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width, int pix_fmt, + int padtop, int padbottom, int padleft, int padright, int *color); + +#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) +attribute_deprecated void img_copy(AVPicture *dst, const AVPicture *src, + int pix_fmt, int width, int height); + +attribute_deprecated int img_crop(AVPicture *dst, const AVPicture *src, + int pix_fmt, int top_band, int left_band); + +attribute_deprecated int img_pad(AVPicture *dst, const AVPicture *src, int height, int width, int pix_fmt, + int padtop, int padbottom, int padleft, int padright, int *color); +#endif + +extern unsigned int av_xiphlacing(unsigned char *s, unsigned int v); + +/* error handling */ +#if EINVAL > 0 +#define AVERROR(e) (-(e)) /**< returns a negative error code from a POSIX error code, to return from library functions. */ +#define AVUNERROR(e) (-(e)) /**< returns a POSIX error code from a library function error return value. */ +#else +/* some platforms have E* and errno already negated. */ +#define AVERROR(e) (e) +#define AVUNERROR(e) (e) +#endif +#define AVERROR_UNKNOWN AVERROR(EINVAL) /**< unknown error */ +#define AVERROR_IO AVERROR(EIO) /**< i/o error */ +#define AVERROR_NUMEXPECTED AVERROR(EDOM) /**< number syntax expected in filename */ +#define AVERROR_INVALIDDATA AVERROR(EINVAL) /**< invalid data found */ +#define AVERROR_NOMEM AVERROR(ENOMEM) /**< not enough memory */ +#define AVERROR_NOFMT AVERROR(EILSEQ) /**< unknown format */ +#define AVERROR_NOTSUPP AVERROR(ENOSYS) /**< operation not supported */ + +#ifdef __cplusplus +} +#endif + +#endif /* AVCODEC_H */ diff --git a/src/ffmpeg/include/ffmpeg/avformat.h b/src/ffmpeg/include/ffmpeg/avformat.h index eb8c4e1534..a62b209efc 100644 --- a/src/ffmpeg/include/ffmpeg/avformat.h +++ b/src/ffmpeg/include/ffmpeg/avformat.h @@ -1,888 +1,888 @@ -/* - * copyright (c) 2001 Fabrice Bellard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVFORMAT_H -#define AVFORMAT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define LIBAVFORMAT_VERSION_INT ((51<<16)+(11<<8)+0) -#define LIBAVFORMAT_VERSION 51.11.0 -#define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT - -#define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION) - -#include <time.h> -#include <stdio.h> /* FILE */ -#include "avcodec.h" - -#include "avio.h" - -/* packet functions */ - -typedef struct AVPacket { - int64_t pts; ///< presentation time stamp in time_base units - int64_t dts; ///< decompression time stamp in time_base units - uint8_t *data; - int size; - int stream_index; - int flags; - int duration; ///< presentation duration in time_base units (0 if not available) - void (*destruct)(struct AVPacket *); - void *priv; - int64_t pos; ///< byte position in stream, -1 if unknown -} AVPacket; -#define PKT_FLAG_KEY 0x0001 - -void av_destruct_packet_nofree(AVPacket *pkt); - -/** - * Default packet destructor. - */ -void av_destruct_packet(AVPacket *pkt); - -/* initialize optional fields of a packet */ -static inline void av_init_packet(AVPacket *pkt) -{ - pkt->pts = AV_NOPTS_VALUE; - pkt->dts = AV_NOPTS_VALUE; - pkt->pos = -1; - pkt->duration = 0; - pkt->flags = 0; - pkt->stream_index = 0; - pkt->destruct= av_destruct_packet_nofree; -} - -/** - * Allocate the payload of a packet and intialized its fields to default values. - * - * @param pkt packet - * @param size wanted payload size - * @return 0 if OK. AVERROR_xxx otherwise. - */ -int av_new_packet(AVPacket *pkt, int size); - -/** - * Allocate and read the payload of a packet and intialized its fields to default values. - * - * @param pkt packet - * @param size wanted payload size - * @return >0 (read size) if OK. AVERROR_xxx otherwise. - */ -int av_get_packet(ByteIOContext *s, AVPacket *pkt, int size); - -/** - * @warning This is a hack - the packet memory allocation stuff is broken. The - * packet is allocated if it was not really allocated - */ -int av_dup_packet(AVPacket *pkt); - -/** - * Free a packet - * - * @param pkt packet to free - */ -static inline void av_free_packet(AVPacket *pkt) -{ - if (pkt && pkt->destruct) { - pkt->destruct(pkt); - } -} - -/*************************************************/ -/* fractional numbers for exact pts handling */ - -/* the exact value of the fractional number is: 'val + num / den'. num - is assumed to be such as 0 <= num < den */ -typedef struct AVFrac { - int64_t val, num, den; -} AVFrac attribute_deprecated; - -/*************************************************/ -/* input/output formats */ - -struct AVCodecTag; - -struct AVFormatContext; - -/** this structure contains the data a format has to probe a file */ -typedef struct AVProbeData { - const char *filename; - unsigned char *buf; - int buf_size; -} AVProbeData; - -#define AVPROBE_SCORE_MAX 100 ///< max score, half of that is used for file extension based detection - -typedef struct AVFormatParameters { - AVRational time_base; - int sample_rate; - int channels; - int width; - int height; - enum PixelFormat pix_fmt; - int channel; /**< used to select dv channel */ -#if LIBAVFORMAT_VERSION_INT < (52<<16) - const char *device; /**< video, audio or DV device */ -#endif - const char *standard; /**< tv standard, NTSC, PAL, SECAM */ - int mpeg2ts_raw:1; /**< force raw MPEG2 transport stream output, if possible */ - int mpeg2ts_compute_pcr:1; /**< compute exact PCR for each transport - stream packet (only meaningful if - mpeg2ts_raw is TRUE */ - int initial_pause:1; /**< do not begin to play the stream - immediately (RTSP only) */ - int prealloced_context:1; - enum CodecID video_codec_id; - enum CodecID audio_codec_id; -} AVFormatParameters; - -//! demuxer will use url_fopen, no opened file should be provided by the caller -#define AVFMT_NOFILE 0x0001 -#define AVFMT_NEEDNUMBER 0x0002 /**< needs '%d' in filename */ -#define AVFMT_SHOW_IDS 0x0008 /**< show format stream IDs numbers */ -#define AVFMT_RAWPICTURE 0x0020 /**< format wants AVPicture structure for - raw picture data */ -#define AVFMT_GLOBALHEADER 0x0040 /**< format wants global header */ -#define AVFMT_NOTIMESTAMPS 0x0080 /**< format doesnt need / has any timestamps */ -#define AVFMT_GENERIC_INDEX 0x0100 /**< use generic index building code */ - -typedef struct AVOutputFormat { - const char *name; - const char *long_name; - const char *mime_type; - const char *extensions; /**< comma separated filename extensions */ - /** size of private data so that it can be allocated in the wrapper */ - int priv_data_size; - /* output support */ - enum CodecID audio_codec; /**< default audio codec */ - enum CodecID video_codec; /**< default video codec */ - int (*write_header)(struct AVFormatContext *); - int (*write_packet)(struct AVFormatContext *, AVPacket *pkt); - int (*write_trailer)(struct AVFormatContext *); - /** can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_GLOBALHEADER */ - int flags; - /** currently only used to set pixel format if not YUV420P */ - int (*set_parameters)(struct AVFormatContext *, AVFormatParameters *); - int (*interleave_packet)(struct AVFormatContext *, AVPacket *out, AVPacket *in, int flush); - - /** - * list of supported codec_id-codec_tag pairs, ordered by "better choice first" - * the arrays are all CODEC_ID_NONE terminated - */ - const struct AVCodecTag **codec_tag; - - /* private fields */ - struct AVOutputFormat *next; -} AVOutputFormat; - -typedef struct AVInputFormat { - const char *name; - const char *long_name; - /** size of private data so that it can be allocated in the wrapper */ - int priv_data_size; - /** tell if a given file has a chance of being parsing by this format */ - int (*read_probe)(AVProbeData *); - /** read the format header and initialize the AVFormatContext - structure. Return 0 if OK. 'ap' if non NULL contains - additionnal paramters. Only used in raw format right - now. 'av_new_stream' should be called to create new streams. */ - int (*read_header)(struct AVFormatContext *, - AVFormatParameters *ap); - /** read one packet and put it in 'pkt'. pts and flags are also - set. 'av_new_stream' can be called only if the flag - AVFMTCTX_NOHEADER is used. */ - int (*read_packet)(struct AVFormatContext *, AVPacket *pkt); - /** close the stream. The AVFormatContext and AVStreams are not - freed by this function */ - int (*read_close)(struct AVFormatContext *); - /** - * seek to a given timestamp relative to the frames in - * stream component stream_index - * @param stream_index must not be -1 - * @param flags selects which direction should be preferred if no exact - * match is available - */ - int (*read_seek)(struct AVFormatContext *, - int stream_index, int64_t timestamp, int flags); - /** - * gets the next timestamp in AV_TIME_BASE units. - */ - int64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index, - int64_t *pos, int64_t pos_limit); - /** can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER */ - int flags; - /** if extensions are defined, then no probe is done. You should - usually not use extension format guessing because it is not - reliable enough */ - const char *extensions; - /** general purpose read only value that the format can use */ - int value; - - /** start/resume playing - only meaningful if using a network based format - (RTSP) */ - int (*read_play)(struct AVFormatContext *); - - /** pause playing - only meaningful if using a network based format - (RTSP) */ - int (*read_pause)(struct AVFormatContext *); - - const struct AVCodecTag **codec_tag; - - /* private fields */ - struct AVInputFormat *next; -} AVInputFormat; - -typedef struct AVIndexEntry { - int64_t pos; - int64_t timestamp; -#define AVINDEX_KEYFRAME 0x0001 - int flags:2; - int size:30; //yeah trying to keep the size of this small to reduce memory requirements (its 24 vs 32 byte due to possible 8byte align) - int min_distance; /**< min distance between this and the previous keyframe, used to avoid unneeded searching */ -} AVIndexEntry; - -typedef struct AVStream { - int index; /**< stream index in AVFormatContext */ - int id; /**< format specific stream id */ - AVCodecContext *codec; /**< codec context */ - /** - * real base frame rate of the stream. - * this is the lowest framerate with which all timestamps can be - * represented accurately (its the least common multiple of all - * framerates in the stream), Note, this value is just a guess! - * for example if the timebase is 1/90000 and all frames have either - * approximately 3600 or 1800 timer ticks then r_frame_rate will be 50/1 - */ - AVRational r_frame_rate; - void *priv_data; -#if LIBAVFORMAT_VERSION_INT < (52<<16) - /* internal data used in av_find_stream_info() */ - int64_t codec_info_duration; - int codec_info_nb_frames; -#endif - /** encoding: PTS generation when outputing stream */ - AVFrac pts; - - /** - * this is the fundamental unit of time (in seconds) in terms - * of which frame timestamps are represented. for fixed-fps content, - * timebase should be 1/framerate and timestamp increments should be - * identically 1. - */ - AVRational time_base; - int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */ - /* ffmpeg.c private use */ - int stream_copy; /**< if set, just copy stream */ - enum AVDiscard discard; ///< selects which packets can be discarded at will and dont need to be demuxed - //FIXME move stuff to a flags field? - /** quality, as it has been removed from AVCodecContext and put in AVVideoFrame - * MN:dunno if thats the right place, for it */ - float quality; - /** decoding: position of the first frame of the component, in - AV_TIME_BASE fractional seconds. */ - int64_t start_time; - /** decoding: duration of the stream, in AV_TIME_BASE fractional - seconds. */ - int64_t duration; - - char language[4]; /** ISO 639 3-letter language code (empty string if undefined) */ - - /* av_read_frame() support */ - int need_parsing; ///< 1->full parsing needed, 2->only parse headers dont repack - struct AVCodecParserContext *parser; - - int64_t cur_dts; - int last_IP_duration; - int64_t last_IP_pts; - /* av_seek_frame() support */ - AVIndexEntry *index_entries; /**< only used if the format does not - support seeking natively */ - int nb_index_entries; - unsigned int index_entries_allocated_size; - - int64_t nb_frames; ///< number of frames in this stream if known or 0 - -#define MAX_REORDER_DELAY 4 - int64_t pts_buffer[MAX_REORDER_DELAY+1]; -} AVStream; - -#define AVFMTCTX_NOHEADER 0x0001 /**< signal that no header is present - (streams are added dynamically) */ - -#define MAX_STREAMS 20 - -/* format I/O context */ -typedef struct AVFormatContext { - const AVClass *av_class; /**< set by av_alloc_format_context */ - /* can only be iformat or oformat, not both at the same time */ - struct AVInputFormat *iformat; - struct AVOutputFormat *oformat; - void *priv_data; - ByteIOContext pb; - unsigned int nb_streams; - AVStream *streams[MAX_STREAMS]; - char filename[1024]; /**< input or output filename */ - /* stream info */ - int64_t timestamp; - char title[512]; - char author[512]; - char copyright[512]; - char comment[512]; - char album[512]; - int year; /**< ID3 year, 0 if none */ - int track; /**< track number, 0 if none */ - char genre[32]; /**< ID3 genre */ - - int ctx_flags; /**< format specific flags, see AVFMTCTX_xx */ - /* private data for pts handling (do not modify directly) */ - /** This buffer is only needed when packets were already buffered but - not decoded, for example to get the codec parameters in mpeg - streams */ - struct AVPacketList *packet_buffer; - - /** decoding: position of the first frame of the component, in - AV_TIME_BASE fractional seconds. NEVER set this value directly: - it is deduced from the AVStream values. */ - int64_t start_time; - /** decoding: duration of the stream, in AV_TIME_BASE fractional - seconds. NEVER set this value directly: it is deduced from the - AVStream values. */ - int64_t duration; - /** decoding: total file size. 0 if unknown */ - int64_t file_size; - /** decoding: total stream bitrate in bit/s, 0 if not - available. Never set it directly if the file_size and the - duration are known as ffmpeg can compute it automatically. */ - int bit_rate; - - /* av_read_frame() support */ - AVStream *cur_st; - const uint8_t *cur_ptr; - int cur_len; - AVPacket cur_pkt; - - /* av_seek_frame() support */ - int64_t data_offset; /** offset of the first packet */ - int index_built; - - int mux_rate; - int packet_size; - int preload; - int max_delay; - -#define AVFMT_NOOUTPUTLOOP -1 -#define AVFMT_INFINITEOUTPUTLOOP 0 - /** number of times to loop output in formats that support it */ - int loop_output; - - int flags; -#define AVFMT_FLAG_GENPTS 0x0001 ///< generate pts if missing even if it requires parsing future frames -#define AVFMT_FLAG_IGNIDX 0x0002 ///< ignore index - - int loop_input; - /** decoding: size of data to probe; encoding unused */ - unsigned int probesize; - - /** - * maximum duration in AV_TIME_BASE units over which the input should be analyzed in av_find_stream_info() - */ - int max_analyze_duration; - - const uint8_t *key; - int keylen; -} AVFormatContext; - -typedef struct AVPacketList { - AVPacket pkt; - struct AVPacketList *next; -} AVPacketList; - -extern AVInputFormat *first_iformat; -extern AVOutputFormat *first_oformat; - -enum CodecID av_guess_image2_codec(const char *filename); - -/* XXX: use automatic init with either ELF sections or C file parser */ -/* modules */ - -#include "rtp.h" - -#include "rtsp.h" - -/* utils.c */ -void av_register_input_format(AVInputFormat *format); -void av_register_output_format(AVOutputFormat *format); -AVOutputFormat *guess_stream_format(const char *short_name, - const char *filename, const char *mime_type); -AVOutputFormat *guess_format(const char *short_name, - const char *filename, const char *mime_type); - -/** - * Guesses the codec id based upon muxer and filename. - */ -enum CodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, - const char *filename, const char *mime_type, enum CodecType type); - -/** - * Send a nice hexadecimal dump of a buffer to the specified file stream. - * - * @param f The file stream pointer where the dump should be sent to. - * @param buf buffer - * @param size buffer size - * - * @see av_hex_dump_log, av_pkt_dump, av_pkt_dump_log - */ -void av_hex_dump(FILE *f, uint8_t *buf, int size); - -/** - * Send a nice hexadecimal dump of a buffer to the log. - * - * @param avcl A pointer to an arbitrary struct of which the first field is a - * pointer to an AVClass struct. - * @param level The importance level of the message, lower values signifying - * higher importance. - * @param buf buffer - * @param size buffer size - * - * @see av_hex_dump, av_pkt_dump, av_pkt_dump_log - */ -void av_hex_dump_log(void *avcl, int level, uint8_t *buf, int size); - -/** - * Send a nice dump of a packet to the specified file stream. - * - * @param f The file stream pointer where the dump should be sent to. - * @param pkt packet to dump - * @param dump_payload true if the payload must be displayed too - */ -void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload); - -/** - * Send a nice dump of a packet to the log. - * - * @param avcl A pointer to an arbitrary struct of which the first field is a - * pointer to an AVClass struct. - * @param level The importance level of the message, lower values signifying - * higher importance. - * @param pkt packet to dump - * @param dump_payload true if the payload must be displayed too - */ -void av_pkt_dump_log(void *avcl, int level, AVPacket *pkt, int dump_payload); - -void av_register_all(void); - -/** codec tag <-> codec id */ -enum CodecID av_codec_get_id(const struct AVCodecTag **tags, unsigned int tag); -unsigned int av_codec_get_tag(const struct AVCodecTag **tags, enum CodecID id); - -/* media file input */ - -/** - * finds AVInputFormat based on input format's short name. - */ -AVInputFormat *av_find_input_format(const char *short_name); - -/** - * Guess file format. - * - * @param is_opened whether the file is already opened, determines whether - * demuxers with or without AVFMT_NOFILE are probed - */ -AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened); - -/** - * Allocates all the structures needed to read an input stream. - * This does not open the needed codecs for decoding the stream[s]. - */ -int av_open_input_stream(AVFormatContext **ic_ptr, - ByteIOContext *pb, const char *filename, - AVInputFormat *fmt, AVFormatParameters *ap); - -/** - * Open a media file as input. The codec are not opened. Only the file - * header (if present) is read. - * - * @param ic_ptr the opened media file handle is put here - * @param filename filename to open. - * @param fmt if non NULL, force the file format to use - * @param buf_size optional buffer size (zero if default is OK) - * @param ap additionnal parameters needed when opening the file (NULL if default) - * @return 0 if OK. AVERROR_xxx otherwise. - */ -int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, - AVInputFormat *fmt, - int buf_size, - AVFormatParameters *ap); -/** no av_open for output, so applications will need this: */ -AVFormatContext *av_alloc_format_context(void); - -/** - * Read packets of a media file to get stream information. This - * is useful for file formats with no headers such as MPEG. This - * function also computes the real frame rate in case of mpeg2 repeat - * frame mode. - * The logical file position is not changed by this function; - * examined packets may be buffered for later processing. - * - * @param ic media file handle - * @return >=0 if OK. AVERROR_xxx if error. - * @todo let user decide somehow what information is needed so we dont waste time geting stuff the user doesnt need - */ -int av_find_stream_info(AVFormatContext *ic); - -/** - * Read a transport packet from a media file. - * - * This function is absolete and should never be used. - * Use av_read_frame() instead. - * - * @param s media file handle - * @param pkt is filled - * @return 0 if OK. AVERROR_xxx if error. - */ -int av_read_packet(AVFormatContext *s, AVPacket *pkt); - -/** - * Return the next frame of a stream. - * - * The returned packet is valid - * until the next av_read_frame() or until av_close_input_file() and - * must be freed with av_free_packet. For video, the packet contains - * exactly one frame. For audio, it contains an integer number of - * frames if each frame has a known fixed size (e.g. PCM or ADPCM - * data). If the audio frames have a variable size (e.g. MPEG audio), - * then it contains one frame. - * - * pkt->pts, pkt->dts and pkt->duration are always set to correct - * values in AVStream.timebase units (and guessed if the format cannot - * provided them). pkt->pts can be AV_NOPTS_VALUE if the video format - * has B frames, so it is better to rely on pkt->dts if you do not - * decompress the payload. - * - * @return 0 if OK, < 0 if error or end of file. - */ -int av_read_frame(AVFormatContext *s, AVPacket *pkt); - -/** - * Seek to the key frame at timestamp. - * 'timestamp' in 'stream_index'. - * @param stream_index If stream_index is (-1), a default - * stream is selected, and timestamp is automatically converted - * from AV_TIME_BASE units to the stream specific time_base. - * @param timestamp timestamp in AVStream.time_base units - * or if there is no stream specified then in AV_TIME_BASE units - * @param flags flags which select direction and seeking mode - * @return >= 0 on success - */ -int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags); - -/** - * start playing a network based stream (e.g. RTSP stream) at the - * current position - */ -int av_read_play(AVFormatContext *s); - -/** - * Pause a network based stream (e.g. RTSP stream). - * - * Use av_read_play() to resume it. - */ -int av_read_pause(AVFormatContext *s); - -/** - * Close a media file (but not its codecs). - * - * @param s media file handle - */ -void av_close_input_file(AVFormatContext *s); - -/** - * Add a new stream to a media file. - * - * Can only be called in the read_header() function. If the flag - * AVFMTCTX_NOHEADER is in the format context, then new streams - * can be added in read_packet too. - * - * @param s media file handle - * @param id file format dependent stream id - */ -AVStream *av_new_stream(AVFormatContext *s, int id); - -/** - * Set the pts for a given stream. - * - * @param s stream - * @param pts_wrap_bits number of bits effectively used by the pts - * (used for wrap control, 33 is the value for MPEG) - * @param pts_num numerator to convert to seconds (MPEG: 1) - * @param pts_den denominator to convert to seconds (MPEG: 90000) - */ -void av_set_pts_info(AVStream *s, int pts_wrap_bits, - int pts_num, int pts_den); - -#define AVSEEK_FLAG_BACKWARD 1 ///< seek backward -#define AVSEEK_FLAG_BYTE 2 ///< seeking based on position in bytes -#define AVSEEK_FLAG_ANY 4 ///< seek to any frame, even non keyframes - -int av_find_default_stream_index(AVFormatContext *s); - -/** - * Gets the index for a specific timestamp. - * @param flags if AVSEEK_FLAG_BACKWARD then the returned index will correspond to - * the timestamp which is <= the requested one, if backward is 0 - * then it will be >= - * if AVSEEK_FLAG_ANY seek to any frame, only keyframes otherwise - * @return < 0 if no such timestamp could be found - */ -int av_index_search_timestamp(AVStream *st, int64_t timestamp, int flags); - -/** - * Add a index entry into a sorted list updateing if it is already there. - * - * @param timestamp timestamp in the timebase of the given stream - */ -int av_add_index_entry(AVStream *st, - int64_t pos, int64_t timestamp, int size, int distance, int flags); - -/** - * Does a binary search using av_index_search_timestamp() and AVCodec.read_timestamp(). - * this isnt supposed to be called directly by a user application, but by demuxers - * @param target_ts target timestamp in the time base of the given stream - * @param stream_index stream number - */ -int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags); - -/** - * Updates cur_dts of all streams based on given timestamp and AVStream. - * - * Stream ref_st unchanged, others set cur_dts in their native timebase - * only needed for timestamp wrapping or if (dts not set and pts!=dts) - * @param timestamp new dts expressed in time_base of param ref_st - * @param ref_st reference stream giving time_base of param timestamp - */ -void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp); - -/** - * Does a binary search using read_timestamp(). - * this isnt supposed to be called directly by a user application, but by demuxers - * @param target_ts target timestamp in the time base of the given stream - * @param stream_index stream number - */ -int64_t av_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, int64_t pos_min, int64_t pos_max, int64_t pos_limit, int64_t ts_min, int64_t ts_max, int flags, int64_t *ts_ret, int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t )); - -/** media file output */ -int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap); - -/** - * allocate the stream private data and write the stream header to an - * output media file - * - * @param s media file handle - * @return 0 if OK. AVERROR_xxx if error. - */ -int av_write_header(AVFormatContext *s); - -/** - * Write a packet to an output media file. - * - * The packet shall contain one audio or video frame. - * The packet must be correctly interleaved according to the container specification, - * if not then av_interleaved_write_frame must be used - * - * @param s media file handle - * @param pkt the packet, which contains the stream_index, buf/buf_size, dts/pts, ... - * @return < 0 if error, = 0 if OK, 1 if end of stream wanted. - */ -int av_write_frame(AVFormatContext *s, AVPacket *pkt); - -/** - * Writes a packet to an output media file ensuring correct interleaving. - * - * The packet must contain one audio or video frame. - * If the packets are already correctly interleaved the application should - * call av_write_frame() instead as its slightly faster, its also important - * to keep in mind that completly non interleaved input will need huge amounts - * of memory to interleave with this, so its prefereable to interleave at the - * demuxer level - * - * @param s media file handle - * @param pkt the packet, which contains the stream_index, buf/buf_size, dts/pts, ... - * @return < 0 if error, = 0 if OK, 1 if end of stream wanted. - */ -int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt); - -/** - * Interleave a packet per DTS in an output media file. - * - * Packets with pkt->destruct == av_destruct_packet will be freed inside this function, - * so they cannot be used after it, note calling av_free_packet() on them is still safe. - * - * @param s media file handle - * @param out the interleaved packet will be output here - * @param in the input packet - * @param flush 1 if no further packets are available as input and all - * remaining packets should be output - * @return 1 if a packet was output, 0 if no packet could be output, - * < 0 if an error occured - */ -int av_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush); - -/** - * @brief Write the stream trailer to an output media file and - * free the file private data. - * - * @param s media file handle - * @return 0 if OK. AVERROR_xxx if error. - */ -int av_write_trailer(AVFormatContext *s); - -void dump_format(AVFormatContext *ic, - int index, - const char *url, - int is_output); - -/** - * parses width and height out of string str. - */ -int parse_image_size(int *width_ptr, int *height_ptr, const char *str); - -/** - * Converts frame rate from string to a fraction. - */ -int parse_frame_rate(int *frame_rate, int *frame_rate_base, const char *arg); - -/** - * Converts date string to number of seconds since Jan 1st, 1970. - * - * @code - * Syntax: - * - If not a duration: - * [{YYYY-MM-DD|YYYYMMDD}]{T| }{HH[:MM[:SS[.m...]]][Z]|HH[MM[SS[.m...]]][Z]} - * Time is localtime unless Z is suffixed to the end. In this case GMT - * Return the date in micro seconds since 1970 - * - * - If a duration: - * HH[:MM[:SS[.m...]]] - * S+[.m...] - * @endcode - */ -int64_t parse_date(const char *datestr, int duration); - -int64_t av_gettime(void); - -/* ffm specific for ffserver */ -#define FFM_PACKET_SIZE 4096 -offset_t ffm_read_write_index(int fd); -void ffm_write_write_index(int fd, offset_t pos); -void ffm_set_write_index(AVFormatContext *s, offset_t pos, offset_t file_size); - -/** - * Attempts to find a specific tag in a URL. - * - * syntax: '?tag1=val1&tag2=val2...'. Little URL decoding is done. - * Return 1 if found. - */ -int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info); - -/** - * Returns in 'buf' the path with '%d' replaced by number. - - * Also handles the '%0nd' format where 'n' is the total number - * of digits and '%%'. - * - * @param buf destination buffer - * @param buf_size destination buffer size - * @param path numbered sequence string - * @number frame number - * @return 0 if OK, -1 if format error. - */ -int av_get_frame_filename(char *buf, int buf_size, - const char *path, int number); - -/** - * Check whether filename actually is a numbered sequence generator. - * - * @param filename possible numbered sequence string - * @return 1 if a valid numbered sequence string, 0 otherwise. - */ -int av_filename_number_test(const char *filename); - -/* grab specific */ -int video_grab_init(void); -int audio_init(void); - -/* DV1394 */ -int dv1394_init(void); -int dc1394_init(void); - -#ifdef HAVE_AV_CONFIG_H - -#include "os_support.h" - -int strstart(const char *str, const char *val, const char **ptr); -int stristart(const char *str, const char *val, const char **ptr); -void pstrcpy(char *buf, int buf_size, const char *str); -char *pstrcat(char *buf, int buf_size, const char *s); - -void __dynarray_add(unsigned long **tab_ptr, int *nb_ptr, unsigned long elem); - -#ifdef __GNUC__ -#define dynarray_add(tab, nb_ptr, elem)\ -do {\ - typeof(tab) _tab = (tab);\ - typeof(elem) _elem = (elem);\ - (void)sizeof(**_tab == _elem); /* check that types are compatible */\ - __dynarray_add((unsigned long **)_tab, nb_ptr, (unsigned long)_elem);\ -} while(0) -#else -#define dynarray_add(tab, nb_ptr, elem)\ -do {\ - __dynarray_add((unsigned long **)(tab), nb_ptr, (unsigned long)(elem));\ -} while(0) -#endif - -time_t mktimegm(struct tm *tm); -struct tm *brktimegm(time_t secs, struct tm *tm); -const char *small_strptime(const char *p, const char *fmt, - struct tm *dt); - -struct in_addr; -int resolve_host(struct in_addr *sin_addr, const char *hostname); - -void url_split(char *proto, int proto_size, - char *authorization, int authorization_size, - char *hostname, int hostname_size, - int *port_ptr, - char *path, int path_size, - const char *url); - -int match_ext(const char *filename, const char *extensions); - -#endif /* HAVE_AV_CONFIG_H */ - -#ifdef __cplusplus -} -#endif - -#endif /* AVFORMAT_H */ - +/* + * copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_H +#define AVFORMAT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define LIBAVFORMAT_VERSION_INT ((51<<16)+(11<<8)+0) +#define LIBAVFORMAT_VERSION 51.11.0 +#define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT + +#define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION) + +#include <time.h> +#include <stdio.h> /* FILE */ +#include "avcodec.h" + +#include "avio.h" + +/* packet functions */ + +typedef struct AVPacket { + int64_t pts; ///< presentation time stamp in time_base units + int64_t dts; ///< decompression time stamp in time_base units + uint8_t *data; + int size; + int stream_index; + int flags; + int duration; ///< presentation duration in time_base units (0 if not available) + void (*destruct)(struct AVPacket *); + void *priv; + int64_t pos; ///< byte position in stream, -1 if unknown +} AVPacket; +#define PKT_FLAG_KEY 0x0001 + +void av_destruct_packet_nofree(AVPacket *pkt); + +/** + * Default packet destructor. + */ +void av_destruct_packet(AVPacket *pkt); + +/* initialize optional fields of a packet */ +static inline void av_init_packet(AVPacket *pkt) +{ + pkt->pts = AV_NOPTS_VALUE; + pkt->dts = AV_NOPTS_VALUE; + pkt->pos = -1; + pkt->duration = 0; + pkt->flags = 0; + pkt->stream_index = 0; + pkt->destruct= av_destruct_packet_nofree; +} + +/** + * Allocate the payload of a packet and intialized its fields to default values. + * + * @param pkt packet + * @param size wanted payload size + * @return 0 if OK. AVERROR_xxx otherwise. + */ +int av_new_packet(AVPacket *pkt, int size); + +/** + * Allocate and read the payload of a packet and intialized its fields to default values. + * + * @param pkt packet + * @param size wanted payload size + * @return >0 (read size) if OK. AVERROR_xxx otherwise. + */ +int av_get_packet(ByteIOContext *s, AVPacket *pkt, int size); + +/** + * @warning This is a hack - the packet memory allocation stuff is broken. The + * packet is allocated if it was not really allocated + */ +int av_dup_packet(AVPacket *pkt); + +/** + * Free a packet + * + * @param pkt packet to free + */ +static inline void av_free_packet(AVPacket *pkt) +{ + if (pkt && pkt->destruct) { + pkt->destruct(pkt); + } +} + +/*************************************************/ +/* fractional numbers for exact pts handling */ + +/* the exact value of the fractional number is: 'val + num / den'. num + is assumed to be such as 0 <= num < den */ +typedef struct AVFrac { + int64_t val, num, den; +} AVFrac attribute_deprecated; + +/*************************************************/ +/* input/output formats */ + +struct AVCodecTag; + +struct AVFormatContext; + +/** this structure contains the data a format has to probe a file */ +typedef struct AVProbeData { + const char *filename; + unsigned char *buf; + int buf_size; +} AVProbeData; + +#define AVPROBE_SCORE_MAX 100 ///< max score, half of that is used for file extension based detection + +typedef struct AVFormatParameters { + AVRational time_base; + int sample_rate; + int channels; + int width; + int height; + enum PixelFormat pix_fmt; + int channel; /**< used to select dv channel */ +#if LIBAVFORMAT_VERSION_INT < (52<<16) + const char *device; /**< video, audio or DV device */ +#endif + const char *standard; /**< tv standard, NTSC, PAL, SECAM */ + int mpeg2ts_raw:1; /**< force raw MPEG2 transport stream output, if possible */ + int mpeg2ts_compute_pcr:1; /**< compute exact PCR for each transport + stream packet (only meaningful if + mpeg2ts_raw is TRUE */ + int initial_pause:1; /**< do not begin to play the stream + immediately (RTSP only) */ + int prealloced_context:1; + enum CodecID video_codec_id; + enum CodecID audio_codec_id; +} AVFormatParameters; + +//! demuxer will use url_fopen, no opened file should be provided by the caller +#define AVFMT_NOFILE 0x0001 +#define AVFMT_NEEDNUMBER 0x0002 /**< needs '%d' in filename */ +#define AVFMT_SHOW_IDS 0x0008 /**< show format stream IDs numbers */ +#define AVFMT_RAWPICTURE 0x0020 /**< format wants AVPicture structure for + raw picture data */ +#define AVFMT_GLOBALHEADER 0x0040 /**< format wants global header */ +#define AVFMT_NOTIMESTAMPS 0x0080 /**< format doesnt need / has any timestamps */ +#define AVFMT_GENERIC_INDEX 0x0100 /**< use generic index building code */ + +typedef struct AVOutputFormat { + const char *name; + const char *long_name; + const char *mime_type; + const char *extensions; /**< comma separated filename extensions */ + /** size of private data so that it can be allocated in the wrapper */ + int priv_data_size; + /* output support */ + enum CodecID audio_codec; /**< default audio codec */ + enum CodecID video_codec; /**< default video codec */ + int (*write_header)(struct AVFormatContext *); + int (*write_packet)(struct AVFormatContext *, AVPacket *pkt); + int (*write_trailer)(struct AVFormatContext *); + /** can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_GLOBALHEADER */ + int flags; + /** currently only used to set pixel format if not YUV420P */ + int (*set_parameters)(struct AVFormatContext *, AVFormatParameters *); + int (*interleave_packet)(struct AVFormatContext *, AVPacket *out, AVPacket *in, int flush); + + /** + * list of supported codec_id-codec_tag pairs, ordered by "better choice first" + * the arrays are all CODEC_ID_NONE terminated + */ + const struct AVCodecTag **codec_tag; + + /* private fields */ + struct AVOutputFormat *next; +} AVOutputFormat; + +typedef struct AVInputFormat { + const char *name; + const char *long_name; + /** size of private data so that it can be allocated in the wrapper */ + int priv_data_size; + /** tell if a given file has a chance of being parsing by this format */ + int (*read_probe)(AVProbeData *); + /** read the format header and initialize the AVFormatContext + structure. Return 0 if OK. 'ap' if non NULL contains + additionnal paramters. Only used in raw format right + now. 'av_new_stream' should be called to create new streams. */ + int (*read_header)(struct AVFormatContext *, + AVFormatParameters *ap); + /** read one packet and put it in 'pkt'. pts and flags are also + set. 'av_new_stream' can be called only if the flag + AVFMTCTX_NOHEADER is used. */ + int (*read_packet)(struct AVFormatContext *, AVPacket *pkt); + /** close the stream. The AVFormatContext and AVStreams are not + freed by this function */ + int (*read_close)(struct AVFormatContext *); + /** + * seek to a given timestamp relative to the frames in + * stream component stream_index + * @param stream_index must not be -1 + * @param flags selects which direction should be preferred if no exact + * match is available + */ + int (*read_seek)(struct AVFormatContext *, + int stream_index, int64_t timestamp, int flags); + /** + * gets the next timestamp in AV_TIME_BASE units. + */ + int64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index, + int64_t *pos, int64_t pos_limit); + /** can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER */ + int flags; + /** if extensions are defined, then no probe is done. You should + usually not use extension format guessing because it is not + reliable enough */ + const char *extensions; + /** general purpose read only value that the format can use */ + int value; + + /** start/resume playing - only meaningful if using a network based format + (RTSP) */ + int (*read_play)(struct AVFormatContext *); + + /** pause playing - only meaningful if using a network based format + (RTSP) */ + int (*read_pause)(struct AVFormatContext *); + + const struct AVCodecTag **codec_tag; + + /* private fields */ + struct AVInputFormat *next; +} AVInputFormat; + +typedef struct AVIndexEntry { + int64_t pos; + int64_t timestamp; +#define AVINDEX_KEYFRAME 0x0001 + int flags:2; + int size:30; //yeah trying to keep the size of this small to reduce memory requirements (its 24 vs 32 byte due to possible 8byte align) + int min_distance; /**< min distance between this and the previous keyframe, used to avoid unneeded searching */ +} AVIndexEntry; + +typedef struct AVStream { + int index; /**< stream index in AVFormatContext */ + int id; /**< format specific stream id */ + AVCodecContext *codec; /**< codec context */ + /** + * real base frame rate of the stream. + * this is the lowest framerate with which all timestamps can be + * represented accurately (its the least common multiple of all + * framerates in the stream), Note, this value is just a guess! + * for example if the timebase is 1/90000 and all frames have either + * approximately 3600 or 1800 timer ticks then r_frame_rate will be 50/1 + */ + AVRational r_frame_rate; + void *priv_data; +#if LIBAVFORMAT_VERSION_INT < (52<<16) + /* internal data used in av_find_stream_info() */ + int64_t codec_info_duration; + int codec_info_nb_frames; +#endif + /** encoding: PTS generation when outputing stream */ + AVFrac pts; + + /** + * this is the fundamental unit of time (in seconds) in terms + * of which frame timestamps are represented. for fixed-fps content, + * timebase should be 1/framerate and timestamp increments should be + * identically 1. + */ + AVRational time_base; + int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */ + /* ffmpeg.c private use */ + int stream_copy; /**< if set, just copy stream */ + enum AVDiscard discard; ///< selects which packets can be discarded at will and dont need to be demuxed + //FIXME move stuff to a flags field? + /** quality, as it has been removed from AVCodecContext and put in AVVideoFrame + * MN:dunno if thats the right place, for it */ + float quality; + /** decoding: position of the first frame of the component, in + AV_TIME_BASE fractional seconds. */ + int64_t start_time; + /** decoding: duration of the stream, in AV_TIME_BASE fractional + seconds. */ + int64_t duration; + + char language[4]; /** ISO 639 3-letter language code (empty string if undefined) */ + + /* av_read_frame() support */ + int need_parsing; ///< 1->full parsing needed, 2->only parse headers dont repack + struct AVCodecParserContext *parser; + + int64_t cur_dts; + int last_IP_duration; + int64_t last_IP_pts; + /* av_seek_frame() support */ + AVIndexEntry *index_entries; /**< only used if the format does not + support seeking natively */ + int nb_index_entries; + unsigned int index_entries_allocated_size; + + int64_t nb_frames; ///< number of frames in this stream if known or 0 + +#define MAX_REORDER_DELAY 4 + int64_t pts_buffer[MAX_REORDER_DELAY+1]; +} AVStream; + +#define AVFMTCTX_NOHEADER 0x0001 /**< signal that no header is present + (streams are added dynamically) */ + +#define MAX_STREAMS 20 + +/* format I/O context */ +typedef struct AVFormatContext { + const AVClass *av_class; /**< set by av_alloc_format_context */ + /* can only be iformat or oformat, not both at the same time */ + struct AVInputFormat *iformat; + struct AVOutputFormat *oformat; + void *priv_data; + ByteIOContext pb; + unsigned int nb_streams; + AVStream *streams[MAX_STREAMS]; + char filename[1024]; /**< input or output filename */ + /* stream info */ + int64_t timestamp; + char title[512]; + char author[512]; + char copyright[512]; + char comment[512]; + char album[512]; + int year; /**< ID3 year, 0 if none */ + int track; /**< track number, 0 if none */ + char genre[32]; /**< ID3 genre */ + + int ctx_flags; /**< format specific flags, see AVFMTCTX_xx */ + /* private data for pts handling (do not modify directly) */ + /** This buffer is only needed when packets were already buffered but + not decoded, for example to get the codec parameters in mpeg + streams */ + struct AVPacketList *packet_buffer; + + /** decoding: position of the first frame of the component, in + AV_TIME_BASE fractional seconds. NEVER set this value directly: + it is deduced from the AVStream values. */ + int64_t start_time; + /** decoding: duration of the stream, in AV_TIME_BASE fractional + seconds. NEVER set this value directly: it is deduced from the + AVStream values. */ + int64_t duration; + /** decoding: total file size. 0 if unknown */ + int64_t file_size; + /** decoding: total stream bitrate in bit/s, 0 if not + available. Never set it directly if the file_size and the + duration are known as ffmpeg can compute it automatically. */ + int bit_rate; + + /* av_read_frame() support */ + AVStream *cur_st; + const uint8_t *cur_ptr; + int cur_len; + AVPacket cur_pkt; + + /* av_seek_frame() support */ + int64_t data_offset; /** offset of the first packet */ + int index_built; + + int mux_rate; + int packet_size; + int preload; + int max_delay; + +#define AVFMT_NOOUTPUTLOOP -1 +#define AVFMT_INFINITEOUTPUTLOOP 0 + /** number of times to loop output in formats that support it */ + int loop_output; + + int flags; +#define AVFMT_FLAG_GENPTS 0x0001 ///< generate pts if missing even if it requires parsing future frames +#define AVFMT_FLAG_IGNIDX 0x0002 ///< ignore index + + int loop_input; + /** decoding: size of data to probe; encoding unused */ + unsigned int probesize; + + /** + * maximum duration in AV_TIME_BASE units over which the input should be analyzed in av_find_stream_info() + */ + int max_analyze_duration; + + const uint8_t *key; + int keylen; +} AVFormatContext; + +typedef struct AVPacketList { + AVPacket pkt; + struct AVPacketList *next; +} AVPacketList; + +extern AVInputFormat *first_iformat; +extern AVOutputFormat *first_oformat; + +enum CodecID av_guess_image2_codec(const char *filename); + +/* XXX: use automatic init with either ELF sections or C file parser */ +/* modules */ + +#include "rtp.h" + +#include "rtsp.h" + +/* utils.c */ +void av_register_input_format(AVInputFormat *format); +void av_register_output_format(AVOutputFormat *format); +AVOutputFormat *guess_stream_format(const char *short_name, + const char *filename, const char *mime_type); +AVOutputFormat *guess_format(const char *short_name, + const char *filename, const char *mime_type); + +/** + * Guesses the codec id based upon muxer and filename. + */ +enum CodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, + const char *filename, const char *mime_type, enum CodecType type); + +/** + * Send a nice hexadecimal dump of a buffer to the specified file stream. + * + * @param f The file stream pointer where the dump should be sent to. + * @param buf buffer + * @param size buffer size + * + * @see av_hex_dump_log, av_pkt_dump, av_pkt_dump_log + */ +void av_hex_dump(FILE *f, uint8_t *buf, int size); + +/** + * Send a nice hexadecimal dump of a buffer to the log. + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message, lower values signifying + * higher importance. + * @param buf buffer + * @param size buffer size + * + * @see av_hex_dump, av_pkt_dump, av_pkt_dump_log + */ +void av_hex_dump_log(void *avcl, int level, uint8_t *buf, int size); + +/** + * Send a nice dump of a packet to the specified file stream. + * + * @param f The file stream pointer where the dump should be sent to. + * @param pkt packet to dump + * @param dump_payload true if the payload must be displayed too + */ +void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload); + +/** + * Send a nice dump of a packet to the log. + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message, lower values signifying + * higher importance. + * @param pkt packet to dump + * @param dump_payload true if the payload must be displayed too + */ +void av_pkt_dump_log(void *avcl, int level, AVPacket *pkt, int dump_payload); + +void av_register_all(void); + +/** codec tag <-> codec id */ +enum CodecID av_codec_get_id(const struct AVCodecTag **tags, unsigned int tag); +unsigned int av_codec_get_tag(const struct AVCodecTag **tags, enum CodecID id); + +/* media file input */ + +/** + * finds AVInputFormat based on input format's short name. + */ +AVInputFormat *av_find_input_format(const char *short_name); + +/** + * Guess file format. + * + * @param is_opened whether the file is already opened, determines whether + * demuxers with or without AVFMT_NOFILE are probed + */ +AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened); + +/** + * Allocates all the structures needed to read an input stream. + * This does not open the needed codecs for decoding the stream[s]. + */ +int av_open_input_stream(AVFormatContext **ic_ptr, + ByteIOContext *pb, const char *filename, + AVInputFormat *fmt, AVFormatParameters *ap); + +/** + * Open a media file as input. The codec are not opened. Only the file + * header (if present) is read. + * + * @param ic_ptr the opened media file handle is put here + * @param filename filename to open. + * @param fmt if non NULL, force the file format to use + * @param buf_size optional buffer size (zero if default is OK) + * @param ap additionnal parameters needed when opening the file (NULL if default) + * @return 0 if OK. AVERROR_xxx otherwise. + */ +int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, + AVInputFormat *fmt, + int buf_size, + AVFormatParameters *ap); +/** no av_open for output, so applications will need this: */ +AVFormatContext *av_alloc_format_context(void); + +/** + * Read packets of a media file to get stream information. This + * is useful for file formats with no headers such as MPEG. This + * function also computes the real frame rate in case of mpeg2 repeat + * frame mode. + * The logical file position is not changed by this function; + * examined packets may be buffered for later processing. + * + * @param ic media file handle + * @return >=0 if OK. AVERROR_xxx if error. + * @todo let user decide somehow what information is needed so we dont waste time geting stuff the user doesnt need + */ +int av_find_stream_info(AVFormatContext *ic); + +/** + * Read a transport packet from a media file. + * + * This function is absolete and should never be used. + * Use av_read_frame() instead. + * + * @param s media file handle + * @param pkt is filled + * @return 0 if OK. AVERROR_xxx if error. + */ +int av_read_packet(AVFormatContext *s, AVPacket *pkt); + +/** + * Return the next frame of a stream. + * + * The returned packet is valid + * until the next av_read_frame() or until av_close_input_file() and + * must be freed with av_free_packet. For video, the packet contains + * exactly one frame. For audio, it contains an integer number of + * frames if each frame has a known fixed size (e.g. PCM or ADPCM + * data). If the audio frames have a variable size (e.g. MPEG audio), + * then it contains one frame. + * + * pkt->pts, pkt->dts and pkt->duration are always set to correct + * values in AVStream.timebase units (and guessed if the format cannot + * provided them). pkt->pts can be AV_NOPTS_VALUE if the video format + * has B frames, so it is better to rely on pkt->dts if you do not + * decompress the payload. + * + * @return 0 if OK, < 0 if error or end of file. + */ +int av_read_frame(AVFormatContext *s, AVPacket *pkt); + +/** + * Seek to the key frame at timestamp. + * 'timestamp' in 'stream_index'. + * @param stream_index If stream_index is (-1), a default + * stream is selected, and timestamp is automatically converted + * from AV_TIME_BASE units to the stream specific time_base. + * @param timestamp timestamp in AVStream.time_base units + * or if there is no stream specified then in AV_TIME_BASE units + * @param flags flags which select direction and seeking mode + * @return >= 0 on success + */ +int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags); + +/** + * start playing a network based stream (e.g. RTSP stream) at the + * current position + */ +int av_read_play(AVFormatContext *s); + +/** + * Pause a network based stream (e.g. RTSP stream). + * + * Use av_read_play() to resume it. + */ +int av_read_pause(AVFormatContext *s); + +/** + * Close a media file (but not its codecs). + * + * @param s media file handle + */ +void av_close_input_file(AVFormatContext *s); + +/** + * Add a new stream to a media file. + * + * Can only be called in the read_header() function. If the flag + * AVFMTCTX_NOHEADER is in the format context, then new streams + * can be added in read_packet too. + * + * @param s media file handle + * @param id file format dependent stream id + */ +AVStream *av_new_stream(AVFormatContext *s, int id); + +/** + * Set the pts for a given stream. + * + * @param s stream + * @param pts_wrap_bits number of bits effectively used by the pts + * (used for wrap control, 33 is the value for MPEG) + * @param pts_num numerator to convert to seconds (MPEG: 1) + * @param pts_den denominator to convert to seconds (MPEG: 90000) + */ +void av_set_pts_info(AVStream *s, int pts_wrap_bits, + int pts_num, int pts_den); + +#define AVSEEK_FLAG_BACKWARD 1 ///< seek backward +#define AVSEEK_FLAG_BYTE 2 ///< seeking based on position in bytes +#define AVSEEK_FLAG_ANY 4 ///< seek to any frame, even non keyframes + +int av_find_default_stream_index(AVFormatContext *s); + +/** + * Gets the index for a specific timestamp. + * @param flags if AVSEEK_FLAG_BACKWARD then the returned index will correspond to + * the timestamp which is <= the requested one, if backward is 0 + * then it will be >= + * if AVSEEK_FLAG_ANY seek to any frame, only keyframes otherwise + * @return < 0 if no such timestamp could be found + */ +int av_index_search_timestamp(AVStream *st, int64_t timestamp, int flags); + +/** + * Add a index entry into a sorted list updateing if it is already there. + * + * @param timestamp timestamp in the timebase of the given stream + */ +int av_add_index_entry(AVStream *st, + int64_t pos, int64_t timestamp, int size, int distance, int flags); + +/** + * Does a binary search using av_index_search_timestamp() and AVCodec.read_timestamp(). + * this isnt supposed to be called directly by a user application, but by demuxers + * @param target_ts target timestamp in the time base of the given stream + * @param stream_index stream number + */ +int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags); + +/** + * Updates cur_dts of all streams based on given timestamp and AVStream. + * + * Stream ref_st unchanged, others set cur_dts in their native timebase + * only needed for timestamp wrapping or if (dts not set and pts!=dts) + * @param timestamp new dts expressed in time_base of param ref_st + * @param ref_st reference stream giving time_base of param timestamp + */ +void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp); + +/** + * Does a binary search using read_timestamp(). + * this isnt supposed to be called directly by a user application, but by demuxers + * @param target_ts target timestamp in the time base of the given stream + * @param stream_index stream number + */ +int64_t av_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, int64_t pos_min, int64_t pos_max, int64_t pos_limit, int64_t ts_min, int64_t ts_max, int flags, int64_t *ts_ret, int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t )); + +/** media file output */ +int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap); + +/** + * allocate the stream private data and write the stream header to an + * output media file + * + * @param s media file handle + * @return 0 if OK. AVERROR_xxx if error. + */ +int av_write_header(AVFormatContext *s); + +/** + * Write a packet to an output media file. + * + * The packet shall contain one audio or video frame. + * The packet must be correctly interleaved according to the container specification, + * if not then av_interleaved_write_frame must be used + * + * @param s media file handle + * @param pkt the packet, which contains the stream_index, buf/buf_size, dts/pts, ... + * @return < 0 if error, = 0 if OK, 1 if end of stream wanted. + */ +int av_write_frame(AVFormatContext *s, AVPacket *pkt); + +/** + * Writes a packet to an output media file ensuring correct interleaving. + * + * The packet must contain one audio or video frame. + * If the packets are already correctly interleaved the application should + * call av_write_frame() instead as its slightly faster, its also important + * to keep in mind that completly non interleaved input will need huge amounts + * of memory to interleave with this, so its prefereable to interleave at the + * demuxer level + * + * @param s media file handle + * @param pkt the packet, which contains the stream_index, buf/buf_size, dts/pts, ... + * @return < 0 if error, = 0 if OK, 1 if end of stream wanted. + */ +int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt); + +/** + * Interleave a packet per DTS in an output media file. + * + * Packets with pkt->destruct == av_destruct_packet will be freed inside this function, + * so they cannot be used after it, note calling av_free_packet() on them is still safe. + * + * @param s media file handle + * @param out the interleaved packet will be output here + * @param in the input packet + * @param flush 1 if no further packets are available as input and all + * remaining packets should be output + * @return 1 if a packet was output, 0 if no packet could be output, + * < 0 if an error occured + */ +int av_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush); + +/** + * @brief Write the stream trailer to an output media file and + * free the file private data. + * + * @param s media file handle + * @return 0 if OK. AVERROR_xxx if error. + */ +int av_write_trailer(AVFormatContext *s); + +void dump_format(AVFormatContext *ic, + int index, + const char *url, + int is_output); + +/** + * parses width and height out of string str. + */ +int parse_image_size(int *width_ptr, int *height_ptr, const char *str); + +/** + * Converts frame rate from string to a fraction. + */ +int parse_frame_rate(int *frame_rate, int *frame_rate_base, const char *arg); + +/** + * Converts date string to number of seconds since Jan 1st, 1970. + * + * @code + * Syntax: + * - If not a duration: + * [{YYYY-MM-DD|YYYYMMDD}]{T| }{HH[:MM[:SS[.m...]]][Z]|HH[MM[SS[.m...]]][Z]} + * Time is localtime unless Z is suffixed to the end. In this case GMT + * Return the date in micro seconds since 1970 + * + * - If a duration: + * HH[:MM[:SS[.m...]]] + * S+[.m...] + * @endcode + */ +int64_t parse_date(const char *datestr, int duration); + +int64_t av_gettime(void); + +/* ffm specific for ffserver */ +#define FFM_PACKET_SIZE 4096 +offset_t ffm_read_write_index(int fd); +void ffm_write_write_index(int fd, offset_t pos); +void ffm_set_write_index(AVFormatContext *s, offset_t pos, offset_t file_size); + +/** + * Attempts to find a specific tag in a URL. + * + * syntax: '?tag1=val1&tag2=val2...'. Little URL decoding is done. + * Return 1 if found. + */ +int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info); + +/** + * Returns in 'buf' the path with '%d' replaced by number. + + * Also handles the '%0nd' format where 'n' is the total number + * of digits and '%%'. + * + * @param buf destination buffer + * @param buf_size destination buffer size + * @param path numbered sequence string + * @number frame number + * @return 0 if OK, -1 if format error. + */ +int av_get_frame_filename(char *buf, int buf_size, + const char *path, int number); + +/** + * Check whether filename actually is a numbered sequence generator. + * + * @param filename possible numbered sequence string + * @return 1 if a valid numbered sequence string, 0 otherwise. + */ +int av_filename_number_test(const char *filename); + +/* grab specific */ +int video_grab_init(void); +int audio_init(void); + +/* DV1394 */ +int dv1394_init(void); +int dc1394_init(void); + +#ifdef HAVE_AV_CONFIG_H + +#include "os_support.h" + +int strstart(const char *str, const char *val, const char **ptr); +int stristart(const char *str, const char *val, const char **ptr); +void pstrcpy(char *buf, int buf_size, const char *str); +char *pstrcat(char *buf, int buf_size, const char *s); + +void __dynarray_add(unsigned long **tab_ptr, int *nb_ptr, unsigned long elem); + +#ifdef __GNUC__ +#define dynarray_add(tab, nb_ptr, elem)\ +do {\ + typeof(tab) _tab = (tab);\ + typeof(elem) _elem = (elem);\ + (void)sizeof(**_tab == _elem); /* check that types are compatible */\ + __dynarray_add((unsigned long **)_tab, nb_ptr, (unsigned long)_elem);\ +} while(0) +#else +#define dynarray_add(tab, nb_ptr, elem)\ +do {\ + __dynarray_add((unsigned long **)(tab), nb_ptr, (unsigned long)(elem));\ +} while(0) +#endif + +time_t mktimegm(struct tm *tm); +struct tm *brktimegm(time_t secs, struct tm *tm); +const char *small_strptime(const char *p, const char *fmt, + struct tm *dt); + +struct in_addr; +int resolve_host(struct in_addr *sin_addr, const char *hostname); + +void url_split(char *proto, int proto_size, + char *authorization, int authorization_size, + char *hostname, int hostname_size, + int *port_ptr, + char *path, int path_size, + const char *url); + +int match_ext(const char *filename, const char *extensions); + +#endif /* HAVE_AV_CONFIG_H */ + +#ifdef __cplusplus +} +#endif + +#endif /* AVFORMAT_H */ + diff --git a/src/ffmpeg/include/ffmpeg/avio.h b/src/ffmpeg/include/ffmpeg/avio.h index be78c9a7b4..227e3bd87e 100644 --- a/src/ffmpeg/include/ffmpeg/avio.h +++ b/src/ffmpeg/include/ffmpeg/avio.h @@ -1,272 +1,272 @@ -/* - * unbuffered io for ffmpeg system - * copyright (c) 2001 Fabrice Bellard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef AVIO_H -#define AVIO_H - -/* output byte stream handling */ - -typedef int64_t offset_t; - -/* unbuffered I/O */ - -struct URLContext { - struct URLProtocol *prot; - int flags; - int is_streamed; /**< true if streamed (no seek possible), default = false */ - int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */ - void *priv_data; -#if LIBAVFORMAT_VERSION_INT >= (52<<16) - char *filename; /**< specified filename */ -#else - char filename[1]; /**< specified filename */ -#endif -}; - -typedef struct URLContext URLContext; - -typedef struct URLPollEntry { - URLContext *handle; - int events; - int revents; -} URLPollEntry; - -#define URL_RDONLY 0 -#define URL_WRONLY 1 -#define URL_RDWR 2 - -typedef int URLInterruptCB(void); - -int url_open(URLContext **h, const char *filename, int flags); -int url_read(URLContext *h, unsigned char *buf, int size); -int url_write(URLContext *h, unsigned char *buf, int size); -offset_t url_seek(URLContext *h, offset_t pos, int whence); -int url_close(URLContext *h); -int url_exist(const char *filename); -offset_t url_filesize(URLContext *h); - -/** - * Return the maximum packet size associated to packetized file - * handle. If the file is not packetized (stream like http or file on - * disk), then 0 is returned. - * - * @param h file handle - * @return maximum packet size in bytes - */ -int url_get_max_packet_size(URLContext *h); -void url_get_filename(URLContext *h, char *buf, int buf_size); - -/** - * the callback is called in blocking functions to test regulary if - * asynchronous interruption is needed. AVERROR(EINTR) is returned - * in this case by the interrupted function. 'NULL' means no interrupt - * callback is given. i - */ -void url_set_interrupt_cb(URLInterruptCB *interrupt_cb); - -/* not implemented */ -int url_poll(URLPollEntry *poll_table, int n, int timeout); - -/** - * passing this as the "whence" parameter to a seek function causes it to - * return the filesize without seeking anywhere, supporting this is optional - * if its not supprted then the seek function will return <0 - */ -#define AVSEEK_SIZE 0x10000 - -typedef struct URLProtocol { - const char *name; - int (*url_open)(URLContext *h, const char *filename, int flags); - int (*url_read)(URLContext *h, unsigned char *buf, int size); - int (*url_write)(URLContext *h, unsigned char *buf, int size); - offset_t (*url_seek)(URLContext *h, offset_t pos, int whence); - int (*url_close)(URLContext *h); - struct URLProtocol *next; -} URLProtocol; - -extern URLProtocol *first_protocol; -extern URLInterruptCB *url_interrupt_cb; - -int register_protocol(URLProtocol *protocol); - -typedef struct { - unsigned char *buffer; - int buffer_size; - unsigned char *buf_ptr, *buf_end; - void *opaque; - int (*read_packet)(void *opaque, uint8_t *buf, int buf_size); - int (*write_packet)(void *opaque, uint8_t *buf, int buf_size); - offset_t (*seek)(void *opaque, offset_t offset, int whence); - offset_t pos; /**< position in the file of the current buffer */ - int must_flush; /**< true if the next seek should flush */ - int eof_reached; /**< true if eof reached */ - int write_flag; /**< true if open for writing */ - int is_streamed; - int max_packet_size; - unsigned long checksum; - unsigned char *checksum_ptr; - unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size); - int error; ///< contains the error code or 0 if no error happened -} ByteIOContext; - -int init_put_byte(ByteIOContext *s, - unsigned char *buffer, - int buffer_size, - int write_flag, - void *opaque, - int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), - int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), - offset_t (*seek)(void *opaque, offset_t offset, int whence)); - -void put_byte(ByteIOContext *s, int b); -void put_buffer(ByteIOContext *s, const unsigned char *buf, int size); -void put_le64(ByteIOContext *s, uint64_t val); -void put_be64(ByteIOContext *s, uint64_t val); -void put_le32(ByteIOContext *s, unsigned int val); -void put_be32(ByteIOContext *s, unsigned int val); -void put_le24(ByteIOContext *s, unsigned int val); -void put_be24(ByteIOContext *s, unsigned int val); -void put_le16(ByteIOContext *s, unsigned int val); -void put_be16(ByteIOContext *s, unsigned int val); -void put_tag(ByteIOContext *s, const char *tag); - -void put_strz(ByteIOContext *s, const char *buf); - -offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence); -void url_fskip(ByteIOContext *s, offset_t offset); -offset_t url_ftell(ByteIOContext *s); -offset_t url_fsize(ByteIOContext *s); -int url_feof(ByteIOContext *s); -int url_ferror(ByteIOContext *s); - -#define URL_EOF (-1) -/** @note return URL_EOF (-1) if EOF */ -int url_fgetc(ByteIOContext *s); - -/** @warning currently size is limited */ -#ifdef __GNUC__ -int url_fprintf(ByteIOContext *s, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); -#else -int url_fprintf(ByteIOContext *s, const char *fmt, ...); -#endif - -/** @note unlike fgets, the EOL character is not returned and a whole - line is parsed. return NULL if first char read was EOF */ -char *url_fgets(ByteIOContext *s, char *buf, int buf_size); - -void put_flush_packet(ByteIOContext *s); - -int get_buffer(ByteIOContext *s, unsigned char *buf, int size); -int get_partial_buffer(ByteIOContext *s, unsigned char *buf, int size); - -/** @note return 0 if EOF, so you cannot use it if EOF handling is - necessary */ -int get_byte(ByteIOContext *s); -unsigned int get_le24(ByteIOContext *s); -unsigned int get_le32(ByteIOContext *s); -uint64_t get_le64(ByteIOContext *s); -unsigned int get_le16(ByteIOContext *s); - -char *get_strz(ByteIOContext *s, char *buf, int maxlen); -unsigned int get_be16(ByteIOContext *s); -unsigned int get_be24(ByteIOContext *s); -unsigned int get_be32(ByteIOContext *s); -uint64_t get_be64(ByteIOContext *s); - -static inline int url_is_streamed(ByteIOContext *s) -{ - return s->is_streamed; -} - -int url_fdopen(ByteIOContext *s, URLContext *h); - -/** @warning must be called before any I/O */ -int url_setbufsize(ByteIOContext *s, int buf_size); - -/** @note when opened as read/write, the buffers are only used for - reading */ -int url_fopen(ByteIOContext *s, const char *filename, int flags); -int url_fclose(ByteIOContext *s); -URLContext *url_fileno(ByteIOContext *s); - -/** - * Return the maximum packet size associated to packetized buffered file - * handle. If the file is not packetized (stream like http or file on - * disk), then 0 is returned. - * - * @param h buffered file handle - * @return maximum packet size in bytes - */ -int url_fget_max_packet_size(ByteIOContext *s); - -int url_open_buf(ByteIOContext *s, uint8_t *buf, int buf_size, int flags); - -/** return the written or read size */ -int url_close_buf(ByteIOContext *s); - -/** - * Open a write only memory stream. - * - * @param s new IO context - * @return zero if no error. - */ -int url_open_dyn_buf(ByteIOContext *s); - -/** - * Open a write only packetized memory stream with a maximum packet - * size of 'max_packet_size'. The stream is stored in a memory buffer - * with a big endian 4 byte header giving the packet size in bytes. - * - * @param s new IO context - * @param max_packet_size maximum packet size (must be > 0) - * @return zero if no error. - */ -int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size); - -/** - * Return the written size and a pointer to the buffer. The buffer - * must be freed with av_free(). - * @param s IO context - * @param pointer to a byte buffer - * @return the length of the byte buffer - */ -int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer); - -unsigned long get_checksum(ByteIOContext *s); -void init_checksum(ByteIOContext *s, unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), unsigned long checksum); - -/* file.c */ -extern URLProtocol file_protocol; -extern URLProtocol pipe_protocol; - -/* udp.c */ -extern URLProtocol udp_protocol; -int udp_set_remote_url(URLContext *h, const char *uri); -int udp_get_local_port(URLContext *h); -int udp_get_file_handle(URLContext *h); - -/* tcp.c */ -extern URLProtocol tcp_protocol; - -/* http.c */ -extern URLProtocol http_protocol; - -#endif - +/* + * unbuffered io for ffmpeg system + * copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef AVIO_H +#define AVIO_H + +/* output byte stream handling */ + +typedef int64_t offset_t; + +/* unbuffered I/O */ + +struct URLContext { + struct URLProtocol *prot; + int flags; + int is_streamed; /**< true if streamed (no seek possible), default = false */ + int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */ + void *priv_data; +#if LIBAVFORMAT_VERSION_INT >= (52<<16) + char *filename; /**< specified filename */ +#else + char filename[1]; /**< specified filename */ +#endif +}; + +typedef struct URLContext URLContext; + +typedef struct URLPollEntry { + URLContext *handle; + int events; + int revents; +} URLPollEntry; + +#define URL_RDONLY 0 +#define URL_WRONLY 1 +#define URL_RDWR 2 + +typedef int URLInterruptCB(void); + +int url_open(URLContext **h, const char *filename, int flags); +int url_read(URLContext *h, unsigned char *buf, int size); +int url_write(URLContext *h, unsigned char *buf, int size); +offset_t url_seek(URLContext *h, offset_t pos, int whence); +int url_close(URLContext *h); +int url_exist(const char *filename); +offset_t url_filesize(URLContext *h); + +/** + * Return the maximum packet size associated to packetized file + * handle. If the file is not packetized (stream like http or file on + * disk), then 0 is returned. + * + * @param h file handle + * @return maximum packet size in bytes + */ +int url_get_max_packet_size(URLContext *h); +void url_get_filename(URLContext *h, char *buf, int buf_size); + +/** + * the callback is called in blocking functions to test regulary if + * asynchronous interruption is needed. AVERROR(EINTR) is returned + * in this case by the interrupted function. 'NULL' means no interrupt + * callback is given. i + */ +void url_set_interrupt_cb(URLInterruptCB *interrupt_cb); + +/* not implemented */ +int url_poll(URLPollEntry *poll_table, int n, int timeout); + +/** + * passing this as the "whence" parameter to a seek function causes it to + * return the filesize without seeking anywhere, supporting this is optional + * if its not supprted then the seek function will return <0 + */ +#define AVSEEK_SIZE 0x10000 + +typedef struct URLProtocol { + const char *name; + int (*url_open)(URLContext *h, const char *filename, int flags); + int (*url_read)(URLContext *h, unsigned char *buf, int size); + int (*url_write)(URLContext *h, unsigned char *buf, int size); + offset_t (*url_seek)(URLContext *h, offset_t pos, int whence); + int (*url_close)(URLContext *h); + struct URLProtocol *next; +} URLProtocol; + +extern URLProtocol *first_protocol; +extern URLInterruptCB *url_interrupt_cb; + +int register_protocol(URLProtocol *protocol); + +typedef struct { + unsigned char *buffer; + int buffer_size; + unsigned char *buf_ptr, *buf_end; + void *opaque; + int (*read_packet)(void *opaque, uint8_t *buf, int buf_size); + int (*write_packet)(void *opaque, uint8_t *buf, int buf_size); + offset_t (*seek)(void *opaque, offset_t offset, int whence); + offset_t pos; /**< position in the file of the current buffer */ + int must_flush; /**< true if the next seek should flush */ + int eof_reached; /**< true if eof reached */ + int write_flag; /**< true if open for writing */ + int is_streamed; + int max_packet_size; + unsigned long checksum; + unsigned char *checksum_ptr; + unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size); + int error; ///< contains the error code or 0 if no error happened +} ByteIOContext; + +int init_put_byte(ByteIOContext *s, + unsigned char *buffer, + int buffer_size, + int write_flag, + void *opaque, + int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), + int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), + offset_t (*seek)(void *opaque, offset_t offset, int whence)); + +void put_byte(ByteIOContext *s, int b); +void put_buffer(ByteIOContext *s, const unsigned char *buf, int size); +void put_le64(ByteIOContext *s, uint64_t val); +void put_be64(ByteIOContext *s, uint64_t val); +void put_le32(ByteIOContext *s, unsigned int val); +void put_be32(ByteIOContext *s, unsigned int val); +void put_le24(ByteIOContext *s, unsigned int val); +void put_be24(ByteIOContext *s, unsigned int val); +void put_le16(ByteIOContext *s, unsigned int val); +void put_be16(ByteIOContext *s, unsigned int val); +void put_tag(ByteIOContext *s, const char *tag); + +void put_strz(ByteIOContext *s, const char *buf); + +offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence); +void url_fskip(ByteIOContext *s, offset_t offset); +offset_t url_ftell(ByteIOContext *s); +offset_t url_fsize(ByteIOContext *s); +int url_feof(ByteIOContext *s); +int url_ferror(ByteIOContext *s); + +#define URL_EOF (-1) +/** @note return URL_EOF (-1) if EOF */ +int url_fgetc(ByteIOContext *s); + +/** @warning currently size is limited */ +#ifdef __GNUC__ +int url_fprintf(ByteIOContext *s, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); +#else +int url_fprintf(ByteIOContext *s, const char *fmt, ...); +#endif + +/** @note unlike fgets, the EOL character is not returned and a whole + line is parsed. return NULL if first char read was EOF */ +char *url_fgets(ByteIOContext *s, char *buf, int buf_size); + +void put_flush_packet(ByteIOContext *s); + +int get_buffer(ByteIOContext *s, unsigned char *buf, int size); +int get_partial_buffer(ByteIOContext *s, unsigned char *buf, int size); + +/** @note return 0 if EOF, so you cannot use it if EOF handling is + necessary */ +int get_byte(ByteIOContext *s); +unsigned int get_le24(ByteIOContext *s); +unsigned int get_le32(ByteIOContext *s); +uint64_t get_le64(ByteIOContext *s); +unsigned int get_le16(ByteIOContext *s); + +char *get_strz(ByteIOContext *s, char *buf, int maxlen); +unsigned int get_be16(ByteIOContext *s); +unsigned int get_be24(ByteIOContext *s); +unsigned int get_be32(ByteIOContext *s); +uint64_t get_be64(ByteIOContext *s); + +static inline int url_is_streamed(ByteIOContext *s) +{ + return s->is_streamed; +} + +int url_fdopen(ByteIOContext *s, URLContext *h); + +/** @warning must be called before any I/O */ +int url_setbufsize(ByteIOContext *s, int buf_size); + +/** @note when opened as read/write, the buffers are only used for + reading */ +int url_fopen(ByteIOContext *s, const char *filename, int flags); +int url_fclose(ByteIOContext *s); +URLContext *url_fileno(ByteIOContext *s); + +/** + * Return the maximum packet size associated to packetized buffered file + * handle. If the file is not packetized (stream like http or file on + * disk), then 0 is returned. + * + * @param h buffered file handle + * @return maximum packet size in bytes + */ +int url_fget_max_packet_size(ByteIOContext *s); + +int url_open_buf(ByteIOContext *s, uint8_t *buf, int buf_size, int flags); + +/** return the written or read size */ +int url_close_buf(ByteIOContext *s); + +/** + * Open a write only memory stream. + * + * @param s new IO context + * @return zero if no error. + */ +int url_open_dyn_buf(ByteIOContext *s); + +/** + * Open a write only packetized memory stream with a maximum packet + * size of 'max_packet_size'. The stream is stored in a memory buffer + * with a big endian 4 byte header giving the packet size in bytes. + * + * @param s new IO context + * @param max_packet_size maximum packet size (must be > 0) + * @return zero if no error. + */ +int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size); + +/** + * Return the written size and a pointer to the buffer. The buffer + * must be freed with av_free(). + * @param s IO context + * @param pointer to a byte buffer + * @return the length of the byte buffer + */ +int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer); + +unsigned long get_checksum(ByteIOContext *s); +void init_checksum(ByteIOContext *s, unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), unsigned long checksum); + +/* file.c */ +extern URLProtocol file_protocol; +extern URLProtocol pipe_protocol; + +/* udp.c */ +extern URLProtocol udp_protocol; +int udp_set_remote_url(URLContext *h, const char *uri); +int udp_get_local_port(URLContext *h); +int udp_get_file_handle(URLContext *h); + +/* tcp.c */ +extern URLProtocol tcp_protocol; + +/* http.c */ +extern URLProtocol http_protocol; + +#endif + diff --git a/src/ffmpeg/include/ffmpeg/avutil.h b/src/ffmpeg/include/ffmpeg/avutil.h index 32bc40bfbf..c983dfe14a 100644 --- a/src/ffmpeg/include/ffmpeg/avutil.h +++ b/src/ffmpeg/include/ffmpeg/avutil.h @@ -1,137 +1,137 @@ -/* - * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVUTIL_H -#define AVUTIL_H - -/** - * @file avutil.h - * external api header. - */ - - -#ifdef __cplusplus -extern "C" { -#endif - -#define AV_STRINGIFY(s) AV_TOSTRING(s) -#define AV_TOSTRING(s) #s - -#define LIBAVUTIL_VERSION_INT ((49<<16)+(4<<8)+0) -#define LIBAVUTIL_VERSION 49.4.0 -#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT - -#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION) - - -#include "common.h" -#include "mathematics.h" -#include "rational.h" -#include "integer.h" -#include "intfloat_readwrite.h" -#include "log.h" - -/** - * Pixel format. Notes: - * - * PIX_FMT_RGB32 is handled in an endian-specific manner. A RGBA - * color is put together as: - * (A << 24) | (R << 16) | (G << 8) | B - * This is stored as BGRA on little endian CPU architectures and ARGB on - * big endian CPUs. - * - * When the pixel format is palettized RGB (PIX_FMT_PAL8), the palettized - * image data is stored in AVFrame.data[0]. The palette is transported in - * AVFrame.data[1] and, is 1024 bytes long (256 4-byte entries) and is - * formatted the same as in PIX_FMT_RGB32 described above (i.e., it is - * also endian-specific). Note also that the individual RGB palette - * components stored in AVFrame.data[1] should be in the range 0..255. - * This is important as many custom PAL8 video codecs that were designed - * to run on the IBM VGA graphics adapter use 6-bit palette components. - */ -enum PixelFormat { - PIX_FMT_NONE= -1, - PIX_FMT_YUV420P, ///< Planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) - PIX_FMT_YUYV422, ///< Packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr - PIX_FMT_RGB24, ///< Packed RGB 8:8:8, 24bpp, RGBRGB... - PIX_FMT_BGR24, ///< Packed RGB 8:8:8, 24bpp, BGRBGR... - PIX_FMT_YUV422P, ///< Planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) - PIX_FMT_YUV444P, ///< Planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) - PIX_FMT_RGB32, ///< Packed RGB 8:8:8, 32bpp, (msb)8A 8R 8G 8B(lsb), in cpu endianness - PIX_FMT_YUV410P, ///< Planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) - PIX_FMT_YUV411P, ///< Planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) - PIX_FMT_RGB565, ///< Packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), in cpu endianness - PIX_FMT_RGB555, ///< Packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), in cpu endianness most significant bit to 0 - PIX_FMT_GRAY8, ///< Y , 8bpp - PIX_FMT_MONOWHITE, ///< Y , 1bpp, 1 is white - PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black - PIX_FMT_PAL8, ///< 8 bit with PIX_FMT_RGB32 palette - PIX_FMT_YUVJ420P, ///< Planar YUV 4:2:0, 12bpp, full scale (jpeg) - PIX_FMT_YUVJ422P, ///< Planar YUV 4:2:2, 16bpp, full scale (jpeg) - PIX_FMT_YUVJ444P, ///< Planar YUV 4:4:4, 24bpp, full scale (jpeg) - PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing(xvmc_render.h) - PIX_FMT_XVMC_MPEG2_IDCT, - PIX_FMT_UYVY422, ///< Packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 - PIX_FMT_UYYVYY411, ///< Packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 - PIX_FMT_BGR32, ///< Packed RGB 8:8:8, 32bpp, (msb)8A 8B 8G 8R(lsb), in cpu endianness - PIX_FMT_BGR565, ///< Packed RGB 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), in cpu endianness - PIX_FMT_BGR555, ///< Packed RGB 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), in cpu endianness most significant bit to 1 - PIX_FMT_BGR8, ///< Packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb) - PIX_FMT_BGR4, ///< Packed RGB 1:2:1, 4bpp, (msb)1B 2G 1R(lsb) - PIX_FMT_BGR4_BYTE, ///< Packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb) - PIX_FMT_RGB8, ///< Packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb) - PIX_FMT_RGB4, ///< Packed RGB 1:2:1, 4bpp, (msb)2R 3G 3B(lsb) - PIX_FMT_RGB4_BYTE, ///< Packed RGB 1:2:1, 8bpp, (msb)2R 3G 3B(lsb) - PIX_FMT_NV12, ///< Planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 for UV - PIX_FMT_NV21, ///< as above, but U and V bytes are swapped - - PIX_FMT_RGB32_1, ///< Packed RGB 8:8:8, 32bpp, (msb)8R 8G 8B 8A(lsb), in cpu endianness - PIX_FMT_BGR32_1, ///< Packed RGB 8:8:8, 32bpp, (msb)8B 8G 8R 8A(lsb), in cpu endianness - - PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian - PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian - PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions -}; - -#ifdef WORDS_BIGENDIAN -#define PIX_FMT_RGBA PIX_FMT_RGB32_1 -#define PIX_FMT_BGRA PIX_FMT_BGR32_1 -#define PIX_FMT_ARGB PIX_FMT_RGB32 -#define PIX_FMT_ABGR PIX_FMT_BGR32 -#define PIX_FMT_GRAY16 PIX_FMT_GRAY16BE -#else -#define PIX_FMT_RGBA PIX_FMT_BGR32 -#define PIX_FMT_BGRA PIX_FMT_RGB32 -#define PIX_FMT_ARGB PIX_FMT_BGR32_1 -#define PIX_FMT_ABGR PIX_FMT_RGB32_1 -#define PIX_FMT_GRAY16 PIX_FMT_GRAY16LE -#endif - -#if LIBAVUTIL_VERSION_INT < (50<<16) -#define PIX_FMT_UYVY411 PIX_FMT_UYYVYY411 -#define PIX_FMT_RGBA32 PIX_FMT_RGB32 -#define PIX_FMT_YUV422 PIX_FMT_YUYV422 -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* AVUTIL_H */ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_H +#define AVUTIL_H + +/** + * @file avutil.h + * external api header. + */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#define AV_STRINGIFY(s) AV_TOSTRING(s) +#define AV_TOSTRING(s) #s + +#define LIBAVUTIL_VERSION_INT ((49<<16)+(4<<8)+0) +#define LIBAVUTIL_VERSION 49.4.0 +#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT + +#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION) + + +#include "common.h" +#include "mathematics.h" +#include "rational.h" +#include "integer.h" +#include "intfloat_readwrite.h" +#include "log.h" + +/** + * Pixel format. Notes: + * + * PIX_FMT_RGB32 is handled in an endian-specific manner. A RGBA + * color is put together as: + * (A << 24) | (R << 16) | (G << 8) | B + * This is stored as BGRA on little endian CPU architectures and ARGB on + * big endian CPUs. + * + * When the pixel format is palettized RGB (PIX_FMT_PAL8), the palettized + * image data is stored in AVFrame.data[0]. The palette is transported in + * AVFrame.data[1] and, is 1024 bytes long (256 4-byte entries) and is + * formatted the same as in PIX_FMT_RGB32 described above (i.e., it is + * also endian-specific). Note also that the individual RGB palette + * components stored in AVFrame.data[1] should be in the range 0..255. + * This is important as many custom PAL8 video codecs that were designed + * to run on the IBM VGA graphics adapter use 6-bit palette components. + */ +enum PixelFormat { + PIX_FMT_NONE= -1, + PIX_FMT_YUV420P, ///< Planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) + PIX_FMT_YUYV422, ///< Packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr + PIX_FMT_RGB24, ///< Packed RGB 8:8:8, 24bpp, RGBRGB... + PIX_FMT_BGR24, ///< Packed RGB 8:8:8, 24bpp, BGRBGR... + PIX_FMT_YUV422P, ///< Planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + PIX_FMT_YUV444P, ///< Planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) + PIX_FMT_RGB32, ///< Packed RGB 8:8:8, 32bpp, (msb)8A 8R 8G 8B(lsb), in cpu endianness + PIX_FMT_YUV410P, ///< Planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) + PIX_FMT_YUV411P, ///< Planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) + PIX_FMT_RGB565, ///< Packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), in cpu endianness + PIX_FMT_RGB555, ///< Packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), in cpu endianness most significant bit to 0 + PIX_FMT_GRAY8, ///< Y , 8bpp + PIX_FMT_MONOWHITE, ///< Y , 1bpp, 1 is white + PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black + PIX_FMT_PAL8, ///< 8 bit with PIX_FMT_RGB32 palette + PIX_FMT_YUVJ420P, ///< Planar YUV 4:2:0, 12bpp, full scale (jpeg) + PIX_FMT_YUVJ422P, ///< Planar YUV 4:2:2, 16bpp, full scale (jpeg) + PIX_FMT_YUVJ444P, ///< Planar YUV 4:4:4, 24bpp, full scale (jpeg) + PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing(xvmc_render.h) + PIX_FMT_XVMC_MPEG2_IDCT, + PIX_FMT_UYVY422, ///< Packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 + PIX_FMT_UYYVYY411, ///< Packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 + PIX_FMT_BGR32, ///< Packed RGB 8:8:8, 32bpp, (msb)8A 8B 8G 8R(lsb), in cpu endianness + PIX_FMT_BGR565, ///< Packed RGB 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), in cpu endianness + PIX_FMT_BGR555, ///< Packed RGB 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), in cpu endianness most significant bit to 1 + PIX_FMT_BGR8, ///< Packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb) + PIX_FMT_BGR4, ///< Packed RGB 1:2:1, 4bpp, (msb)1B 2G 1R(lsb) + PIX_FMT_BGR4_BYTE, ///< Packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb) + PIX_FMT_RGB8, ///< Packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb) + PIX_FMT_RGB4, ///< Packed RGB 1:2:1, 4bpp, (msb)2R 3G 3B(lsb) + PIX_FMT_RGB4_BYTE, ///< Packed RGB 1:2:1, 8bpp, (msb)2R 3G 3B(lsb) + PIX_FMT_NV12, ///< Planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 for UV + PIX_FMT_NV21, ///< as above, but U and V bytes are swapped + + PIX_FMT_RGB32_1, ///< Packed RGB 8:8:8, 32bpp, (msb)8R 8G 8B 8A(lsb), in cpu endianness + PIX_FMT_BGR32_1, ///< Packed RGB 8:8:8, 32bpp, (msb)8B 8G 8R 8A(lsb), in cpu endianness + + PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian + PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian + PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions +}; + +#ifdef WORDS_BIGENDIAN +#define PIX_FMT_RGBA PIX_FMT_RGB32_1 +#define PIX_FMT_BGRA PIX_FMT_BGR32_1 +#define PIX_FMT_ARGB PIX_FMT_RGB32 +#define PIX_FMT_ABGR PIX_FMT_BGR32 +#define PIX_FMT_GRAY16 PIX_FMT_GRAY16BE +#else +#define PIX_FMT_RGBA PIX_FMT_BGR32 +#define PIX_FMT_BGRA PIX_FMT_RGB32 +#define PIX_FMT_ARGB PIX_FMT_BGR32_1 +#define PIX_FMT_ABGR PIX_FMT_RGB32_1 +#define PIX_FMT_GRAY16 PIX_FMT_GRAY16LE +#endif + +#if LIBAVUTIL_VERSION_INT < (50<<16) +#define PIX_FMT_UYVY411 PIX_FMT_UYYVYY411 +#define PIX_FMT_RGBA32 PIX_FMT_RGB32 +#define PIX_FMT_YUV422 PIX_FMT_YUYV422 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* AVUTIL_H */ diff --git a/src/ffmpeg/include/ffmpeg/common.h b/src/ffmpeg/include/ffmpeg/common.h index 07c4276faf..c47a2df9a6 100644 --- a/src/ffmpeg/include/ffmpeg/common.h +++ b/src/ffmpeg/include/ffmpeg/common.h @@ -1,328 +1,328 @@ -/* - * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file common.h - * common internal and external api header. - */ - -#ifndef COMMON_H -#define COMMON_H - -#if 0 -#include <inttypes.h> -#endif - -#ifdef HAVE_AV_CONFIG_H -/* only include the following when compiling package */ -# include "config.h" - -# include <stdlib.h> -# include <stdio.h> -# include <string.h> -# include <ctype.h> -# include <limits.h> -# include <errno.h> -# include <math.h> -#endif /* HAVE_AV_CONFIG_H */ - -#ifndef av_always_inline -#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) -# define av_always_inline __attribute__((always_inline)) inline -# define av_noinline __attribute__((noinline)) -#else -# define av_always_inline inline -# define av_noinline -#endif -#endif - -#ifdef HAVE_AV_CONFIG_H -# include "internal.h" -#endif /* HAVE_AV_CONFIG_H */ - -#ifndef attribute_deprecated -#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) -# define attribute_deprecated __attribute__((deprecated)) -#else -# define attribute_deprecated -#endif -#endif - -#include "mem.h" - -//rounded divison & shift -#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b)) -/* assume b>0 */ -#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) -#define FFABS(a) ((a) >= 0 ? (a) : (-(a))) -#define FFSIGN(a) ((a) > 0 ? 1 : -1) - -#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) -#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) - -#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) - -/* misc math functions */ -extern const uint8_t ff_log2_tab[256]; - -static inline int av_log2(unsigned int v) -{ - int n; - - n = 0; - if (v & 0xffff0000) { - v >>= 16; - n += 16; - } - if (v & 0xff00) { - v >>= 8; - n += 8; - } - n += ff_log2_tab[v]; - - return n; -} - -static inline int av_log2_16bit(unsigned int v) -{ - int n; - - n = 0; - if (v & 0xff00) { - v >>= 8; - n += 8; - } - n += ff_log2_tab[v]; - - return n; -} - -/* median of 3 */ -static inline int mid_pred(int a, int b, int c) -{ -#ifdef HAVE_CMOV - int i=b; - asm volatile( - "cmp %2, %1 \n\t" - "cmovg %1, %0 \n\t" - "cmovg %2, %1 \n\t" - "cmp %3, %1 \n\t" - "cmovl %3, %1 \n\t" - "cmp %1, %0 \n\t" - "cmovg %1, %0 \n\t" - :"+&r"(i), "+&r"(a) - :"r"(b), "r"(c) - ); - return i; -#elif 0 - int t= (a-b)&((a-b)>>31); - a-=t; - b+=t; - b-= (b-c)&((b-c)>>31); - b+= (a-b)&((a-b)>>31); - - return b; -#else - if(a>b){ - if(c>b){ - if(c>a) b=a; - else b=c; - } - }else{ - if(b>c){ - if(c>a) b=c; - else b=a; - } - } - return b; -#endif -} - -/** - * clip a signed integer value into the amin-amax range - * @param a value to clip - * @param amin minimum value of the clip range - * @param amax maximum value of the clip range - * @return clipped value - */ -static inline int av_clip(int a, int amin, int amax) -{ - if (a < amin) return amin; - else if (a > amax) return amax; - else return a; -} - -/** - * clip a signed integer value into the 0-255 range - * @param a value to clip - * @return clipped value - */ -static inline uint8_t av_clip_uint8(int a) -{ - if (a&(~255)) return (-a)>>31; - else return a; -} - -/* math */ -int64_t ff_gcd(int64_t a, int64_t b); - -/** - * converts fourcc string to int - */ -static inline int ff_get_fourcc(const char *s){ -#ifdef HAVE_AV_CONFIG_H - assert( strlen(s)==4 ); -#endif - - return (s[0]) + (s[1]<<8) + (s[2]<<16) + (s[3]<<24); -} - -#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24)) -#define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24)) - -/*! - * \def GET_UTF8(val, GET_BYTE, ERROR) - * converts a utf-8 character (up to 4 bytes long) to its 32-bit ucs-4 encoded form - * \param val is the output and should be of type uint32_t. It holds the converted - * ucs-4 character and should be a left value. - * \param GET_BYTE gets utf-8 encoded bytes from any proper source. It can be - * a function or a statement whose return value or evaluated value is of type - * uint8_t. It will be executed up to 4 times for values in the valid utf-8 range, - * and up to 7 times in the general case. - * \param ERROR action that should be taken when an invalid utf-8 byte is returned - * from GET_BYTE. It should be a statement that jumps out of the macro, - * like exit(), goto, return, break, or continue. - */ -#define GET_UTF8(val, GET_BYTE, ERROR)\ - val= GET_BYTE;\ - {\ - int ones= 7 - av_log2(val ^ 255);\ - if(ones==1)\ - ERROR\ - val&= 127>>ones;\ - while(--ones > 0){\ - int tmp= GET_BYTE - 128;\ - if(tmp>>6)\ - ERROR\ - val= (val<<6) + tmp;\ - }\ - } - -/*! - * \def PUT_UTF8(val, tmp, PUT_BYTE) - * converts a 32-bit unicode character to its utf-8 encoded form (up to 4 bytes long). - * \param val is an input only argument and should be of type uint32_t. It holds - * a ucs4 encoded unicode character that is to be converted to utf-8. If - * val is given as a function it's executed only once. - * \param tmp is a temporary variable and should be of type uint8_t. It - * represents an intermediate value during conversion that is to be - * outputted by PUT_BYTE. - * \param PUT_BYTE writes the converted utf-8 bytes to any proper destination. - * It could be a function or a statement, and uses tmp as the input byte. - * For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be - * executed up to 4 times for values in the valid utf-8 range and up to - * 7 times in the general case, depending on the length of the converted - * unicode character. - */ -#define PUT_UTF8(val, tmp, PUT_BYTE)\ - {\ - int bytes, shift;\ - uint32_t in = val;\ - if (in < 0x80) {\ - tmp = in;\ - PUT_BYTE\ - } else {\ - bytes = (av_log2(in) + 4) / 5;\ - shift = (bytes - 1) * 6;\ - tmp = (256 - (256 >> bytes)) | (in >> shift);\ - PUT_BYTE\ - while (shift >= 6) {\ - shift -= 6;\ - tmp = 0x80 | ((in >> shift) & 0x3f);\ - PUT_BYTE\ - }\ - }\ - } - -#if defined(ARCH_X86) || defined(ARCH_POWERPC) -#if defined(ARCH_X86_64) -static inline uint64_t read_time(void) -{ - uint64_t a, d; - asm volatile( "rdtsc\n\t" - : "=a" (a), "=d" (d) - ); - return (d << 32) | (a & 0xffffffff); -} -#elif defined(ARCH_X86_32) -static inline long long read_time(void) -{ - long long l; - asm volatile( "rdtsc\n\t" - : "=A" (l) - ); - return l; -} -#else //FIXME check ppc64 -static inline uint64_t read_time(void) -{ - uint32_t tbu, tbl, temp; - - /* from section 2.2.1 of the 32-bit PowerPC PEM */ - __asm__ __volatile__( - "1:\n" - "mftbu %2\n" - "mftb %0\n" - "mftbu %1\n" - "cmpw %2,%1\n" - "bne 1b\n" - : "=r"(tbl), "=r"(tbu), "=r"(temp) - : - : "cc"); - - return (((uint64_t)tbu)<<32) | (uint64_t)tbl; -} -#endif - -#define START_TIMER \ -uint64_t tend;\ -uint64_t tstart= read_time();\ - -#define STOP_TIMER(id) \ -tend= read_time();\ -{\ - static uint64_t tsum=0;\ - static int tcount=0;\ - static int tskip_count=0;\ - if(tcount<2 || tend - tstart < FFMAX(8*tsum/tcount, 2000)){\ - tsum+= tend - tstart;\ - tcount++;\ - }else\ - tskip_count++;\ - if(((tcount+tskip_count)&(tcount+tskip_count-1))==0){\ - av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\ - }\ -} -#else -#define START_TIMER -#define STOP_TIMER(id) {} -#endif - -#endif /* COMMON_H */ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file common.h + * common internal and external api header. + */ + +#ifndef COMMON_H +#define COMMON_H + +#if 0 +#include <inttypes.h> +#endif + +#ifdef HAVE_AV_CONFIG_H +/* only include the following when compiling package */ +# include "config.h" + +# include <stdlib.h> +# include <stdio.h> +# include <string.h> +# include <ctype.h> +# include <limits.h> +# include <errno.h> +# include <math.h> +#endif /* HAVE_AV_CONFIG_H */ + +#ifndef av_always_inline +#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define av_always_inline __attribute__((always_inline)) inline +# define av_noinline __attribute__((noinline)) +#else +# define av_always_inline inline +# define av_noinline +#endif +#endif + +#ifdef HAVE_AV_CONFIG_H +# include "internal.h" +#endif /* HAVE_AV_CONFIG_H */ + +#ifndef attribute_deprecated +#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define attribute_deprecated __attribute__((deprecated)) +#else +# define attribute_deprecated +#endif +#endif + +#include "mem.h" + +//rounded divison & shift +#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b)) +/* assume b>0 */ +#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) +#define FFABS(a) ((a) >= 0 ? (a) : (-(a))) +#define FFSIGN(a) ((a) > 0 ? 1 : -1) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) + +#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) + +/* misc math functions */ +extern const uint8_t ff_log2_tab[256]; + +static inline int av_log2(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xffff0000) { + v >>= 16; + n += 16; + } + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + +static inline int av_log2_16bit(unsigned int v) +{ + int n; + + n = 0; + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} + +/* median of 3 */ +static inline int mid_pred(int a, int b, int c) +{ +#ifdef HAVE_CMOV + int i=b; + asm volatile( + "cmp %2, %1 \n\t" + "cmovg %1, %0 \n\t" + "cmovg %2, %1 \n\t" + "cmp %3, %1 \n\t" + "cmovl %3, %1 \n\t" + "cmp %1, %0 \n\t" + "cmovg %1, %0 \n\t" + :"+&r"(i), "+&r"(a) + :"r"(b), "r"(c) + ); + return i; +#elif 0 + int t= (a-b)&((a-b)>>31); + a-=t; + b+=t; + b-= (b-c)&((b-c)>>31); + b+= (a-b)&((a-b)>>31); + + return b; +#else + if(a>b){ + if(c>b){ + if(c>a) b=a; + else b=c; + } + }else{ + if(b>c){ + if(c>a) b=c; + else b=a; + } + } + return b; +#endif +} + +/** + * clip a signed integer value into the amin-amax range + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static inline int av_clip(int a, int amin, int amax) +{ + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * clip a signed integer value into the 0-255 range + * @param a value to clip + * @return clipped value + */ +static inline uint8_t av_clip_uint8(int a) +{ + if (a&(~255)) return (-a)>>31; + else return a; +} + +/* math */ +int64_t ff_gcd(int64_t a, int64_t b); + +/** + * converts fourcc string to int + */ +static inline int ff_get_fourcc(const char *s){ +#ifdef HAVE_AV_CONFIG_H + assert( strlen(s)==4 ); +#endif + + return (s[0]) + (s[1]<<8) + (s[2]<<16) + (s[3]<<24); +} + +#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24)) +#define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24)) + +/*! + * \def GET_UTF8(val, GET_BYTE, ERROR) + * converts a utf-8 character (up to 4 bytes long) to its 32-bit ucs-4 encoded form + * \param val is the output and should be of type uint32_t. It holds the converted + * ucs-4 character and should be a left value. + * \param GET_BYTE gets utf-8 encoded bytes from any proper source. It can be + * a function or a statement whose return value or evaluated value is of type + * uint8_t. It will be executed up to 4 times for values in the valid utf-8 range, + * and up to 7 times in the general case. + * \param ERROR action that should be taken when an invalid utf-8 byte is returned + * from GET_BYTE. It should be a statement that jumps out of the macro, + * like exit(), goto, return, break, or continue. + */ +#define GET_UTF8(val, GET_BYTE, ERROR)\ + val= GET_BYTE;\ + {\ + int ones= 7 - av_log2(val ^ 255);\ + if(ones==1)\ + ERROR\ + val&= 127>>ones;\ + while(--ones > 0){\ + int tmp= GET_BYTE - 128;\ + if(tmp>>6)\ + ERROR\ + val= (val<<6) + tmp;\ + }\ + } + +/*! + * \def PUT_UTF8(val, tmp, PUT_BYTE) + * converts a 32-bit unicode character to its utf-8 encoded form (up to 4 bytes long). + * \param val is an input only argument and should be of type uint32_t. It holds + * a ucs4 encoded unicode character that is to be converted to utf-8. If + * val is given as a function it's executed only once. + * \param tmp is a temporary variable and should be of type uint8_t. It + * represents an intermediate value during conversion that is to be + * outputted by PUT_BYTE. + * \param PUT_BYTE writes the converted utf-8 bytes to any proper destination. + * It could be a function or a statement, and uses tmp as the input byte. + * For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be + * executed up to 4 times for values in the valid utf-8 range and up to + * 7 times in the general case, depending on the length of the converted + * unicode character. + */ +#define PUT_UTF8(val, tmp, PUT_BYTE)\ + {\ + int bytes, shift;\ + uint32_t in = val;\ + if (in < 0x80) {\ + tmp = in;\ + PUT_BYTE\ + } else {\ + bytes = (av_log2(in) + 4) / 5;\ + shift = (bytes - 1) * 6;\ + tmp = (256 - (256 >> bytes)) | (in >> shift);\ + PUT_BYTE\ + while (shift >= 6) {\ + shift -= 6;\ + tmp = 0x80 | ((in >> shift) & 0x3f);\ + PUT_BYTE\ + }\ + }\ + } + +#if defined(ARCH_X86) || defined(ARCH_POWERPC) +#if defined(ARCH_X86_64) +static inline uint64_t read_time(void) +{ + uint64_t a, d; + asm volatile( "rdtsc\n\t" + : "=a" (a), "=d" (d) + ); + return (d << 32) | (a & 0xffffffff); +} +#elif defined(ARCH_X86_32) +static inline long long read_time(void) +{ + long long l; + asm volatile( "rdtsc\n\t" + : "=A" (l) + ); + return l; +} +#else //FIXME check ppc64 +static inline uint64_t read_time(void) +{ + uint32_t tbu, tbl, temp; + + /* from section 2.2.1 of the 32-bit PowerPC PEM */ + __asm__ __volatile__( + "1:\n" + "mftbu %2\n" + "mftb %0\n" + "mftbu %1\n" + "cmpw %2,%1\n" + "bne 1b\n" + : "=r"(tbl), "=r"(tbu), "=r"(temp) + : + : "cc"); + + return (((uint64_t)tbu)<<32) | (uint64_t)tbl; +} +#endif + +#define START_TIMER \ +uint64_t tend;\ +uint64_t tstart= read_time();\ + +#define STOP_TIMER(id) \ +tend= read_time();\ +{\ + static uint64_t tsum=0;\ + static int tcount=0;\ + static int tskip_count=0;\ + if(tcount<2 || tend - tstart < FFMAX(8*tsum/tcount, 2000)){\ + tsum+= tend - tstart;\ + tcount++;\ + }else\ + tskip_count++;\ + if(((tcount+tskip_count)&(tcount+tskip_count-1))==0){\ + av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" dezicycles in %s, %d runs, %d skips\n", tsum*10/tcount, id, tcount, tskip_count);\ + }\ +} +#else +#define START_TIMER +#define STOP_TIMER(id) {} +#endif + +#endif /* COMMON_H */ diff --git a/src/ffmpeg/include/ffmpeg/integer.h b/src/ffmpeg/include/ffmpeg/integer.h index 2a4d703166..b1911deace 100644 --- a/src/ffmpeg/include/ffmpeg/integer.h +++ b/src/ffmpeg/include/ffmpeg/integer.h @@ -1,82 +1,82 @@ -/* - * arbitrary precision integers - * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -/** - * @file integer.h - * arbitrary precision integers - * @author Michael Niedermayer <michaelni@gmx.at> - */ - -#ifndef INTEGER_H -#define INTEGER_H - -#define AV_INTEGER_SIZE 8 - -typedef struct AVInteger{ - uint16_t v[AV_INTEGER_SIZE]; -} AVInteger; - -AVInteger av_add_i(AVInteger a, AVInteger b); -AVInteger av_sub_i(AVInteger a, AVInteger b); - -/** - * returns the rounded down value of the logarithm of base 2 of the given AVInteger. - * this is simply the index of the most significant bit which is 1. Or 0 of all bits are 0 - */ -int av_log2_i(AVInteger a); -AVInteger av_mul_i(AVInteger a, AVInteger b); - -/** - * returns 0 if a==b, 1 if a>b and -1 if a<b. - */ -int av_cmp_i(AVInteger a, AVInteger b); - -/** - * bitwise shift. - * @param s the number of bits by which the value should be shifted right, may be negative for shifting left - */ -AVInteger av_shr_i(AVInteger a, int s); - -/** - * returns a % b. - * @param quot a/b will be stored here - */ -AVInteger av_mod_i(AVInteger *quot, AVInteger a, AVInteger b); - -/** - * returns a/b. - */ -AVInteger av_div_i(AVInteger a, AVInteger b); - -/** - * converts the given int64_t to an AVInteger. - */ -AVInteger av_int2i(int64_t a); - -/** - * converts the given AVInteger to an int64_t. - * if the AVInteger is too large to fit into an int64_t, - * then only the least significant 64bit will be used - */ -int64_t av_i2int(AVInteger a); - -#endif // INTEGER_H +/* + * arbitrary precision integers + * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/** + * @file integer.h + * arbitrary precision integers + * @author Michael Niedermayer <michaelni@gmx.at> + */ + +#ifndef INTEGER_H +#define INTEGER_H + +#define AV_INTEGER_SIZE 8 + +typedef struct AVInteger{ + uint16_t v[AV_INTEGER_SIZE]; +} AVInteger; + +AVInteger av_add_i(AVInteger a, AVInteger b); +AVInteger av_sub_i(AVInteger a, AVInteger b); + +/** + * returns the rounded down value of the logarithm of base 2 of the given AVInteger. + * this is simply the index of the most significant bit which is 1. Or 0 of all bits are 0 + */ +int av_log2_i(AVInteger a); +AVInteger av_mul_i(AVInteger a, AVInteger b); + +/** + * returns 0 if a==b, 1 if a>b and -1 if a<b. + */ +int av_cmp_i(AVInteger a, AVInteger b); + +/** + * bitwise shift. + * @param s the number of bits by which the value should be shifted right, may be negative for shifting left + */ +AVInteger av_shr_i(AVInteger a, int s); + +/** + * returns a % b. + * @param quot a/b will be stored here + */ +AVInteger av_mod_i(AVInteger *quot, AVInteger a, AVInteger b); + +/** + * returns a/b. + */ +AVInteger av_div_i(AVInteger a, AVInteger b); + +/** + * converts the given int64_t to an AVInteger. + */ +AVInteger av_int2i(int64_t a); + +/** + * converts the given AVInteger to an int64_t. + * if the AVInteger is too large to fit into an int64_t, + * then only the least significant 64bit will be used + */ +int64_t av_i2int(AVInteger a); + +#endif // INTEGER_H diff --git a/src/ffmpeg/include/ffmpeg/intfloat_readwrite.h b/src/ffmpeg/include/ffmpeg/intfloat_readwrite.h index c535b64c8b..874c8ce318 100644 --- a/src/ffmpeg/include/ffmpeg/intfloat_readwrite.h +++ b/src/ffmpeg/include/ffmpeg/intfloat_readwrite.h @@ -1,39 +1,39 @@ -/* - * copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at> - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef INTFLOAT_READWRITE_H -#define INTFLOAT_READWRITE_H - -#include "common.h" - -/* IEEE 80 bits extended float */ -typedef struct AVExtFloat { - uint8_t exponent[2]; - uint8_t mantissa[8]; -} AVExtFloat; - -double av_int2dbl(int64_t v); -float av_int2flt(int32_t v); -double av_ext2dbl(const AVExtFloat ext); -int64_t av_dbl2int(double d); -int32_t av_flt2int(float d); -AVExtFloat av_dbl2ext(double d); - -#endif /* INTFLOAT_READWRITE_H */ +/* + * copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef INTFLOAT_READWRITE_H +#define INTFLOAT_READWRITE_H + +#include "common.h" + +/* IEEE 80 bits extended float */ +typedef struct AVExtFloat { + uint8_t exponent[2]; + uint8_t mantissa[8]; +} AVExtFloat; + +double av_int2dbl(int64_t v); +float av_int2flt(int32_t v); +double av_ext2dbl(const AVExtFloat ext); +int64_t av_dbl2int(double d); +int32_t av_flt2int(float d); +AVExtFloat av_dbl2ext(double d); + +#endif /* INTFLOAT_READWRITE_H */ diff --git a/src/ffmpeg/include/ffmpeg/log.h b/src/ffmpeg/include/ffmpeg/log.h index fa88f5fb25..3a1e245dfc 100644 --- a/src/ffmpeg/include/ffmpeg/log.h +++ b/src/ffmpeg/include/ffmpeg/log.h @@ -1,116 +1,116 @@ -/* - * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LOG_H -#define LOG_H - -#include <stdarg.h> - -/** - * Used by av_log - */ -typedef struct AVCLASS AVClass; -struct AVCLASS { - const char* class_name; - const char* (*item_name)(void*); /* actually passing a pointer to an AVCodecContext - or AVFormatContext, which begin with an AVClass. - Needed because av_log is in libavcodec and has no visibility - of AVIn/OutputFormat */ - const struct AVOption *option; -}; - -/* av_log API */ - -#if LIBAVUTIL_VERSION_INT < (50<<16) -#define AV_LOG_QUIET -1 -#define AV_LOG_FATAL 0 -#define AV_LOG_ERROR 0 -#define AV_LOG_WARNING 1 -#define AV_LOG_INFO 1 -#define AV_LOG_VERBOSE 1 -#define AV_LOG_DEBUG 2 -#else -#define AV_LOG_QUIET -8 - -/** - * something went really wrong and we will crash now - */ -#define AV_LOG_PANIC 0 - -/** - * something went wrong and recovery is not possible - * like no header in a format which depends on it or a combination - * of parameters which are not allowed - */ -#define AV_LOG_FATAL 8 - -/** - * something went wrong and cannot losslessly be recovered - * but not all future data is affected - */ -#define AV_LOG_ERROR 16 - -/** - * something somehow does not look correct / something which may or may not - * lead to some problems like use of -vstrict -2 - */ -#define AV_LOG_WARNING 24 - -#define AV_LOG_INFO 32 -#define AV_LOG_VERBOSE 40 - -/** - * stuff which is only useful for libav* developers - */ -#define AV_LOG_DEBUG 48 -#endif -extern int av_log_level; - -/** - * Send the specified message to the log if the level is less than or equal to - * the current av_log_level. By default, all logging messages are sent to - * stderr. This behavior can be altered by setting a different av_vlog callback - * function. - * - * @param avcl A pointer to an arbitrary struct of which the first field is a - * pointer to an AVClass struct. - * @param level The importance level of the message, lower values signifying - * higher importance. - * @param fmt The format string (printf-compatible) that specifies how - * subsequent arguments are converted to output. - * @see av_vlog - */ -#ifdef __GNUC__ -extern void av_log(void*, int level, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); -#else -extern void av_log(void*, int level, const char *fmt, ...); -#endif - -#if LIBAVUTIL_VERSION_INT < (50<<16) -extern void av_vlog(void*, int level, const char *fmt, va_list); -extern int av_log_get_level(void); -extern void av_log_set_level(int); -extern void av_log_set_callback(void (*)(void*, int, const char*, va_list)); -extern void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl); -#else -extern void (*av_vlog)(void*, int, const char*, va_list); -#endif - -#endif /* LOG_H */ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LOG_H +#define LOG_H + +#include <stdarg.h> + +/** + * Used by av_log + */ +typedef struct AVCLASS AVClass; +struct AVCLASS { + const char* class_name; + const char* (*item_name)(void*); /* actually passing a pointer to an AVCodecContext + or AVFormatContext, which begin with an AVClass. + Needed because av_log is in libavcodec and has no visibility + of AVIn/OutputFormat */ + const struct AVOption *option; +}; + +/* av_log API */ + +#if LIBAVUTIL_VERSION_INT < (50<<16) +#define AV_LOG_QUIET -1 +#define AV_LOG_FATAL 0 +#define AV_LOG_ERROR 0 +#define AV_LOG_WARNING 1 +#define AV_LOG_INFO 1 +#define AV_LOG_VERBOSE 1 +#define AV_LOG_DEBUG 2 +#else +#define AV_LOG_QUIET -8 + +/** + * something went really wrong and we will crash now + */ +#define AV_LOG_PANIC 0 + +/** + * something went wrong and recovery is not possible + * like no header in a format which depends on it or a combination + * of parameters which are not allowed + */ +#define AV_LOG_FATAL 8 + +/** + * something went wrong and cannot losslessly be recovered + * but not all future data is affected + */ +#define AV_LOG_ERROR 16 + +/** + * something somehow does not look correct / something which may or may not + * lead to some problems like use of -vstrict -2 + */ +#define AV_LOG_WARNING 24 + +#define AV_LOG_INFO 32 +#define AV_LOG_VERBOSE 40 + +/** + * stuff which is only useful for libav* developers + */ +#define AV_LOG_DEBUG 48 +#endif +extern int av_log_level; + +/** + * Send the specified message to the log if the level is less than or equal to + * the current av_log_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different av_vlog callback + * function. + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message, lower values signifying + * higher importance. + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @see av_vlog + */ +#ifdef __GNUC__ +extern void av_log(void*, int level, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); +#else +extern void av_log(void*, int level, const char *fmt, ...); +#endif + +#if LIBAVUTIL_VERSION_INT < (50<<16) +extern void av_vlog(void*, int level, const char *fmt, va_list); +extern int av_log_get_level(void); +extern void av_log_set_level(int); +extern void av_log_set_callback(void (*)(void*, int, const char*, va_list)); +extern void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl); +#else +extern void (*av_vlog)(void*, int, const char*, va_list); +#endif + +#endif /* LOG_H */ diff --git a/src/ffmpeg/include/ffmpeg/mathematics.h b/src/ffmpeg/include/ffmpeg/mathematics.h index 0b74b254b9..40a96d1c42 100644 --- a/src/ffmpeg/include/ffmpeg/mathematics.h +++ b/src/ffmpeg/include/ffmpeg/mathematics.h @@ -1,51 +1,51 @@ -/* - * copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at> - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef MATHEMATICS_H -#define MATHEMATICS_H - -#include "rational.h" - -enum AVRounding { - AV_ROUND_ZERO = 0, ///< round toward zero - AV_ROUND_INF = 1, ///< round away from zero - AV_ROUND_DOWN = 2, ///< round toward -infinity - AV_ROUND_UP = 3, ///< round toward +infinity - AV_ROUND_NEAR_INF = 5, ///< round to nearest and halfway cases away from zero -}; - -/** - * rescale a 64bit integer with rounding to nearest. - * a simple a*b/c isn't possible as it can overflow - */ -int64_t av_rescale(int64_t a, int64_t b, int64_t c); - -/** - * rescale a 64bit integer with specified rounding. - * a simple a*b/c isn't possible as it can overflow - */ -int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding); - -/** - * rescale a 64bit integer by 2 rational numbers. - */ -int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq); - -#endif /* MATHEMATICS_H */ +/* + * copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MATHEMATICS_H +#define MATHEMATICS_H + +#include "rational.h" + +enum AVRounding { + AV_ROUND_ZERO = 0, ///< round toward zero + AV_ROUND_INF = 1, ///< round away from zero + AV_ROUND_DOWN = 2, ///< round toward -infinity + AV_ROUND_UP = 3, ///< round toward +infinity + AV_ROUND_NEAR_INF = 5, ///< round to nearest and halfway cases away from zero +}; + +/** + * rescale a 64bit integer with rounding to nearest. + * a simple a*b/c isn't possible as it can overflow + */ +int64_t av_rescale(int64_t a, int64_t b, int64_t c); + +/** + * rescale a 64bit integer with specified rounding. + * a simple a*b/c isn't possible as it can overflow + */ +int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding); + +/** + * rescale a 64bit integer by 2 rational numbers. + */ +int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq); + +#endif /* MATHEMATICS_H */ diff --git a/src/ffmpeg/include/ffmpeg/mem.h b/src/ffmpeg/include/ffmpeg/mem.h index 4ebdad8f57..e81b9b7a84 100644 --- a/src/ffmpeg/include/ffmpeg/mem.h +++ b/src/ffmpeg/include/ffmpeg/mem.h @@ -1,65 +1,65 @@ -/* - * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file mem.h - * Memory handling functions. - */ - -#ifndef AV_MEM_H -#define AV_MEM_H - -#ifdef __GNUC__ - #define DECLARE_ALIGNED(n,t,v) t v __attribute__ ((aligned (n))) -#else - #define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v -#endif - -/** - * Memory allocation of size byte with alignment suitable for all - * memory accesses (including vectors if available on the - * CPU). av_malloc(0) must return a non NULL pointer. - */ -void *av_malloc(unsigned int size); - -/** - * av_realloc semantics (same as glibc): if ptr is NULL and size > 0, - * identical to malloc(size). If size is zero, it is identical to - * free(ptr) and NULL is returned. - */ -void *av_realloc(void *ptr, unsigned int size); - -/** - * Free memory which has been allocated with av_malloc(z)() or av_realloc(). - * NOTE: ptr = NULL is explicetly allowed - * Note2: it is recommended that you use av_freep() instead - */ -void av_free(void *ptr); - -void *av_mallocz(unsigned int size); -char *av_strdup(const char *s); - -/** - * Frees memory and sets the pointer to NULL. - * @param ptr pointer to the pointer which should be freed - */ -void av_freep(void *ptr); - -#endif /* AV_MEM_H */ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file mem.h + * Memory handling functions. + */ + +#ifndef AV_MEM_H +#define AV_MEM_H + +#ifdef __GNUC__ + #define DECLARE_ALIGNED(n,t,v) t v __attribute__ ((aligned (n))) +#else + #define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v +#endif + +/** + * Memory allocation of size byte with alignment suitable for all + * memory accesses (including vectors if available on the + * CPU). av_malloc(0) must return a non NULL pointer. + */ +void *av_malloc(unsigned int size); + +/** + * av_realloc semantics (same as glibc): if ptr is NULL and size > 0, + * identical to malloc(size). If size is zero, it is identical to + * free(ptr) and NULL is returned. + */ +void *av_realloc(void *ptr, unsigned int size); + +/** + * Free memory which has been allocated with av_malloc(z)() or av_realloc(). + * NOTE: ptr = NULL is explicetly allowed + * Note2: it is recommended that you use av_freep() instead + */ +void av_free(void *ptr); + +void *av_mallocz(unsigned int size); +char *av_strdup(const char *s); + +/** + * Frees memory and sets the pointer to NULL. + * @param ptr pointer to the pointer which should be freed + */ +void av_freep(void *ptr); + +#endif /* AV_MEM_H */ diff --git a/src/ffmpeg/include/ffmpeg/rational.h b/src/ffmpeg/include/ffmpeg/rational.h index 23da2e2421..e3ad4a4b52 100644 --- a/src/ffmpeg/include/ffmpeg/rational.h +++ b/src/ffmpeg/include/ffmpeg/rational.h @@ -1,114 +1,114 @@ -/* - * Rational numbers - * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at> - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -/** - * @file rational.h - * Rational numbers. - * @author Michael Niedermayer <michaelni@gmx.at> - */ - -#ifndef RATIONAL_H -#define RATIONAL_H - -/** - * Rational number num/den. - */ -typedef struct AVRational{ - int num; ///< numerator - int den; ///< denominator -} AVRational; - -/** - * Compare two rationals. - * @param a first rational - * @param b second rational - * @return 0 if a==b, 1 if a>b and -1 if a<b. - */ -static inline int av_cmp_q(AVRational a, AVRational b){ - const int64_t tmp= a.num * (int64_t)b.den - b.num * (int64_t)a.den; - - if(tmp) return (int)((tmp>>63)|1); - else return 0; -} - -/** - * Rational to double conversion. - * @param a rational to convert - * @return (double) a - */ -static inline double av_q2d(AVRational a){ - return a.num / (double) a.den; -} - -/** - * Reduce a fraction. - * This is useful for framerate calculations. - * @param dst_nom destination numerator - * @param dst_den destination denominator - * @param nom source numerator - * @param den source denominator - * @param max the maximum allowed for dst_nom & dst_den - * @return 1 if exact, 0 otherwise - */ -int av_reduce(int *dst_nom, int *dst_den, int64_t nom, int64_t den, int64_t max); - -/** - * Multiplies two rationals. - * @param b first rational. - * @param c second rational. - * @return b*c. - */ -AVRational av_mul_q(AVRational b, AVRational c); - -/** - * Divides one rational by another. - * @param b first rational. - * @param c second rational. - * @return b/c. - */ -AVRational av_div_q(AVRational b, AVRational c); - -/** - * Adds two rationals. - * @param b first rational. - * @param c second rational. - * @return b+c. - */ -AVRational av_add_q(AVRational b, AVRational c); - -/** - * Subtracts one rational from another. - * @param b first rational. - * @param c second rational. - * returns b-c. - */ -AVRational av_sub_q(AVRational b, AVRational c); - -/** - * Converts a double precision floating point number to a rational. - * @param d double to convert - * @param max the maximum allowed numerator and denominator - * @return (AVRational) d. - */ -AVRational av_d2q(double d, int max); - -#endif // RATIONAL_H +/* + * Rational numbers + * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/** + * @file rational.h + * Rational numbers. + * @author Michael Niedermayer <michaelni@gmx.at> + */ + +#ifndef RATIONAL_H +#define RATIONAL_H + +/** + * Rational number num/den. + */ +typedef struct AVRational{ + int num; ///< numerator + int den; ///< denominator +} AVRational; + +/** + * Compare two rationals. + * @param a first rational + * @param b second rational + * @return 0 if a==b, 1 if a>b and -1 if a<b. + */ +static inline int av_cmp_q(AVRational a, AVRational b){ + const int64_t tmp= a.num * (int64_t)b.den - b.num * (int64_t)a.den; + + if(tmp) return (int)((tmp>>63)|1); + else return 0; +} + +/** + * Rational to double conversion. + * @param a rational to convert + * @return (double) a + */ +static inline double av_q2d(AVRational a){ + return a.num / (double) a.den; +} + +/** + * Reduce a fraction. + * This is useful for framerate calculations. + * @param dst_nom destination numerator + * @param dst_den destination denominator + * @param nom source numerator + * @param den source denominator + * @param max the maximum allowed for dst_nom & dst_den + * @return 1 if exact, 0 otherwise + */ +int av_reduce(int *dst_nom, int *dst_den, int64_t nom, int64_t den, int64_t max); + +/** + * Multiplies two rationals. + * @param b first rational. + * @param c second rational. + * @return b*c. + */ +AVRational av_mul_q(AVRational b, AVRational c); + +/** + * Divides one rational by another. + * @param b first rational. + * @param c second rational. + * @return b/c. + */ +AVRational av_div_q(AVRational b, AVRational c); + +/** + * Adds two rationals. + * @param b first rational. + * @param c second rational. + * @return b+c. + */ +AVRational av_add_q(AVRational b, AVRational c); + +/** + * Subtracts one rational from another. + * @param b first rational. + * @param c second rational. + * returns b-c. + */ +AVRational av_sub_q(AVRational b, AVRational c); + +/** + * Converts a double precision floating point number to a rational. + * @param d double to convert + * @param max the maximum allowed numerator and denominator + * @return (AVRational) d. + */ +AVRational av_d2q(double d, int max); + +#endif // RATIONAL_H diff --git a/src/ffmpeg/include/ffmpeg/rtp.h b/src/ffmpeg/include/ffmpeg/rtp.h index fec7630517..5b3017a9d1 100644 --- a/src/ffmpeg/include/ffmpeg/rtp.h +++ b/src/ffmpeg/include/ffmpeg/rtp.h @@ -1,127 +1,127 @@ -/* - * RTP definitions - * Copyright (c) 2002 Fabrice Bellard. - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef RTP_H -#define RTP_H - -#define RTP_MIN_PACKET_LENGTH 12 -#define RTP_MAX_PACKET_LENGTH 1500 /* XXX: suppress this define */ - -int rtp_init(void); -int rtp_get_codec_info(AVCodecContext *codec, int payload_type); - -/** return < 0 if unknown payload type */ -int rtp_get_payload_type(AVCodecContext *codec); - -typedef struct RTPDemuxContext RTPDemuxContext; -typedef struct rtp_payload_data_s rtp_payload_data_s; -RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, URLContext *rtpc, int payload_type, rtp_payload_data_s *rtp_payload_data); -int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, - const uint8_t *buf, int len); -void rtp_parse_close(RTPDemuxContext *s); - -extern AVOutputFormat rtp_muxer; -extern AVInputFormat rtp_demuxer; - -int rtp_get_local_port(URLContext *h); -int rtp_set_remote_url(URLContext *h, const char *uri); -void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd); - -/** - * some rtp servers assume client is dead if they don't hear from them... - * so we send a Receiver Report to the provided ByteIO context - * (we don't have access to the rtcp handle from here) - */ -int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count); - -extern URLProtocol rtp_protocol; - -#define RTP_PT_PRIVATE 96 -#define RTP_VERSION 2 -#define RTP_MAX_SDES 256 /**< maximum text length for SDES */ - -/* RTCP paquets use 0.5 % of the bandwidth */ -#define RTCP_TX_RATIO_NUM 5 -#define RTCP_TX_RATIO_DEN 1000 - -/** Structure listing useful vars to parse RTP packet payload*/ -typedef struct rtp_payload_data_s -{ - int sizelength; - int indexlength; - int indexdeltalength; - int profile_level_id; - int streamtype; - int objecttype; - char *mode; - - /** mpeg 4 AU headers */ - struct AUHeaders { - int size; - int index; - int cts_flag; - int cts; - int dts_flag; - int dts; - int rap_flag; - int streamstate; - } *au_headers; - int nb_au_headers; - int au_headers_length_bytes; - int cur_au_index; -} rtp_payload_data_t; - -typedef struct AVRtpPayloadType_s -{ - int pt; - const char enc_name[50]; /* XXX: why 50 ? */ - enum CodecType codec_type; - enum CodecID codec_id; - int clock_rate; - int audio_channels; -} AVRtpPayloadType_t; - -#if 0 -typedef enum { - RTCP_SR = 200, - RTCP_RR = 201, - RTCP_SDES = 202, - RTCP_BYE = 203, - RTCP_APP = 204 -} rtcp_type_t; - -typedef enum { - RTCP_SDES_END = 0, - RTCP_SDES_CNAME = 1, - RTCP_SDES_NAME = 2, - RTCP_SDES_EMAIL = 3, - RTCP_SDES_PHONE = 4, - RTCP_SDES_LOC = 5, - RTCP_SDES_TOOL = 6, - RTCP_SDES_NOTE = 7, - RTCP_SDES_PRIV = 8, - RTCP_SDES_IMG = 9, - RTCP_SDES_DOOR = 10, - RTCP_SDES_SOURCE = 11 -} rtcp_sdes_type_t; -#endif - -extern AVRtpPayloadType_t AVRtpPayloadTypes[]; -#endif /* RTP_H */ +/* + * RTP definitions + * Copyright (c) 2002 Fabrice Bellard. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef RTP_H +#define RTP_H + +#define RTP_MIN_PACKET_LENGTH 12 +#define RTP_MAX_PACKET_LENGTH 1500 /* XXX: suppress this define */ + +int rtp_init(void); +int rtp_get_codec_info(AVCodecContext *codec, int payload_type); + +/** return < 0 if unknown payload type */ +int rtp_get_payload_type(AVCodecContext *codec); + +typedef struct RTPDemuxContext RTPDemuxContext; +typedef struct rtp_payload_data_s rtp_payload_data_s; +RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, URLContext *rtpc, int payload_type, rtp_payload_data_s *rtp_payload_data); +int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, + const uint8_t *buf, int len); +void rtp_parse_close(RTPDemuxContext *s); + +extern AVOutputFormat rtp_muxer; +extern AVInputFormat rtp_demuxer; + +int rtp_get_local_port(URLContext *h); +int rtp_set_remote_url(URLContext *h, const char *uri); +void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd); + +/** + * some rtp servers assume client is dead if they don't hear from them... + * so we send a Receiver Report to the provided ByteIO context + * (we don't have access to the rtcp handle from here) + */ +int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count); + +extern URLProtocol rtp_protocol; + +#define RTP_PT_PRIVATE 96 +#define RTP_VERSION 2 +#define RTP_MAX_SDES 256 /**< maximum text length for SDES */ + +/* RTCP paquets use 0.5 % of the bandwidth */ +#define RTCP_TX_RATIO_NUM 5 +#define RTCP_TX_RATIO_DEN 1000 + +/** Structure listing useful vars to parse RTP packet payload*/ +typedef struct rtp_payload_data_s +{ + int sizelength; + int indexlength; + int indexdeltalength; + int profile_level_id; + int streamtype; + int objecttype; + char *mode; + + /** mpeg 4 AU headers */ + struct AUHeaders { + int size; + int index; + int cts_flag; + int cts; + int dts_flag; + int dts; + int rap_flag; + int streamstate; + } *au_headers; + int nb_au_headers; + int au_headers_length_bytes; + int cur_au_index; +} rtp_payload_data_t; + +typedef struct AVRtpPayloadType_s +{ + int pt; + const char enc_name[50]; /* XXX: why 50 ? */ + enum CodecType codec_type; + enum CodecID codec_id; + int clock_rate; + int audio_channels; +} AVRtpPayloadType_t; + +#if 0 +typedef enum { + RTCP_SR = 200, + RTCP_RR = 201, + RTCP_SDES = 202, + RTCP_BYE = 203, + RTCP_APP = 204 +} rtcp_type_t; + +typedef enum { + RTCP_SDES_END = 0, + RTCP_SDES_CNAME = 1, + RTCP_SDES_NAME = 2, + RTCP_SDES_EMAIL = 3, + RTCP_SDES_PHONE = 4, + RTCP_SDES_LOC = 5, + RTCP_SDES_TOOL = 6, + RTCP_SDES_NOTE = 7, + RTCP_SDES_PRIV = 8, + RTCP_SDES_IMG = 9, + RTCP_SDES_DOOR = 10, + RTCP_SDES_SOURCE = 11 +} rtcp_sdes_type_t; +#endif + +extern AVRtpPayloadType_t AVRtpPayloadTypes[]; +#endif /* RTP_H */ diff --git a/src/ffmpeg/include/ffmpeg/rtsp.h b/src/ffmpeg/include/ffmpeg/rtsp.h index 481e2ba499..b28e20714a 100644 --- a/src/ffmpeg/include/ffmpeg/rtsp.h +++ b/src/ffmpeg/include/ffmpeg/rtsp.h @@ -1,94 +1,94 @@ -/* - * RTSP definitions - * Copyright (c) 2002 Fabrice Bellard. - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef RTSP_H -#define RTSP_H - -#include "rtspcodes.h" - -enum RTSPProtocol { - RTSP_PROTOCOL_RTP_UDP = 0, - RTSP_PROTOCOL_RTP_TCP = 1, - RTSP_PROTOCOL_RTP_UDP_MULTICAST = 2, -}; - -#define RTSP_DEFAULT_PORT 554 -#define RTSP_MAX_TRANSPORTS 8 -#define RTSP_TCP_MAX_PACKET_SIZE 1472 -#define RTSP_DEFAULT_NB_AUDIO_CHANNELS 2 -#define RTSP_DEFAULT_AUDIO_SAMPLERATE 44100 -#define RTSP_RTP_PORT_MIN 5000 -#define RTSP_RTP_PORT_MAX 10000 - -typedef struct RTSPTransportField { - int interleaved_min, interleaved_max; /**< interleave ids, if TCP transport */ - int port_min, port_max; /**< RTP ports */ - int client_port_min, client_port_max; /**< RTP ports */ - int server_port_min, server_port_max; /**< RTP ports */ - int ttl; /**< ttl value */ - uint32_t destination; /**< destination IP address */ - enum RTSPProtocol protocol; -} RTSPTransportField; - -typedef struct RTSPHeader { - int content_length; - enum RTSPStatusCode status_code; /**< response code from server */ - int nb_transports; - /** in AV_TIME_BASE unit, AV_NOPTS_VALUE if not used */ - int64_t range_start, range_end; - RTSPTransportField transports[RTSP_MAX_TRANSPORTS]; - int seq; /**< sequence number */ - char session_id[512]; -} RTSPHeader; - -/** the callback can be used to extend the connection setup/teardown step */ -enum RTSPCallbackAction { - RTSP_ACTION_SERVER_SETUP, - RTSP_ACTION_SERVER_TEARDOWN, - RTSP_ACTION_CLIENT_SETUP, - RTSP_ACTION_CLIENT_TEARDOWN, -}; - -typedef struct RTSPActionServerSetup { - uint32_t ipaddr; - char transport_option[512]; -} RTSPActionServerSetup; - -typedef int FFRTSPCallback(enum RTSPCallbackAction action, - const char *session_id, - char *buf, int buf_size, - void *arg); - -/** useful for modules: set RTSP callback function */ -void rtsp_set_callback(FFRTSPCallback *rtsp_cb); - -int rtsp_init(void); -void rtsp_parse_line(RTSPHeader *reply, const char *buf); - -extern int rtsp_default_protocols; -extern int rtsp_rtp_port_min; -extern int rtsp_rtp_port_max; -extern FFRTSPCallback *ff_rtsp_callback; -extern AVInputFormat rtsp_demuxer; - -int rtsp_pause(AVFormatContext *s); -int rtsp_resume(AVFormatContext *s); - -#endif /* RTSP_H */ +/* + * RTSP definitions + * Copyright (c) 2002 Fabrice Bellard. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef RTSP_H +#define RTSP_H + +#include "rtspcodes.h" + +enum RTSPProtocol { + RTSP_PROTOCOL_RTP_UDP = 0, + RTSP_PROTOCOL_RTP_TCP = 1, + RTSP_PROTOCOL_RTP_UDP_MULTICAST = 2, +}; + +#define RTSP_DEFAULT_PORT 554 +#define RTSP_MAX_TRANSPORTS 8 +#define RTSP_TCP_MAX_PACKET_SIZE 1472 +#define RTSP_DEFAULT_NB_AUDIO_CHANNELS 2 +#define RTSP_DEFAULT_AUDIO_SAMPLERATE 44100 +#define RTSP_RTP_PORT_MIN 5000 +#define RTSP_RTP_PORT_MAX 10000 + +typedef struct RTSPTransportField { + int interleaved_min, interleaved_max; /**< interleave ids, if TCP transport */ + int port_min, port_max; /**< RTP ports */ + int client_port_min, client_port_max; /**< RTP ports */ + int server_port_min, server_port_max; /**< RTP ports */ + int ttl; /**< ttl value */ + uint32_t destination; /**< destination IP address */ + enum RTSPProtocol protocol; +} RTSPTransportField; + +typedef struct RTSPHeader { + int content_length; + enum RTSPStatusCode status_code; /**< response code from server */ + int nb_transports; + /** in AV_TIME_BASE unit, AV_NOPTS_VALUE if not used */ + int64_t range_start, range_end; + RTSPTransportField transports[RTSP_MAX_TRANSPORTS]; + int seq; /**< sequence number */ + char session_id[512]; +} RTSPHeader; + +/** the callback can be used to extend the connection setup/teardown step */ +enum RTSPCallbackAction { + RTSP_ACTION_SERVER_SETUP, + RTSP_ACTION_SERVER_TEARDOWN, + RTSP_ACTION_CLIENT_SETUP, + RTSP_ACTION_CLIENT_TEARDOWN, +}; + +typedef struct RTSPActionServerSetup { + uint32_t ipaddr; + char transport_option[512]; +} RTSPActionServerSetup; + +typedef int FFRTSPCallback(enum RTSPCallbackAction action, + const char *session_id, + char *buf, int buf_size, + void *arg); + +/** useful for modules: set RTSP callback function */ +void rtsp_set_callback(FFRTSPCallback *rtsp_cb); + +int rtsp_init(void); +void rtsp_parse_line(RTSPHeader *reply, const char *buf); + +extern int rtsp_default_protocols; +extern int rtsp_rtp_port_min; +extern int rtsp_rtp_port_max; +extern FFRTSPCallback *ff_rtsp_callback; +extern AVInputFormat rtsp_demuxer; + +int rtsp_pause(AVFormatContext *s); +int rtsp_resume(AVFormatContext *s); + +#endif /* RTSP_H */ diff --git a/src/ffmpeg/include/ffmpeg/rtspcodes.h b/src/ffmpeg/include/ffmpeg/rtspcodes.h index 74cfb5d5b9..ba3d086436 100644 --- a/src/ffmpeg/include/ffmpeg/rtspcodes.h +++ b/src/ffmpeg/include/ffmpeg/rtspcodes.h @@ -1,36 +1,36 @@ -/* - * RTSP definitions - * copyright (c) 2002 Fabrice Bellard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** RTSP handling */ -enum RTSPStatusCode { -RTSP_STATUS_OK =200, /**< OK */ -RTSP_STATUS_METHOD =405, /**< Method Not Allowed */ -RTSP_STATUS_BANDWIDTH =453, /**< Not Enough Bandwidth */ -RTSP_STATUS_SESSION =454, /**< Session Not Found */ -RTSP_STATUS_STATE =455, /**< Method Not Valid in This State */ -RTSP_STATUS_AGGREGATE =459, /**< Aggregate operation not allowed */ -RTSP_STATUS_ONLY_AGGREGATE =460, /**< Only aggregate operation allowed */ -RTSP_STATUS_TRANSPORT =461, /**< Unsupported transport */ -RTSP_STATUS_INTERNAL =500, /**< Internal Server Error */ -RTSP_STATUS_SERVICE =503, /**< Service Unavailable */ -RTSP_STATUS_VERSION =505, /**< RTSP Version not supported */ -}; - +/* + * RTSP definitions + * copyright (c) 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** RTSP handling */ +enum RTSPStatusCode { +RTSP_STATUS_OK =200, /**< OK */ +RTSP_STATUS_METHOD =405, /**< Method Not Allowed */ +RTSP_STATUS_BANDWIDTH =453, /**< Not Enough Bandwidth */ +RTSP_STATUS_SESSION =454, /**< Session Not Found */ +RTSP_STATUS_STATE =455, /**< Method Not Valid in This State */ +RTSP_STATUS_AGGREGATE =459, /**< Aggregate operation not allowed */ +RTSP_STATUS_ONLY_AGGREGATE =460, /**< Only aggregate operation allowed */ +RTSP_STATUS_TRANSPORT =461, /**< Unsupported transport */ +RTSP_STATUS_INTERNAL =500, /**< Internal Server Error */ +RTSP_STATUS_SERVICE =503, /**< Service Unavailable */ +RTSP_STATUS_VERSION =505, /**< RTSP Version not supported */ +}; + diff --git a/src/jsoncpp/README.txt b/src/jsoncpp/README.txt index ed7ef8ff91..429cc65dad 100644 --- a/src/jsoncpp/README.txt +++ b/src/jsoncpp/README.txt @@ -1,117 +1,117 @@ -* Introduction: - ============= - -JSON (JavaScript Object Notation) is a lightweight data-interchange format. -It can represent integer, real number, string, an ordered sequence of -value, and a collection of name/value pairs. - -JsonCpp is a simple API to manipulate JSON value, handle serialization -and unserialization to string. - -It can also preserve existing comment in unserialization/serialization steps, -making it a convenient format to store user input files. - -Unserialization parsing is user friendly and provides precise error reports. - - -* Building/Testing: - ================= - -JsonCpp uses Scons (http://www.scons.org) as a build system. Scons requires -python to be installed (http://www.python.org). - -You download scons-local distribution from the following url: -http://sourceforge.net/project/showfiles.php?group_id=30337&package_id=67375 - -Unzip it in the directory where you found this README file. scons.py Should be -at the same level as README. - -python scons.py platform=PLTFRM [TARGET] -where PLTFRM may be one of: - suncc Sun C++ (Solaris) - vacpp Visual Age C++ (AIX) - mingw - msvc6 Microsoft Visual Studio 6 service pack 5-6 - msvc70 Microsoft Visual Studio 2002 - msvc71 Microsoft Visual Studio 2003 - msvc80 Microsoft Visual Studio 2005 - linux-gcc Gnu C++ (linux, also reported to work for Mac OS X) - -adding platform is fairly simple. You need to change the Sconstruct file -to do so. - -and TARGET may be: - check: build library and run unit tests. - - -* Running the test manually: - ========================== - -cd test -# This will run the Reader/Writer tests -python runjsontests.py "path to jsontest.exe" - -# This will run the Reader/Writer tests, using JSONChecker test suite -# (http://www.json.org/JSON_checker/). -# Notes: not all tests pass: JsonCpp is too lenient (for example, -# it allows an integer to start with '0'). The goal is to improve -# strict mode parsing to get all tests to pass. -python runjsontests.py --with-json-checker "path to jsontest.exe" - -# This will run the unit tests (mostly Value) -python rununittests.py "path to test_lib_json.exe" - -You can run the tests using valgrind: -python rununittests.py --valgrind "path to test_lib_json.exe" - - -* Building the documentation: - =========================== - -Run the python script doxybuild.py from the top directory: - -python doxybuild.py --open --with-dot - -See doxybuild.py --help for options. - - -* Adding a reader/writer test: - ============================ - -To add a test, you need to create two files in test/data: -- a TESTNAME.json file, that contains the input document in JSON format. -- a TESTNAME.expected file, that contains a flatened representation of - the input document. - -TESTNAME.expected file format: -- each line represents a JSON element of the element tree represented - by the input document. -- each line has two parts: the path to access the element separated from - the element value by '='. Array and object values are always empty - (e.g. represented by either [] or {}). -- element path: '.' represented the root element, and is used to separate - object members. [N] is used to specify the value of an array element - at index N. -See test_complex_01.json and test_complex_01.expected to better understand -element path. - - -* Understanding reader/writer test output: - ======================================== - -When a test is run, output files are generated aside the input test files. -Below is a short description of the content of each file: - -- test_complex_01.json: input JSON document -- test_complex_01.expected: flattened JSON element tree used to check if - parsing was corrected. - -- test_complex_01.actual: flattened JSON element tree produced by - jsontest.exe from reading test_complex_01.json -- test_complex_01.rewrite: JSON document written by jsontest.exe using the - Json::Value parsed from test_complex_01.json and serialized using - Json::StyledWritter. -- test_complex_01.actual-rewrite: flattened JSON element tree produced by - jsontest.exe from reading test_complex_01.rewrite. -test_complex_01.process-output: jsontest.exe output, typically useful to - understand parsing error. +* Introduction: + ============= + +JSON (JavaScript Object Notation) is a lightweight data-interchange format. +It can represent integer, real number, string, an ordered sequence of +value, and a collection of name/value pairs. + +JsonCpp is a simple API to manipulate JSON value, handle serialization +and unserialization to string. + +It can also preserve existing comment in unserialization/serialization steps, +making it a convenient format to store user input files. + +Unserialization parsing is user friendly and provides precise error reports. + + +* Building/Testing: + ================= + +JsonCpp uses Scons (http://www.scons.org) as a build system. Scons requires +python to be installed (http://www.python.org). + +You download scons-local distribution from the following url: +http://sourceforge.net/project/showfiles.php?group_id=30337&package_id=67375 + +Unzip it in the directory where you found this README file. scons.py Should be +at the same level as README. + +python scons.py platform=PLTFRM [TARGET] +where PLTFRM may be one of: + suncc Sun C++ (Solaris) + vacpp Visual Age C++ (AIX) + mingw + msvc6 Microsoft Visual Studio 6 service pack 5-6 + msvc70 Microsoft Visual Studio 2002 + msvc71 Microsoft Visual Studio 2003 + msvc80 Microsoft Visual Studio 2005 + linux-gcc Gnu C++ (linux, also reported to work for Mac OS X) + +adding platform is fairly simple. You need to change the Sconstruct file +to do so. + +and TARGET may be: + check: build library and run unit tests. + + +* Running the test manually: + ========================== + +cd test +# This will run the Reader/Writer tests +python runjsontests.py "path to jsontest.exe" + +# This will run the Reader/Writer tests, using JSONChecker test suite +# (http://www.json.org/JSON_checker/). +# Notes: not all tests pass: JsonCpp is too lenient (for example, +# it allows an integer to start with '0'). The goal is to improve +# strict mode parsing to get all tests to pass. +python runjsontests.py --with-json-checker "path to jsontest.exe" + +# This will run the unit tests (mostly Value) +python rununittests.py "path to test_lib_json.exe" + +You can run the tests using valgrind: +python rununittests.py --valgrind "path to test_lib_json.exe" + + +* Building the documentation: + =========================== + +Run the python script doxybuild.py from the top directory: + +python doxybuild.py --open --with-dot + +See doxybuild.py --help for options. + + +* Adding a reader/writer test: + ============================ + +To add a test, you need to create two files in test/data: +- a TESTNAME.json file, that contains the input document in JSON format. +- a TESTNAME.expected file, that contains a flatened representation of + the input document. + +TESTNAME.expected file format: +- each line represents a JSON element of the element tree represented + by the input document. +- each line has two parts: the path to access the element separated from + the element value by '='. Array and object values are always empty + (e.g. represented by either [] or {}). +- element path: '.' represented the root element, and is used to separate + object members. [N] is used to specify the value of an array element + at index N. +See test_complex_01.json and test_complex_01.expected to better understand +element path. + + +* Understanding reader/writer test output: + ======================================== + +When a test is run, output files are generated aside the input test files. +Below is a short description of the content of each file: + +- test_complex_01.json: input JSON document +- test_complex_01.expected: flattened JSON element tree used to check if + parsing was corrected. + +- test_complex_01.actual: flattened JSON element tree produced by + jsontest.exe from reading test_complex_01.json +- test_complex_01.rewrite: JSON document written by jsontest.exe using the + Json::Value parsed from test_complex_01.json and serialized using + Json::StyledWritter. +- test_complex_01.actual-rewrite: flattened JSON element tree produced by + jsontest.exe from reading test_complex_01.rewrite. +test_complex_01.process-output: jsontest.exe output, typically useful to + understand parsing error. diff --git a/src/jsoncpp/doc/readme.txt b/src/jsoncpp/doc/readme.txt index 0e42cdfb4c..499422ec3b 100644 --- a/src/jsoncpp/doc/readme.txt +++ b/src/jsoncpp/doc/readme.txt @@ -1 +1 @@ -The documentation is generated using doxygen (http://www.doxygen.org). +The documentation is generated using doxygen (http://www.doxygen.org). diff --git a/src/jsoncpp/include/json/autolink.h b/src/jsoncpp/include/json/autolink.h index 37c9258ed5..ef5e0ab5ef 100644 --- a/src/jsoncpp/include/json/autolink.h +++ b/src/jsoncpp/include/json/autolink.h @@ -1,19 +1,19 @@ -#ifndef JSON_AUTOLINK_H_INCLUDED -# define JSON_AUTOLINK_H_INCLUDED - -# include "config.h" - -# ifdef JSON_IN_CPPTL -# include <cpptl/cpptl_autolink.h> -# endif - -# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) -# define CPPTL_AUTOLINK_NAME "json" -# undef CPPTL_AUTOLINK_DLL -# ifdef JSON_DLL -# define CPPTL_AUTOLINK_DLL -# endif -# include "autolink.h" -# endif - -#endif // JSON_AUTOLINK_H_INCLUDED +#ifndef JSON_AUTOLINK_H_INCLUDED +# define JSON_AUTOLINK_H_INCLUDED + +# include "config.h" + +# ifdef JSON_IN_CPPTL +# include <cpptl/cpptl_autolink.h> +# endif + +# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) +# define CPPTL_AUTOLINK_NAME "json" +# undef CPPTL_AUTOLINK_DLL +# ifdef JSON_DLL +# define CPPTL_AUTOLINK_DLL +# endif +# include "autolink.h" +# endif + +#endif // JSON_AUTOLINK_H_INCLUDED diff --git a/src/jsoncpp/include/json/config.h b/src/jsoncpp/include/json/config.h index 5d334cbc5e..20e81aa7bf 100644 --- a/src/jsoncpp/include/json/config.h +++ b/src/jsoncpp/include/json/config.h @@ -1,43 +1,43 @@ -#ifndef JSON_CONFIG_H_INCLUDED -# define JSON_CONFIG_H_INCLUDED - -/// If defined, indicates that json library is embedded in CppTL library. -//# define JSON_IN_CPPTL 1 - -/// If defined, indicates that json may leverage CppTL library -//# define JSON_USE_CPPTL 1 -/// If defined, indicates that cpptl vector based map should be used instead of std::map -/// as Value container. -//# define JSON_USE_CPPTL_SMALLMAP 1 -/// If defined, indicates that Json specific container should be used -/// (hash table & simple deque container with customizable allocator). -/// THIS FEATURE IS STILL EXPERIMENTAL! -//# define JSON_VALUE_USE_INTERNAL_MAP 1 -/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. -/// The memory pools allocator used optimization (initializing Value and ValueInternalLink -/// as if it was a POD) that may cause some validation tool to report errors. -/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. -//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 - -/// If defined, indicates that Json use exception to report invalid type manipulation -/// instead of C assert macro. -# define JSON_USE_EXCEPTION 1 - -# ifdef JSON_IN_CPPTL -# include <cpptl/config.h> -# ifndef JSON_USE_CPPTL -# define JSON_USE_CPPTL 1 -# endif -# endif - -# ifdef JSON_IN_CPPTL -# define JSON_API CPPTL_API -# elif defined(JSON_DLL_BUILD) -# define JSON_API __declspec(dllexport) -# elif defined(JSON_DLL) -# define JSON_API __declspec(dllimport) -# else -# define JSON_API -# endif - -#endif // JSON_CONFIG_H_INCLUDED +#ifndef JSON_CONFIG_H_INCLUDED +# define JSON_CONFIG_H_INCLUDED + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 +/// If defined, indicates that Json specific container should be used +/// (hash table & simple deque container with customizable allocator). +/// THIS FEATURE IS STILL EXPERIMENTAL! +//# define JSON_VALUE_USE_INTERNAL_MAP 1 +/// Force usage of standard new/malloc based allocator instead of memory pool based allocator. +/// The memory pools allocator used optimization (initializing Value and ValueInternalLink +/// as if it was a POD) that may cause some validation tool to report errors. +/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. +//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 + +/// If defined, indicates that Json use exception to report invalid type manipulation +/// instead of C assert macro. +# define JSON_USE_EXCEPTION 1 + +# ifdef JSON_IN_CPPTL +# include <cpptl/config.h> +# ifndef JSON_USE_CPPTL +# define JSON_USE_CPPTL 1 +# endif +# endif + +# ifdef JSON_IN_CPPTL +# define JSON_API CPPTL_API +# elif defined(JSON_DLL_BUILD) +# define JSON_API __declspec(dllexport) +# elif defined(JSON_DLL) +# define JSON_API __declspec(dllimport) +# else +# define JSON_API +# endif + +#endif // JSON_CONFIG_H_INCLUDED diff --git a/src/jsoncpp/include/json/features.h b/src/jsoncpp/include/json/features.h index 5a9adec118..f1404f6204 100644 --- a/src/jsoncpp/include/json/features.h +++ b/src/jsoncpp/include/json/features.h @@ -1,42 +1,42 @@ -#ifndef CPPTL_JSON_FEATURES_H_INCLUDED -# define CPPTL_JSON_FEATURES_H_INCLUDED - -# include "forwards.h" - -namespace Json { - - /** \brief Configuration passed to reader and writer. - * This configuration object can be used to force the Reader or Writer - * to behave in a standard conforming way. - */ - class JSON_API Features - { - public: - /** \brief A configuration that allows all features and assumes all strings are UTF-8. - * - C & C++ comments are allowed - * - Root object can be any JSON value - * - Assumes Value strings are encoded in UTF-8 - */ - static Features all(); - - /** \brief A configuration that is strictly compatible with the JSON specification. - * - Comments are forbidden. - * - Root object must be either an array or an object value. - * - Assumes Value strings are encoded in UTF-8 - */ - static Features strictMode(); - - /** \brief Initialize the configuration like JsonConfig::allFeatures; - */ - Features(); - - /// \c true if comments are allowed. Default: \c true. - bool allowComments_; - - /// \c true if root must be either an array or an object value. Default: \c false. - bool strictRoot_; - }; - -} // namespace Json - -#endif // CPPTL_JSON_FEATURES_H_INCLUDED +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED +# define CPPTL_JSON_FEATURES_H_INCLUDED + +# include "forwards.h" + +namespace Json { + + /** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ + class JSON_API Features + { + public: + /** \brief A configuration that allows all features and assumes all strings are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_; + + /// \c true if root must be either an array or an object value. Default: \c false. + bool strictRoot_; + }; + +} // namespace Json + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED diff --git a/src/jsoncpp/include/json/forwards.h b/src/jsoncpp/include/json/forwards.h index d0ce8300ce..68e4d78136 100644 --- a/src/jsoncpp/include/json/forwards.h +++ b/src/jsoncpp/include/json/forwards.h @@ -1,39 +1,39 @@ -#ifndef JSON_FORWARDS_H_INCLUDED -# define JSON_FORWARDS_H_INCLUDED - -# include "config.h" - -namespace Json { - - // writer.h - class FastWriter; - class StyledWriter; - - // reader.h - class Reader; - - // features.h - class Features; - - // value.h - typedef int Int; - typedef unsigned int UInt; - class StaticString; - class Path; - class PathArgument; - class Value; - class ValueIteratorBase; - class ValueIterator; - class ValueConstIterator; -#ifdef JSON_VALUE_USE_INTERNAL_MAP - class ValueAllocator; - class ValueMapAllocator; - class ValueInternalLink; - class ValueInternalArray; - class ValueInternalMap; -#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP - -} // namespace Json - - -#endif // JSON_FORWARDS_H_INCLUDED +#ifndef JSON_FORWARDS_H_INCLUDED +# define JSON_FORWARDS_H_INCLUDED + +# include "config.h" + +namespace Json { + + // writer.h + class FastWriter; + class StyledWriter; + + // reader.h + class Reader; + + // features.h + class Features; + + // value.h + typedef int Int; + typedef unsigned int UInt; + class StaticString; + class Path; + class PathArgument; + class Value; + class ValueIteratorBase; + class ValueIterator; + class ValueConstIterator; +#ifdef JSON_VALUE_USE_INTERNAL_MAP + class ValueAllocator; + class ValueMapAllocator; + class ValueInternalLink; + class ValueInternalArray; + class ValueInternalMap; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + +} // namespace Json + + +#endif // JSON_FORWARDS_H_INCLUDED diff --git a/src/jsoncpp/include/json/json.h b/src/jsoncpp/include/json/json.h index c71ed65abf..b7d645803a 100644 --- a/src/jsoncpp/include/json/json.h +++ b/src/jsoncpp/include/json/json.h @@ -1,10 +1,10 @@ -#ifndef JSON_JSON_H_INCLUDED -# define JSON_JSON_H_INCLUDED - -# include "autolink.h" -# include "value.h" -# include "reader.h" -# include "writer.h" -# include "features.h" - -#endif // JSON_JSON_H_INCLUDED +#ifndef JSON_JSON_H_INCLUDED +# define JSON_JSON_H_INCLUDED + +# include "autolink.h" +# include "value.h" +# include "reader.h" +# include "writer.h" +# include "features.h" + +#endif // JSON_JSON_H_INCLUDED diff --git a/src/jsoncpp/include/json/reader.h b/src/jsoncpp/include/json/reader.h index ee1d6a2444..5daee8f9d3 100644 --- a/src/jsoncpp/include/json/reader.h +++ b/src/jsoncpp/include/json/reader.h @@ -1,196 +1,196 @@ -#ifndef CPPTL_JSON_READER_H_INCLUDED -# define CPPTL_JSON_READER_H_INCLUDED - -# include "features.h" -# include "value.h" -# include <deque> -# include <stack> -# include <string> -# include <iostream> - -namespace Json { - - /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value. - * - */ - class JSON_API Reader - { - public: - typedef char Char; - typedef const Char *Location; - - /** \brief Constructs a Reader allowing all features - * for parsing. - */ - Reader(); - - /** \brief Constructs a Reader allowing the specified feature set - * for parsing. - */ - Reader( const Features &features ); - - /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document. - * \param document UTF-8 encoded string containing the document to read. - * \param root [out] Contains the root value of the document if it was - * successfully parsed. - * \param collectComments \c true to collect comment and allow writing them back during - * serialization, \c false to discard comments. - * This parameter is ignored if Features::allowComments_ - * is \c false. - * \return \c true if the document was successfully parsed, \c false if an error occurred. - */ - bool parse( const std::string &document, - Value &root, - bool collectComments = true ); - - /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document. - * \param document UTF-8 encoded string containing the document to read. - * \param root [out] Contains the root value of the document if it was - * successfully parsed. - * \param collectComments \c true to collect comment and allow writing them back during - * serialization, \c false to discard comments. - * This parameter is ignored if Features::allowComments_ - * is \c false. - * \return \c true if the document was successfully parsed, \c false if an error occurred. - */ - bool parse( const char *beginDoc, const char *endDoc, - Value &root, - bool collectComments = true ); - - /// \brief Parse from input stream. - /// \see Json::operator>>(std::istream&, Json::Value&). - bool parse( std::istream &is, - Value &root, - bool collectComments = true ); - - /** \brief Returns a user friendly string that list errors in the parsed document. - * \return Formatted error message with the list of errors with their location in - * the parsed document. An empty string is returned if no error occurred - * during parsing. - */ - std::string getFormatedErrorMessages() const; - - private: - enum TokenType - { - tokenEndOfStream = 0, - tokenObjectBegin, - tokenObjectEnd, - tokenArrayBegin, - tokenArrayEnd, - tokenString, - tokenNumber, - tokenTrue, - tokenFalse, - tokenNull, - tokenArraySeparator, - tokenMemberSeparator, - tokenComment, - tokenError - }; - - class Token - { - public: - TokenType type_; - Location start_; - Location end_; - }; - - class ErrorInfo - { - public: - Token token_; - std::string message_; - Location extra_; - }; - - typedef std::deque<ErrorInfo> Errors; - - bool expectToken( TokenType type, Token &token, const char *message ); - bool readToken( Token &token ); - void skipSpaces(); - bool match( Location pattern, - int patternLength ); - bool readComment(); - bool readCStyleComment(); - bool readCppStyleComment(); - bool readString(); - void readNumber(); - bool readValue(); - bool readObject( Token &token ); - bool readArray( Token &token ); - bool decodeNumber( Token &token ); - bool decodeString( Token &token ); - bool decodeString( Token &token, std::string &decoded ); - bool decodeDouble( Token &token ); - bool decodeUnicodeCodePoint( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ); - bool decodeUnicodeEscapeSequence( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ); - bool addError( const std::string &message, - Token &token, - Location extra = 0 ); - bool recoverFromError( TokenType skipUntilToken ); - bool addErrorAndRecover( const std::string &message, - Token &token, - TokenType skipUntilToken ); - void skipUntilSpace(); - Value ¤tValue(); - Char getNextChar(); - void getLocationLineAndColumn( Location location, - int &line, - int &column ) const; - std::string getLocationLineAndColumn( Location location ) const; - void addComment( Location begin, - Location end, - CommentPlacement placement ); - void skipCommentTokens( Token &token ); - - typedef std::stack<Value *> Nodes; - Nodes nodes_; - Errors errors_; - std::string document_; - Location begin_; - Location end_; - Location current_; - Location lastValueEnd_; - Value *lastValue_; - std::string commentsBefore_; - Features features_; - bool collectComments_; - }; - - /** \brief Read from 'sin' into 'root'. - - Always keep comments from the input JSON. - - This can be used to read a file into a particular sub-object. - For example: - \code - Json::Value root; - cin >> root["dir"]["file"]; - cout << root; - \endcode - Result: - \verbatim - { - "dir": { - "file": { - // The input stream JSON would be nested here. - } - } - } - \endverbatim - \throw std::exception on parse error. - \see Json::operator<<() - */ - std::istream& operator>>( std::istream&, Value& ); - -} // namespace Json - -#endif // CPPTL_JSON_READER_H_INCLUDED +#ifndef CPPTL_JSON_READER_H_INCLUDED +# define CPPTL_JSON_READER_H_INCLUDED + +# include "features.h" +# include "value.h" +# include <deque> +# include <stack> +# include <string> +# include <iostream> + +namespace Json { + + /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value. + * + */ + class JSON_API Reader + { + public: + typedef char Char; + typedef const Char *Location; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + Reader( const Features &features ); + + /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse( const std::string &document, + Value &root, + bool collectComments = true ); + + /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them back during + * serialization, \c false to discard comments. + * This parameter is ignored if Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an error occurred. + */ + bool parse( const char *beginDoc, const char *endDoc, + Value &root, + bool collectComments = true ); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse( std::istream &is, + Value &root, + bool collectComments = true ); + + /** \brief Returns a user friendly string that list errors in the parsed document. + * \return Formatted error message with the list of errors with their location in + * the parsed document. An empty string is returned if no error occurred + * during parsing. + */ + std::string getFormatedErrorMessages() const; + + private: + enum TokenType + { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token + { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo + { + public: + Token token_; + std::string message_; + Location extra_; + }; + + typedef std::deque<ErrorInfo> Errors; + + bool expectToken( TokenType type, Token &token, const char *message ); + bool readToken( Token &token ); + void skipSpaces(); + bool match( Location pattern, + int patternLength ); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject( Token &token ); + bool readArray( Token &token ); + bool decodeNumber( Token &token ); + bool decodeString( Token &token ); + bool decodeString( Token &token, std::string &decoded ); + bool decodeDouble( Token &token ); + bool decodeUnicodeCodePoint( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ); + bool decodeUnicodeEscapeSequence( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ); + bool addError( const std::string &message, + Token &token, + Location extra = 0 ); + bool recoverFromError( TokenType skipUntilToken ); + bool addErrorAndRecover( const std::string &message, + Token &token, + TokenType skipUntilToken ); + void skipUntilSpace(); + Value ¤tValue(); + Char getNextChar(); + void getLocationLineAndColumn( Location location, + int &line, + int &column ) const; + std::string getLocationLineAndColumn( Location location ) const; + void addComment( Location begin, + Location end, + CommentPlacement placement ); + void skipCommentTokens( Token &token ); + + typedef std::stack<Value *> Nodes; + Nodes nodes_; + Errors errors_; + std::string document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value *lastValue_; + std::string commentsBefore_; + Features features_; + bool collectComments_; + }; + + /** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() + */ + std::istream& operator>>( std::istream&, Value& ); + +} // namespace Json + +#endif // CPPTL_JSON_READER_H_INCLUDED diff --git a/src/jsoncpp/include/json/value.h b/src/jsoncpp/include/json/value.h index 58bfd88e7a..0f4bc0ff48 100644 --- a/src/jsoncpp/include/json/value.h +++ b/src/jsoncpp/include/json/value.h @@ -1,1069 +1,1069 @@ -#ifndef CPPTL_JSON_H_INCLUDED -# define CPPTL_JSON_H_INCLUDED - -# include "forwards.h" -# include <string> -# include <vector> - -# ifndef JSON_USE_CPPTL_SMALLMAP -# include <map> -# else -# include <cpptl/smallmap.h> -# endif -# ifdef JSON_USE_CPPTL -# include <cpptl/forwards.h> -# endif - -/** \brief JSON (JavaScript Object Notation). - */ -namespace Json { - - /** \brief Type of the value held by a Value object. - */ - enum ValueType - { - nullValue = 0, ///< 'null' value - intValue, ///< signed integer value - uintValue, ///< unsigned integer value - realValue, ///< double value - stringValue, ///< UTF-8 string value - booleanValue, ///< bool value - arrayValue, ///< array value (ordered list) - objectValue ///< object value (collection of name/value pairs). - }; - - enum CommentPlacement - { - commentBefore = 0, ///< a comment placed on the line before a value - commentAfterOnSameLine, ///< a comment just after a value on the same line - commentAfter, ///< a comment on the line after a value (only make sense for root value) - numberOfCommentPlacement - }; - -//# ifdef JSON_USE_CPPTL -// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames; -// typedef CppTL::AnyEnumerator<const Value &> EnumValues; -//# endif - - /** \brief Lightweight wrapper to tag static string. - * - * Value constructor and objectValue member assignement takes advantage of the - * StaticString and avoid the cost of string duplication when storing the - * string or the member name. - * - * Example of usage: - * \code - * Json::Value aValue( StaticString("some text") ); - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ - class JSON_API StaticString - { - public: - explicit StaticString( const char *czstring ) - : str_( czstring ) - { - } - - operator const char *() const - { - return str_; - } - - const char *c_str() const - { - return str_; - } - - private: - const char *str_; - }; - - /** \brief Represents a <a HREF="http://www.json.org">JSON</a> value. - * - * This class is a discriminated union wrapper that can represents a: - * - signed integer [range: Value::minInt - Value::maxInt] - * - unsigned integer (range: 0 - Value::maxUInt) - * - double - * - UTF-8 string - * - boolean - * - 'null' - * - an ordered list of Value - * - collection of name/value pairs (javascript object) - * - * The type of the held value is represented by a #ValueType and - * can be obtained using type(). - * - * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. - * Non const methods will automatically create the a #nullValue element - * if it does not exist. - * The sequence of an #arrayValue will be automatically resize and initialized - * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. - * - * The get() methods can be used to obtanis default value in the case the required element - * does not exist. - * - * It is possible to iterate over the list of a #objectValue values using - * the getMemberNames() method. - */ - class JSON_API Value - { - friend class ValueIteratorBase; -# ifdef JSON_VALUE_USE_INTERNAL_MAP - friend class ValueInternalLink; - friend class ValueInternalMap; -# endif - public: - typedef std::vector<std::string> Members; - typedef ValueIterator iterator; - typedef ValueConstIterator const_iterator; - typedef Json::UInt UInt; - typedef Json::Int Int; - typedef UInt ArrayIndex; - - static const Value null; - static const Int minInt; - static const Int maxInt; - static const UInt maxUInt; - - private: -#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION -# ifndef JSON_VALUE_USE_INTERNAL_MAP - class CZString - { - public: - enum DuplicationPolicy - { - noDuplication = 0, - duplicate, - duplicateOnCopy - }; - CZString( int index ); - CZString( const char *cstr, DuplicationPolicy allocate ); - CZString( const CZString &other ); - ~CZString(); - CZString &operator =( const CZString &other ); - bool operator<( const CZString &other ) const; - bool operator==( const CZString &other ) const; - int index() const; - const char *c_str() const; - bool isStaticString() const; - private: - void swap( CZString &other ); - const char *cstr_; - int index_; - }; - - public: -# ifndef JSON_USE_CPPTL_SMALLMAP - typedef std::map<CZString, Value> ObjectValues; -# else - typedef CppTL::SmallMap<CZString, Value> ObjectValues; -# endif // ifndef JSON_USE_CPPTL_SMALLMAP -# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP -#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - - public: - /** \brief Create a default Value of the given type. - - This is a very useful constructor. - To create an empty array, pass arrayValue. - To create an empty object, pass objectValue. - Another Value can then be set to this one by assignment. - This is useful since clear() and resize() will not alter types. - - Examples: - \code - Json::Value null_value; // null - Json::Value arr_value(Json::arrayValue); // [] - Json::Value obj_value(Json::objectValue); // {} - \endcode - */ - Value( ValueType type = nullValue ); - Value( Int value ); - Value( UInt value ); - Value( double value ); - Value( const char *value ); - Value( const char *beginValue, const char *endValue ); - /** \brief Constructs a value from a static string. - - * Like other value string constructor but do not duplicate the string for - * internal storage. The given string must remain alive after the call to this - * constructor. - * Example of usage: - * \code - * Json::Value aValue( StaticString("some text") ); - * \endcode - */ - Value( const StaticString &value ); - Value( const std::string &value ); -# ifdef JSON_USE_CPPTL - Value( const CppTL::ConstString &value ); -# endif - Value( bool value ); - Value( const Value &other ); - ~Value(); - - Value &operator=( const Value &other ); - /// Swap values. - /// \note Currently, comments are intentionally not swapped, for - /// both logic and efficiency. - void swap( Value &other ); - - ValueType type() const; - - bool operator <( const Value &other ) const; - bool operator <=( const Value &other ) const; - bool operator >=( const Value &other ) const; - bool operator >( const Value &other ) const; - - bool operator ==( const Value &other ) const; - bool operator !=( const Value &other ) const; - - int compare( const Value &other ); - - const char *asCString() const; - std::string asString() const; -# ifdef JSON_USE_CPPTL - CppTL::ConstString asConstString() const; -# endif - Int asInt() const; - UInt asUInt() const; - double asDouble() const; - bool asBool() const; - - bool isNull() const; - bool isBool() const; - bool isInt() const; - bool isUInt() const; - bool isIntegral() const; - bool isDouble() const; - bool isNumeric() const; - bool isString() const; - bool isArray() const; - bool isObject() const; - - bool isConvertibleTo( ValueType other ) const; - - /// Number of values in array or object - UInt size() const; - - /// \brief Return true if empty array, empty object, or null; - /// otherwise, false. - bool empty() const; - - /// Return isNull() - bool operator!() const; - - /// Remove all object members and array elements. - /// \pre type() is arrayValue, objectValue, or nullValue - /// \post type() is unchanged - void clear(); - - /// Resize the array to size elements. - /// New elements are initialized to null. - /// May only be called on nullValue or arrayValue. - /// \pre type() is arrayValue or nullValue - /// \post type() is arrayValue - void resize( UInt size ); - - /// Access an array element (zero based index ). - /// If the array contains less than index element, then null value are inserted - /// in the array so that its size is index+1. - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - Value &operator[]( UInt index ); - /// Access an array element (zero based index ) - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - const Value &operator[]( UInt index ) const; - /// If the array contains at least index+1 elements, returns the element value, - /// otherwise returns defaultValue. - Value get( UInt index, - const Value &defaultValue ) const; - /// Return true if index < size(). - bool isValidIndex( UInt index ) const; - /// \brief Append value to array at the end. - /// - /// Equivalent to jsonvalue[jsonvalue.size()] = value; - Value &append( const Value &value ); - - /// Access an object value by name, create a null member if it does not exist. - Value &operator[]( const char *key ); - /// Access an object value by name, returns null if there is no member with that name. - const Value &operator[]( const char *key ) const; - /// Access an object value by name, create a null member if it does not exist. - Value &operator[]( const std::string &key ); - /// Access an object value by name, returns null if there is no member with that name. - const Value &operator[]( const std::string &key ) const; - /** \brief Access an object value by name, create a null member if it does not exist. - - * If the object as no entry for that name, then the member name used to store - * the new entry is not duplicated. - * Example of use: - * \code - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ - Value &operator[]( const StaticString &key ); -# ifdef JSON_USE_CPPTL - /// Access an object value by name, create a null member if it does not exist. - Value &operator[]( const CppTL::ConstString &key ); - /// Access an object value by name, returns null if there is no member with that name. - const Value &operator[]( const CppTL::ConstString &key ) const; -# endif - /// Return the member named key if it exist, defaultValue otherwise. - Value get( const char *key, - const Value &defaultValue ) const; - /// Return the member named key if it exist, defaultValue otherwise. - Value get( const std::string &key, - const Value &defaultValue ) const; -# ifdef JSON_USE_CPPTL - /// Return the member named key if it exist, defaultValue otherwise. - Value get( const CppTL::ConstString &key, - const Value &defaultValue ) const; -# endif - /// \brief Remove and return the named member. - /// - /// Do nothing if it did not exist. - /// \return the removed Value, or null. - /// \pre type() is objectValue or nullValue - /// \post type() is unchanged - Value removeMember( const char* key ); - /// Same as removeMember(const char*) - Value removeMember( const std::string &key ); - - /// Return true if the object has a member named key. - bool isMember( const char *key ) const; - /// Return true if the object has a member named key. - bool isMember( const std::string &key ) const; -# ifdef JSON_USE_CPPTL - /// Return true if the object has a member named key. - bool isMember( const CppTL::ConstString &key ) const; -# endif - - /// \brief Return a list of the member names. - /// - /// If null, return an empty list. - /// \pre type() is objectValue or nullValue - /// \post if type() was nullValue, it remains nullValue - Members getMemberNames() const; - -//# ifdef JSON_USE_CPPTL -// EnumMemberNames enumMemberNames() const; -// EnumValues enumValues() const; -//# endif - - /// Comments must be //... or /* ... */ - void setComment( const char *comment, - CommentPlacement placement ); - /// Comments must be //... or /* ... */ - void setComment( const std::string &comment, - CommentPlacement placement ); - bool hasComment( CommentPlacement placement ) const; - /// Include delimiters and embedded newlines. - std::string getComment( CommentPlacement placement ) const; - - std::string toStyledString() const; - - const_iterator begin() const; - const_iterator end() const; - - iterator begin(); - iterator end(); - - private: - Value &resolveReference( const char *key, - bool isStatic ); - -# ifdef JSON_VALUE_USE_INTERNAL_MAP - inline bool isItemAvailable() const - { - return itemIsUsed_ == 0; - } - - inline void setItemUsed( bool isUsed = true ) - { - itemIsUsed_ = isUsed ? 1 : 0; - } - - inline bool isMemberNameStatic() const - { - return memberNameIsStatic_ == 0; - } - - inline void setMemberNameIsStatic( bool isStatic ) - { - memberNameIsStatic_ = isStatic ? 1 : 0; - } -# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP - - private: - struct CommentInfo - { - CommentInfo(); - ~CommentInfo(); - - void setComment( const char *text ); - - char *comment_; - }; - - //struct MemberNamesTransform - //{ - // typedef const char *result_type; - // const char *operator()( const CZString &name ) const - // { - // return name.c_str(); - // } - //}; - - union ValueHolder - { - Int int_; - UInt uint_; - double real_; - bool bool_; - char *string_; -# ifdef JSON_VALUE_USE_INTERNAL_MAP - ValueInternalArray *array_; - ValueInternalMap *map_; -#else - ObjectValues *map_; -# endif - } value_; - ValueType type_ : 8; - int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. -# ifdef JSON_VALUE_USE_INTERNAL_MAP - unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. - int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. -# endif - CommentInfo *comments_; - }; - - - /** \brief Experimental and untested: represents an element of the "path" to access a node. - */ - class PathArgument - { - public: - friend class Path; - - PathArgument(); - PathArgument( UInt index ); - PathArgument( const char *key ); - PathArgument( const std::string &key ); - - private: - enum Kind - { - kindNone = 0, - kindIndex, - kindKey - }; - std::string key_; - UInt index_; - Kind kind_; - }; - - /** \brief Experimental and untested: represents a "path" to access a node. - * - * Syntax: - * - "." => root node - * - ".[n]" => elements at index 'n' of root node (an array value) - * - ".name" => member named 'name' of root node (an object value) - * - ".name1.name2.name3" - * - ".[0][1][2].name1[3]" - * - ".%" => member name is provided as parameter - * - ".[%]" => index is provied as parameter - */ - class Path - { - public: - Path( const std::string &path, - const PathArgument &a1 = PathArgument(), - const PathArgument &a2 = PathArgument(), - const PathArgument &a3 = PathArgument(), - const PathArgument &a4 = PathArgument(), - const PathArgument &a5 = PathArgument() ); - - const Value &resolve( const Value &root ) const; - Value resolve( const Value &root, - const Value &defaultValue ) const; - /// Creates the "path" to access the specified node and returns a reference on the node. - Value &make( Value &root ) const; - - private: - typedef std::vector<const PathArgument *> InArgs; - typedef std::vector<PathArgument> Args; - - void makePath( const std::string &path, - const InArgs &in ); - void addPathInArg( const std::string &path, - const InArgs &in, - InArgs::const_iterator &itInArg, - PathArgument::Kind kind ); - void invalidPath( const std::string &path, - int location ); - - Args args_; - }; - - /** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value. - * - * - makeMemberName() and releaseMemberName() are called to respectively duplicate and - * free an Json::objectValue member name. - * - duplicateStringValue() and releaseStringValue() are called similarly to - * duplicate and free a Json::stringValue value. - */ - class ValueAllocator - { - public: - enum { unknown = (unsigned)-1 }; - - virtual ~ValueAllocator(); - - virtual char *makeMemberName( const char *memberName ) = 0; - virtual void releaseMemberName( char *memberName ) = 0; - virtual char *duplicateStringValue( const char *value, - unsigned int length = unknown ) = 0; - virtual void releaseStringValue( char *value ) = 0; - }; - -#ifdef JSON_VALUE_USE_INTERNAL_MAP - /** \brief Allocator to customize Value internal map. - * Below is an example of a simple implementation (default implementation actually - * use memory pool for speed). - * \code - class DefaultValueMapAllocator : public ValueMapAllocator - { - public: // overridden from ValueMapAllocator - virtual ValueInternalMap *newMap() - { - return new ValueInternalMap(); - } - - virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) - { - return new ValueInternalMap( other ); - } - - virtual void destructMap( ValueInternalMap *map ) - { - delete map; - } - - virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) - { - return new ValueInternalLink[size]; - } - - virtual void releaseMapBuckets( ValueInternalLink *links ) - { - delete [] links; - } - - virtual ValueInternalLink *allocateMapLink() - { - return new ValueInternalLink(); - } - - virtual void releaseMapLink( ValueInternalLink *link ) - { - delete link; - } - }; - * \endcode - */ - class JSON_API ValueMapAllocator - { - public: - virtual ~ValueMapAllocator(); - virtual ValueInternalMap *newMap() = 0; - virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; - virtual void destructMap( ValueInternalMap *map ) = 0; - virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; - virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; - virtual ValueInternalLink *allocateMapLink() = 0; - virtual void releaseMapLink( ValueInternalLink *link ) = 0; - }; - - /** \brief ValueInternalMap hash-map bucket chain link (for internal use only). - * \internal previous_ & next_ allows for bidirectional traversal. - */ - class JSON_API ValueInternalLink - { - public: - enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. - enum InternalFlags { - flagAvailable = 0, - flagUsed = 1 - }; - - ValueInternalLink(); - - ~ValueInternalLink(); - - Value items_[itemPerLink]; - char *keys_[itemPerLink]; - ValueInternalLink *previous_; - ValueInternalLink *next_; - }; - - - /** \brief A linked page based hash-table implementation used internally by Value. - * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked - * list in each bucket to handle collision. There is an addional twist in that - * each node of the collision linked list is a page containing a fixed amount of - * value. This provides a better compromise between memory usage and speed. - * - * Each bucket is made up of a chained list of ValueInternalLink. The last - * link of a given bucket can be found in the 'previous_' field of the following bucket. - * The last link of the last bucket is stored in tailLink_ as it has no following bucket. - * Only the last link of a bucket may contains 'available' item. The last link always - * contains at least one element unless is it the bucket one very first link. - */ - class JSON_API ValueInternalMap - { - friend class ValueIteratorBase; - friend class Value; - public: - typedef unsigned int HashKey; - typedef unsigned int BucketIndex; - -# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - struct IteratorState - { - IteratorState() - : map_(0) - , link_(0) - , itemIndex_(0) - , bucketIndex_(0) - { - } - ValueInternalMap *map_; - ValueInternalLink *link_; - BucketIndex itemIndex_; - BucketIndex bucketIndex_; - }; -# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - - ValueInternalMap(); - ValueInternalMap( const ValueInternalMap &other ); - ValueInternalMap &operator =( const ValueInternalMap &other ); - ~ValueInternalMap(); - - void swap( ValueInternalMap &other ); - - BucketIndex size() const; - - void clear(); - - bool reserveDelta( BucketIndex growth ); - - bool reserve( BucketIndex newItemCount ); - - const Value *find( const char *key ) const; - - Value *find( const char *key ); - - Value &resolveReference( const char *key, - bool isStatic ); - - void remove( const char *key ); - - void doActualRemove( ValueInternalLink *link, - BucketIndex index, - BucketIndex bucketIndex ); - - ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); - - Value &setNewItem( const char *key, - bool isStatic, - ValueInternalLink *link, - BucketIndex index ); - - Value &unsafeAdd( const char *key, - bool isStatic, - HashKey hashedKey ); - - HashKey hash( const char *key ) const; - - int compare( const ValueInternalMap &other ) const; - - private: - void makeBeginIterator( IteratorState &it ) const; - void makeEndIterator( IteratorState &it ) const; - static bool equals( const IteratorState &x, const IteratorState &other ); - static void increment( IteratorState &iterator ); - static void incrementBucket( IteratorState &iterator ); - static void decrement( IteratorState &iterator ); - static const char *key( const IteratorState &iterator ); - static const char *key( const IteratorState &iterator, bool &isStatic ); - static Value &value( const IteratorState &iterator ); - static int distance( const IteratorState &x, const IteratorState &y ); - - private: - ValueInternalLink *buckets_; - ValueInternalLink *tailLink_; - BucketIndex bucketsSize_; - BucketIndex itemCount_; - }; - - /** \brief A simplified deque implementation used internally by Value. - * \internal - * It is based on a list of fixed "page", each page contains a fixed number of items. - * Instead of using a linked-list, a array of pointer is used for fast item look-up. - * Look-up for an element is as follow: - * - compute page index: pageIndex = itemIndex / itemsPerPage - * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] - * - * Insertion is amortized constant time (only the array containing the index of pointers - * need to be reallocated when items are appended). - */ - class JSON_API ValueInternalArray - { - friend class Value; - friend class ValueIteratorBase; - public: - enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. - typedef Value::ArrayIndex ArrayIndex; - typedef unsigned int PageIndex; - -# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - struct IteratorState // Must be a POD - { - IteratorState() - : array_(0) - , currentPageIndex_(0) - , currentItemIndex_(0) - { - } - ValueInternalArray *array_; - Value **currentPageIndex_; - unsigned int currentItemIndex_; - }; -# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - - ValueInternalArray(); - ValueInternalArray( const ValueInternalArray &other ); - ValueInternalArray &operator =( const ValueInternalArray &other ); - ~ValueInternalArray(); - void swap( ValueInternalArray &other ); - - void clear(); - void resize( ArrayIndex newSize ); - - Value &resolveReference( ArrayIndex index ); - - Value *find( ArrayIndex index ) const; - - ArrayIndex size() const; - - int compare( const ValueInternalArray &other ) const; - - private: - static bool equals( const IteratorState &x, const IteratorState &other ); - static void increment( IteratorState &iterator ); - static void decrement( IteratorState &iterator ); - static Value &dereference( const IteratorState &iterator ); - static Value &unsafeDereference( const IteratorState &iterator ); - static int distance( const IteratorState &x, const IteratorState &y ); - static ArrayIndex indexOf( const IteratorState &iterator ); - void makeBeginIterator( IteratorState &it ) const; - void makeEndIterator( IteratorState &it ) const; - void makeIterator( IteratorState &it, ArrayIndex index ) const; - - void makeIndexValid( ArrayIndex index ); - - Value **pages_; - ArrayIndex size_; - PageIndex pageCount_; - }; - - /** \brief Experimental: do not use. Allocator to customize Value internal array. - * Below is an example of a simple implementation (actual implementation use - * memory pool). - \code -class DefaultValueArrayAllocator : public ValueArrayAllocator -{ -public: // overridden from ValueArrayAllocator - virtual ~DefaultValueArrayAllocator() - { - } - - virtual ValueInternalArray *newArray() - { - return new ValueInternalArray(); - } - - virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) - { - return new ValueInternalArray( other ); - } - - virtual void destruct( ValueInternalArray *array ) - { - delete array; - } - - virtual void reallocateArrayPageIndex( Value **&indexes, - ValueInternalArray::PageIndex &indexCount, - ValueInternalArray::PageIndex minNewIndexCount ) - { - ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; - if ( minNewIndexCount > newIndexCount ) - newIndexCount = minNewIndexCount; - void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); - if ( !newIndexes ) - throw std::bad_alloc(); - indexCount = newIndexCount; - indexes = static_cast<Value **>( newIndexes ); - } - virtual void releaseArrayPageIndex( Value **indexes, - ValueInternalArray::PageIndex indexCount ) - { - if ( indexes ) - free( indexes ); - } - - virtual Value *allocateArrayPage() - { - return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); - } - - virtual void releaseArrayPage( Value *value ) - { - if ( value ) - free( value ); - } -}; - \endcode - */ - class JSON_API ValueArrayAllocator - { - public: - virtual ~ValueArrayAllocator(); - virtual ValueInternalArray *newArray() = 0; - virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; - virtual void destructArray( ValueInternalArray *array ) = 0; - /** \brief Reallocate array page index. - * Reallocates an array of pointer on each page. - * \param indexes [input] pointer on the current index. May be \c NULL. - * [output] pointer on the new index of at least - * \a minNewIndexCount pages. - * \param indexCount [input] current number of pages in the index. - * [output] number of page the reallocated index can handle. - * \b MUST be >= \a minNewIndexCount. - * \param minNewIndexCount Minimum number of page the new index must be able to - * handle. - */ - virtual void reallocateArrayPageIndex( Value **&indexes, - ValueInternalArray::PageIndex &indexCount, - ValueInternalArray::PageIndex minNewIndexCount ) = 0; - virtual void releaseArrayPageIndex( Value **indexes, - ValueInternalArray::PageIndex indexCount ) = 0; - virtual Value *allocateArrayPage() = 0; - virtual void releaseArrayPage( Value *value ) = 0; - }; -#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP - - - /** \brief base class for Value iterators. - * - */ - class ValueIteratorBase - { - public: - typedef unsigned int size_t; - typedef int difference_type; - typedef ValueIteratorBase SelfType; - - ValueIteratorBase(); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); -#else - ValueIteratorBase( const ValueInternalArray::IteratorState &state ); - ValueIteratorBase( const ValueInternalMap::IteratorState &state ); -#endif - - bool operator ==( const SelfType &other ) const - { - return isEqual( other ); - } - - bool operator !=( const SelfType &other ) const - { - return !isEqual( other ); - } - - difference_type operator -( const SelfType &other ) const - { - return computeDistance( other ); - } - - /// Return either the index or the member name of the referenced value as a Value. - Value key() const; - - /// Return the index of the referenced Value. -1 if it is not an arrayValue. - UInt index() const; - - /// Return the member name of the referenced Value. "" if it is not an objectValue. - const char *memberName() const; - - protected: - Value &deref() const; - - void increment(); - - void decrement(); - - difference_type computeDistance( const SelfType &other ) const; - - bool isEqual( const SelfType &other ) const; - - void copy( const SelfType &other ); - - private: -#ifndef JSON_VALUE_USE_INTERNAL_MAP - Value::ObjectValues::iterator current_; - // Indicates that iterator is for a null value. - bool isNull_; -#else - union - { - ValueInternalArray::IteratorState array_; - ValueInternalMap::IteratorState map_; - } iterator_; - bool isArray_; -#endif - }; - - /** \brief const iterator for object and array value. - * - */ - class ValueConstIterator : public ValueIteratorBase - { - friend class Value; - public: - typedef unsigned int size_t; - typedef int difference_type; - typedef const Value &reference; - typedef const Value *pointer; - typedef ValueConstIterator SelfType; - - ValueConstIterator(); - private: - /*! \internal Use by Value to create an iterator. - */ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); -#else - ValueConstIterator( const ValueInternalArray::IteratorState &state ); - ValueConstIterator( const ValueInternalMap::IteratorState &state ); -#endif - public: - SelfType &operator =( const ValueIteratorBase &other ); - - SelfType operator++( int ) - { - SelfType temp( *this ); - ++*this; - return temp; - } - - SelfType operator--( int ) - { - SelfType temp( *this ); - --*this; - return temp; - } - - SelfType &operator--() - { - decrement(); - return *this; - } - - SelfType &operator++() - { - increment(); - return *this; - } - - reference operator *() const - { - return deref(); - } - }; - - - /** \brief Iterator for object and array value. - */ - class ValueIterator : public ValueIteratorBase - { - friend class Value; - public: - typedef unsigned int size_t; - typedef int difference_type; - typedef Value &reference; - typedef Value *pointer; - typedef ValueIterator SelfType; - - ValueIterator(); - ValueIterator( const ValueConstIterator &other ); - ValueIterator( const ValueIterator &other ); - private: - /*! \internal Use by Value to create an iterator. - */ -#ifndef JSON_VALUE_USE_INTERNAL_MAP - explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); -#else - ValueIterator( const ValueInternalArray::IteratorState &state ); - ValueIterator( const ValueInternalMap::IteratorState &state ); -#endif - public: - - SelfType &operator =( const SelfType &other ); - - SelfType operator++( int ) - { - SelfType temp( *this ); - ++*this; - return temp; - } - - SelfType operator--( int ) - { - SelfType temp( *this ); - --*this; - return temp; - } - - SelfType &operator--() - { - decrement(); - return *this; - } - - SelfType &operator++() - { - increment(); - return *this; - } - - reference operator *() const - { - return deref(); - } - }; - - -} // namespace Json - - -#endif // CPPTL_JSON_H_INCLUDED +#ifndef CPPTL_JSON_H_INCLUDED +# define CPPTL_JSON_H_INCLUDED + +# include "forwards.h" +# include <string> +# include <vector> + +# ifndef JSON_USE_CPPTL_SMALLMAP +# include <map> +# else +# include <cpptl/smallmap.h> +# endif +# ifdef JSON_USE_CPPTL +# include <cpptl/forwards.h> +# endif + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + + /** \brief Type of the value held by a Value object. + */ + enum ValueType + { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). + }; + + enum CommentPlacement + { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for root value) + numberOfCommentPlacement + }; + +//# ifdef JSON_USE_CPPTL +// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames; +// typedef CppTL::AnyEnumerator<const Value &> EnumValues; +//# endif + + /** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignement takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + class JSON_API StaticString + { + public: + explicit StaticString( const char *czstring ) + : str_( czstring ) + { + } + + operator const char *() const + { + return str_; + } + + const char *c_str() const + { + return str_; + } + + private: + const char *str_; + }; + + /** \brief Represents a <a HREF="http://www.json.org">JSON</a> value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. + * Non const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resize and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtanis default value in the case the required element + * does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + */ + class JSON_API Value + { + friend class ValueIteratorBase; +# ifdef JSON_VALUE_USE_INTERNAL_MAP + friend class ValueInternalLink; + friend class ValueInternalMap; +# endif + public: + typedef std::vector<std::string> Members; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef Json::UInt UInt; + typedef Json::Int Int; + typedef UInt ArrayIndex; + + static const Value null; + static const Int minInt; + static const Int maxInt; + static const UInt maxUInt; + + private: +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION +# ifndef JSON_VALUE_USE_INTERNAL_MAP + class CZString + { + public: + enum DuplicationPolicy + { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString( int index ); + CZString( const char *cstr, DuplicationPolicy allocate ); + CZString( const CZString &other ); + ~CZString(); + CZString &operator =( const CZString &other ); + bool operator<( const CZString &other ) const; + bool operator==( const CZString &other ) const; + int index() const; + const char *c_str() const; + bool isStaticString() const; + private: + void swap( CZString &other ); + const char *cstr_; + int index_; + }; + + public: +# ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map<CZString, Value> ObjectValues; +# else + typedef CppTL::SmallMap<CZString, Value> ObjectValues; +# endif // ifndef JSON_USE_CPPTL_SMALLMAP +# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. + This is useful since clear() and resize() will not alter types. + + Examples: + \code + Json::Value null_value; // null + Json::Value arr_value(Json::arrayValue); // [] + Json::Value obj_value(Json::objectValue); // {} + \endcode + */ + Value( ValueType type = nullValue ); + Value( Int value ); + Value( UInt value ); + Value( double value ); + Value( const char *value ); + Value( const char *beginValue, const char *endValue ); + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * \endcode + */ + Value( const StaticString &value ); + Value( const std::string &value ); +# ifdef JSON_USE_CPPTL + Value( const CppTL::ConstString &value ); +# endif + Value( bool value ); + Value( const Value &other ); + ~Value(); + + Value &operator=( const Value &other ); + /// Swap values. + /// \note Currently, comments are intentionally not swapped, for + /// both logic and efficiency. + void swap( Value &other ); + + ValueType type() const; + + bool operator <( const Value &other ) const; + bool operator <=( const Value &other ) const; + bool operator >=( const Value &other ) const; + bool operator >( const Value &other ) const; + + bool operator ==( const Value &other ) const; + bool operator !=( const Value &other ) const; + + int compare( const Value &other ); + + const char *asCString() const; + std::string asString() const; +# ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +# endif + Int asInt() const; + UInt asUInt() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isUInt() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo( ValueType other ) const; + + /// Number of values in array or object + UInt size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return isNull() + bool operator!() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to size elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize( UInt size ); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value &operator[]( UInt index ); + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value &operator[]( UInt index ) const; + /// If the array contains at least index+1 elements, returns the element value, + /// otherwise returns defaultValue. + Value get( UInt index, + const Value &defaultValue ) const; + /// Return true if index < size(). + bool isValidIndex( UInt index ) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value &append( const Value &value ); + + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const char *key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const char *key ) const; + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const std::string &key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const std::string &key ) const; + /** \brief Access an object value by name, create a null member if it does not exist. + + * If the object as no entry for that name, then the member name used to store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value &operator[]( const StaticString &key ); +# ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value &operator[]( const CppTL::ConstString &key ); + /// Access an object value by name, returns null if there is no member with that name. + const Value &operator[]( const CppTL::ConstString &key ) const; +# endif + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const char *key, + const Value &defaultValue ) const; + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const std::string &key, + const Value &defaultValue ) const; +# ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + Value get( const CppTL::ConstString &key, + const Value &defaultValue ) const; +# endif + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + Value removeMember( const char* key ); + /// Same as removeMember(const char*) + Value removeMember( const std::string &key ); + + /// Return true if the object has a member named key. + bool isMember( const char *key ) const; + /// Return true if the object has a member named key. + bool isMember( const std::string &key ) const; +# ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember( const CppTL::ConstString &key ) const; +# endif + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + +//# ifdef JSON_USE_CPPTL +// EnumMemberNames enumMemberNames() const; +// EnumValues enumValues() const; +//# endif + + /// Comments must be //... or /* ... */ + void setComment( const char *comment, + CommentPlacement placement ); + /// Comments must be //... or /* ... */ + void setComment( const std::string &comment, + CommentPlacement placement ); + bool hasComment( CommentPlacement placement ) const; + /// Include delimiters and embedded newlines. + std::string getComment( CommentPlacement placement ) const; + + std::string toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + private: + Value &resolveReference( const char *key, + bool isStatic ); + +# ifdef JSON_VALUE_USE_INTERNAL_MAP + inline bool isItemAvailable() const + { + return itemIsUsed_ == 0; + } + + inline void setItemUsed( bool isUsed = true ) + { + itemIsUsed_ = isUsed ? 1 : 0; + } + + inline bool isMemberNameStatic() const + { + return memberNameIsStatic_ == 0; + } + + inline void setMemberNameIsStatic( bool isStatic ) + { + memberNameIsStatic_ = isStatic ? 1 : 0; + } +# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP + + private: + struct CommentInfo + { + CommentInfo(); + ~CommentInfo(); + + void setComment( const char *text ); + + char *comment_; + }; + + //struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder + { + Int int_; + UInt uint_; + double real_; + bool bool_; + char *string_; +# ifdef JSON_VALUE_USE_INTERNAL_MAP + ValueInternalArray *array_; + ValueInternalMap *map_; +#else + ObjectValues *map_; +# endif + } value_; + ValueType type_ : 8; + int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. +# ifdef JSON_VALUE_USE_INTERNAL_MAP + unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. + int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. +# endif + CommentInfo *comments_; + }; + + + /** \brief Experimental and untested: represents an element of the "path" to access a node. + */ + class PathArgument + { + public: + friend class Path; + + PathArgument(); + PathArgument( UInt index ); + PathArgument( const char *key ); + PathArgument( const std::string &key ); + + private: + enum Kind + { + kindNone = 0, + kindIndex, + kindKey + }; + std::string key_; + UInt index_; + Kind kind_; + }; + + /** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ + class Path + { + public: + Path( const std::string &path, + const PathArgument &a1 = PathArgument(), + const PathArgument &a2 = PathArgument(), + const PathArgument &a3 = PathArgument(), + const PathArgument &a4 = PathArgument(), + const PathArgument &a5 = PathArgument() ); + + const Value &resolve( const Value &root ) const; + Value resolve( const Value &root, + const Value &defaultValue ) const; + /// Creates the "path" to access the specified node and returns a reference on the node. + Value &make( Value &root ) const; + + private: + typedef std::vector<const PathArgument *> InArgs; + typedef std::vector<PathArgument> Args; + + void makePath( const std::string &path, + const InArgs &in ); + void addPathInArg( const std::string &path, + const InArgs &in, + InArgs::const_iterator &itInArg, + PathArgument::Kind kind ); + void invalidPath( const std::string &path, + int location ); + + Args args_; + }; + + /** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value. + * + * - makeMemberName() and releaseMemberName() are called to respectively duplicate and + * free an Json::objectValue member name. + * - duplicateStringValue() and releaseStringValue() are called similarly to + * duplicate and free a Json::stringValue value. + */ + class ValueAllocator + { + public: + enum { unknown = (unsigned)-1 }; + + virtual ~ValueAllocator(); + + virtual char *makeMemberName( const char *memberName ) = 0; + virtual void releaseMemberName( char *memberName ) = 0; + virtual char *duplicateStringValue( const char *value, + unsigned int length = unknown ) = 0; + virtual void releaseStringValue( char *value ) = 0; + }; + +#ifdef JSON_VALUE_USE_INTERNAL_MAP + /** \brief Allocator to customize Value internal map. + * Below is an example of a simple implementation (default implementation actually + * use memory pool for speed). + * \code + class DefaultValueMapAllocator : public ValueMapAllocator + { + public: // overridden from ValueMapAllocator + virtual ValueInternalMap *newMap() + { + return new ValueInternalMap(); + } + + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) + { + return new ValueInternalMap( other ); + } + + virtual void destructMap( ValueInternalMap *map ) + { + delete map; + } + + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) + { + return new ValueInternalLink[size]; + } + + virtual void releaseMapBuckets( ValueInternalLink *links ) + { + delete [] links; + } + + virtual ValueInternalLink *allocateMapLink() + { + return new ValueInternalLink(); + } + + virtual void releaseMapLink( ValueInternalLink *link ) + { + delete link; + } + }; + * \endcode + */ + class JSON_API ValueMapAllocator + { + public: + virtual ~ValueMapAllocator(); + virtual ValueInternalMap *newMap() = 0; + virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; + virtual void destructMap( ValueInternalMap *map ) = 0; + virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; + virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; + virtual ValueInternalLink *allocateMapLink() = 0; + virtual void releaseMapLink( ValueInternalLink *link ) = 0; + }; + + /** \brief ValueInternalMap hash-map bucket chain link (for internal use only). + * \internal previous_ & next_ allows for bidirectional traversal. + */ + class JSON_API ValueInternalLink + { + public: + enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. + enum InternalFlags { + flagAvailable = 0, + flagUsed = 1 + }; + + ValueInternalLink(); + + ~ValueInternalLink(); + + Value items_[itemPerLink]; + char *keys_[itemPerLink]; + ValueInternalLink *previous_; + ValueInternalLink *next_; + }; + + + /** \brief A linked page based hash-table implementation used internally by Value. + * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked + * list in each bucket to handle collision. There is an addional twist in that + * each node of the collision linked list is a page containing a fixed amount of + * value. This provides a better compromise between memory usage and speed. + * + * Each bucket is made up of a chained list of ValueInternalLink. The last + * link of a given bucket can be found in the 'previous_' field of the following bucket. + * The last link of the last bucket is stored in tailLink_ as it has no following bucket. + * Only the last link of a bucket may contains 'available' item. The last link always + * contains at least one element unless is it the bucket one very first link. + */ + class JSON_API ValueInternalMap + { + friend class ValueIteratorBase; + friend class Value; + public: + typedef unsigned int HashKey; + typedef unsigned int BucketIndex; + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState + { + IteratorState() + : map_(0) + , link_(0) + , itemIndex_(0) + , bucketIndex_(0) + { + } + ValueInternalMap *map_; + ValueInternalLink *link_; + BucketIndex itemIndex_; + BucketIndex bucketIndex_; + }; +# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + ValueInternalMap(); + ValueInternalMap( const ValueInternalMap &other ); + ValueInternalMap &operator =( const ValueInternalMap &other ); + ~ValueInternalMap(); + + void swap( ValueInternalMap &other ); + + BucketIndex size() const; + + void clear(); + + bool reserveDelta( BucketIndex growth ); + + bool reserve( BucketIndex newItemCount ); + + const Value *find( const char *key ) const; + + Value *find( const char *key ); + + Value &resolveReference( const char *key, + bool isStatic ); + + void remove( const char *key ); + + void doActualRemove( ValueInternalLink *link, + BucketIndex index, + BucketIndex bucketIndex ); + + ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); + + Value &setNewItem( const char *key, + bool isStatic, + ValueInternalLink *link, + BucketIndex index ); + + Value &unsafeAdd( const char *key, + bool isStatic, + HashKey hashedKey ); + + HashKey hash( const char *key ) const; + + int compare( const ValueInternalMap &other ) const; + + private: + void makeBeginIterator( IteratorState &it ) const; + void makeEndIterator( IteratorState &it ) const; + static bool equals( const IteratorState &x, const IteratorState &other ); + static void increment( IteratorState &iterator ); + static void incrementBucket( IteratorState &iterator ); + static void decrement( IteratorState &iterator ); + static const char *key( const IteratorState &iterator ); + static const char *key( const IteratorState &iterator, bool &isStatic ); + static Value &value( const IteratorState &iterator ); + static int distance( const IteratorState &x, const IteratorState &y ); + + private: + ValueInternalLink *buckets_; + ValueInternalLink *tailLink_; + BucketIndex bucketsSize_; + BucketIndex itemCount_; + }; + + /** \brief A simplified deque implementation used internally by Value. + * \internal + * It is based on a list of fixed "page", each page contains a fixed number of items. + * Instead of using a linked-list, a array of pointer is used for fast item look-up. + * Look-up for an element is as follow: + * - compute page index: pageIndex = itemIndex / itemsPerPage + * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] + * + * Insertion is amortized constant time (only the array containing the index of pointers + * need to be reallocated when items are appended). + */ + class JSON_API ValueInternalArray + { + friend class Value; + friend class ValueIteratorBase; + public: + enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. + typedef Value::ArrayIndex ArrayIndex; + typedef unsigned int PageIndex; + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + struct IteratorState // Must be a POD + { + IteratorState() + : array_(0) + , currentPageIndex_(0) + , currentItemIndex_(0) + { + } + ValueInternalArray *array_; + Value **currentPageIndex_; + unsigned int currentItemIndex_; + }; +# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + + ValueInternalArray(); + ValueInternalArray( const ValueInternalArray &other ); + ValueInternalArray &operator =( const ValueInternalArray &other ); + ~ValueInternalArray(); + void swap( ValueInternalArray &other ); + + void clear(); + void resize( ArrayIndex newSize ); + + Value &resolveReference( ArrayIndex index ); + + Value *find( ArrayIndex index ) const; + + ArrayIndex size() const; + + int compare( const ValueInternalArray &other ) const; + + private: + static bool equals( const IteratorState &x, const IteratorState &other ); + static void increment( IteratorState &iterator ); + static void decrement( IteratorState &iterator ); + static Value &dereference( const IteratorState &iterator ); + static Value &unsafeDereference( const IteratorState &iterator ); + static int distance( const IteratorState &x, const IteratorState &y ); + static ArrayIndex indexOf( const IteratorState &iterator ); + void makeBeginIterator( IteratorState &it ) const; + void makeEndIterator( IteratorState &it ) const; + void makeIterator( IteratorState &it, ArrayIndex index ) const; + + void makeIndexValid( ArrayIndex index ); + + Value **pages_; + ArrayIndex size_; + PageIndex pageCount_; + }; + + /** \brief Experimental: do not use. Allocator to customize Value internal array. + * Below is an example of a simple implementation (actual implementation use + * memory pool). + \code +class DefaultValueArrayAllocator : public ValueArrayAllocator +{ +public: // overridden from ValueArrayAllocator + virtual ~DefaultValueArrayAllocator() + { + } + + virtual ValueInternalArray *newArray() + { + return new ValueInternalArray(); + } + + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) + { + return new ValueInternalArray( other ); + } + + virtual void destruct( ValueInternalArray *array ) + { + delete array; + } + + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) + { + ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; + if ( minNewIndexCount > newIndexCount ) + newIndexCount = minNewIndexCount; + void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); + if ( !newIndexes ) + throw std::bad_alloc(); + indexCount = newIndexCount; + indexes = static_cast<Value **>( newIndexes ); + } + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) + { + if ( indexes ) + free( indexes ); + } + + virtual Value *allocateArrayPage() + { + return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); + } + + virtual void releaseArrayPage( Value *value ) + { + if ( value ) + free( value ); + } +}; + \endcode + */ + class JSON_API ValueArrayAllocator + { + public: + virtual ~ValueArrayAllocator(); + virtual ValueInternalArray *newArray() = 0; + virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; + virtual void destructArray( ValueInternalArray *array ) = 0; + /** \brief Reallocate array page index. + * Reallocates an array of pointer on each page. + * \param indexes [input] pointer on the current index. May be \c NULL. + * [output] pointer on the new index of at least + * \a minNewIndexCount pages. + * \param indexCount [input] current number of pages in the index. + * [output] number of page the reallocated index can handle. + * \b MUST be >= \a minNewIndexCount. + * \param minNewIndexCount Minimum number of page the new index must be able to + * handle. + */ + virtual void reallocateArrayPageIndex( Value **&indexes, + ValueInternalArray::PageIndex &indexCount, + ValueInternalArray::PageIndex minNewIndexCount ) = 0; + virtual void releaseArrayPageIndex( Value **indexes, + ValueInternalArray::PageIndex indexCount ) = 0; + virtual Value *allocateArrayPage() = 0; + virtual void releaseArrayPage( Value *value ) = 0; + }; +#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP + + + /** \brief base class for Value iterators. + * + */ + class ValueIteratorBase + { + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + ValueIteratorBase(); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); +#else + ValueIteratorBase( const ValueInternalArray::IteratorState &state ); + ValueIteratorBase( const ValueInternalMap::IteratorState &state ); +#endif + + bool operator ==( const SelfType &other ) const + { + return isEqual( other ); + } + + bool operator !=( const SelfType &other ) const + { + return !isEqual( other ); + } + + difference_type operator -( const SelfType &other ) const + { + return computeDistance( other ); + } + + /// Return either the index or the member name of the referenced value as a Value. + Value key() const; + + /// Return the index of the referenced Value. -1 if it is not an arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value. "" if it is not an objectValue. + const char *memberName() const; + + protected: + Value &deref() const; + + void increment(); + + void decrement(); + + difference_type computeDistance( const SelfType &other ) const; + + bool isEqual( const SelfType &other ) const; + + void copy( const SelfType &other ); + + private: +#ifndef JSON_VALUE_USE_INTERNAL_MAP + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; +#else + union + { + ValueInternalArray::IteratorState array_; + ValueInternalMap::IteratorState map_; + } iterator_; + bool isArray_; +#endif + }; + + /** \brief const iterator for object and array value. + * + */ + class ValueConstIterator : public ValueIteratorBase + { + friend class Value; + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef const Value &reference; + typedef const Value *pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); +#else + ValueConstIterator( const ValueInternalArray::IteratorState &state ); + ValueConstIterator( const ValueInternalMap::IteratorState &state ); +#endif + public: + SelfType &operator =( const ValueIteratorBase &other ); + + SelfType operator++( int ) + { + SelfType temp( *this ); + ++*this; + return temp; + } + + SelfType operator--( int ) + { + SelfType temp( *this ); + --*this; + return temp; + } + + SelfType &operator--() + { + decrement(); + return *this; + } + + SelfType &operator++() + { + increment(); + return *this; + } + + reference operator *() const + { + return deref(); + } + }; + + + /** \brief Iterator for object and array value. + */ + class ValueIterator : public ValueIteratorBase + { + friend class Value; + public: + typedef unsigned int size_t; + typedef int difference_type; + typedef Value &reference; + typedef Value *pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + ValueIterator( const ValueConstIterator &other ); + ValueIterator( const ValueIterator &other ); + private: + /*! \internal Use by Value to create an iterator. + */ +#ifndef JSON_VALUE_USE_INTERNAL_MAP + explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); +#else + ValueIterator( const ValueInternalArray::IteratorState &state ); + ValueIterator( const ValueInternalMap::IteratorState &state ); +#endif + public: + + SelfType &operator =( const SelfType &other ); + + SelfType operator++( int ) + { + SelfType temp( *this ); + ++*this; + return temp; + } + + SelfType operator--( int ) + { + SelfType temp( *this ); + --*this; + return temp; + } + + SelfType &operator--() + { + decrement(); + return *this; + } + + SelfType &operator++() + { + increment(); + return *this; + } + + reference operator *() const + { + return deref(); + } + }; + + +} // namespace Json + + +#endif // CPPTL_JSON_H_INCLUDED diff --git a/src/jsoncpp/include/json/writer.h b/src/jsoncpp/include/json/writer.h index 5f4b83be41..3232683713 100644 --- a/src/jsoncpp/include/json/writer.h +++ b/src/jsoncpp/include/json/writer.h @@ -1,174 +1,174 @@ -#ifndef JSON_WRITER_H_INCLUDED -# define JSON_WRITER_H_INCLUDED - -# include "value.h" -# include <vector> -# include <string> -# include <iostream> - -namespace Json { - - class Value; - - /** \brief Abstract class for writers. - */ - class JSON_API Writer - { - public: - virtual ~Writer(); - - virtual std::string write( const Value &root ) = 0; - }; - - /** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly). - * - * The JSON document is written in a single line. It is not intended for 'human' consumption, - * but may be usefull to support feature such as RPC where bandwith is limited. - * \sa Reader, Value - */ - class JSON_API FastWriter : public Writer - { - public: - FastWriter(); - virtual ~FastWriter(){} - - void enableYAMLCompatibility(); - - public: // overridden from Writer - virtual std::string write( const Value &root ); - - private: - void writeValue( const Value &value ); - - std::string document_; - bool yamlCompatiblityEnabled_; - }; - - /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value types, - * and all the values fit on one lines, then print the array on a single line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputed according to their #CommentPlacement. - * - * \sa Reader, Value, Value::setComment() - */ - class JSON_API StyledWriter: public Writer - { - public: - StyledWriter(); - virtual ~StyledWriter(){} - - public: // overridden from Writer - /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. - * \param root Value to serialize. - * \return String containing the JSON document that represents the root value. - */ - virtual std::string write( const Value &root ); - - private: - void writeValue( const Value &value ); - void writeArrayValue( const Value &value ); - bool isMultineArray( const Value &value ); - void pushValue( const std::string &value ); - void writeIndent(); - void writeWithIndent( const std::string &value ); - void indent(); - void unindent(); - void writeCommentBeforeValue( const Value &root ); - void writeCommentAfterValueOnSameLine( const Value &root ); - bool hasCommentForValue( const Value &value ); - static std::string normalizeEOL( const std::string &text ); - - typedef std::vector<std::string> ChildValues; - - ChildValues childValues_; - std::string document_; - std::string indentString_; - int rightMargin_; - int indentSize_; - bool addChildValues_; - }; - - /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way, - to a stream rather than to a string. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value types, - * and all the values fit on one lines, then print the array on a single line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputed according to their #CommentPlacement. - * - * \param indentation Each level will be indented by this amount extra. - * \sa Reader, Value, Value::setComment() - */ - class JSON_API StyledStreamWriter - { - public: - StyledStreamWriter( std::string indentation="\t" ); - ~StyledStreamWriter(){} - - public: - /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. - * \param out Stream to write to. (Can be ostringstream, e.g.) - * \param root Value to serialize. - * \note There is no point in deriving from Writer, since write() should not return a value. - */ - void write( std::ostream &out, const Value &root ); - - private: - void writeValue( const Value &value ); - void writeArrayValue( const Value &value ); - bool isMultineArray( const Value &value ); - void pushValue( const std::string &value ); - void writeIndent(); - void writeWithIndent( const std::string &value ); - void indent(); - void unindent(); - void writeCommentBeforeValue( const Value &root ); - void writeCommentAfterValueOnSameLine( const Value &root ); - bool hasCommentForValue( const Value &value ); - static std::string normalizeEOL( const std::string &text ); - - typedef std::vector<std::string> ChildValues; - - ChildValues childValues_; - std::ostream* document_; - std::string indentString_; - int rightMargin_; - std::string indentation_; - bool addChildValues_; - }; - - std::string JSON_API valueToString( Int value ); - std::string JSON_API valueToString( UInt value ); - std::string JSON_API valueToString( double value ); - std::string JSON_API valueToString( bool value ); - std::string JSON_API valueToQuotedString( const char *value ); - - /// \brief Output using the StyledStreamWriter. - /// \see Json::operator>>() - std::ostream& operator<<( std::ostream&, const Value &root ); - -} // namespace Json - - - -#endif // JSON_WRITER_H_INCLUDED +#ifndef JSON_WRITER_H_INCLUDED +# define JSON_WRITER_H_INCLUDED + +# include "value.h" +# include <vector> +# include <string> +# include <iostream> + +namespace Json { + + class Value; + + /** \brief Abstract class for writers. + */ + class JSON_API Writer + { + public: + virtual ~Writer(); + + virtual std::string write( const Value &root ) = 0; + }; + + /** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' consumption, + * but may be usefull to support feature such as RPC where bandwith is limited. + * \sa Reader, Value + */ + class JSON_API FastWriter : public Writer + { + public: + FastWriter(); + virtual ~FastWriter(){} + + void enableYAMLCompatibility(); + + public: // overridden from Writer + virtual std::string write( const Value &root ); + + private: + void writeValue( const Value &value ); + + std::string document_; + bool yamlCompatiblityEnabled_; + }; + + /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + */ + class JSON_API StyledWriter: public Writer + { + public: + StyledWriter(); + virtual ~StyledWriter(){} + + public: // overridden from Writer + /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + virtual std::string write( const Value &root ); + + private: + void writeValue( const Value &value ); + void writeArrayValue( const Value &value ); + bool isMultineArray( const Value &value ); + void pushValue( const std::string &value ); + void writeIndent(); + void writeWithIndent( const std::string &value ); + void indent(); + void unindent(); + void writeCommentBeforeValue( const Value &root ); + void writeCommentAfterValueOnSameLine( const Value &root ); + bool hasCommentForValue( const Value &value ); + static std::string normalizeEOL( const std::string &text ); + + typedef std::vector<std::string> ChildValues; + + ChildValues childValues_; + std::string document_; + std::string indentString_; + int rightMargin_; + int indentSize_; + bool addChildValues_; + }; + + /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value types, + * and all the values fit on one lines, then print the array on a single line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their #CommentPlacement. + * + * \param indentation Each level will be indented by this amount extra. + * \sa Reader, Value, Value::setComment() + */ + class JSON_API StyledStreamWriter + { + public: + StyledStreamWriter( std::string indentation="\t" ); + ~StyledStreamWriter(){} + + public: + /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not return a value. + */ + void write( std::ostream &out, const Value &root ); + + private: + void writeValue( const Value &value ); + void writeArrayValue( const Value &value ); + bool isMultineArray( const Value &value ); + void pushValue( const std::string &value ); + void writeIndent(); + void writeWithIndent( const std::string &value ); + void indent(); + void unindent(); + void writeCommentBeforeValue( const Value &root ); + void writeCommentAfterValueOnSameLine( const Value &root ); + bool hasCommentForValue( const Value &value ); + static std::string normalizeEOL( const std::string &text ); + + typedef std::vector<std::string> ChildValues; + + ChildValues childValues_; + std::ostream* document_; + std::string indentString_; + int rightMargin_; + std::string indentation_; + bool addChildValues_; + }; + + std::string JSON_API valueToString( Int value ); + std::string JSON_API valueToString( UInt value ); + std::string JSON_API valueToString( double value ); + std::string JSON_API valueToString( bool value ); + std::string JSON_API valueToQuotedString( const char *value ); + + /// \brief Output using the StyledStreamWriter. + /// \see Json::operator>>() + std::ostream& operator<<( std::ostream&, const Value &root ); + +} // namespace Json + + + +#endif // JSON_WRITER_H_INCLUDED diff --git a/src/jsoncpp/src/lib_json/json_batchallocator.h b/src/jsoncpp/src/lib_json/json_batchallocator.h index 87ea5ed807..1e35c19def 100644 --- a/src/jsoncpp/src/lib_json/json_batchallocator.h +++ b/src/jsoncpp/src/lib_json/json_batchallocator.h @@ -1,125 +1,125 @@ -#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED -# define JSONCPP_BATCHALLOCATOR_H_INCLUDED - -# include <stdlib.h> -# include <assert.h> - -# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - -namespace Json { - -/* Fast memory allocator. - * - * This memory allocator allocates memory for a batch of object (specified by - * the page size, the number of object in each page). - * - * It does not allow the destruction of a single object. All the allocated objects - * can be destroyed at once. The memory can be either released or reused for future - * allocation. - * - * The in-place new operator must be used to construct the object using the pointer - * returned by allocate. - */ -template<typename AllocatedType - ,const unsigned int objectPerAllocation> -class BatchAllocator -{ -public: - typedef AllocatedType Type; - - BatchAllocator( unsigned int objectsPerPage = 255 ) - : freeHead_( 0 ) - , objectsPerPage_( objectsPerPage ) - { -// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); - assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. - assert( objectsPerPage >= 16 ); - batches_ = allocateBatch( 0 ); // allocated a dummy page - currentBatch_ = batches_; - } - - ~BatchAllocator() - { - for ( BatchInfo *batch = batches_; batch; ) - { - BatchInfo *nextBatch = batch->next_; - free( batch ); - batch = nextBatch; - } - } - - /// allocate space for an array of objectPerAllocation object. - /// @warning it is the responsability of the caller to call objects constructors. - AllocatedType *allocate() - { - if ( freeHead_ ) // returns node from free list. - { - AllocatedType *object = freeHead_; - freeHead_ = *(AllocatedType **)object; - return object; - } - if ( currentBatch_->used_ == currentBatch_->end_ ) - { - currentBatch_ = currentBatch_->next_; - while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) - currentBatch_ = currentBatch_->next_; - - if ( !currentBatch_ ) // no free batch found, allocate a new one - { - currentBatch_ = allocateBatch( objectsPerPage_ ); - currentBatch_->next_ = batches_; // insert at the head of the list - batches_ = currentBatch_; - } - } - AllocatedType *allocated = currentBatch_->used_; - currentBatch_->used_ += objectPerAllocation; - return allocated; - } - - /// Release the object. - /// @warning it is the responsability of the caller to actually destruct the object. - void release( AllocatedType *object ) - { - assert( object != 0 ); - *(AllocatedType **)object = freeHead_; - freeHead_ = object; - } - -private: - struct BatchInfo - { - BatchInfo *next_; - AllocatedType *used_; - AllocatedType *end_; - AllocatedType buffer_[objectPerAllocation]; - }; - - // disabled copy constructor and assignement operator. - BatchAllocator( const BatchAllocator & ); - void operator =( const BatchAllocator &); - - static BatchInfo *allocateBatch( unsigned int objectsPerPage ) - { - const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation - + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; - BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) ); - batch->next_ = 0; - batch->used_ = batch->buffer_; - batch->end_ = batch->buffer_ + objectsPerPage; - return batch; - } - - BatchInfo *batches_; - BatchInfo *currentBatch_; - /// Head of a single linked list within the allocated space of freeed object - AllocatedType *freeHead_; - unsigned int objectsPerPage_; -}; - - -} // namespace Json - -# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION - -#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED - +#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED +# define JSONCPP_BATCHALLOCATOR_H_INCLUDED + +# include <stdlib.h> +# include <assert.h> + +# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +namespace Json { + +/* Fast memory allocator. + * + * This memory allocator allocates memory for a batch of object (specified by + * the page size, the number of object in each page). + * + * It does not allow the destruction of a single object. All the allocated objects + * can be destroyed at once. The memory can be either released or reused for future + * allocation. + * + * The in-place new operator must be used to construct the object using the pointer + * returned by allocate. + */ +template<typename AllocatedType + ,const unsigned int objectPerAllocation> +class BatchAllocator +{ +public: + typedef AllocatedType Type; + + BatchAllocator( unsigned int objectsPerPage = 255 ) + : freeHead_( 0 ) + , objectsPerPage_( objectsPerPage ) + { +// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); + assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. + assert( objectsPerPage >= 16 ); + batches_ = allocateBatch( 0 ); // allocated a dummy page + currentBatch_ = batches_; + } + + ~BatchAllocator() + { + for ( BatchInfo *batch = batches_; batch; ) + { + BatchInfo *nextBatch = batch->next_; + free( batch ); + batch = nextBatch; + } + } + + /// allocate space for an array of objectPerAllocation object. + /// @warning it is the responsability of the caller to call objects constructors. + AllocatedType *allocate() + { + if ( freeHead_ ) // returns node from free list. + { + AllocatedType *object = freeHead_; + freeHead_ = *(AllocatedType **)object; + return object; + } + if ( currentBatch_->used_ == currentBatch_->end_ ) + { + currentBatch_ = currentBatch_->next_; + while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) + currentBatch_ = currentBatch_->next_; + + if ( !currentBatch_ ) // no free batch found, allocate a new one + { + currentBatch_ = allocateBatch( objectsPerPage_ ); + currentBatch_->next_ = batches_; // insert at the head of the list + batches_ = currentBatch_; + } + } + AllocatedType *allocated = currentBatch_->used_; + currentBatch_->used_ += objectPerAllocation; + return allocated; + } + + /// Release the object. + /// @warning it is the responsability of the caller to actually destruct the object. + void release( AllocatedType *object ) + { + assert( object != 0 ); + *(AllocatedType **)object = freeHead_; + freeHead_ = object; + } + +private: + struct BatchInfo + { + BatchInfo *next_; + AllocatedType *used_; + AllocatedType *end_; + AllocatedType buffer_[objectPerAllocation]; + }; + + // disabled copy constructor and assignement operator. + BatchAllocator( const BatchAllocator & ); + void operator =( const BatchAllocator &); + + static BatchInfo *allocateBatch( unsigned int objectsPerPage ) + { + const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation + + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; + BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) ); + batch->next_ = 0; + batch->used_ = batch->buffer_; + batch->end_ = batch->buffer_ + objectsPerPage; + return batch; + } + + BatchInfo *batches_; + BatchInfo *currentBatch_; + /// Head of a single linked list within the allocated space of freeed object + AllocatedType *freeHead_; + unsigned int objectsPerPage_; +}; + + +} // namespace Json + +# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION + +#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED + diff --git a/src/jsoncpp/src/lib_json/json_reader.cpp b/src/jsoncpp/src/lib_json/json_reader.cpp index cefcc8c198..edb65adbb8 100644 --- a/src/jsoncpp/src/lib_json/json_reader.cpp +++ b/src/jsoncpp/src/lib_json/json_reader.cpp @@ -1,886 +1,886 @@ -#include <jsoncpp/include/json/reader.h> -#include <jsoncpp/include/json/value.h> -#include <utility> -#include <cstdio> -#include <cassert> -#include <cstring> -#include <iostream> -#include <stdexcept> - -#if _MSC_VER >= 1400 // VC++ 8.0 -#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. -#endif - -namespace Json { - -// Implementation of class Features -// //////////////////////////////// - -Features::Features() - : allowComments_( true ) - , strictRoot_( false ) -{ -} - - -Features -Features::all() -{ - return Features(); -} - - -Features -Features::strictMode() -{ - Features features; - features.allowComments_ = false; - features.strictRoot_ = true; - return features; -} - -// Implementation of class Reader -// //////////////////////////////// - - -static inline bool -in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) -{ - return c == c1 || c == c2 || c == c3 || c == c4; -} - -static inline bool -in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) -{ - return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; -} - - -static bool -containsNewLine( Reader::Location begin, - Reader::Location end ) -{ - for ( ;begin < end; ++begin ) - if ( *begin == '\n' || *begin == '\r' ) - return true; - return false; -} - -static std::string codePointToUTF8(unsigned int cp) -{ - std::string result; - - // based on description from http://en.wikipedia.org/wiki/UTF-8 - - if (cp <= 0x7f) - { - result.resize(1); - result[0] = static_cast<char>(cp); - } - else if (cp <= 0x7FF) - { - result.resize(2); - result[1] = static_cast<char>(0x80 | (0x3f & cp)); - result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6))); - } - else if (cp <= 0xFFFF) - { - result.resize(3); - result[2] = static_cast<char>(0x80 | (0x3f & cp)); - result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6))); - result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12))); - } - else if (cp <= 0x10FFFF) - { - result.resize(4); - result[3] = static_cast<char>(0x80 | (0x3f & cp)); - result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); - result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12))); - result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18))); - } - - return result; -} - - -// Class Reader -// ////////////////////////////////////////////////////////////////// - -Reader::Reader() - : features_( Features::all() ) -{ -} - - -Reader::Reader( const Features &features ) - : features_( features ) -{ -} - - -bool -Reader::parse( const std::string &document, - Value &root, - bool collectComments ) -{ - document_ = document; - const char *begin = document_.c_str(); - const char *end = begin + document_.length(); - return parse( begin, end, root, collectComments ); -} - - -bool -Reader::parse( std::istream& sin, - Value &root, - bool collectComments ) -{ - //std::istream_iterator<char> begin(sin); - //std::istream_iterator<char> end; - // Those would allow streamed input from a file, if parse() were a - // template function. - - // Since std::string is reference-counted, this at least does not - // create an extra copy. - std::string doc; - std::getline(sin, doc, (char)EOF); - return parse( doc, root, collectComments ); -} - -bool -Reader::parse( const char *beginDoc, const char *endDoc, - Value &root, - bool collectComments ) -{ - if ( !features_.allowComments_ ) - { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = 0; - lastValue_ = 0; - commentsBefore_ = ""; - errors_.clear(); - while ( !nodes_.empty() ) - nodes_.pop(); - nodes_.push( &root ); - - bool successful = readValue(); - Token token; - skipCommentTokens( token ); - if ( collectComments_ && !commentsBefore_.empty() ) - root.setComment( commentsBefore_, commentAfter ); - if ( features_.strictRoot_ ) - { - if ( !root.isArray() && !root.isObject() ) - { - // Set error location to start of doc, ideally should be first token found in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( "A valid JSON document must be either an array or an object value.", - token ); - return false; - } - } - return successful; -} - - -bool -Reader::readValue() -{ - Token token; - skipCommentTokens( token ); - bool successful = true; - - if ( collectComments_ && !commentsBefore_.empty() ) - { - currentValue().setComment( commentsBefore_, commentBefore ); - commentsBefore_ = ""; - } - - - switch ( token.type_ ) - { - case tokenObjectBegin: - successful = readObject( token ); - break; - case tokenArrayBegin: - successful = readArray( token ); - break; - case tokenNumber: - successful = decodeNumber( token ); - break; - case tokenString: - successful = decodeString( token ); - break; - case tokenTrue: - currentValue() = true; - break; - case tokenFalse: - currentValue() = false; - break; - case tokenNull: - currentValue() = Value(); - break; - default: - return addError( "Syntax error: value, object or array expected.", token ); - } - - if ( collectComments_ ) - { - lastValueEnd_ = current_; - lastValue_ = ¤tValue(); - } - - return successful; -} - - -void -Reader::skipCommentTokens( Token &token ) -{ - if ( features_.allowComments_ ) - { - do - { - readToken( token ); - } - while ( token.type_ == tokenComment ); - } - else - { - readToken( token ); - } -} - - -bool -Reader::expectToken( TokenType type, Token &token, const char *message ) -{ - readToken( token ); - if ( token.type_ != type ) - return addError( message, token ); - return true; -} - - -bool -Reader::readToken( Token &token ) -{ - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch ( c ) - { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - token.type_ = tokenNumber; - readNumber(); - break; - case 't': - token.type_ = tokenTrue; - ok = match( "rue", 3 ); - break; - case 'f': - token.type_ = tokenFalse; - ok = match( "alse", 4 ); - break; - case 'n': - token.type_ = tokenNull; - ok = match( "ull", 3 ); - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if ( !ok ) - token.type_ = tokenError; - token.end_ = current_; - return true; -} - - -void -Reader::skipSpaces() -{ - while ( current_ != end_ ) - { - Char c = *current_; - if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) - ++current_; - else - break; - } -} - - -bool -Reader::match( Location pattern, - int patternLength ) -{ - if ( end_ - current_ < patternLength ) - return false; - int index = patternLength; - while ( index-- ) - if ( current_[index] != pattern[index] ) - return false; - current_ += patternLength; - return true; -} - - -bool -Reader::readComment() -{ - Location commentBegin = current_ - 1; - Char c = getNextChar(); - bool successful = false; - if ( c == '*' ) - successful = readCStyleComment(); - else if ( c == '/' ) - successful = readCppStyleComment(); - if ( !successful ) - return false; - - if ( collectComments_ ) - { - CommentPlacement placement = commentBefore; - if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) - { - if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) - placement = commentAfterOnSameLine; - } - - addComment( commentBegin, current_, placement ); - } - return true; -} - - -void -Reader::addComment( Location begin, - Location end, - CommentPlacement placement ) -{ - assert( collectComments_ ); - if ( placement == commentAfterOnSameLine ) - { - assert( lastValue_ != 0 ); - lastValue_->setComment( std::string( begin, end ), placement ); - } - else - { - if ( !commentsBefore_.empty() ) - commentsBefore_ += "\n"; - commentsBefore_ += std::string( begin, end ); - } -} - - -bool -Reader::readCStyleComment() -{ - while ( current_ != end_ ) - { - Char c = getNextChar(); - if ( c == '*' && *current_ == '/' ) - break; - } - return getNextChar() == '/'; -} - - -bool -Reader::readCppStyleComment() -{ - while ( current_ != end_ ) - { - Char c = getNextChar(); - if ( c == '\r' || c == '\n' ) - break; - } - return true; -} - - -void -Reader::readNumber() -{ - while ( current_ != end_ ) - { - if ( !(*current_ >= '0' && *current_ <= '9') && - !in( *current_, '.', 'e', 'E', '+', '-' ) ) - break; - ++current_; - } -} - -bool -Reader::readString() -{ - Char c = 0; - while ( current_ != end_ ) - { - c = getNextChar(); - if ( c == '\\' ) - getNextChar(); - else if ( c == '"' ) - break; - } - return c == '"'; -} - - -bool -Reader::readObject( Token &tokenStart ) -{ - Token tokenName; - std::string name; - currentValue() = Value( objectValue ); - while ( readToken( tokenName ) ) - { - bool initialTokenOk = true; - while ( tokenName.type_ == tokenComment && initialTokenOk ) - initialTokenOk = readToken( tokenName ); - if ( !initialTokenOk ) - break; - if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object - return true; - if ( tokenName.type_ != tokenString ) - break; - - name = ""; - if ( !decodeString( tokenName, name ) ) - return recoverFromError( tokenObjectEnd ); - - Token colon; - if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) - { - return addErrorAndRecover( "Missing ':' after object member name", - colon, - tokenObjectEnd ); - } - Value &value = currentValue()[ name ]; - nodes_.push( &value ); - bool ok = readValue(); - nodes_.pop(); - if ( !ok ) // error already set - return recoverFromError( tokenObjectEnd ); - - Token comma; - if ( !readToken( comma ) - || ( comma.type_ != tokenObjectEnd && - comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment ) ) - { - return addErrorAndRecover( "Missing ',' or '}' in object declaration", - comma, - tokenObjectEnd ); - } - bool finalizeTokenOk = true; - while ( comma.type_ == tokenComment && - finalizeTokenOk ) - finalizeTokenOk = readToken( comma ); - if ( comma.type_ == tokenObjectEnd ) - return true; - } - return addErrorAndRecover( "Missing '}' or object member name", - tokenName, - tokenObjectEnd ); -} - - -bool -Reader::readArray( Token &tokenStart ) -{ - currentValue() = Value( arrayValue ); - skipSpaces(); - if ( *current_ == ']' ) // empty array - { - Token endArray; - readToken( endArray ); - return true; - } - int index = 0; - while ( true ) - { - Value &value = currentValue()[ index++ ]; - nodes_.push( &value ); - bool ok = readValue(); - nodes_.pop(); - if ( !ok ) // error already set - return recoverFromError( tokenArrayEnd ); - - Token token; - // Accept Comment after last item in the array. - ok = readToken( token ); - while ( token.type_ == tokenComment && ok ) - { - ok = readToken( token ); - } - bool badTokenType = ( token.type_ == tokenArraySeparator && - token.type_ == tokenArrayEnd ); - if ( !ok || badTokenType ) - { - return addErrorAndRecover( "Missing ',' or ']' in array declaration", - token, - tokenArrayEnd ); - } - if ( token.type_ == tokenArrayEnd ) - break; - } - return true; -} - - -bool -Reader::decodeNumber( Token &token ) -{ - bool isDouble = false; - for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) - { - isDouble = isDouble - || in( *inspect, '.', 'e', 'E', '+' ) - || ( *inspect == '-' && inspect != token.start_ ); - } - if ( isDouble ) - return decodeDouble( token ); - Location current = token.start_; - bool isNegative = *current == '-'; - if ( isNegative ) - ++current; - Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) - : Value::maxUInt) / 10; - Value::UInt value = 0; - while ( current < token.end_ ) - { - Char c = *current++; - if ( c < '0' || c > '9' ) - return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); - if ( value >= threshold ) - return decodeDouble( token ); - value = value * 10 + Value::UInt(c - '0'); - } - if ( isNegative ) - currentValue() = -Value::Int( value ); - else if ( value <= Value::UInt(Value::maxInt) ) - currentValue() = Value::Int( value ); - else - currentValue() = value; - return true; -} - - -bool -Reader::decodeDouble( Token &token ) -{ - double value = 0; - const int bufferSize = 32; - int count; - int length = int(token.end_ - token.start_); - if ( length <= bufferSize ) - { - Char buffer[bufferSize]; - memcpy( buffer, token.start_, length ); - buffer[length] = 0; - count = sscanf( buffer, "%lf", &value ); - } - else - { - std::string buffer( token.start_, token.end_ ); - count = sscanf( buffer.c_str(), "%lf", &value ); - } - - if ( count != 1 ) - return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); - currentValue() = value; - return true; -} - - -bool -Reader::decodeString( Token &token ) -{ - std::string decoded; - if ( !decodeString( token, decoded ) ) - return false; - currentValue() = decoded; - return true; -} - - -bool -Reader::decodeString( Token &token, std::string &decoded ) -{ - decoded.reserve( token.end_ - token.start_ - 2 ); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while ( current != end ) - { - Char c = *current++; - if ( c == '"' ) - break; - else if ( c == '\\' ) - { - if ( current == end ) - return addError( "Empty escape sequence in string", token, current ); - Char escape = *current++; - switch ( escape ) - { - case '"': decoded += '"'; break; - case '/': decoded += '/'; break; - case '\\': decoded += '\\'; break; - case 'b': decoded += '\b'; break; - case 'f': decoded += '\f'; break; - case 'n': decoded += '\n'; break; - case 'r': decoded += '\r'; break; - case 't': decoded += '\t'; break; - case 'u': - { - unsigned int unicode; - if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) - return false; - decoded += codePointToUTF8(unicode); - } - break; - default: - return addError( "Bad escape sequence in string", token, current ); - } - } - else - { - decoded += c; - } - } - return true; -} - -bool -Reader::decodeUnicodeCodePoint( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ) -{ - - if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) - { - // surrogate pairs - if (end - current < 6) - return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); - unsigned int surrogatePair; - if (*(current++) == '\\' && *(current++)== 'u') - { - if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) - { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } - else - return false; - } - else - return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); - } - return true; -} - -bool -Reader::decodeUnicodeEscapeSequence( Token &token, - Location ¤t, - Location end, - unsigned int &unicode ) -{ - if ( end - current < 4 ) - return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); - unicode = 0; - for ( int index =0; index < 4; ++index ) - { - Char c = *current++; - unicode *= 16; - if ( c >= '0' && c <= '9' ) - unicode += c - '0'; - else if ( c >= 'a' && c <= 'f' ) - unicode += c - 'a' + 10; - else if ( c >= 'A' && c <= 'F' ) - unicode += c - 'A' + 10; - else - return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); - } - return true; -} - - -bool -Reader::addError( const std::string &message, - Token &token, - Location extra ) -{ - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back( info ); - return false; -} - - -bool -Reader::recoverFromError( TokenType skipUntilToken ) -{ - int errorCount = int(errors_.size()); - Token skip; - while ( true ) - { - if ( !readToken(skip) ) - errors_.resize( errorCount ); // discard errors caused by recovery - if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) - break; - } - errors_.resize( errorCount ); - return false; -} - - -bool -Reader::addErrorAndRecover( const std::string &message, - Token &token, - TokenType skipUntilToken ) -{ - addError( message, token ); - return recoverFromError( skipUntilToken ); -} - - -Value & -Reader::currentValue() -{ - return *(nodes_.top()); -} - - -Reader::Char -Reader::getNextChar() -{ - if ( current_ == end_ ) - return 0; - return *current_++; -} - - -void -Reader::getLocationLineAndColumn( Location location, - int &line, - int &column ) const -{ - Location current = begin_; - Location lastLineStart = current; - line = 0; - while ( current < location && current != end_ ) - { - Char c = *current++; - if ( c == '\r' ) - { - if ( *current == '\n' ) - ++current; - lastLineStart = current; - ++line; - } - else if ( c == '\n' ) - { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - - -std::string -Reader::getLocationLineAndColumn( Location location ) const -{ - int line, column; - getLocationLineAndColumn( location, line, column ); - char buffer[18+16+16+1]; - sprintf( buffer, "Line %d, Column %d", line, column ); - return buffer; -} - - -std::string -Reader::getFormatedErrorMessages() const -{ - std::string formattedMessage; - for ( Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError ) - { - const ErrorInfo &error = *itError; - formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if ( error.extra_ ) - formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; - } - return formattedMessage; -} - - -std::istream& operator>>( std::istream &sin, Value &root ) -{ - Json::Reader reader; - bool ok = reader.parse(sin, root, true); - //JSON_ASSERT( ok ); -// if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages()); - assert(ok); - return sin; -} - - -} // namespace Json +#include <jsoncpp/include/json/reader.h> +#include <jsoncpp/include/json/value.h> +#include <utility> +#include <cstdio> +#include <cassert> +#include <cstring> +#include <iostream> +#include <stdexcept> + +#if _MSC_VER >= 1400 // VC++ 8.0 +#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. +#endif + +namespace Json { + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() + : allowComments_( true ) + , strictRoot_( false ) +{ +} + + +Features +Features::all() +{ + return Features(); +} + + +Features +Features::strictMode() +{ + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + + +static inline bool +in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) +{ + return c == c1 || c == c2 || c == c3 || c == c4; +} + +static inline bool +in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) +{ + return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; +} + + +static bool +containsNewLine( Reader::Location begin, + Reader::Location end ) +{ + for ( ;begin < end; ++begin ) + if ( *begin == '\n' || *begin == '\r' ) + return true; + return false; +} + +static std::string codePointToUTF8(unsigned int cp) +{ + std::string result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) + { + result.resize(1); + result[0] = static_cast<char>(cp); + } + else if (cp <= 0x7FF) + { + result.resize(2); + result[1] = static_cast<char>(0x80 | (0x3f & cp)); + result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6))); + } + else if (cp <= 0xFFFF) + { + result.resize(3); + result[2] = static_cast<char>(0x80 | (0x3f & cp)); + result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6))); + result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12))); + } + else if (cp <= 0x10FFFF) + { + result.resize(4); + result[3] = static_cast<char>(0x80 | (0x3f & cp)); + result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18))); + } + + return result; +} + + +// Class Reader +// ////////////////////////////////////////////////////////////////// + +Reader::Reader() + : features_( Features::all() ) +{ +} + + +Reader::Reader( const Features &features ) + : features_( features ) +{ +} + + +bool +Reader::parse( const std::string &document, + Value &root, + bool collectComments ) +{ + document_ = document; + const char *begin = document_.c_str(); + const char *end = begin + document_.length(); + return parse( begin, end, root, collectComments ); +} + + +bool +Reader::parse( std::istream& sin, + Value &root, + bool collectComments ) +{ + //std::istream_iterator<char> begin(sin); + //std::istream_iterator<char> end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since std::string is reference-counted, this at least does not + // create an extra copy. + std::string doc; + std::getline(sin, doc, (char)EOF); + return parse( doc, root, collectComments ); +} + +bool +Reader::parse( const char *beginDoc, const char *endDoc, + Value &root, + bool collectComments ) +{ + if ( !features_.allowComments_ ) + { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_ = ""; + errors_.clear(); + while ( !nodes_.empty() ) + nodes_.pop(); + nodes_.push( &root ); + + bool successful = readValue(); + Token token; + skipCommentTokens( token ); + if ( collectComments_ && !commentsBefore_.empty() ) + root.setComment( commentsBefore_, commentAfter ); + if ( features_.strictRoot_ ) + { + if ( !root.isArray() && !root.isObject() ) + { + // Set error location to start of doc, ideally should be first token found in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( "A valid JSON document must be either an array or an object value.", + token ); + return false; + } + } + return successful; +} + + +bool +Reader::readValue() +{ + Token token; + skipCommentTokens( token ); + bool successful = true; + + if ( collectComments_ && !commentsBefore_.empty() ) + { + currentValue().setComment( commentsBefore_, commentBefore ); + commentsBefore_ = ""; + } + + + switch ( token.type_ ) + { + case tokenObjectBegin: + successful = readObject( token ); + break; + case tokenArrayBegin: + successful = readArray( token ); + break; + case tokenNumber: + successful = decodeNumber( token ); + break; + case tokenString: + successful = decodeString( token ); + break; + case tokenTrue: + currentValue() = true; + break; + case tokenFalse: + currentValue() = false; + break; + case tokenNull: + currentValue() = Value(); + break; + default: + return addError( "Syntax error: value, object or array expected.", token ); + } + + if ( collectComments_ ) + { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + return successful; +} + + +void +Reader::skipCommentTokens( Token &token ) +{ + if ( features_.allowComments_ ) + { + do + { + readToken( token ); + } + while ( token.type_ == tokenComment ); + } + else + { + readToken( token ); + } +} + + +bool +Reader::expectToken( TokenType type, Token &token, const char *message ) +{ + readToken( token ); + if ( token.type_ != type ) + return addError( message, token ); + return true; +} + + +bool +Reader::readToken( Token &token ) +{ + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch ( c ) + { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + token.type_ = tokenNumber; + readNumber(); + break; + case 't': + token.type_ = tokenTrue; + ok = match( "rue", 3 ); + break; + case 'f': + token.type_ = tokenFalse; + ok = match( "alse", 4 ); + break; + case 'n': + token.type_ = tokenNull; + ok = match( "ull", 3 ); + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if ( !ok ) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + + +void +Reader::skipSpaces() +{ + while ( current_ != end_ ) + { + Char c = *current_; + if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) + ++current_; + else + break; + } +} + + +bool +Reader::match( Location pattern, + int patternLength ) +{ + if ( end_ - current_ < patternLength ) + return false; + int index = patternLength; + while ( index-- ) + if ( current_[index] != pattern[index] ) + return false; + current_ += patternLength; + return true; +} + + +bool +Reader::readComment() +{ + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if ( c == '*' ) + successful = readCStyleComment(); + else if ( c == '/' ) + successful = readCppStyleComment(); + if ( !successful ) + return false; + + if ( collectComments_ ) + { + CommentPlacement placement = commentBefore; + if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) + { + if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) + placement = commentAfterOnSameLine; + } + + addComment( commentBegin, current_, placement ); + } + return true; +} + + +void +Reader::addComment( Location begin, + Location end, + CommentPlacement placement ) +{ + assert( collectComments_ ); + if ( placement == commentAfterOnSameLine ) + { + assert( lastValue_ != 0 ); + lastValue_->setComment( std::string( begin, end ), placement ); + } + else + { + if ( !commentsBefore_.empty() ) + commentsBefore_ += "\n"; + commentsBefore_ += std::string( begin, end ); + } +} + + +bool +Reader::readCStyleComment() +{ + while ( current_ != end_ ) + { + Char c = getNextChar(); + if ( c == '*' && *current_ == '/' ) + break; + } + return getNextChar() == '/'; +} + + +bool +Reader::readCppStyleComment() +{ + while ( current_ != end_ ) + { + Char c = getNextChar(); + if ( c == '\r' || c == '\n' ) + break; + } + return true; +} + + +void +Reader::readNumber() +{ + while ( current_ != end_ ) + { + if ( !(*current_ >= '0' && *current_ <= '9') && + !in( *current_, '.', 'e', 'E', '+', '-' ) ) + break; + ++current_; + } +} + +bool +Reader::readString() +{ + Char c = 0; + while ( current_ != end_ ) + { + c = getNextChar(); + if ( c == '\\' ) + getNextChar(); + else if ( c == '"' ) + break; + } + return c == '"'; +} + + +bool +Reader::readObject( Token &tokenStart ) +{ + Token tokenName; + std::string name; + currentValue() = Value( objectValue ); + while ( readToken( tokenName ) ) + { + bool initialTokenOk = true; + while ( tokenName.type_ == tokenComment && initialTokenOk ) + initialTokenOk = readToken( tokenName ); + if ( !initialTokenOk ) + break; + if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object + return true; + if ( tokenName.type_ != tokenString ) + break; + + name = ""; + if ( !decodeString( tokenName, name ) ) + return recoverFromError( tokenObjectEnd ); + + Token colon; + if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) + { + return addErrorAndRecover( "Missing ':' after object member name", + colon, + tokenObjectEnd ); + } + Value &value = currentValue()[ name ]; + nodes_.push( &value ); + bool ok = readValue(); + nodes_.pop(); + if ( !ok ) // error already set + return recoverFromError( tokenObjectEnd ); + + Token comma; + if ( !readToken( comma ) + || ( comma.type_ != tokenObjectEnd && + comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment ) ) + { + return addErrorAndRecover( "Missing ',' or '}' in object declaration", + comma, + tokenObjectEnd ); + } + bool finalizeTokenOk = true; + while ( comma.type_ == tokenComment && + finalizeTokenOk ) + finalizeTokenOk = readToken( comma ); + if ( comma.type_ == tokenObjectEnd ) + return true; + } + return addErrorAndRecover( "Missing '}' or object member name", + tokenName, + tokenObjectEnd ); +} + + +bool +Reader::readArray( Token &tokenStart ) +{ + currentValue() = Value( arrayValue ); + skipSpaces(); + if ( *current_ == ']' ) // empty array + { + Token endArray; + readToken( endArray ); + return true; + } + int index = 0; + while ( true ) + { + Value &value = currentValue()[ index++ ]; + nodes_.push( &value ); + bool ok = readValue(); + nodes_.pop(); + if ( !ok ) // error already set + return recoverFromError( tokenArrayEnd ); + + Token token; + // Accept Comment after last item in the array. + ok = readToken( token ); + while ( token.type_ == tokenComment && ok ) + { + ok = readToken( token ); + } + bool badTokenType = ( token.type_ == tokenArraySeparator && + token.type_ == tokenArrayEnd ); + if ( !ok || badTokenType ) + { + return addErrorAndRecover( "Missing ',' or ']' in array declaration", + token, + tokenArrayEnd ); + } + if ( token.type_ == tokenArrayEnd ) + break; + } + return true; +} + + +bool +Reader::decodeNumber( Token &token ) +{ + bool isDouble = false; + for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) + { + isDouble = isDouble + || in( *inspect, '.', 'e', 'E', '+' ) + || ( *inspect == '-' && inspect != token.start_ ); + } + if ( isDouble ) + return decodeDouble( token ); + Location current = token.start_; + bool isNegative = *current == '-'; + if ( isNegative ) + ++current; + Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) + : Value::maxUInt) / 10; + Value::UInt value = 0; + while ( current < token.end_ ) + { + Char c = *current++; + if ( c < '0' || c > '9' ) + return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); + if ( value >= threshold ) + return decodeDouble( token ); + value = value * 10 + Value::UInt(c - '0'); + } + if ( isNegative ) + currentValue() = -Value::Int( value ); + else if ( value <= Value::UInt(Value::maxInt) ) + currentValue() = Value::Int( value ); + else + currentValue() = value; + return true; +} + + +bool +Reader::decodeDouble( Token &token ) +{ + double value = 0; + const int bufferSize = 32; + int count; + int length = int(token.end_ - token.start_); + if ( length <= bufferSize ) + { + Char buffer[bufferSize]; + memcpy( buffer, token.start_, length ); + buffer[length] = 0; + count = sscanf( buffer, "%lf", &value ); + } + else + { + std::string buffer( token.start_, token.end_ ); + count = sscanf( buffer.c_str(), "%lf", &value ); + } + + if ( count != 1 ) + return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); + currentValue() = value; + return true; +} + + +bool +Reader::decodeString( Token &token ) +{ + std::string decoded; + if ( !decodeString( token, decoded ) ) + return false; + currentValue() = decoded; + return true; +} + + +bool +Reader::decodeString( Token &token, std::string &decoded ) +{ + decoded.reserve( token.end_ - token.start_ - 2 ); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while ( current != end ) + { + Char c = *current++; + if ( c == '"' ) + break; + else if ( c == '\\' ) + { + if ( current == end ) + return addError( "Empty escape sequence in string", token, current ); + Char escape = *current++; + switch ( escape ) + { + case '"': decoded += '"'; break; + case '/': decoded += '/'; break; + case '\\': decoded += '\\'; break; + case 'b': decoded += '\b'; break; + case 'f': decoded += '\f'; break; + case 'n': decoded += '\n'; break; + case 'r': decoded += '\r'; break; + case 't': decoded += '\t'; break; + case 'u': + { + unsigned int unicode; + if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) + return false; + decoded += codePointToUTF8(unicode); + } + break; + default: + return addError( "Bad escape sequence in string", token, current ); + } + } + else + { + decoded += c; + } + } + return true; +} + +bool +Reader::decodeUnicodeCodePoint( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ) +{ + + if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) + { + // surrogate pairs + if (end - current < 6) + return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); + unsigned int surrogatePair; + if (*(current++) == '\\' && *(current++)== 'u') + { + if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) + { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } + else + return false; + } + else + return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); + } + return true; +} + +bool +Reader::decodeUnicodeEscapeSequence( Token &token, + Location ¤t, + Location end, + unsigned int &unicode ) +{ + if ( end - current < 4 ) + return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); + unicode = 0; + for ( int index =0; index < 4; ++index ) + { + Char c = *current++; + unicode *= 16; + if ( c >= '0' && c <= '9' ) + unicode += c - '0'; + else if ( c >= 'a' && c <= 'f' ) + unicode += c - 'a' + 10; + else if ( c >= 'A' && c <= 'F' ) + unicode += c - 'A' + 10; + else + return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); + } + return true; +} + + +bool +Reader::addError( const std::string &message, + Token &token, + Location extra ) +{ + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back( info ); + return false; +} + + +bool +Reader::recoverFromError( TokenType skipUntilToken ) +{ + int errorCount = int(errors_.size()); + Token skip; + while ( true ) + { + if ( !readToken(skip) ) + errors_.resize( errorCount ); // discard errors caused by recovery + if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) + break; + } + errors_.resize( errorCount ); + return false; +} + + +bool +Reader::addErrorAndRecover( const std::string &message, + Token &token, + TokenType skipUntilToken ) +{ + addError( message, token ); + return recoverFromError( skipUntilToken ); +} + + +Value & +Reader::currentValue() +{ + return *(nodes_.top()); +} + + +Reader::Char +Reader::getNextChar() +{ + if ( current_ == end_ ) + return 0; + return *current_++; +} + + +void +Reader::getLocationLineAndColumn( Location location, + int &line, + int &column ) const +{ + Location current = begin_; + Location lastLineStart = current; + line = 0; + while ( current < location && current != end_ ) + { + Char c = *current++; + if ( c == '\r' ) + { + if ( *current == '\n' ) + ++current; + lastLineStart = current; + ++line; + } + else if ( c == '\n' ) + { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + + +std::string +Reader::getLocationLineAndColumn( Location location ) const +{ + int line, column; + getLocationLineAndColumn( location, line, column ); + char buffer[18+16+16+1]; + sprintf( buffer, "Line %d, Column %d", line, column ); + return buffer; +} + + +std::string +Reader::getFormatedErrorMessages() const +{ + std::string formattedMessage; + for ( Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError ) + { + const ErrorInfo &error = *itError; + formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if ( error.extra_ ) + formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; + } + return formattedMessage; +} + + +std::istream& operator>>( std::istream &sin, Value &root ) +{ + Json::Reader reader; + bool ok = reader.parse(sin, root, true); + //JSON_ASSERT( ok ); +// if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages()); + assert(ok); + return sin; +} + + +} // namespace Json diff --git a/src/jsoncpp/src/lib_json/json_value.cpp b/src/jsoncpp/src/lib_json/json_value.cpp index fd773ec119..edc5ebadc4 100644 --- a/src/jsoncpp/src/lib_json/json_value.cpp +++ b/src/jsoncpp/src/lib_json/json_value.cpp @@ -1,1718 +1,1718 @@ -#include <iostream> -#include <jsoncpp/include/json/value.h> -#include <jsoncpp/include/json/writer.h> -#include <utility> -#include <stdexcept> -#include <cstring> -#include <cassert> -#ifdef JSON_USE_CPPTL -# include <cpptl/conststring.h> -#endif -#include <cstddef> // size_t -#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR -# include "json_batchallocator.h" -#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR - -#define JSON_ASSERT_UNREACHABLE assert( false ) -#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw -#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) assert(false); /* throw std::runtime_error( message ); */ - -namespace Json { - -const Value Value::null; -const Int Value::minInt = Int( ~(UInt(-1)/2) ); -const Int Value::maxInt = Int( UInt(-1)/2 ); -const UInt Value::maxUInt = UInt(-1); - -// A "safe" implementation of strdup. Allow null pointer to be passed. -// Also avoid warning on msvc80. -// -//inline char *safeStringDup( const char *czstring ) -//{ -// if ( czstring ) -// { -// const size_t length = (unsigned int)( strlen(czstring) + 1 ); -// char *newString = static_cast<char *>( malloc( length ) ); -// memcpy( newString, czstring, length ); -// return newString; -// } -// return 0; -//} -// -//inline char *safeStringDup( const std::string &str ) -//{ -// if ( !str.empty() ) -// { -// const size_t length = str.length(); -// char *newString = static_cast<char *>( malloc( length + 1 ) ); -// memcpy( newString, str.c_str(), length ); -// newString[length] = 0; -// return newString; -// } -// return 0; -//} - -ValueAllocator::~ValueAllocator() -{ -} - -class DefaultValueAllocator : public ValueAllocator -{ -public: - virtual ~DefaultValueAllocator() - { - } - - virtual char *makeMemberName( const char *memberName ) - { - return duplicateStringValue( memberName ); - } - - virtual void releaseMemberName( char *memberName ) - { - releaseStringValue( memberName ); - } - - virtual char *duplicateStringValue( const char *value, - unsigned int length = unknown ) - { - //@todo invesgate this old optimization - //if ( !value || value[0] == 0 ) - // return 0; - - if ( length == unknown ) - length = (unsigned int)strlen(value); - char *newString = static_cast<char *>( malloc( length + 1 ) ); - memcpy( newString, value, length ); - newString[length] = 0; - return newString; - } - - virtual void releaseStringValue( char *value ) - { - if ( value ) - free( value ); - } -}; - -static ValueAllocator *&valueAllocator() -{ - static DefaultValueAllocator defaultAllocator; - static ValueAllocator *valueAllocator = &defaultAllocator; - return valueAllocator; -} - -static struct DummyValueAllocatorInitializer { - DummyValueAllocatorInitializer() - { - valueAllocator(); // ensure valueAllocator() statics are initialized before main(). - } -} dummyValueAllocatorInitializer; - - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ValueInternals... -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -#ifdef JSON_VALUE_USE_INTERNAL_MAP -# include "json_internalarray.inl" -# include "json_internalmap.inl" -#endif // JSON_VALUE_USE_INTERNAL_MAP - -# include "json_valueiterator.inl" - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CommentInfo -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - - -Value::CommentInfo::CommentInfo() - : comment_( 0 ) -{ -} - -Value::CommentInfo::~CommentInfo() -{ - if ( comment_ ) - valueAllocator()->releaseStringValue( comment_ ); -} - - -void -Value::CommentInfo::setComment( const char *text ) -{ - if ( comment_ ) - valueAllocator()->releaseStringValue( comment_ ); - JSON_ASSERT( text ); - JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); - // It seems that /**/ style comments are acceptable as well. - comment_ = valueAllocator()->duplicateStringValue( text ); -} - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CZString -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -# ifndef JSON_VALUE_USE_INTERNAL_MAP - -// Notes: index_ indicates if the string was allocated when -// a string is stored. - -Value::CZString::CZString( int index ) - : cstr_( 0 ) - , index_( index ) -{ -} - -Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) - : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr) - : cstr ) - , index_( allocate ) -{ -} - -Value::CZString::CZString( const CZString &other ) -: cstr_( other.index_ != noDuplication && other.cstr_ != 0 - ? valueAllocator()->makeMemberName( other.cstr_ ) - : other.cstr_ ) - , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) - : other.index_ ) -{ -} - -Value::CZString::~CZString() -{ - if ( cstr_ && index_ == duplicate ) - valueAllocator()->releaseMemberName( const_cast<char *>( cstr_ ) ); -} - -void -Value::CZString::swap( CZString &other ) -{ - std::swap( cstr_, other.cstr_ ); - std::swap( index_, other.index_ ); -} - -Value::CZString & -Value::CZString::operator =( const CZString &other ) -{ - CZString temp( other ); - swap( temp ); - return *this; -} - -bool -Value::CZString::operator<( const CZString &other ) const -{ - if ( cstr_ ) - return strcmp( cstr_, other.cstr_ ) < 0; - return index_ < other.index_; -} - -bool -Value::CZString::operator==( const CZString &other ) const -{ - if ( cstr_ ) - return strcmp( cstr_, other.cstr_ ) == 0; - return index_ == other.index_; -} - - -int -Value::CZString::index() const -{ - return index_; -} - - -const char * -Value::CZString::c_str() const -{ - return cstr_; -} - -bool -Value::CZString::isStaticString() const -{ - return index_ == noDuplication; -} - -#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP - - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::Value -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -/*! \internal Default constructor initialization must be equivalent to: - * memset( this, 0, sizeof(Value) ) - * This optimization is used in ValueInternalMap fast allocator. - */ -Value::Value( ValueType type ) - : type_( type ) - , allocated_( 0 ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - switch ( type ) - { - case nullValue: - break; - case intValue: - case uintValue: - value_.int_ = 0; - break; - case realValue: - value_.real_ = 0.0; - break; - case stringValue: - value_.string_ = 0; - break; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(); - break; -#else - case arrayValue: - value_.array_ = arrayAllocator()->newArray(); - break; - case objectValue: - value_.map_ = mapAllocator()->newMap(); - break; -#endif - case booleanValue: - value_.bool_ = false; - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - - -Value::Value( Int value ) - : type_( intValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.int_ = value; -} - - -Value::Value( UInt value ) - : type_( uintValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.uint_ = value; -} - -Value::Value( double value ) - : type_( realValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.real_ = value; -} - -Value::Value( const char *value ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = valueAllocator()->duplicateStringValue( value ); -} - - -Value::Value( const char *beginValue, - const char *endValue ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = valueAllocator()->duplicateStringValue( beginValue, - UInt(endValue - beginValue) ); -} - - -Value::Value( const std::string &value ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(), - (unsigned int)value.length() ); - -} - -Value::Value( const StaticString &value ) - : type_( stringValue ) - , allocated_( false ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = const_cast<char *>( value.c_str() ); -} - - -# ifdef JSON_USE_CPPTL -Value::Value( const CppTL::ConstString &value ) - : type_( stringValue ) - , allocated_( true ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() ); -} -# endif - -Value::Value( bool value ) - : type_( booleanValue ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - value_.bool_ = value; -} - - -Value::Value( const Value &other ) - : type_( other.type_ ) - , comments_( 0 ) -# ifdef JSON_VALUE_USE_INTERNAL_MAP - , itemIsUsed_( 0 ) -#endif -{ - switch ( type_ ) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - value_ = other.value_; - break; - case stringValue: - if ( other.value_.string_ ) - { - value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ ); - allocated_ = true; - } - else - value_.string_ = 0; - break; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues( *other.value_.map_ ); - break; -#else - case arrayValue: - value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); - break; - case objectValue: - value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); - break; -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - if ( other.comments_ ) - { - comments_ = new CommentInfo[numberOfCommentPlacement]; - for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) - { - const CommentInfo &otherComment = other.comments_[comment]; - if ( otherComment.comment_ ) - comments_[comment].setComment( otherComment.comment_ ); - } - } -} - - -Value::~Value() -{ - switch ( type_ ) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue: - if ( allocated_ ) - valueAllocator()->releaseStringValue( value_.string_ ); - break; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - delete value_.map_; - break; -#else - case arrayValue: - arrayAllocator()->destructArray( value_.array_ ); - break; - case objectValue: - mapAllocator()->destructMap( value_.map_ ); - break; -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - - if ( comments_ ) - delete[] comments_; -} - -Value & -Value::operator=( const Value &other ) -{ - Value temp( other ); - swap( temp ); - return *this; -} - -void -Value::swap( Value &other ) -{ - ValueType temp = type_; - type_ = other.type_; - other.type_ = temp; - std::swap( value_, other.value_ ); - int temp2 = allocated_; - allocated_ = other.allocated_; - other.allocated_ = temp2; -} - -ValueType -Value::type() const -{ - return type_; -} - - -int -Value::compare( const Value &other ) -{ - /* - int typeDelta = other.type_ - type_; - switch ( type_ ) - { - case nullValue: - - return other.type_ == type_; - case intValue: - if ( other.type_.isNumeric() - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue, - break; - case arrayValue: - delete value_.array_; - break; - case objectValue: - delete value_.map_; - default: - JSON_ASSERT_UNREACHABLE; - } - */ - return 0; // unreachable -} - -bool -Value::operator <( const Value &other ) const -{ - int typeDelta = type_ - other.type_; - if ( typeDelta ) - return typeDelta < 0 ? true : false; - switch ( type_ ) - { - case nullValue: - return false; - case intValue: - return value_.int_ < other.value_.int_; - case uintValue: - return value_.uint_ < other.value_.uint_; - case realValue: - return value_.real_ < other.value_.real_; - case booleanValue: - return value_.bool_ < other.value_.bool_; - case stringValue: - return ( value_.string_ == 0 && other.value_.string_ ) - || ( other.value_.string_ - && value_.string_ - && strcmp( value_.string_, other.value_.string_ ) < 0 ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - { - int delta = int( value_.map_->size() - other.value_.map_->size() ); - if ( delta ) - return delta < 0; - return (*value_.map_) < (*other.value_.map_); - } -#else - case arrayValue: - return value_.array_->compare( *(other.value_.array_) ) < 0; - case objectValue: - return value_.map_->compare( *(other.value_.map_) ) < 0; -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable -} - -bool -Value::operator <=( const Value &other ) const -{ - return !(other > *this); -} - -bool -Value::operator >=( const Value &other ) const -{ - return !(*this < other); -} - -bool -Value::operator >( const Value &other ) const -{ - return other < *this; -} - -bool -Value::operator ==( const Value &other ) const -{ - //if ( type_ != other.type_ ) - // GCC 2.95.3 says: - // attempt to take address of bit-field structure member `Json::Value::type_' - // Beats me, but a temp solves the problem. - int temp = other.type_; - if ( type_ != temp ) - return false; - switch ( type_ ) - { - case nullValue: - return true; - case intValue: - return value_.int_ == other.value_.int_; - case uintValue: - return value_.uint_ == other.value_.uint_; - case realValue: - return value_.real_ == other.value_.real_; - case booleanValue: - return value_.bool_ == other.value_.bool_; - case stringValue: - return ( value_.string_ == other.value_.string_ ) - || ( other.value_.string_ - && value_.string_ - && strcmp( value_.string_, other.value_.string_ ) == 0 ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - return value_.map_->size() == other.value_.map_->size() - && (*value_.map_) == (*other.value_.map_); -#else - case arrayValue: - return value_.array_->compare( *(other.value_.array_) ) == 0; - case objectValue: - return value_.map_->compare( *(other.value_.map_) ) == 0; -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable -} - -bool -Value::operator !=( const Value &other ) const -{ - return !( *this == other ); -} - -const char * -Value::asCString() const -{ - JSON_ASSERT( type_ == stringValue ); - return value_.string_; -} - - -std::string -Value::asString() const -{ - switch ( type_ ) - { - case nullValue: - return ""; - case stringValue: - return value_.string_ ? value_.string_ : ""; - case booleanValue: - return value_.bool_ ? "true" : "false"; - case intValue: - case uintValue: - case realValue: - case arrayValue: - case objectValue: - JSON_ASSERT_MESSAGE( false, "Type is not convertible to string" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return ""; // unreachable -} - -# ifdef JSON_USE_CPPTL -CppTL::ConstString -Value::asConstString() const -{ - return CppTL::ConstString( asString().c_str() ); -} -# endif - -Value::Int -Value::asInt() const -{ - switch ( type_ ) - { - case nullValue: - return 0; - case intValue: - return value_.int_; - case uintValue: - JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" ); - return value_.uint_; - case realValue: - JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); - return Int( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - JSON_ASSERT_MESSAGE( false, "Type is not convertible to int" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - -Value::UInt -Value::asUInt() const -{ - switch ( type_ ) - { - case nullValue: - return 0; - case intValue: - JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); - return value_.int_; - case uintValue: - return value_.uint_; - case realValue: - JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); - return UInt( value_.real_ ); - case booleanValue: - return value_.bool_ ? 1 : 0; - case stringValue: - case arrayValue: - case objectValue: - JSON_ASSERT_MESSAGE( false, "Type is not convertible to uint" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - -double -Value::asDouble() const -{ - switch ( type_ ) - { - case nullValue: - return 0.0; - case intValue: - return value_.int_; - case uintValue: - return value_.uint_; - case realValue: - return value_.real_; - case booleanValue: - return value_.bool_ ? 1.0 : 0.0; - case stringValue: - case arrayValue: - case objectValue: - JSON_ASSERT_MESSAGE( false, "Type is not convertible to double" ); - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - -bool -Value::asBool() const -{ - switch ( type_ ) - { - case nullValue: - return false; - case intValue: - case uintValue: - return value_.int_ != 0; - case realValue: - return value_.real_ != 0.0; - case booleanValue: - return value_.bool_; - case stringValue: - return value_.string_ && value_.string_[0] != 0; - case arrayValue: - case objectValue: - return value_.map_->size() != 0; - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable; -} - - -bool -Value::isConvertibleTo( ValueType other ) const -{ - switch ( type_ ) - { - case nullValue: - return true; - case intValue: - return ( other == nullValue && value_.int_ == 0 ) - || other == intValue - || ( other == uintValue && value_.int_ >= 0 ) - || other == realValue - || other == stringValue - || other == booleanValue; - case uintValue: - return ( other == nullValue && value_.uint_ == 0 ) - || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) - || other == uintValue - || other == realValue - || other == stringValue - || other == booleanValue; - case realValue: - return ( other == nullValue && value_.real_ == 0.0 ) - || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) - || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) - || other == realValue - || other == stringValue - || other == booleanValue; - case booleanValue: - return ( other == nullValue && value_.bool_ == false ) - || other == intValue - || other == uintValue - || other == realValue - || other == stringValue - || other == booleanValue; - case stringValue: - return other == stringValue - || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); - case arrayValue: - return other == arrayValue - || ( other == nullValue && value_.map_->size() == 0 ); - case objectValue: - return other == objectValue - || ( other == nullValue && value_.map_->size() == 0 ); - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable; -} - - -/// Number of values in array or object -Value::UInt -Value::size() const -{ - switch ( type_ ) - { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - case stringValue: - return 0; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: // size of the array is highest index + 1 - if ( !value_.map_->empty() ) - { - ObjectValues::const_iterator itLast = value_.map_->end(); - --itLast; - return (*itLast).first.index()+1; - } - return 0; - case objectValue: - return Int( value_.map_->size() ); -#else - case arrayValue: - return Int( value_.array_->size() ); - case objectValue: - return Int( value_.map_->size() ); -#endif - default: - JSON_ASSERT_UNREACHABLE; - } - return 0; // unreachable; -} - - -bool -Value::empty() const -{ - if ( isNull() || isArray() || isObject() ) - return size() == 0u; - else - return false; -} - - -bool -Value::operator!() const -{ - return isNull(); -} - - -void -Value::clear() -{ - JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); - - switch ( type_ ) - { -#ifndef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - case objectValue: - value_.map_->clear(); - break; -#else - case arrayValue: - value_.array_->clear(); - break; - case objectValue: - value_.map_->clear(); - break; -#endif - default: - break; - } -} - -void -Value::resize( UInt newSize ) -{ - JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); - if ( type_ == nullValue ) - *this = Value( arrayValue ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - UInt oldSize = size(); - if ( newSize == 0 ) - clear(); - else if ( newSize > oldSize ) - (*this)[ newSize - 1 ]; - else - { - for ( UInt index = newSize; index < oldSize; ++index ) - value_.map_->erase( index ); - assert( size() == newSize ); - } -#else - value_.array_->resize( newSize ); -#endif -} - - -Value & -Value::operator[]( UInt index ) -{ - JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); - if ( type_ == nullValue ) - *this = Value( arrayValue ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString key( index ); - ObjectValues::iterator it = value_.map_->lower_bound( key ); - if ( it != value_.map_->end() && (*it).first == key ) - return (*it).second; - - ObjectValues::value_type defaultValue( key, null ); - it = value_.map_->insert( it, defaultValue ); - return (*it).second; -#else - return value_.array_->resolveReference( index ); -#endif -} - - -const Value & -Value::operator[]( UInt index ) const -{ - JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); - if ( type_ == nullValue ) - return null; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString key( index ); - ObjectValues::const_iterator it = value_.map_->find( key ); - if ( it == value_.map_->end() ) - return null; - return (*it).second; -#else - Value *value = value_.array_->find( index ); - return value ? *value : null; -#endif -} - - -Value & -Value::operator[]( const char *key ) -{ - return resolveReference( key, false ); -} - - -Value & -Value::resolveReference( const char *key, - bool isStatic ) -{ - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - *this = Value( objectValue ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString actualKey( key, isStatic ? CZString::noDuplication - : CZString::duplicateOnCopy ); - ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); - if ( it != value_.map_->end() && (*it).first == actualKey ) - return (*it).second; - - ObjectValues::value_type defaultValue( actualKey, null ); - it = value_.map_->insert( it, defaultValue ); - Value &value = (*it).second; - return value; -#else - return value_.map_->resolveReference( key, isStatic ); -#endif -} - - -Value -Value::get( UInt index, - const Value &defaultValue ) const -{ - const Value *value = &((*this)[index]); - return value == &null ? defaultValue : *value; -} - - -bool -Value::isValidIndex( UInt index ) const -{ - return index < size(); -} - - - -const Value & -Value::operator[]( const char *key ) const -{ - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - return null; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString actualKey( key, CZString::noDuplication ); - ObjectValues::const_iterator it = value_.map_->find( actualKey ); - if ( it == value_.map_->end() ) - return null; - return (*it).second; -#else - const Value *value = value_.map_->find( key ); - return value ? *value : null; -#endif -} - - -Value & -Value::operator[]( const std::string &key ) -{ - return (*this)[ key.c_str() ]; -} - - -const Value & -Value::operator[]( const std::string &key ) const -{ - return (*this)[ key.c_str() ]; -} - -Value & -Value::operator[]( const StaticString &key ) -{ - return resolveReference( key, true ); -} - - -# ifdef JSON_USE_CPPTL -Value & -Value::operator[]( const CppTL::ConstString &key ) -{ - return (*this)[ key.c_str() ]; -} - - -const Value & -Value::operator[]( const CppTL::ConstString &key ) const -{ - return (*this)[ key.c_str() ]; -} -# endif - - -Value & -Value::append( const Value &value ) -{ - return (*this)[size()] = value; -} - - -Value -Value::get( const char *key, - const Value &defaultValue ) const -{ - const Value *value = &((*this)[key]); - return value == &null ? defaultValue : *value; -} - - -Value -Value::get( const std::string &key, - const Value &defaultValue ) const -{ - return get( key.c_str(), defaultValue ); -} - -Value -Value::removeMember( const char* key ) -{ - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - return null; -#ifndef JSON_VALUE_USE_INTERNAL_MAP - CZString actualKey( key, CZString::noDuplication ); - ObjectValues::iterator it = value_.map_->find( actualKey ); - if ( it == value_.map_->end() ) - return null; - Value old(it->second); - value_.map_->erase(it); - return old; -#else - Value *value = value_.map_->find( key ); - if (value){ - Value old(*value); - value_.map_.remove( key ); - return old; - } else { - return null; - } -#endif -} - -Value -Value::removeMember( const std::string &key ) -{ - return removeMember( key.c_str() ); -} - -# ifdef JSON_USE_CPPTL -Value -Value::get( const CppTL::ConstString &key, - const Value &defaultValue ) const -{ - return get( key.c_str(), defaultValue ); -} -# endif - -bool -Value::isMember( const char *key ) const -{ - const Value *value = &((*this)[key]); - return value != &null; -} - - -bool -Value::isMember( const std::string &key ) const -{ - return isMember( key.c_str() ); -} - - -# ifdef JSON_USE_CPPTL -bool -Value::isMember( const CppTL::ConstString &key ) const -{ - return isMember( key.c_str() ); -} -#endif - -Value::Members -Value::getMemberNames() const -{ - JSON_ASSERT( type_ == nullValue || type_ == objectValue ); - if ( type_ == nullValue ) - return Value::Members(); - Members members; - members.reserve( value_.map_->size() ); -#ifndef JSON_VALUE_USE_INTERNAL_MAP - ObjectValues::const_iterator it = value_.map_->begin(); - ObjectValues::const_iterator itEnd = value_.map_->end(); - for ( ; it != itEnd; ++it ) - members.push_back( std::string( (*it).first.c_str() ) ); -#else - ValueInternalMap::IteratorState it; - ValueInternalMap::IteratorState itEnd; - value_.map_->makeBeginIterator( it ); - value_.map_->makeEndIterator( itEnd ); - for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) - members.push_back( std::string( ValueInternalMap::key( it ) ) ); -#endif - return members; -} -// -//# ifdef JSON_USE_CPPTL -//EnumMemberNames -//Value::enumMemberNames() const -//{ -// if ( type_ == objectValue ) -// { -// return CppTL::Enum::any( CppTL::Enum::transform( -// CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ), -// MemberNamesTransform() ) ); -// } -// return EnumMemberNames(); -//} -// -// -//EnumValues -//Value::enumValues() const -//{ -// if ( type_ == objectValue || type_ == arrayValue ) -// return CppTL::Enum::anyValues( *(value_.map_), -// CppTL::Type<const Value &>() ); -// return EnumValues(); -//} -// -//# endif - - -bool -Value::isNull() const -{ - return type_ == nullValue; -} - - -bool -Value::isBool() const -{ - return type_ == booleanValue; -} - - -bool -Value::isInt() const -{ - return type_ == intValue; -} - - -bool -Value::isUInt() const -{ - return type_ == uintValue; -} - - -bool -Value::isIntegral() const -{ - return type_ == intValue - || type_ == uintValue - || type_ == booleanValue; -} - - -bool -Value::isDouble() const -{ - return type_ == realValue; -} - - -bool -Value::isNumeric() const -{ - return isIntegral() || isDouble(); -} - - -bool -Value::isString() const -{ - return type_ == stringValue; -} - - -bool -Value::isArray() const -{ - return type_ == nullValue || type_ == arrayValue; -} - - -bool -Value::isObject() const -{ - return type_ == nullValue || type_ == objectValue; -} - - -void -Value::setComment( const char *comment, - CommentPlacement placement ) -{ - if ( !comments_ ) - comments_ = new CommentInfo[numberOfCommentPlacement]; - comments_[placement].setComment( comment ); -} - - -void -Value::setComment( const std::string &comment, - CommentPlacement placement ) -{ - setComment( comment.c_str(), placement ); -} - - -bool -Value::hasComment( CommentPlacement placement ) const -{ - return comments_ != 0 && comments_[placement].comment_ != 0; -} - -std::string -Value::getComment( CommentPlacement placement ) const -{ - if ( hasComment(placement) ) - return comments_[placement].comment_; - return ""; -} - - -std::string -Value::toStyledString() const -{ - StyledWriter writer; - return writer.write( *this ); -} - - -Value::const_iterator -Value::begin() const -{ - switch ( type_ ) - { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeBeginIterator( it ); - return const_iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeBeginIterator( it ); - return const_iterator( it ); - } - break; -#else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return const_iterator( value_.map_->begin() ); - break; -#endif - default: - break; - } - return const_iterator(); -} - -Value::const_iterator -Value::end() const -{ - switch ( type_ ) - { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeEndIterator( it ); - return const_iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeEndIterator( it ); - return const_iterator( it ); - } - break; -#else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return const_iterator( value_.map_->end() ); - break; -#endif - default: - break; - } - return const_iterator(); -} - - -Value::iterator -Value::begin() -{ - switch ( type_ ) - { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeBeginIterator( it ); - return iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeBeginIterator( it ); - return iterator( it ); - } - break; -#else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return iterator( value_.map_->begin() ); - break; -#endif - default: - break; - } - return iterator(); -} - -Value::iterator -Value::end() -{ - switch ( type_ ) - { -#ifdef JSON_VALUE_USE_INTERNAL_MAP - case arrayValue: - if ( value_.array_ ) - { - ValueInternalArray::IteratorState it; - value_.array_->makeEndIterator( it ); - return iterator( it ); - } - break; - case objectValue: - if ( value_.map_ ) - { - ValueInternalMap::IteratorState it; - value_.map_->makeEndIterator( it ); - return iterator( it ); - } - break; -#else - case arrayValue: - case objectValue: - if ( value_.map_ ) - return iterator( value_.map_->end() ); - break; -#endif - default: - break; - } - return iterator(); -} - - -// class PathArgument -// ////////////////////////////////////////////////////////////////// - -PathArgument::PathArgument() - : kind_( kindNone ) -{ -} - - -PathArgument::PathArgument( Value::UInt index ) - : index_( index ) - , kind_( kindIndex ) -{ -} - - -PathArgument::PathArgument( const char *key ) - : key_( key ) - , kind_( kindKey ) -{ -} - - -PathArgument::PathArgument( const std::string &key ) - : key_( key.c_str() ) - , kind_( kindKey ) -{ -} - -// class Path -// ////////////////////////////////////////////////////////////////// - -Path::Path( const std::string &path, - const PathArgument &a1, - const PathArgument &a2, - const PathArgument &a3, - const PathArgument &a4, - const PathArgument &a5 ) -{ - InArgs in; - in.push_back( &a1 ); - in.push_back( &a2 ); - in.push_back( &a3 ); - in.push_back( &a4 ); - in.push_back( &a5 ); - makePath( path, in ); -} - - -void -Path::makePath( const std::string &path, - const InArgs &in ) -{ - const char *current = path.c_str(); - const char *end = current + path.length(); - InArgs::const_iterator itInArg = in.begin(); - while ( current != end ) - { - if ( *current == '[' ) - { - ++current; - if ( *current == '%' ) - addPathInArg( path, in, itInArg, PathArgument::kindIndex ); - else - { - Value::UInt index = 0; - for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) - index = index * 10 + Value::UInt(*current - '0'); - args_.push_back( index ); - } - if ( current == end || *current++ != ']' ) - invalidPath( path, int(current - path.c_str()) ); - } - else if ( *current == '%' ) - { - addPathInArg( path, in, itInArg, PathArgument::kindKey ); - ++current; - } - else if ( *current == '.' ) - { - ++current; - } - else - { - const char *beginName = current; - while ( current != end && !strchr( "[.", *current ) ) - ++current; - args_.push_back( std::string( beginName, current ) ); - } - } -} - - -void -Path::addPathInArg( const std::string &path, - const InArgs &in, - InArgs::const_iterator &itInArg, - PathArgument::Kind kind ) -{ - if ( itInArg == in.end() ) - { - // Error: missing argument %d - } - else if ( (*itInArg)->kind_ != kind ) - { - // Error: bad argument type - } - else - { - args_.push_back( **itInArg ); - } -} - - -void -Path::invalidPath( const std::string &path, - int location ) -{ - // Error: invalid path. -} - - -const Value & -Path::resolve( const Value &root ) const -{ - const Value *node = &root; - for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) - { - const PathArgument &arg = *it; - if ( arg.kind_ == PathArgument::kindIndex ) - { - if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) - { - // Error: unable to resolve path (array value expected at position... - } - node = &((*node)[arg.index_]); - } - else if ( arg.kind_ == PathArgument::kindKey ) - { - if ( !node->isObject() ) - { - // Error: unable to resolve path (object value expected at position...) - } - node = &((*node)[arg.key_]); - if ( node == &Value::null ) - { - // Error: unable to resolve path (object has no member named '' at position...) - } - } - } - return *node; -} - - -Value -Path::resolve( const Value &root, - const Value &defaultValue ) const -{ - const Value *node = &root; - for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) - { - const PathArgument &arg = *it; - if ( arg.kind_ == PathArgument::kindIndex ) - { - if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) - return defaultValue; - node = &((*node)[arg.index_]); - } - else if ( arg.kind_ == PathArgument::kindKey ) - { - if ( !node->isObject() ) - return defaultValue; - node = &((*node)[arg.key_]); - if ( node == &Value::null ) - return defaultValue; - } - } - return *node; -} - - -Value & -Path::make( Value &root ) const -{ - Value *node = &root; - for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) - { - const PathArgument &arg = *it; - if ( arg.kind_ == PathArgument::kindIndex ) - { - if ( !node->isArray() ) - { - // Error: node is not an array at position ... - } - node = &((*node)[arg.index_]); - } - else if ( arg.kind_ == PathArgument::kindKey ) - { - if ( !node->isObject() ) - { - // Error: node is not an object at position... - } - node = &((*node)[arg.key_]); - } - } - return *node; -} - - -} // namespace Json +#include <iostream> +#include <jsoncpp/include/json/value.h> +#include <jsoncpp/include/json/writer.h> +#include <utility> +#include <stdexcept> +#include <cstring> +#include <cassert> +#ifdef JSON_USE_CPPTL +# include <cpptl/conststring.h> +#endif +#include <cstddef> // size_t +#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR +# include "json_batchallocator.h" +#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR + +#define JSON_ASSERT_UNREACHABLE assert( false ) +#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw +#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) assert(false); /* throw std::runtime_error( message ); */ + +namespace Json { + +const Value Value::null; +const Int Value::minInt = Int( ~(UInt(-1)/2) ); +const Int Value::maxInt = Int( UInt(-1)/2 ); +const UInt Value::maxUInt = UInt(-1); + +// A "safe" implementation of strdup. Allow null pointer to be passed. +// Also avoid warning on msvc80. +// +//inline char *safeStringDup( const char *czstring ) +//{ +// if ( czstring ) +// { +// const size_t length = (unsigned int)( strlen(czstring) + 1 ); +// char *newString = static_cast<char *>( malloc( length ) ); +// memcpy( newString, czstring, length ); +// return newString; +// } +// return 0; +//} +// +//inline char *safeStringDup( const std::string &str ) +//{ +// if ( !str.empty() ) +// { +// const size_t length = str.length(); +// char *newString = static_cast<char *>( malloc( length + 1 ) ); +// memcpy( newString, str.c_str(), length ); +// newString[length] = 0; +// return newString; +// } +// return 0; +//} + +ValueAllocator::~ValueAllocator() +{ +} + +class DefaultValueAllocator : public ValueAllocator +{ +public: + virtual ~DefaultValueAllocator() + { + } + + virtual char *makeMemberName( const char *memberName ) + { + return duplicateStringValue( memberName ); + } + + virtual void releaseMemberName( char *memberName ) + { + releaseStringValue( memberName ); + } + + virtual char *duplicateStringValue( const char *value, + unsigned int length = unknown ) + { + //@todo invesgate this old optimization + //if ( !value || value[0] == 0 ) + // return 0; + + if ( length == unknown ) + length = (unsigned int)strlen(value); + char *newString = static_cast<char *>( malloc( length + 1 ) ); + memcpy( newString, value, length ); + newString[length] = 0; + return newString; + } + + virtual void releaseStringValue( char *value ) + { + if ( value ) + free( value ); + } +}; + +static ValueAllocator *&valueAllocator() +{ + static DefaultValueAllocator defaultAllocator; + static ValueAllocator *valueAllocator = &defaultAllocator; + return valueAllocator; +} + +static struct DummyValueAllocatorInitializer { + DummyValueAllocatorInitializer() + { + valueAllocator(); // ensure valueAllocator() statics are initialized before main(). + } +} dummyValueAllocatorInitializer; + + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#ifdef JSON_VALUE_USE_INTERNAL_MAP +# include "json_internalarray.inl" +# include "json_internalmap.inl" +#endif // JSON_VALUE_USE_INTERNAL_MAP + +# include "json_valueiterator.inl" + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + + +Value::CommentInfo::CommentInfo() + : comment_( 0 ) +{ +} + +Value::CommentInfo::~CommentInfo() +{ + if ( comment_ ) + valueAllocator()->releaseStringValue( comment_ ); +} + + +void +Value::CommentInfo::setComment( const char *text ) +{ + if ( comment_ ) + valueAllocator()->releaseStringValue( comment_ ); + JSON_ASSERT( text ); + JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = valueAllocator()->duplicateStringValue( text ); +} + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +# ifndef JSON_VALUE_USE_INTERNAL_MAP + +// Notes: index_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString( int index ) + : cstr_( 0 ) + , index_( index ) +{ +} + +Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) + : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr) + : cstr ) + , index_( allocate ) +{ +} + +Value::CZString::CZString( const CZString &other ) +: cstr_( other.index_ != noDuplication && other.cstr_ != 0 + ? valueAllocator()->makeMemberName( other.cstr_ ) + : other.cstr_ ) + , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) + : other.index_ ) +{ +} + +Value::CZString::~CZString() +{ + if ( cstr_ && index_ == duplicate ) + valueAllocator()->releaseMemberName( const_cast<char *>( cstr_ ) ); +} + +void +Value::CZString::swap( CZString &other ) +{ + std::swap( cstr_, other.cstr_ ); + std::swap( index_, other.index_ ); +} + +Value::CZString & +Value::CZString::operator =( const CZString &other ) +{ + CZString temp( other ); + swap( temp ); + return *this; +} + +bool +Value::CZString::operator<( const CZString &other ) const +{ + if ( cstr_ ) + return strcmp( cstr_, other.cstr_ ) < 0; + return index_ < other.index_; +} + +bool +Value::CZString::operator==( const CZString &other ) const +{ + if ( cstr_ ) + return strcmp( cstr_, other.cstr_ ) == 0; + return index_ == other.index_; +} + + +int +Value::CZString::index() const +{ + return index_; +} + + +const char * +Value::CZString::c_str() const +{ + return cstr_; +} + +bool +Value::CZString::isStaticString() const +{ + return index_ == noDuplication; +} + +#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP + + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::Value +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/*! \internal Default constructor initialization must be equivalent to: + * memset( this, 0, sizeof(Value) ) + * This optimization is used in ValueInternalMap fast allocator. + */ +Value::Value( ValueType type ) + : type_( type ) + , allocated_( 0 ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + switch ( type ) + { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + value_.string_ = 0; + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; +#else + case arrayValue: + value_.array_ = arrayAllocator()->newArray(); + break; + case objectValue: + value_.map_ = mapAllocator()->newMap(); + break; +#endif + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + + +Value::Value( Int value ) + : type_( intValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.int_ = value; +} + + +Value::Value( UInt value ) + : type_( uintValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.uint_ = value; +} + +Value::Value( double value ) + : type_( realValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.real_ = value; +} + +Value::Value( const char *value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = valueAllocator()->duplicateStringValue( value ); +} + + +Value::Value( const char *beginValue, + const char *endValue ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = valueAllocator()->duplicateStringValue( beginValue, + UInt(endValue - beginValue) ); +} + + +Value::Value( const std::string &value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(), + (unsigned int)value.length() ); + +} + +Value::Value( const StaticString &value ) + : type_( stringValue ) + , allocated_( false ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = const_cast<char *>( value.c_str() ); +} + + +# ifdef JSON_USE_CPPTL +Value::Value( const CppTL::ConstString &value ) + : type_( stringValue ) + , allocated_( true ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() ); +} +# endif + +Value::Value( bool value ) + : type_( booleanValue ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + value_.bool_ = value; +} + + +Value::Value( const Value &other ) + : type_( other.type_ ) + , comments_( 0 ) +# ifdef JSON_VALUE_USE_INTERNAL_MAP + , itemIsUsed_( 0 ) +#endif +{ + switch ( type_ ) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if ( other.value_.string_ ) + { + value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ ); + allocated_ = true; + } + else + value_.string_ = 0; + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues( *other.value_.map_ ); + break; +#else + case arrayValue: + value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); + break; + case objectValue: + value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); + break; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + if ( other.comments_ ) + { + comments_ = new CommentInfo[numberOfCommentPlacement]; + for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) + { + const CommentInfo &otherComment = other.comments_[comment]; + if ( otherComment.comment_ ) + comments_[comment].setComment( otherComment.comment_ ); + } + } +} + + +Value::~Value() +{ + switch ( type_ ) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if ( allocated_ ) + valueAllocator()->releaseStringValue( value_.string_ ); + break; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + delete value_.map_; + break; +#else + case arrayValue: + arrayAllocator()->destructArray( value_.array_ ); + break; + case objectValue: + mapAllocator()->destructMap( value_.map_ ); + break; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + + if ( comments_ ) + delete[] comments_; +} + +Value & +Value::operator=( const Value &other ) +{ + Value temp( other ); + swap( temp ); + return *this; +} + +void +Value::swap( Value &other ) +{ + ValueType temp = type_; + type_ = other.type_; + other.type_ = temp; + std::swap( value_, other.value_ ); + int temp2 = allocated_; + allocated_ = other.allocated_; + other.allocated_ = temp2; +} + +ValueType +Value::type() const +{ + return type_; +} + + +int +Value::compare( const Value &other ) +{ + /* + int typeDelta = other.type_ - type_; + switch ( type_ ) + { + case nullValue: + + return other.type_ == type_; + case intValue: + if ( other.type_.isNumeric() + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue, + break; + case arrayValue: + delete value_.array_; + break; + case objectValue: + delete value_.map_; + default: + JSON_ASSERT_UNREACHABLE; + } + */ + return 0; // unreachable +} + +bool +Value::operator <( const Value &other ) const +{ + int typeDelta = type_ - other.type_; + if ( typeDelta ) + return typeDelta < 0 ? true : false; + switch ( type_ ) + { + case nullValue: + return false; + case intValue: + return value_.int_ < other.value_.int_; + case uintValue: + return value_.uint_ < other.value_.uint_; + case realValue: + return value_.real_ < other.value_.real_; + case booleanValue: + return value_.bool_ < other.value_.bool_; + case stringValue: + return ( value_.string_ == 0 && other.value_.string_ ) + || ( other.value_.string_ + && value_.string_ + && strcmp( value_.string_, other.value_.string_ ) < 0 ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + { + int delta = int( value_.map_->size() - other.value_.map_->size() ); + if ( delta ) + return delta < 0; + return (*value_.map_) < (*other.value_.map_); + } +#else + case arrayValue: + return value_.array_->compare( *(other.value_.array_) ) < 0; + case objectValue: + return value_.map_->compare( *(other.value_.map_) ) < 0; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable +} + +bool +Value::operator <=( const Value &other ) const +{ + return !(other > *this); +} + +bool +Value::operator >=( const Value &other ) const +{ + return !(*this < other); +} + +bool +Value::operator >( const Value &other ) const +{ + return other < *this; +} + +bool +Value::operator ==( const Value &other ) const +{ + //if ( type_ != other.type_ ) + // GCC 2.95.3 says: + // attempt to take address of bit-field structure member `Json::Value::type_' + // Beats me, but a temp solves the problem. + int temp = other.type_; + if ( type_ != temp ) + return false; + switch ( type_ ) + { + case nullValue: + return true; + case intValue: + return value_.int_ == other.value_.int_; + case uintValue: + return value_.uint_ == other.value_.uint_; + case realValue: + return value_.real_ == other.value_.real_; + case booleanValue: + return value_.bool_ == other.value_.bool_; + case stringValue: + return ( value_.string_ == other.value_.string_ ) + || ( other.value_.string_ + && value_.string_ + && strcmp( value_.string_, other.value_.string_ ) == 0 ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() + && (*value_.map_) == (*other.value_.map_); +#else + case arrayValue: + return value_.array_->compare( *(other.value_.array_) ) == 0; + case objectValue: + return value_.map_->compare( *(other.value_.map_) ) == 0; +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable +} + +bool +Value::operator !=( const Value &other ) const +{ + return !( *this == other ); +} + +const char * +Value::asCString() const +{ + JSON_ASSERT( type_ == stringValue ); + return value_.string_; +} + + +std::string +Value::asString() const +{ + switch ( type_ ) + { + case nullValue: + return ""; + case stringValue: + return value_.string_ ? value_.string_ : ""; + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + case uintValue: + case realValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE( false, "Type is not convertible to string" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return ""; // unreachable +} + +# ifdef JSON_USE_CPPTL +CppTL::ConstString +Value::asConstString() const +{ + return CppTL::ConstString( asString().c_str() ); +} +# endif + +Value::Int +Value::asInt() const +{ + switch ( type_ ) + { + case nullValue: + return 0; + case intValue: + return value_.int_; + case uintValue: + JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" ); + return value_.uint_; + case realValue: + JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); + return Int( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE( false, "Type is not convertible to int" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + +Value::UInt +Value::asUInt() const +{ + switch ( type_ ) + { + case nullValue: + return 0; + case intValue: + JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); + return value_.int_; + case uintValue: + return value_.uint_; + case realValue: + JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); + return UInt( value_.real_ ); + case booleanValue: + return value_.bool_ ? 1 : 0; + case stringValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE( false, "Type is not convertible to uint" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + +double +Value::asDouble() const +{ + switch ( type_ ) + { + case nullValue: + return 0.0; + case intValue: + return value_.int_; + case uintValue: + return value_.uint_; + case realValue: + return value_.real_; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + case stringValue: + case arrayValue: + case objectValue: + JSON_ASSERT_MESSAGE( false, "Type is not convertible to double" ); + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + +bool +Value::asBool() const +{ + switch ( type_ ) + { + case nullValue: + return false; + case intValue: + case uintValue: + return value_.int_ != 0; + case realValue: + return value_.real_ != 0.0; + case booleanValue: + return value_.bool_; + case stringValue: + return value_.string_ && value_.string_[0] != 0; + case arrayValue: + case objectValue: + return value_.map_->size() != 0; + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable; +} + + +bool +Value::isConvertibleTo( ValueType other ) const +{ + switch ( type_ ) + { + case nullValue: + return true; + case intValue: + return ( other == nullValue && value_.int_ == 0 ) + || other == intValue + || ( other == uintValue && value_.int_ >= 0 ) + || other == realValue + || other == stringValue + || other == booleanValue; + case uintValue: + return ( other == nullValue && value_.uint_ == 0 ) + || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) + || other == uintValue + || other == realValue + || other == stringValue + || other == booleanValue; + case realValue: + return ( other == nullValue && value_.real_ == 0.0 ) + || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) + || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) + || other == realValue + || other == stringValue + || other == booleanValue; + case booleanValue: + return ( other == nullValue && value_.bool_ == false ) + || other == intValue + || other == uintValue + || other == realValue + || other == stringValue + || other == booleanValue; + case stringValue: + return other == stringValue + || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); + case arrayValue: + return other == arrayValue + || ( other == nullValue && value_.map_->size() == 0 ); + case objectValue: + return other == objectValue + || ( other == nullValue && value_.map_->size() == 0 ); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable; +} + + +/// Number of values in array or object +Value::UInt +Value::size() const +{ + switch ( type_ ) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + case stringValue: + return 0; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: // size of the array is highest index + 1 + if ( !value_.map_->empty() ) + { + ObjectValues::const_iterator itLast = value_.map_->end(); + --itLast; + return (*itLast).first.index()+1; + } + return 0; + case objectValue: + return Int( value_.map_->size() ); +#else + case arrayValue: + return Int( value_.array_->size() ); + case objectValue: + return Int( value_.map_->size() ); +#endif + default: + JSON_ASSERT_UNREACHABLE; + } + return 0; // unreachable; +} + + +bool +Value::empty() const +{ + if ( isNull() || isArray() || isObject() ) + return size() == 0u; + else + return false; +} + + +bool +Value::operator!() const +{ + return isNull(); +} + + +void +Value::clear() +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); + + switch ( type_ ) + { +#ifndef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + case objectValue: + value_.map_->clear(); + break; +#else + case arrayValue: + value_.array_->clear(); + break; + case objectValue: + value_.map_->clear(); + break; +#endif + default: + break; + } +} + +void +Value::resize( UInt newSize ) +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) + *this = Value( arrayValue ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + UInt oldSize = size(); + if ( newSize == 0 ) + clear(); + else if ( newSize > oldSize ) + (*this)[ newSize - 1 ]; + else + { + for ( UInt index = newSize; index < oldSize; ++index ) + value_.map_->erase( index ); + assert( size() == newSize ); + } +#else + value_.array_->resize( newSize ); +#endif +} + + +Value & +Value::operator[]( UInt index ) +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) + *this = Value( arrayValue ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString key( index ); + ObjectValues::iterator it = value_.map_->lower_bound( key ); + if ( it != value_.map_->end() && (*it).first == key ) + return (*it).second; + + ObjectValues::value_type defaultValue( key, null ); + it = value_.map_->insert( it, defaultValue ); + return (*it).second; +#else + return value_.array_->resolveReference( index ); +#endif +} + + +const Value & +Value::operator[]( UInt index ) const +{ + JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); + if ( type_ == nullValue ) + return null; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString key( index ); + ObjectValues::const_iterator it = value_.map_->find( key ); + if ( it == value_.map_->end() ) + return null; + return (*it).second; +#else + Value *value = value_.array_->find( index ); + return value ? *value : null; +#endif +} + + +Value & +Value::operator[]( const char *key ) +{ + return resolveReference( key, false ); +} + + +Value & +Value::resolveReference( const char *key, + bool isStatic ) +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + *this = Value( objectValue ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, isStatic ? CZString::noDuplication + : CZString::duplicateOnCopy ); + ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); + if ( it != value_.map_->end() && (*it).first == actualKey ) + return (*it).second; + + ObjectValues::value_type defaultValue( actualKey, null ); + it = value_.map_->insert( it, defaultValue ); + Value &value = (*it).second; + return value; +#else + return value_.map_->resolveReference( key, isStatic ); +#endif +} + + +Value +Value::get( UInt index, + const Value &defaultValue ) const +{ + const Value *value = &((*this)[index]); + return value == &null ? defaultValue : *value; +} + + +bool +Value::isValidIndex( UInt index ) const +{ + return index < size(); +} + + + +const Value & +Value::operator[]( const char *key ) const +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + return null; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, CZString::noDuplication ); + ObjectValues::const_iterator it = value_.map_->find( actualKey ); + if ( it == value_.map_->end() ) + return null; + return (*it).second; +#else + const Value *value = value_.map_->find( key ); + return value ? *value : null; +#endif +} + + +Value & +Value::operator[]( const std::string &key ) +{ + return (*this)[ key.c_str() ]; +} + + +const Value & +Value::operator[]( const std::string &key ) const +{ + return (*this)[ key.c_str() ]; +} + +Value & +Value::operator[]( const StaticString &key ) +{ + return resolveReference( key, true ); +} + + +# ifdef JSON_USE_CPPTL +Value & +Value::operator[]( const CppTL::ConstString &key ) +{ + return (*this)[ key.c_str() ]; +} + + +const Value & +Value::operator[]( const CppTL::ConstString &key ) const +{ + return (*this)[ key.c_str() ]; +} +# endif + + +Value & +Value::append( const Value &value ) +{ + return (*this)[size()] = value; +} + + +Value +Value::get( const char *key, + const Value &defaultValue ) const +{ + const Value *value = &((*this)[key]); + return value == &null ? defaultValue : *value; +} + + +Value +Value::get( const std::string &key, + const Value &defaultValue ) const +{ + return get( key.c_str(), defaultValue ); +} + +Value +Value::removeMember( const char* key ) +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + return null; +#ifndef JSON_VALUE_USE_INTERNAL_MAP + CZString actualKey( key, CZString::noDuplication ); + ObjectValues::iterator it = value_.map_->find( actualKey ); + if ( it == value_.map_->end() ) + return null; + Value old(it->second); + value_.map_->erase(it); + return old; +#else + Value *value = value_.map_->find( key ); + if (value){ + Value old(*value); + value_.map_.remove( key ); + return old; + } else { + return null; + } +#endif +} + +Value +Value::removeMember( const std::string &key ) +{ + return removeMember( key.c_str() ); +} + +# ifdef JSON_USE_CPPTL +Value +Value::get( const CppTL::ConstString &key, + const Value &defaultValue ) const +{ + return get( key.c_str(), defaultValue ); +} +# endif + +bool +Value::isMember( const char *key ) const +{ + const Value *value = &((*this)[key]); + return value != &null; +} + + +bool +Value::isMember( const std::string &key ) const +{ + return isMember( key.c_str() ); +} + + +# ifdef JSON_USE_CPPTL +bool +Value::isMember( const CppTL::ConstString &key ) const +{ + return isMember( key.c_str() ); +} +#endif + +Value::Members +Value::getMemberNames() const +{ + JSON_ASSERT( type_ == nullValue || type_ == objectValue ); + if ( type_ == nullValue ) + return Value::Members(); + Members members; + members.reserve( value_.map_->size() ); +#ifndef JSON_VALUE_USE_INTERNAL_MAP + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for ( ; it != itEnd; ++it ) + members.push_back( std::string( (*it).first.c_str() ) ); +#else + ValueInternalMap::IteratorState it; + ValueInternalMap::IteratorState itEnd; + value_.map_->makeBeginIterator( it ); + value_.map_->makeEndIterator( itEnd ); + for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) + members.push_back( std::string( ValueInternalMap::key( it ) ) ); +#endif + return members; +} +// +//# ifdef JSON_USE_CPPTL +//EnumMemberNames +//Value::enumMemberNames() const +//{ +// if ( type_ == objectValue ) +// { +// return CppTL::Enum::any( CppTL::Enum::transform( +// CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +//EnumValues +//Value::enumValues() const +//{ +// if ( type_ == objectValue || type_ == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type<const Value &>() ); +// return EnumValues(); +//} +// +//# endif + + +bool +Value::isNull() const +{ + return type_ == nullValue; +} + + +bool +Value::isBool() const +{ + return type_ == booleanValue; +} + + +bool +Value::isInt() const +{ + return type_ == intValue; +} + + +bool +Value::isUInt() const +{ + return type_ == uintValue; +} + + +bool +Value::isIntegral() const +{ + return type_ == intValue + || type_ == uintValue + || type_ == booleanValue; +} + + +bool +Value::isDouble() const +{ + return type_ == realValue; +} + + +bool +Value::isNumeric() const +{ + return isIntegral() || isDouble(); +} + + +bool +Value::isString() const +{ + return type_ == stringValue; +} + + +bool +Value::isArray() const +{ + return type_ == nullValue || type_ == arrayValue; +} + + +bool +Value::isObject() const +{ + return type_ == nullValue || type_ == objectValue; +} + + +void +Value::setComment( const char *comment, + CommentPlacement placement ) +{ + if ( !comments_ ) + comments_ = new CommentInfo[numberOfCommentPlacement]; + comments_[placement].setComment( comment ); +} + + +void +Value::setComment( const std::string &comment, + CommentPlacement placement ) +{ + setComment( comment.c_str(), placement ); +} + + +bool +Value::hasComment( CommentPlacement placement ) const +{ + return comments_ != 0 && comments_[placement].comment_ != 0; +} + +std::string +Value::getComment( CommentPlacement placement ) const +{ + if ( hasComment(placement) ) + return comments_[placement].comment_; + return ""; +} + + +std::string +Value::toStyledString() const +{ + StyledWriter writer; + return writer.write( *this ); +} + + +Value::const_iterator +Value::begin() const +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeBeginIterator( it ); + return const_iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeBeginIterator( it ); + return const_iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return const_iterator( value_.map_->begin() ); + break; +#endif + default: + break; + } + return const_iterator(); +} + +Value::const_iterator +Value::end() const +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeEndIterator( it ); + return const_iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeEndIterator( it ); + return const_iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return const_iterator( value_.map_->end() ); + break; +#endif + default: + break; + } + return const_iterator(); +} + + +Value::iterator +Value::begin() +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeBeginIterator( it ); + return iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeBeginIterator( it ); + return iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return iterator( value_.map_->begin() ); + break; +#endif + default: + break; + } + return iterator(); +} + +Value::iterator +Value::end() +{ + switch ( type_ ) + { +#ifdef JSON_VALUE_USE_INTERNAL_MAP + case arrayValue: + if ( value_.array_ ) + { + ValueInternalArray::IteratorState it; + value_.array_->makeEndIterator( it ); + return iterator( it ); + } + break; + case objectValue: + if ( value_.map_ ) + { + ValueInternalMap::IteratorState it; + value_.map_->makeEndIterator( it ); + return iterator( it ); + } + break; +#else + case arrayValue: + case objectValue: + if ( value_.map_ ) + return iterator( value_.map_->end() ); + break; +#endif + default: + break; + } + return iterator(); +} + + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() + : kind_( kindNone ) +{ +} + + +PathArgument::PathArgument( Value::UInt index ) + : index_( index ) + , kind_( kindIndex ) +{ +} + + +PathArgument::PathArgument( const char *key ) + : key_( key ) + , kind_( kindKey ) +{ +} + + +PathArgument::PathArgument( const std::string &key ) + : key_( key.c_str() ) + , kind_( kindKey ) +{ +} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path( const std::string &path, + const PathArgument &a1, + const PathArgument &a2, + const PathArgument &a3, + const PathArgument &a4, + const PathArgument &a5 ) +{ + InArgs in; + in.push_back( &a1 ); + in.push_back( &a2 ); + in.push_back( &a3 ); + in.push_back( &a4 ); + in.push_back( &a5 ); + makePath( path, in ); +} + + +void +Path::makePath( const std::string &path, + const InArgs &in ) +{ + const char *current = path.c_str(); + const char *end = current + path.length(); + InArgs::const_iterator itInArg = in.begin(); + while ( current != end ) + { + if ( *current == '[' ) + { + ++current; + if ( *current == '%' ) + addPathInArg( path, in, itInArg, PathArgument::kindIndex ); + else + { + Value::UInt index = 0; + for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) + index = index * 10 + Value::UInt(*current - '0'); + args_.push_back( index ); + } + if ( current == end || *current++ != ']' ) + invalidPath( path, int(current - path.c_str()) ); + } + else if ( *current == '%' ) + { + addPathInArg( path, in, itInArg, PathArgument::kindKey ); + ++current; + } + else if ( *current == '.' ) + { + ++current; + } + else + { + const char *beginName = current; + while ( current != end && !strchr( "[.", *current ) ) + ++current; + args_.push_back( std::string( beginName, current ) ); + } + } +} + + +void +Path::addPathInArg( const std::string &path, + const InArgs &in, + InArgs::const_iterator &itInArg, + PathArgument::Kind kind ) +{ + if ( itInArg == in.end() ) + { + // Error: missing argument %d + } + else if ( (*itInArg)->kind_ != kind ) + { + // Error: bad argument type + } + else + { + args_.push_back( **itInArg ); + } +} + + +void +Path::invalidPath( const std::string &path, + int location ) +{ + // Error: invalid path. +} + + +const Value & +Path::resolve( const Value &root ) const +{ + const Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) + { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) + { + if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) + { + // Error: unable to resolve path (array value expected at position... + } + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) + { + if ( !node->isObject() ) + { + // Error: unable to resolve path (object value expected at position...) + } + node = &((*node)[arg.key_]); + if ( node == &Value::null ) + { + // Error: unable to resolve path (object has no member named '' at position...) + } + } + } + return *node; +} + + +Value +Path::resolve( const Value &root, + const Value &defaultValue ) const +{ + const Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) + { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) + { + if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) + return defaultValue; + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) + { + if ( !node->isObject() ) + return defaultValue; + node = &((*node)[arg.key_]); + if ( node == &Value::null ) + return defaultValue; + } + } + return *node; +} + + +Value & +Path::make( Value &root ) const +{ + Value *node = &root; + for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) + { + const PathArgument &arg = *it; + if ( arg.kind_ == PathArgument::kindIndex ) + { + if ( !node->isArray() ) + { + // Error: node is not an array at position ... + } + node = &((*node)[arg.index_]); + } + else if ( arg.kind_ == PathArgument::kindKey ) + { + if ( !node->isObject() ) + { + // Error: node is not an object at position... + } + node = &((*node)[arg.key_]); + } + } + return *node; +} + + +} // namespace Json diff --git a/src/jsoncpp/src/lib_json/json_writer.cpp b/src/jsoncpp/src/lib_json/json_writer.cpp index 051d0dcbbb..264df11670 100644 --- a/src/jsoncpp/src/lib_json/json_writer.cpp +++ b/src/jsoncpp/src/lib_json/json_writer.cpp @@ -1,829 +1,829 @@ -#include <jsoncpp/include/json/writer.h> -#include <utility> -#include <assert.h> -#include <stdio.h> -#include <string.h> -#include <iostream> -#include <sstream> -#include <iomanip> - -#if _MSC_VER >= 1400 // VC++ 8.0 -#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. -#endif - -namespace Json { - -static bool isControlCharacter(char ch) -{ - return ch > 0 && ch <= 0x1F; -} - -static bool containsControlCharacter( const char* str ) -{ - while ( *str ) - { - if ( isControlCharacter( *(str++) ) ) - return true; - } - return false; -} -static void uintToString( unsigned int value, - char *¤t ) -{ - *--current = 0; - do - { - *--current = (value % 10) + '0'; - value /= 10; - } - while ( value != 0 ); -} - -std::string valueToString( Int value ) -{ - char buffer[32]; - char *current = buffer + sizeof(buffer); - bool isNegative = value < 0; - if ( isNegative ) - value = -value; - uintToString( UInt(value), current ); - if ( isNegative ) - *--current = '-'; - assert( current >= buffer ); - return current; -} - - -std::string valueToString( UInt value ) -{ - char buffer[32]; - char *current = buffer + sizeof(buffer); - uintToString( value, current ); - assert( current >= buffer ); - return current; -} - -std::string valueToString( double value ) -{ - char buffer[32]; -#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. - sprintf_s(buffer, sizeof(buffer), "%#.16g", value); -#else - sprintf(buffer, "%#.16g", value); -#endif - char* ch = buffer + strlen(buffer) - 1; - if (*ch != '0') return buffer; // nothing to truncate, so save time - while(ch > buffer && *ch == '0'){ - --ch; - } - char* last_nonzero = ch; - while(ch >= buffer){ - switch(*ch){ - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - --ch; - continue; - case '.': - // Truncate zeroes to save bytes in output, but keep one. - *(last_nonzero+2) = '\0'; - return buffer; - default: - return buffer; - } - } - return buffer; -} - - -std::string valueToString( bool value ) -{ - return value ? "true" : "false"; -} - -std::string valueToQuotedString( const char *value ) -{ - // Not sure how to handle unicode... - if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) - return std::string("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to std::string is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL - std::string result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - for (const char* c=value; *c != 0; ++c) - { - switch(*c) - { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - //case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something. - // blep notes: actually escaping \/ may be useful in javascript to avoid </ - // sequence. - // Should add a flag to allow this compatibility mode and prevent this - // sequence from occurring. - default: - if ( isControlCharacter( *c ) ) - { - std::ostringstream oss; - oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c); - result += oss.str(); - } - else - { - result += *c; - } - break; - } - } - result += "\""; - return result; -} - -// Class Writer -// ////////////////////////////////////////////////////////////////// -Writer::~Writer() -{ -} - - -// Class FastWriter -// ////////////////////////////////////////////////////////////////// - -FastWriter::FastWriter() - : yamlCompatiblityEnabled_( false ) -{ -} - - -void -FastWriter::enableYAMLCompatibility() -{ - yamlCompatiblityEnabled_ = true; -} - - -std::string -FastWriter::write( const Value &root ) -{ - document_ = ""; - writeValue( root ); - document_ += "\n"; - return document_; -} - - -void -FastWriter::writeValue( const Value &value ) -{ - switch ( value.type() ) - { - case nullValue: - document_ += "null"; - break; - case intValue: - document_ += valueToString( value.asInt() ); - break; - case uintValue: - document_ += valueToString( value.asUInt() ); - break; - case realValue: - document_ += valueToString( value.asDouble() ); - break; - case stringValue: - document_ += valueToQuotedString( value.asCString() ); - break; - case booleanValue: - document_ += valueToString( value.asBool() ); - break; - case arrayValue: - { - document_ += "["; - int size = value.size(); - for ( int index =0; index < size; ++index ) - { - if ( index > 0 ) - document_ += ","; - writeValue( value[index] ); - } - document_ += "]"; - } - break; - case objectValue: - { - Value::Members members( value.getMemberNames() ); - document_ += "{"; - for ( Value::Members::iterator it = members.begin(); - it != members.end(); - ++it ) - { - const std::string &name = *it; - if ( it != members.begin() ) - document_ += ","; - document_ += valueToQuotedString( name.c_str() ); - document_ += yamlCompatiblityEnabled_ ? ": " - : ":"; - writeValue( value[name] ); - } - document_ += "}"; - } - break; - } -} - - -// Class StyledWriter -// ////////////////////////////////////////////////////////////////// - -StyledWriter::StyledWriter() - : rightMargin_( 74 ) - , indentSize_( 3 ) -{ -} - - -std::string -StyledWriter::write( const Value &root ) -{ - document_ = ""; - addChildValues_ = false; - indentString_ = ""; - writeCommentBeforeValue( root ); - writeValue( root ); - writeCommentAfterValueOnSameLine( root ); - document_ += "\n"; - return document_; -} - - -void -StyledWriter::writeValue( const Value &value ) -{ - switch ( value.type() ) - { - case nullValue: - pushValue( "null" ); - break; - case intValue: - pushValue( valueToString( value.asInt() ) ); - break; - case uintValue: - pushValue( valueToString( value.asUInt() ) ); - break; - case realValue: - pushValue( valueToString( value.asDouble() ) ); - break; - case stringValue: - pushValue( valueToQuotedString( value.asCString() ) ); - break; - case booleanValue: - pushValue( valueToString( value.asBool() ) ); - break; - case arrayValue: - writeArrayValue( value); - break; - case objectValue: - { - Value::Members members( value.getMemberNames() ); - if ( members.empty() ) - pushValue( "{}" ); - else - { - writeWithIndent( "{" ); - indent(); - Value::Members::iterator it = members.begin(); - while ( true ) - { - const std::string &name = *it; - const Value &childValue = value[name]; - writeCommentBeforeValue( childValue ); - writeWithIndent( valueToQuotedString( name.c_str() ) ); - document_ += " : "; - writeValue( childValue ); - if ( ++it == members.end() ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - document_ += ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "}" ); - } - } - break; - } -} - - -void -StyledWriter::writeArrayValue( const Value &value ) -{ - unsigned size = value.size(); - if ( size == 0 ) - pushValue( "[]" ); - else - { - bool isArrayMultiLine = isMultineArray( value ); - if ( isArrayMultiLine ) - { - writeWithIndent( "[" ); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index =0; - while ( true ) - { - const Value &childValue = value[index]; - writeCommentBeforeValue( childValue ); - if ( hasChildValue ) - writeWithIndent( childValues_[index] ); - else - { - writeIndent(); - writeValue( childValue ); - } - if ( ++index == size ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - document_ += ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "]" ); - } - else // output on a single line - { - assert( childValues_.size() == size ); - document_ += "[ "; - for ( unsigned index =0; index < size; ++index ) - { - if ( index > 0 ) - document_ += ", "; - document_ += childValues_[index]; - } - document_ += " ]"; - } - } -} - - -bool -StyledWriter::isMultineArray( const Value &value ) -{ - int size = value.size(); - bool isMultiLine = size*3 >= rightMargin_ ; - childValues_.clear(); - for ( int index =0; index < size && !isMultiLine; ++index ) - { - const Value &childValue = value[index]; - isMultiLine = isMultiLine || - ( (childValue.isArray() || childValue.isObject()) && - childValue.size() > 0 ); - } - if ( !isMultiLine ) // check if line length > max line length - { - childValues_.reserve( size ); - addChildValues_ = true; - int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' - for ( int index =0; index < size && !isMultiLine; ++index ) - { - writeValue( value[index] ); - lineLength += int( childValues_[index].length() ); - isMultiLine = isMultiLine && hasCommentForValue( value[index] ); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - - -void -StyledWriter::pushValue( const std::string &value ) -{ - if ( addChildValues_ ) - childValues_.push_back( value ); - else - document_ += value; -} - - -void -StyledWriter::writeIndent() -{ - if ( !document_.empty() ) - { - char last = document_[document_.length()-1]; - if ( last == ' ' ) // already indented - return; - if ( last != '\n' ) // Comments may add new-line - document_ += '\n'; - } - document_ += indentString_; -} - - -void -StyledWriter::writeWithIndent( const std::string &value ) -{ - writeIndent(); - document_ += value; -} - - -void -StyledWriter::indent() -{ - indentString_ += std::string( indentSize_, ' ' ); -} - - -void -StyledWriter::unindent() -{ - assert( int(indentString_.size()) >= indentSize_ ); - indentString_.resize( indentString_.size() - indentSize_ ); -} - - -void -StyledWriter::writeCommentBeforeValue( const Value &root ) -{ - if ( !root.hasComment( commentBefore ) ) - return; - document_ += normalizeEOL( root.getComment( commentBefore ) ); - document_ += "\n"; -} - - -void -StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) -{ - if ( root.hasComment( commentAfterOnSameLine ) ) - document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); - - if ( root.hasComment( commentAfter ) ) - { - document_ += "\n"; - document_ += normalizeEOL( root.getComment( commentAfter ) ); - document_ += "\n"; - } -} - - -bool -StyledWriter::hasCommentForValue( const Value &value ) -{ - return value.hasComment( commentBefore ) - || value.hasComment( commentAfterOnSameLine ) - || value.hasComment( commentAfter ); -} - - -std::string -StyledWriter::normalizeEOL( const std::string &text ) -{ - std::string normalized; - normalized.reserve( text.length() ); - const char *begin = text.c_str(); - const char *end = begin + text.length(); - const char *current = begin; - while ( current != end ) - { - char c = *current++; - if ( c == '\r' ) // mac or dos EOL - { - if ( *current == '\n' ) // convert dos EOL - ++current; - normalized += '\n'; - } - else // handle unix EOL & other char - normalized += c; - } - return normalized; -} - - -// Class StyledStreamWriter -// ////////////////////////////////////////////////////////////////// - -StyledStreamWriter::StyledStreamWriter( std::string indentation ) - : document_(NULL) - , rightMargin_( 74 ) - , indentation_( indentation ) -{ -} - - -void -StyledStreamWriter::write( std::ostream &out, const Value &root ) -{ - document_ = &out; - addChildValues_ = false; - indentString_ = ""; - writeCommentBeforeValue( root ); - writeValue( root ); - writeCommentAfterValueOnSameLine( root ); - *document_ << "\n"; - document_ = NULL; // Forget the stream, for safety. -} - - -void -StyledStreamWriter::writeValue( const Value &value ) -{ - switch ( value.type() ) - { - case nullValue: - pushValue( "null" ); - break; - case intValue: - pushValue( valueToString( value.asInt() ) ); - break; - case uintValue: - pushValue( valueToString( value.asUInt() ) ); - break; - case realValue: - pushValue( valueToString( value.asDouble() ) ); - break; - case stringValue: - pushValue( valueToQuotedString( value.asCString() ) ); - break; - case booleanValue: - pushValue( valueToString( value.asBool() ) ); - break; - case arrayValue: - writeArrayValue( value); - break; - case objectValue: - { - Value::Members members( value.getMemberNames() ); - if ( members.empty() ) - pushValue( "{}" ); - else - { - writeWithIndent( "{" ); - indent(); - Value::Members::iterator it = members.begin(); - while ( true ) - { - const std::string &name = *it; - const Value &childValue = value[name]; - writeCommentBeforeValue( childValue ); - writeWithIndent( valueToQuotedString( name.c_str() ) ); - *document_ << " : "; - writeValue( childValue ); - if ( ++it == members.end() ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "}" ); - } - } - break; - } -} - - -void -StyledStreamWriter::writeArrayValue( const Value &value ) -{ - unsigned size = value.size(); - if ( size == 0 ) - pushValue( "[]" ); - else - { - bool isArrayMultiLine = isMultineArray( value ); - if ( isArrayMultiLine ) - { - writeWithIndent( "[" ); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index =0; - while ( true ) - { - const Value &childValue = value[index]; - writeCommentBeforeValue( childValue ); - if ( hasChildValue ) - writeWithIndent( childValues_[index] ); - else - { - writeIndent(); - writeValue( childValue ); - } - if ( ++index == size ) - { - writeCommentAfterValueOnSameLine( childValue ); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine( childValue ); - } - unindent(); - writeWithIndent( "]" ); - } - else // output on a single line - { - assert( childValues_.size() == size ); - *document_ << "[ "; - for ( unsigned index =0; index < size; ++index ) - { - if ( index > 0 ) - *document_ << ", "; - *document_ << childValues_[index]; - } - *document_ << " ]"; - } - } -} - - -bool -StyledStreamWriter::isMultineArray( const Value &value ) -{ - int size = value.size(); - bool isMultiLine = size*3 >= rightMargin_ ; - childValues_.clear(); - for ( int index =0; index < size && !isMultiLine; ++index ) - { - const Value &childValue = value[index]; - isMultiLine = isMultiLine || - ( (childValue.isArray() || childValue.isObject()) && - childValue.size() > 0 ); - } - if ( !isMultiLine ) // check if line length > max line length - { - childValues_.reserve( size ); - addChildValues_ = true; - int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' - for ( int index =0; index < size && !isMultiLine; ++index ) - { - writeValue( value[index] ); - lineLength += int( childValues_[index].length() ); - isMultiLine = isMultiLine && hasCommentForValue( value[index] ); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - - -void -StyledStreamWriter::pushValue( const std::string &value ) -{ - if ( addChildValues_ ) - childValues_.push_back( value ); - else - *document_ << value; -} - - -void -StyledStreamWriter::writeIndent() -{ - /* - Some comments in this method would have been nice. ;-) - - if ( !document_.empty() ) - { - char last = document_[document_.length()-1]; - if ( last == ' ' ) // already indented - return; - if ( last != '\n' ) // Comments may add new-line - *document_ << '\n'; - } - */ - *document_ << '\n' << indentString_; -} - - -void -StyledStreamWriter::writeWithIndent( const std::string &value ) -{ - writeIndent(); - *document_ << value; -} - - -void -StyledStreamWriter::indent() -{ - indentString_ += indentation_; -} - - -void -StyledStreamWriter::unindent() -{ - assert( indentString_.size() >= indentation_.size() ); - indentString_.resize( indentString_.size() - indentation_.size() ); -} - - -void -StyledStreamWriter::writeCommentBeforeValue( const Value &root ) -{ - if ( !root.hasComment( commentBefore ) ) - return; - *document_ << normalizeEOL( root.getComment( commentBefore ) ); - *document_ << "\n"; -} - - -void -StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) -{ - if ( root.hasComment( commentAfterOnSameLine ) ) - *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); - - if ( root.hasComment( commentAfter ) ) - { - *document_ << "\n"; - *document_ << normalizeEOL( root.getComment( commentAfter ) ); - *document_ << "\n"; - } -} - - -bool -StyledStreamWriter::hasCommentForValue( const Value &value ) -{ - return value.hasComment( commentBefore ) - || value.hasComment( commentAfterOnSameLine ) - || value.hasComment( commentAfter ); -} - - -std::string -StyledStreamWriter::normalizeEOL( const std::string &text ) -{ - std::string normalized; - normalized.reserve( text.length() ); - const char *begin = text.c_str(); - const char *end = begin + text.length(); - const char *current = begin; - while ( current != end ) - { - char c = *current++; - if ( c == '\r' ) // mac or dos EOL - { - if ( *current == '\n' ) // convert dos EOL - ++current; - normalized += '\n'; - } - else // handle unix EOL & other char - normalized += c; - } - return normalized; -} - - -std::ostream& operator<<( std::ostream &sout, const Value &root ) -{ - Json::StyledStreamWriter writer; - writer.write(sout, root); - return sout; -} - - -} // namespace Json +#include <jsoncpp/include/json/writer.h> +#include <utility> +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <iostream> +#include <sstream> +#include <iomanip> + +#if _MSC_VER >= 1400 // VC++ 8.0 +#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. +#endif + +namespace Json { + +static bool isControlCharacter(char ch) +{ + return ch > 0 && ch <= 0x1F; +} + +static bool containsControlCharacter( const char* str ) +{ + while ( *str ) + { + if ( isControlCharacter( *(str++) ) ) + return true; + } + return false; +} +static void uintToString( unsigned int value, + char *¤t ) +{ + *--current = 0; + do + { + *--current = (value % 10) + '0'; + value /= 10; + } + while ( value != 0 ); +} + +std::string valueToString( Int value ) +{ + char buffer[32]; + char *current = buffer + sizeof(buffer); + bool isNegative = value < 0; + if ( isNegative ) + value = -value; + uintToString( UInt(value), current ); + if ( isNegative ) + *--current = '-'; + assert( current >= buffer ); + return current; +} + + +std::string valueToString( UInt value ) +{ + char buffer[32]; + char *current = buffer + sizeof(buffer); + uintToString( value, current ); + assert( current >= buffer ); + return current; +} + +std::string valueToString( double value ) +{ + char buffer[32]; +#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. + sprintf_s(buffer, sizeof(buffer), "%#.16g", value); +#else + sprintf(buffer, "%#.16g", value); +#endif + char* ch = buffer + strlen(buffer) - 1; + if (*ch != '0') return buffer; // nothing to truncate, so save time + while(ch > buffer && *ch == '0'){ + --ch; + } + char* last_nonzero = ch; + while(ch >= buffer){ + switch(*ch){ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + --ch; + continue; + case '.': + // Truncate zeroes to save bytes in output, but keep one. + *(last_nonzero+2) = '\0'; + return buffer; + default: + return buffer; + } + } + return buffer; +} + + +std::string valueToString( bool value ) +{ + return value ? "true" : "false"; +} + +std::string valueToQuotedString( const char *value ) +{ + // Not sure how to handle unicode... + if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) + return std::string("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to std::string is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL + std::string result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + for (const char* c=value; *c != 0; ++c) + { + switch(*c) + { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + //case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something. + // blep notes: actually escaping \/ may be useful in javascript to avoid </ + // sequence. + // Should add a flag to allow this compatibility mode and prevent this + // sequence from occurring. + default: + if ( isControlCharacter( *c ) ) + { + std::ostringstream oss; + oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c); + result += oss.str(); + } + else + { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() +{ +} + + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatiblityEnabled_( false ) +{ +} + + +void +FastWriter::enableYAMLCompatibility() +{ + yamlCompatiblityEnabled_ = true; +} + + +std::string +FastWriter::write( const Value &root ) +{ + document_ = ""; + writeValue( root ); + document_ += "\n"; + return document_; +} + + +void +FastWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) + { + case nullValue: + document_ += "null"; + break; + case intValue: + document_ += valueToString( value.asInt() ); + break; + case uintValue: + document_ += valueToString( value.asUInt() ); + break; + case realValue: + document_ += valueToString( value.asDouble() ); + break; + case stringValue: + document_ += valueToQuotedString( value.asCString() ); + break; + case booleanValue: + document_ += valueToString( value.asBool() ); + break; + case arrayValue: + { + document_ += "["; + int size = value.size(); + for ( int index =0; index < size; ++index ) + { + if ( index > 0 ) + document_ += ","; + writeValue( value[index] ); + } + document_ += "]"; + } + break; + case objectValue: + { + Value::Members members( value.getMemberNames() ); + document_ += "{"; + for ( Value::Members::iterator it = members.begin(); + it != members.end(); + ++it ) + { + const std::string &name = *it; + if ( it != members.begin() ) + document_ += ","; + document_ += valueToQuotedString( name.c_str() ); + document_ += yamlCompatiblityEnabled_ ? ": " + : ":"; + writeValue( value[name] ); + } + document_ += "}"; + } + break; + } +} + + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_( 74 ) + , indentSize_( 3 ) +{ +} + + +std::string +StyledWriter::write( const Value &root ) +{ + document_ = ""; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue( root ); + writeValue( root ); + writeCommentAfterValueOnSameLine( root ); + document_ += "\n"; + return document_; +} + + +void +StyledWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) + { + case nullValue: + pushValue( "null" ); + break; + case intValue: + pushValue( valueToString( value.asInt() ) ); + break; + case uintValue: + pushValue( valueToString( value.asUInt() ) ); + break; + case realValue: + pushValue( valueToString( value.asDouble() ) ); + break; + case stringValue: + pushValue( valueToQuotedString( value.asCString() ) ); + break; + case booleanValue: + pushValue( valueToString( value.asBool() ) ); + break; + case arrayValue: + writeArrayValue( value); + break; + case objectValue: + { + Value::Members members( value.getMemberNames() ); + if ( members.empty() ) + pushValue( "{}" ); + else + { + writeWithIndent( "{" ); + indent(); + Value::Members::iterator it = members.begin(); + while ( true ) + { + const std::string &name = *it; + const Value &childValue = value[name]; + writeCommentBeforeValue( childValue ); + writeWithIndent( valueToQuotedString( name.c_str() ) ); + document_ += " : "; + writeValue( childValue ); + if ( ++it == members.end() ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + document_ += ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "}" ); + } + } + break; + } +} + + +void +StyledWriter::writeArrayValue( const Value &value ) +{ + unsigned size = value.size(); + if ( size == 0 ) + pushValue( "[]" ); + else + { + bool isArrayMultiLine = isMultineArray( value ); + if ( isArrayMultiLine ) + { + writeWithIndent( "[" ); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index =0; + while ( true ) + { + const Value &childValue = value[index]; + writeCommentBeforeValue( childValue ); + if ( hasChildValue ) + writeWithIndent( childValues_[index] ); + else + { + writeIndent(); + writeValue( childValue ); + } + if ( ++index == size ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + document_ += ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "]" ); + } + else // output on a single line + { + assert( childValues_.size() == size ); + document_ += "[ "; + for ( unsigned index =0; index < size; ++index ) + { + if ( index > 0 ) + document_ += ", "; + document_ += childValues_[index]; + } + document_ += " ]"; + } + } +} + + +bool +StyledWriter::isMultineArray( const Value &value ) +{ + int size = value.size(); + bool isMultiLine = size*3 >= rightMargin_ ; + childValues_.clear(); + for ( int index =0; index < size && !isMultiLine; ++index ) + { + const Value &childValue = value[index]; + isMultiLine = isMultiLine || + ( (childValue.isArray() || childValue.isObject()) && + childValue.size() > 0 ); + } + if ( !isMultiLine ) // check if line length > max line length + { + childValues_.reserve( size ); + addChildValues_ = true; + int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' + for ( int index =0; index < size && !isMultiLine; ++index ) + { + writeValue( value[index] ); + lineLength += int( childValues_[index].length() ); + isMultiLine = isMultiLine && hasCommentForValue( value[index] ); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + + +void +StyledWriter::pushValue( const std::string &value ) +{ + if ( addChildValues_ ) + childValues_.push_back( value ); + else + document_ += value; +} + + +void +StyledWriter::writeIndent() +{ + if ( !document_.empty() ) + { + char last = document_[document_.length()-1]; + if ( last == ' ' ) // already indented + return; + if ( last != '\n' ) // Comments may add new-line + document_ += '\n'; + } + document_ += indentString_; +} + + +void +StyledWriter::writeWithIndent( const std::string &value ) +{ + writeIndent(); + document_ += value; +} + + +void +StyledWriter::indent() +{ + indentString_ += std::string( indentSize_, ' ' ); +} + + +void +StyledWriter::unindent() +{ + assert( int(indentString_.size()) >= indentSize_ ); + indentString_.resize( indentString_.size() - indentSize_ ); +} + + +void +StyledWriter::writeCommentBeforeValue( const Value &root ) +{ + if ( !root.hasComment( commentBefore ) ) + return; + document_ += normalizeEOL( root.getComment( commentBefore ) ); + document_ += "\n"; +} + + +void +StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) +{ + if ( root.hasComment( commentAfterOnSameLine ) ) + document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); + + if ( root.hasComment( commentAfter ) ) + { + document_ += "\n"; + document_ += normalizeEOL( root.getComment( commentAfter ) ); + document_ += "\n"; + } +} + + +bool +StyledWriter::hasCommentForValue( const Value &value ) +{ + return value.hasComment( commentBefore ) + || value.hasComment( commentAfterOnSameLine ) + || value.hasComment( commentAfter ); +} + + +std::string +StyledWriter::normalizeEOL( const std::string &text ) +{ + std::string normalized; + normalized.reserve( text.length() ); + const char *begin = text.c_str(); + const char *end = begin + text.length(); + const char *current = begin; + while ( current != end ) + { + char c = *current++; + if ( c == '\r' ) // mac or dos EOL + { + if ( *current == '\n' ) // convert dos EOL + ++current; + normalized += '\n'; + } + else // handle unix EOL & other char + normalized += c; + } + return normalized; +} + + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter( std::string indentation ) + : document_(NULL) + , rightMargin_( 74 ) + , indentation_( indentation ) +{ +} + + +void +StyledStreamWriter::write( std::ostream &out, const Value &root ) +{ + document_ = &out; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue( root ); + writeValue( root ); + writeCommentAfterValueOnSameLine( root ); + *document_ << "\n"; + document_ = NULL; // Forget the stream, for safety. +} + + +void +StyledStreamWriter::writeValue( const Value &value ) +{ + switch ( value.type() ) + { + case nullValue: + pushValue( "null" ); + break; + case intValue: + pushValue( valueToString( value.asInt() ) ); + break; + case uintValue: + pushValue( valueToString( value.asUInt() ) ); + break; + case realValue: + pushValue( valueToString( value.asDouble() ) ); + break; + case stringValue: + pushValue( valueToQuotedString( value.asCString() ) ); + break; + case booleanValue: + pushValue( valueToString( value.asBool() ) ); + break; + case arrayValue: + writeArrayValue( value); + break; + case objectValue: + { + Value::Members members( value.getMemberNames() ); + if ( members.empty() ) + pushValue( "{}" ); + else + { + writeWithIndent( "{" ); + indent(); + Value::Members::iterator it = members.begin(); + while ( true ) + { + const std::string &name = *it; + const Value &childValue = value[name]; + writeCommentBeforeValue( childValue ); + writeWithIndent( valueToQuotedString( name.c_str() ) ); + *document_ << " : "; + writeValue( childValue ); + if ( ++it == members.end() ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "}" ); + } + } + break; + } +} + + +void +StyledStreamWriter::writeArrayValue( const Value &value ) +{ + unsigned size = value.size(); + if ( size == 0 ) + pushValue( "[]" ); + else + { + bool isArrayMultiLine = isMultineArray( value ); + if ( isArrayMultiLine ) + { + writeWithIndent( "[" ); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index =0; + while ( true ) + { + const Value &childValue = value[index]; + writeCommentBeforeValue( childValue ); + if ( hasChildValue ) + writeWithIndent( childValues_[index] ); + else + { + writeIndent(); + writeValue( childValue ); + } + if ( ++index == size ) + { + writeCommentAfterValueOnSameLine( childValue ); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine( childValue ); + } + unindent(); + writeWithIndent( "]" ); + } + else // output on a single line + { + assert( childValues_.size() == size ); + *document_ << "[ "; + for ( unsigned index =0; index < size; ++index ) + { + if ( index > 0 ) + *document_ << ", "; + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + + +bool +StyledStreamWriter::isMultineArray( const Value &value ) +{ + int size = value.size(); + bool isMultiLine = size*3 >= rightMargin_ ; + childValues_.clear(); + for ( int index =0; index < size && !isMultiLine; ++index ) + { + const Value &childValue = value[index]; + isMultiLine = isMultiLine || + ( (childValue.isArray() || childValue.isObject()) && + childValue.size() > 0 ); + } + if ( !isMultiLine ) // check if line length > max line length + { + childValues_.reserve( size ); + addChildValues_ = true; + int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' + for ( int index =0; index < size && !isMultiLine; ++index ) + { + writeValue( value[index] ); + lineLength += int( childValues_[index].length() ); + isMultiLine = isMultiLine && hasCommentForValue( value[index] ); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + + +void +StyledStreamWriter::pushValue( const std::string &value ) +{ + if ( addChildValues_ ) + childValues_.push_back( value ); + else + *document_ << value; +} + + +void +StyledStreamWriter::writeIndent() +{ + /* + Some comments in this method would have been nice. ;-) + + if ( !document_.empty() ) + { + char last = document_[document_.length()-1]; + if ( last == ' ' ) // already indented + return; + if ( last != '\n' ) // Comments may add new-line + *document_ << '\n'; + } + */ + *document_ << '\n' << indentString_; +} + + +void +StyledStreamWriter::writeWithIndent( const std::string &value ) +{ + writeIndent(); + *document_ << value; +} + + +void +StyledStreamWriter::indent() +{ + indentString_ += indentation_; +} + + +void +StyledStreamWriter::unindent() +{ + assert( indentString_.size() >= indentation_.size() ); + indentString_.resize( indentString_.size() - indentation_.size() ); +} + + +void +StyledStreamWriter::writeCommentBeforeValue( const Value &root ) +{ + if ( !root.hasComment( commentBefore ) ) + return; + *document_ << normalizeEOL( root.getComment( commentBefore ) ); + *document_ << "\n"; +} + + +void +StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) +{ + if ( root.hasComment( commentAfterOnSameLine ) ) + *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); + + if ( root.hasComment( commentAfter ) ) + { + *document_ << "\n"; + *document_ << normalizeEOL( root.getComment( commentAfter ) ); + *document_ << "\n"; + } +} + + +bool +StyledStreamWriter::hasCommentForValue( const Value &value ) +{ + return value.hasComment( commentBefore ) + || value.hasComment( commentAfterOnSameLine ) + || value.hasComment( commentAfter ); +} + + +std::string +StyledStreamWriter::normalizeEOL( const std::string &text ) +{ + std::string normalized; + normalized.reserve( text.length() ); + const char *begin = text.c_str(); + const char *end = begin + text.length(); + const char *current = begin; + while ( current != end ) + { + char c = *current++; + if ( c == '\r' ) // mac or dos EOL + { + if ( *current == '\n' ) // convert dos EOL + ++current; + normalized += '\n'; + } + else // handle unix EOL & other char + normalized += c; + } + return normalized; +} + + +std::ostream& operator<<( std::ostream &sout, const Value &root ) +{ + Json::StyledStreamWriter writer; + writer.write(sout, root); + return sout; +} + + +} // namespace Json diff --git a/src/mad-0.15.1b/ltmain.sh b/src/mad-0.15.1b/ltmain.sh index 012b04e3e7..c3d8879f87 100644 --- a/src/mad-0.15.1b/ltmain.sh +++ b/src/mad-0.15.1b/ltmain.sh @@ -1,6398 +1,6398 @@ -# ltmain.sh - Provide generalized library-building support services. -# NOTE: Changing this file will not affect anything until you rerun configure. -# -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003 -# Free Software Foundation, Inc. -# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# Check that we have a working $echo. -if test "X$1" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift -elif test "X$1" = X--fallback-echo; then - # Avoid inline document here, it may be left over - : -elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then - # Yippee, $echo works! - : -else - # Restart under the correct shell, and then maybe $echo will work. - exec $SHELL "$0" --no-reexec ${1+"$@"} -fi - -if test "X$1" = X--fallback-echo; then - # used as fallback echo - shift - cat <<EOF -$* -EOF - exit 0 -fi - -# The name of this program. -progname=`$echo "$0" | ${SED} 's%^.*/%%'` -modename="$progname" - -# Constants. -PROGRAM=ltmain.sh -PACKAGE=libtool -VERSION=1.5.2 - -default_mode= -help="Try \`$progname --help' for more information." -magic="%%%MAGIC variable%%%" -mkdir="mkdir" -mv="mv -f" -rm="rm -f" - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -Xsed="${SED}"' -e 1s/^X//' -sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g' -# test EBCDIC or ASCII -case `echo A|tr A '\301'` in - A) # EBCDIC based system - SP2NL="tr '\100' '\n'" - NL2SP="tr '\r\n' '\100\100'" - ;; - *) # Assume ASCII based system - SP2NL="tr '\040' '\012'" - NL2SP="tr '\015\012' '\040\040'" - ;; -esac - -# NLS nuisances. -# Only set LANG and LC_ALL to C if already set. -# These must not be set unconditionally because not all systems understand -# e.g. LANG=C (notably SCO). -# We save the old values to restore during execute mode. -if test "${LC_ALL+set}" = set; then - save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL -fi -if test "${LANG+set}" = set; then - save_LANG="$LANG"; LANG=C; export LANG -fi - -# Make sure IFS has a sensible default -: ${IFS=" -"} - -if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then - $echo "$modename: not configured to build any kind of library" 1>&2 - $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 - exit 1 -fi - -# Global variables. -mode=$default_mode -nonopt= -prev= -prevopt= -run= -show="$echo" -show_help= -execute_dlfiles= -lo2o="s/\\.lo\$/.${objext}/" -o2lo="s/\\.${objext}\$/.lo/" - -##################################### -# Shell function definitions: -# This seems to be the best place for them - -# Need a lot of goo to handle *both* DLLs and import libs -# Has to be a shell function in order to 'eat' the argument -# that is supplied when $file_magic_command is called. -win32_libid () { - win32_libid_type="unknown" - win32_fileres=`file -L $1 2>/dev/null` - case $win32_fileres in - *ar\ archive\ import\ library*) # definitely import - win32_libid_type="x86 archive import" - ;; - *ar\ archive*) # could be an import, or static - if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ - grep -E 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then - win32_nmres=`eval $NM -f posix -A $1 | \ - sed -n -e '1,100{/ I /{x;/import/!{s/^/import/;h;p;};x;};}'` - if test "X$win32_nmres" = "Ximport" ; then - win32_libid_type="x86 archive import" - else - win32_libid_type="x86 archive static" - fi - fi - ;; - *DLL*) - win32_libid_type="x86 DLL" - ;; - *executable*) # but shell scripts are "executable" too... - case $win32_fileres in - *MS\ Windows\ PE\ Intel*) - win32_libid_type="x86 DLL" - ;; - esac - ;; - esac - $echo $win32_libid_type -} - -# End of Shell function definitions -##################################### - -# Parse our command line options once, thoroughly. -while test "$#" -gt 0 -do - arg="$1" - shift - - case $arg in - -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; - *) optarg= ;; - esac - - # If the previous option needs an argument, assign it. - if test -n "$prev"; then - case $prev in - execute_dlfiles) - execute_dlfiles="$execute_dlfiles $arg" - ;; - tag) - tagname="$arg" - preserve_args="${preserve_args}=$arg" - - # Check whether tagname contains only valid characters - case $tagname in - *[!-_A-Za-z0-9,/]*) - $echo "$progname: invalid tag name: $tagname" 1>&2 - exit 1 - ;; - esac - - case $tagname in - CC) - # Don't test for the "default" C tag, as we know, it's there, but - # not specially marked. - ;; - *) - if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$0" > /dev/null; then - taglist="$taglist $tagname" - # Evaluate the configuration. - eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $0`" - else - $echo "$progname: ignoring unknown tag $tagname" 1>&2 - fi - ;; - esac - ;; - *) - eval "$prev=\$arg" - ;; - esac - - prev= - prevopt= - continue - fi - - # Have we seen a non-optional argument yet? - case $arg in - --help) - show_help=yes - ;; - - --version) - $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" - $echo - $echo "Copyright (C) 2003 Free Software Foundation, Inc." - $echo "This is free software; see the source for copying conditions. There is NO" - $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - exit 0 - ;; - - --config) - ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $0 - # Now print the configurations for the tags. - for tagname in $taglist; do - ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$0" - done - exit 0 - ;; - - --debug) - $echo "$progname: enabling shell trace mode" - set -x - preserve_args="$preserve_args $arg" - ;; - - --dry-run | -n) - run=: - ;; - - --features) - $echo "host: $host" - if test "$build_libtool_libs" = yes; then - $echo "enable shared libraries" - else - $echo "disable shared libraries" - fi - if test "$build_old_libs" = yes; then - $echo "enable static libraries" - else - $echo "disable static libraries" - fi - exit 0 - ;; - - --finish) mode="finish" ;; - - --mode) prevopt="--mode" prev=mode ;; - --mode=*) mode="$optarg" ;; - - --preserve-dup-deps) duplicate_deps="yes" ;; - - --quiet | --silent) - show=: - preserve_args="$preserve_args $arg" - ;; - - --tag) prevopt="--tag" prev=tag ;; - --tag=*) - set tag "$optarg" ${1+"$@"} - shift - prev=tag - preserve_args="$preserve_args --tag" - ;; - - -dlopen) - prevopt="-dlopen" - prev=execute_dlfiles - ;; - - -*) - $echo "$modename: unrecognized option \`$arg'" 1>&2 - $echo "$help" 1>&2 - exit 1 - ;; - - *) - nonopt="$arg" - break - ;; - esac -done - -if test -n "$prevopt"; then - $echo "$modename: option \`$prevopt' requires an argument" 1>&2 - $echo "$help" 1>&2 - exit 1 -fi - -# If this variable is set in any of the actions, the command in it -# will be execed at the end. This prevents here-documents from being -# left over by shells. -exec_cmd= - -if test -z "$show_help"; then - - # Infer the operation mode. - if test -z "$mode"; then - $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 - $echo "*** Future versions of Libtool will require -mode=MODE be specified." 1>&2 - case $nonopt in - *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) - mode=link - for arg - do - case $arg in - -c) - mode=compile - break - ;; - esac - done - ;; - *db | *dbx | *strace | *truss) - mode=execute - ;; - *install*|cp|mv) - mode=install - ;; - *rm) - mode=uninstall - ;; - *) - # If we have no mode, but dlfiles were specified, then do execute mode. - test -n "$execute_dlfiles" && mode=execute - - # Just use the default operation mode. - if test -z "$mode"; then - if test -n "$nonopt"; then - $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 - else - $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 - fi - fi - ;; - esac - fi - - # Only execute mode is allowed to have -dlopen flags. - if test -n "$execute_dlfiles" && test "$mode" != execute; then - $echo "$modename: unrecognized option \`-dlopen'" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - # Change the help message to a mode-specific one. - generic_help="$help" - help="Try \`$modename --help --mode=$mode' for more information." - - # These modes are in order of execution frequency so that they run quickly. - case $mode in - # libtool compile mode - compile) - modename="$modename: compile" - # Get the compilation command and the source file. - base_compile= - srcfile="$nonopt" # always keep a non-empty value in "srcfile" - suppress_opt=yes - suppress_output= - arg_mode=normal - libobj= - later= - - for arg - do - case "$arg_mode" in - arg ) - # do not "continue". Instead, add this to base_compile - lastarg="$arg" - arg_mode=normal - ;; - - target ) - libobj="$arg" - arg_mode=normal - continue - ;; - - normal ) - # Accept any command-line options. - case $arg in - -o) - if test -n "$libobj" ; then - $echo "$modename: you cannot specify \`-o' more than once" 1>&2 - exit 1 - fi - arg_mode=target - continue - ;; - - -static | -prefer-pic | -prefer-non-pic) - later="$later $arg" - continue - ;; - - -no-suppress) - suppress_opt=no - continue - ;; - - -Xcompiler) - arg_mode=arg # the next one goes into the "base_compile" arg list - continue # The current "srcfile" will either be retained or - ;; # replaced later. I would guess that would be a bug. - - -Wc,*) - args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` - lastarg= - save_ifs="$IFS"; IFS=',' - for arg in $args; do - IFS="$save_ifs" - - # Double-quote args containing other shell metacharacters. - # Many Bourne shells cannot handle close brackets correctly - # in scan sets, so we specify it separately. - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - lastarg="$lastarg $arg" - done - IFS="$save_ifs" - lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` - - # Add the arguments to base_compile. - base_compile="$base_compile $lastarg" - continue - ;; - - * ) - # Accept the current argument as the source file. - # The previous "srcfile" becomes the current argument. - # - lastarg="$srcfile" - srcfile="$arg" - ;; - esac # case $arg - ;; - esac # case $arg_mode - - # Aesthetically quote the previous argument. - lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` - - case $lastarg in - # Double-quote args containing other shell metacharacters. - # Many Bourne shells cannot handle close brackets correctly - # in scan sets, so we specify it separately. - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - lastarg="\"$lastarg\"" - ;; - esac - - base_compile="$base_compile $lastarg" - done # for arg - - case $arg_mode in - arg) - $echo "$modename: you must specify an argument for -Xcompile" - exit 1 - ;; - target) - $echo "$modename: you must specify a target with \`-o'" 1>&2 - exit 1 - ;; - *) - # Get the name of the library object. - [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` - ;; - esac - - # Recognize several different file suffixes. - # If the user specifies -o file.o, it is replaced with file.lo - xform='[cCFSifmso]' - case $libobj in - *.ada) xform=ada ;; - *.adb) xform=adb ;; - *.ads) xform=ads ;; - *.asm) xform=asm ;; - *.c++) xform=c++ ;; - *.cc) xform=cc ;; - *.ii) xform=ii ;; - *.class) xform=class ;; - *.cpp) xform=cpp ;; - *.cxx) xform=cxx ;; - *.f90) xform=f90 ;; - *.for) xform=for ;; - *.java) xform=java ;; - esac - - libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` - - case $libobj in - *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; - *) - $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 - exit 1 - ;; - esac - - # Infer tagged configuration to use if any are available and - # if one wasn't chosen via the "--tag" command line option. - # Only attempt this if the compiler in the base compile - # command doesn't match the default compiler. - if test -n "$available_tags" && test -z "$tagname"; then - case $base_compile in - # Blanks in the command may have been stripped by the calling shell, - # but not from the CC environment variable when configure was run. - " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "*) ;; - # Blanks at the start of $base_compile will cause this to fail - # if we don't check for them as well. - *) - for z in $available_tags; do - if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$0" > /dev/null; then - # Evaluate the configuration. - eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $0`" - case "$base_compile " in - "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*) - # The compiler in the base compile command matches - # the one in the tagged configuration. - # Assume this is the tagged configuration we want. - tagname=$z - break - ;; - esac - fi - done - # If $tagname still isn't set, then no tagged configuration - # was found and let the user know that the "--tag" command - # line option must be used. - if test -z "$tagname"; then - $echo "$modename: unable to infer tagged configuration" - $echo "$modename: specify a tag with \`--tag'" 1>&2 - exit 1 -# else -# $echo "$modename: using $tagname tagged configuration" - fi - ;; - esac - fi - - for arg in $later; do - case $arg in - -static) - build_old_libs=yes - continue - ;; - - -prefer-pic) - pic_mode=yes - continue - ;; - - -prefer-non-pic) - pic_mode=no - continue - ;; - esac - done - - objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` - xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` - if test "X$xdir" = "X$obj"; then - xdir= - else - xdir=$xdir/ - fi - lobj=${xdir}$objdir/$objname - - if test -z "$base_compile"; then - $echo "$modename: you must specify a compilation command" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - # Delete any leftover library objects. - if test "$build_old_libs" = yes; then - removelist="$obj $lobj $libobj ${libobj}T" - else - removelist="$lobj $libobj ${libobj}T" - fi - - $run $rm $removelist - trap "$run $rm $removelist; exit 1" 1 2 15 - - # On Cygwin there's no "real" PIC flag so we must build both object types - case $host_os in - cygwin* | mingw* | pw32* | os2*) - pic_mode=default - ;; - esac - if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then - # non-PIC code in shared libraries is not supported - pic_mode=default - fi - - # Calculate the filename of the output object if compiler does - # not support -o with -c - if test "$compiler_c_o" = no; then - output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} - lockfile="$output_obj.lock" - removelist="$removelist $output_obj $lockfile" - trap "$run $rm $removelist; exit 1" 1 2 15 - else - output_obj= - need_locks=no - lockfile= - fi - - # Lock this critical section if it is needed - # We use this script file to make the link, it avoids creating a new file - if test "$need_locks" = yes; then - until $run ln "$0" "$lockfile" 2>/dev/null; do - $show "Waiting for $lockfile to be removed" - sleep 2 - done - elif test "$need_locks" = warn; then - if test -f "$lockfile"; then - $echo "\ -*** ERROR, $lockfile exists and contains: -`cat $lockfile 2>/dev/null` - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $run $rm $removelist - exit 1 - fi - $echo $srcfile > "$lockfile" - fi - - if test -n "$fix_srcfile_path"; then - eval srcfile=\"$fix_srcfile_path\" - fi - - $run $rm "$libobj" "${libobj}T" - - # Create a libtool object file (analogous to a ".la" file), - # but don't create it if we're doing a dry run. - test -z "$run" && cat > ${libobj}T <<EOF -# $libobj - a libtool object file -# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# Name of the PIC object. -EOF - - # Only build a PIC object if we are building libtool libraries. - if test "$build_libtool_libs" = yes; then - # Without this assignment, base_compile gets emptied. - fbsd_hideous_sh_bug=$base_compile - - if test "$pic_mode" != no; then - command="$base_compile $srcfile $pic_flag" - else - # Don't build PIC code - command="$base_compile $srcfile" - fi - - if test ! -d "${xdir}$objdir"; then - $show "$mkdir ${xdir}$objdir" - $run $mkdir ${xdir}$objdir - status=$? - if test "$status" -ne 0 && test ! -d "${xdir}$objdir"; then - exit $status - fi - fi - - if test -z "$output_obj"; then - # Place PIC objects in $objdir - command="$command -o $lobj" - fi - - $run $rm "$lobj" "$output_obj" - - $show "$command" - if $run eval "$command"; then : - else - test -n "$output_obj" && $run $rm $removelist - exit 1 - fi - - if test "$need_locks" = warn && - test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then - $echo "\ -*** ERROR, $lockfile contains: -`cat $lockfile 2>/dev/null` - -but it should contain: -$srcfile - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $run $rm $removelist - exit 1 - fi - - # Just move the object if needed, then go on to compile the next one - if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then - $show "$mv $output_obj $lobj" - if $run $mv $output_obj $lobj; then : - else - error=$? - $run $rm $removelist - exit $error - fi - fi - - # Append the name of the PIC object to the libtool object file. - test -z "$run" && cat >> ${libobj}T <<EOF -pic_object='$objdir/$objname' - -EOF - - # Allow error messages only from the first compilation. - if test "$suppress_opt" = yes; then - suppress_output=' >/dev/null 2>&1' - fi - else - # No PIC object so indicate it doesn't exist in the libtool - # object file. - test -z "$run" && cat >> ${libobj}T <<EOF -pic_object=none - -EOF - fi - - # Only build a position-dependent object if we build old libraries. - if test "$build_old_libs" = yes; then - if test "$pic_mode" != yes; then - # Don't build PIC code - command="$base_compile $srcfile" - else - command="$base_compile $srcfile $pic_flag" - fi - if test "$compiler_c_o" = yes; then - command="$command -o $obj" - fi - - # Suppress compiler output if we already did a PIC compilation. - command="$command$suppress_output" - $run $rm "$obj" "$output_obj" - $show "$command" - if $run eval "$command"; then : - else - $run $rm $removelist - exit 1 - fi - - if test "$need_locks" = warn && - test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then - $echo "\ -*** ERROR, $lockfile contains: -`cat $lockfile 2>/dev/null` - -but it should contain: -$srcfile - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $run $rm $removelist - exit 1 - fi - - # Just move the object if needed - if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then - $show "$mv $output_obj $obj" - if $run $mv $output_obj $obj; then : - else - error=$? - $run $rm $removelist - exit $error - fi - fi - - # Append the name of the non-PIC object the libtool object file. - # Only append if the libtool object file exists. - test -z "$run" && cat >> ${libobj}T <<EOF -# Name of the non-PIC object. -non_pic_object='$objname' - -EOF - else - # Append the name of the non-PIC object the libtool object file. - # Only append if the libtool object file exists. - test -z "$run" && cat >> ${libobj}T <<EOF -# Name of the non-PIC object. -non_pic_object=none - -EOF - fi - - $run $mv "${libobj}T" "${libobj}" - - # Unlock the critical section if it was locked - if test "$need_locks" != no; then - $run $rm "$lockfile" - fi - - exit 0 - ;; - - # libtool link mode - link | relink) - modename="$modename: link" - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) - # It is impossible to link a dll without this setting, and - # we shouldn't force the makefile maintainer to figure out - # which system we are compiling for in order to pass an extra - # flag for every libtool invocation. - # allow_undefined=no - - # FIXME: Unfortunately, there are problems with the above when trying - # to make a dll which has undefined symbols, in which case not - # even a static library is built. For now, we need to specify - # -no-undefined on the libtool link line when we can be certain - # that all symbols are satisfied, otherwise we get a static library. - allow_undefined=yes - ;; - *) - allow_undefined=yes - ;; - esac - libtool_args="$nonopt" - base_compile="$nonopt $@" - compile_command="$nonopt" - finalize_command="$nonopt" - - compile_rpath= - finalize_rpath= - compile_shlibpath= - finalize_shlibpath= - convenience= - old_convenience= - deplibs= - old_deplibs= - compiler_flags= - linker_flags= - dllsearchpath= - lib_search_path=`pwd` - inst_prefix_dir= - - avoid_version=no - dlfiles= - dlprefiles= - dlself=no - export_dynamic=no - export_symbols= - export_symbols_regex= - generated= - libobjs= - ltlibs= - module=no - no_install=no - objs= - non_pic_objects= - precious_files_regex= - prefer_static_libs=no - preload=no - prev= - prevarg= - release= - rpath= - xrpath= - perm_rpath= - temp_rpath= - thread_safe=no - vinfo= - vinfo_number=no - - # Infer tagged configuration to use if any are available and - # if one wasn't chosen via the "--tag" command line option. - # Only attempt this if the compiler in the base link - # command doesn't match the default compiler. - if test -n "$available_tags" && test -z "$tagname"; then - case $base_compile in - # Blanks in the command may have been stripped by the calling shell, - # but not from the CC environment variable when configure was run. - "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*) ;; - # Blanks at the start of $base_compile will cause this to fail - # if we don't check for them as well. - *) - for z in $available_tags; do - if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$0" > /dev/null; then - # Evaluate the configuration. - eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $0`" - case $base_compile in - "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*) - # The compiler in $compile_command matches - # the one in the tagged configuration. - # Assume this is the tagged configuration we want. - tagname=$z - break - ;; - esac - fi - done - # If $tagname still isn't set, then no tagged configuration - # was found and let the user know that the "--tag" command - # line option must be used. - if test -z "$tagname"; then - $echo "$modename: unable to infer tagged configuration" - $echo "$modename: specify a tag with \`--tag'" 1>&2 - exit 1 -# else -# $echo "$modename: using $tagname tagged configuration" - fi - ;; - esac - fi - - # We need to know -static, to get the right output filenames. - for arg - do - case $arg in - -all-static | -static) - if test "X$arg" = "X-all-static"; then - if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then - $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2 - fi - if test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - else - if test -z "$pic_flag" && test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - fi - build_libtool_libs=no - build_old_libs=yes - prefer_static_libs=yes - break - ;; - esac - done - - # See if our shared archives depend on static archives. - test -n "$old_archive_from_new_cmds" && build_old_libs=yes - - # Go through the arguments, transforming them on the way. - while test "$#" -gt 0; do - arg="$1" - shift - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test - ;; - *) qarg=$arg ;; - esac - libtool_args="$libtool_args $qarg" - - # If the previous option needs an argument, assign it. - if test -n "$prev"; then - case $prev in - output) - compile_command="$compile_command @OUTPUT@" - finalize_command="$finalize_command @OUTPUT@" - ;; - esac - - case $prev in - dlfiles|dlprefiles) - if test "$preload" = no; then - # Add the symbol object into the linking commands. - compile_command="$compile_command @SYMFILE@" - finalize_command="$finalize_command @SYMFILE@" - preload=yes - fi - case $arg in - *.la | *.lo) ;; # We handle these cases below. - force) - if test "$dlself" = no; then - dlself=needless - export_dynamic=yes - fi - prev= - continue - ;; - self) - if test "$prev" = dlprefiles; then - dlself=yes - elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then - dlself=yes - else - dlself=needless - export_dynamic=yes - fi - prev= - continue - ;; - *) - if test "$prev" = dlfiles; then - dlfiles="$dlfiles $arg" - else - dlprefiles="$dlprefiles $arg" - fi - prev= - continue - ;; - esac - ;; - expsyms) - export_symbols="$arg" - if test ! -f "$arg"; then - $echo "$modename: symbol file \`$arg' does not exist" - exit 1 - fi - prev= - continue - ;; - expsyms_regex) - export_symbols_regex="$arg" - prev= - continue - ;; - inst_prefix) - inst_prefix_dir="$arg" - prev= - continue - ;; - precious_regex) - precious_files_regex="$arg" - prev= - continue - ;; - release) - release="-$arg" - prev= - continue - ;; - objectlist) - if test -f "$arg"; then - save_arg=$arg - moreargs= - for fil in `cat $save_arg` - do -# moreargs="$moreargs $fil" - arg=$fil - # A libtool-controlled object. - - # Check to see that this really is a libtool object. - if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - pic_object= - non_pic_object= - - # Read the .lo file - # If there is no directory component, then add one. - case $arg in - */* | *\\*) . $arg ;; - *) . ./$arg ;; - esac - - if test -z "$pic_object" || \ - test -z "$non_pic_object" || - test "$pic_object" = none && \ - test "$non_pic_object" = none; then - $echo "$modename: cannot find name of object for \`$arg'" 1>&2 - exit 1 - fi - - # Extract subdirectory from the argument. - xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` - if test "X$xdir" = "X$arg"; then - xdir= - else - xdir="$xdir/" - fi - - if test "$pic_object" != none; then - # Prepend the subdirectory the object is found in. - pic_object="$xdir$pic_object" - - if test "$prev" = dlfiles; then - if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then - dlfiles="$dlfiles $pic_object" - prev= - continue - else - # If libtool objects are unsupported, then we need to preload. - prev=dlprefiles - fi - fi - - # CHECK ME: I think I busted this. -Ossama - if test "$prev" = dlprefiles; then - # Preload the old-style object. - dlprefiles="$dlprefiles $pic_object" - prev= - fi - - # A PIC object. - libobjs="$libobjs $pic_object" - arg="$pic_object" - fi - - # Non-PIC object. - if test "$non_pic_object" != none; then - # Prepend the subdirectory the object is found in. - non_pic_object="$xdir$non_pic_object" - - # A standard non-PIC object - non_pic_objects="$non_pic_objects $non_pic_object" - if test -z "$pic_object" || test "$pic_object" = none ; then - arg="$non_pic_object" - fi - fi - else - # Only an error if not doing a dry-run. - if test -z "$run"; then - $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 - exit 1 - else - # Dry-run case. - - # Extract subdirectory from the argument. - xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` - if test "X$xdir" = "X$arg"; then - xdir= - else - xdir="$xdir/" - fi - - pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` - non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` - libobjs="$libobjs $pic_object" - non_pic_objects="$non_pic_objects $non_pic_object" - fi - fi - done - else - $echo "$modename: link input file \`$save_arg' does not exist" - exit 1 - fi - arg=$save_arg - prev= - continue - ;; - rpath | xrpath) - # We need an absolute path. - case $arg in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - $echo "$modename: only absolute run-paths are allowed" 1>&2 - exit 1 - ;; - esac - if test "$prev" = rpath; then - case "$rpath " in - *" $arg "*) ;; - *) rpath="$rpath $arg" ;; - esac - else - case "$xrpath " in - *" $arg "*) ;; - *) xrpath="$xrpath $arg" ;; - esac - fi - prev= - continue - ;; - xcompiler) - compiler_flags="$compiler_flags $qarg" - prev= - compile_command="$compile_command $qarg" - finalize_command="$finalize_command $qarg" - continue - ;; - xlinker) - linker_flags="$linker_flags $qarg" - compiler_flags="$compiler_flags $wl$qarg" - prev= - compile_command="$compile_command $wl$qarg" - finalize_command="$finalize_command $wl$qarg" - continue - ;; - xcclinker) - linker_flags="$linker_flags $qarg" - compiler_flags="$compiler_flags $qarg" - prev= - compile_command="$compile_command $qarg" - finalize_command="$finalize_command $qarg" - continue - ;; - *) - eval "$prev=\"\$arg\"" - prev= - continue - ;; - esac - fi # test -n "$prev" - - prevarg="$arg" - - case $arg in - -all-static) - if test -n "$link_static_flag"; then - compile_command="$compile_command $link_static_flag" - finalize_command="$finalize_command $link_static_flag" - fi - continue - ;; - - -allow-undefined) - # FIXME: remove this flag sometime in the future. - $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 - continue - ;; - - -avoid-version) - avoid_version=yes - continue - ;; - - -dlopen) - prev=dlfiles - continue - ;; - - -dlpreopen) - prev=dlprefiles - continue - ;; - - -export-dynamic) - export_dynamic=yes - continue - ;; - - -export-symbols | -export-symbols-regex) - if test -n "$export_symbols" || test -n "$export_symbols_regex"; then - $echo "$modename: more than one -exported-symbols argument is not allowed" - exit 1 - fi - if test "X$arg" = "X-export-symbols"; then - prev=expsyms - else - prev=expsyms_regex - fi - continue - ;; - - -inst-prefix-dir) - prev=inst_prefix - continue - ;; - - # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* - # so, if we see these flags be careful not to treat them like -L - -L[A-Z][A-Z]*:*) - case $with_gcc/$host in - no/*-*-irix* | /*-*-irix*) - compile_command="$compile_command $arg" - finalize_command="$finalize_command $arg" - ;; - esac - continue - ;; - - -L*) - dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - absdir=`cd "$dir" && pwd` - if test -z "$absdir"; then - $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 - exit 1 - fi - dir="$absdir" - ;; - esac - case "$deplibs " in - *" -L$dir "*) ;; - *) - deplibs="$deplibs -L$dir" - lib_search_path="$lib_search_path $dir" - ;; - esac - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) - case :$dllsearchpath: in - *":$dir:"*) ;; - *) dllsearchpath="$dllsearchpath:$dir";; - esac - ;; - esac - continue - ;; - - -l*) - if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then - case $host in - *-*-cygwin* | *-*-pw32* | *-*-beos*) - # These systems don't actually have a C or math library (as such) - continue - ;; - *-*-mingw* | *-*-os2*) - # These systems don't actually have a C library (as such) - test "X$arg" = "X-lc" && continue - ;; - *-*-openbsd* | *-*-freebsd*) - # Do not include libc due to us having libc/libc_r. - test "X$arg" = "X-lc" && continue - ;; - *-*-rhapsody* | *-*-darwin1.[012]) - # Rhapsody C and math libraries are in the System framework - deplibs="$deplibs -framework System" - continue - esac - elif test "X$arg" = "X-lc_r"; then - case $host in - *-*-openbsd* | *-*-freebsd*) - # Do not include libc_r directly, use -pthread flag. - continue - ;; - esac - fi - deplibs="$deplibs $arg" - continue - ;; - - -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) - deplibs="$deplibs $arg" - continue - ;; - - -module) - module=yes - continue - ;; - - # gcc -m* arguments should be passed to the linker via $compiler_flags - # in order to pass architecture information to the linker - # (e.g. 32 vs 64-bit). This may also be accomplished via -Wl,-mfoo - # but this is not reliable with gcc because gcc may use -mfoo to - # select a different linker, different libraries, etc, while - # -Wl,-mfoo simply passes -mfoo to the linker. - -m*) - # Unknown arguments in both finalize_command and compile_command need - # to be aesthetically quoted because they are evaled later. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - compile_command="$compile_command $arg" - finalize_command="$finalize_command $arg" - if test "$with_gcc" = "yes" ; then - compiler_flags="$compiler_flags $arg" - fi - continue - ;; - - -shrext) - prev=shrext - continue - ;; - - -no-fast-install) - fast_install=no - continue - ;; - - -no-install) - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) - # The PATH hackery in wrapper scripts is required on Windows - # in order for the loader to find any dlls it needs. - $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 - $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 - fast_install=no - ;; - *) no_install=yes ;; - esac - continue - ;; - - -no-undefined) - allow_undefined=no - continue - ;; - - -objectlist) - prev=objectlist - continue - ;; - - -o) prev=output ;; - - -precious-files-regex) - prev=precious_regex - continue - ;; - - -release) - prev=release - continue - ;; - - -rpath) - prev=rpath - continue - ;; - - -R) - prev=xrpath - continue - ;; - - -R*) - dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - $echo "$modename: only absolute run-paths are allowed" 1>&2 - exit 1 - ;; - esac - case "$xrpath " in - *" $dir "*) ;; - *) xrpath="$xrpath $dir" ;; - esac - continue - ;; - - -static) - # The effects of -static are defined in a previous loop. - # We used to do the same as -all-static on platforms that - # didn't have a PIC flag, but the assumption that the effects - # would be equivalent was wrong. It would break on at least - # Digital Unix and AIX. - continue - ;; - - -thread-safe) - thread_safe=yes - continue - ;; - - -version-info) - prev=vinfo - continue - ;; - -version-number) - prev=vinfo - vinfo_number=yes - continue - ;; - - -Wc,*) - args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` - arg= - save_ifs="$IFS"; IFS=',' - for flag in $args; do - IFS="$save_ifs" - case $flag in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - flag="\"$flag\"" - ;; - esac - arg="$arg $wl$flag" - compiler_flags="$compiler_flags $flag" - done - IFS="$save_ifs" - arg=`$echo "X$arg" | $Xsed -e "s/^ //"` - ;; - - -Wl,*) - args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` - arg= - save_ifs="$IFS"; IFS=',' - for flag in $args; do - IFS="$save_ifs" - case $flag in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - flag="\"$flag\"" - ;; - esac - arg="$arg $wl$flag" - compiler_flags="$compiler_flags $wl$flag" - linker_flags="$linker_flags $flag" - done - IFS="$save_ifs" - arg=`$echo "X$arg" | $Xsed -e "s/^ //"` - ;; - - -Xcompiler) - prev=xcompiler - continue - ;; - - -Xlinker) - prev=xlinker - continue - ;; - - -XCClinker) - prev=xcclinker - continue - ;; - - # Some other compiler flag. - -* | +*) - # Unknown arguments in both finalize_command and compile_command need - # to be aesthetically quoted because they are evaled later. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - ;; - - *.$objext) - # A standard object. - objs="$objs $arg" - ;; - - *.lo) - # A libtool-controlled object. - - # Check to see that this really is a libtool object. - if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - pic_object= - non_pic_object= - - # Read the .lo file - # If there is no directory component, then add one. - case $arg in - */* | *\\*) . $arg ;; - *) . ./$arg ;; - esac - - if test -z "$pic_object" || \ - test -z "$non_pic_object" || - test "$pic_object" = none && \ - test "$non_pic_object" = none; then - $echo "$modename: cannot find name of object for \`$arg'" 1>&2 - exit 1 - fi - - # Extract subdirectory from the argument. - xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` - if test "X$xdir" = "X$arg"; then - xdir= - else - xdir="$xdir/" - fi - - if test "$pic_object" != none; then - # Prepend the subdirectory the object is found in. - pic_object="$xdir$pic_object" - - if test "$prev" = dlfiles; then - if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then - dlfiles="$dlfiles $pic_object" - prev= - continue - else - # If libtool objects are unsupported, then we need to preload. - prev=dlprefiles - fi - fi - - # CHECK ME: I think I busted this. -Ossama - if test "$prev" = dlprefiles; then - # Preload the old-style object. - dlprefiles="$dlprefiles $pic_object" - prev= - fi - - # A PIC object. - libobjs="$libobjs $pic_object" - arg="$pic_object" - fi - - # Non-PIC object. - if test "$non_pic_object" != none; then - # Prepend the subdirectory the object is found in. - non_pic_object="$xdir$non_pic_object" - - # A standard non-PIC object - non_pic_objects="$non_pic_objects $non_pic_object" - if test -z "$pic_object" || test "$pic_object" = none ; then - arg="$non_pic_object" - fi - fi - else - # Only an error if not doing a dry-run. - if test -z "$run"; then - $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 - exit 1 - else - # Dry-run case. - - # Extract subdirectory from the argument. - xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` - if test "X$xdir" = "X$arg"; then - xdir= - else - xdir="$xdir/" - fi - - pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` - non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` - libobjs="$libobjs $pic_object" - non_pic_objects="$non_pic_objects $non_pic_object" - fi - fi - ;; - - *.$libext) - # An archive. - deplibs="$deplibs $arg" - old_deplibs="$old_deplibs $arg" - continue - ;; - - *.la) - # A libtool-controlled library. - - if test "$prev" = dlfiles; then - # This library was specified with -dlopen. - dlfiles="$dlfiles $arg" - prev= - elif test "$prev" = dlprefiles; then - # The library was specified with -dlpreopen. - dlprefiles="$dlprefiles $arg" - prev= - else - deplibs="$deplibs $arg" - fi - continue - ;; - - # Some other compiler argument. - *) - # Unknown arguments in both finalize_command and compile_command need - # to be aesthetically quoted because they are evaled later. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - arg="\"$arg\"" - ;; - esac - ;; - esac # arg - - # Now actually substitute the argument into the commands. - if test -n "$arg"; then - compile_command="$compile_command $arg" - finalize_command="$finalize_command $arg" - fi - done # argument parsing loop - - if test -n "$prev"; then - $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then - eval arg=\"$export_dynamic_flag_spec\" - compile_command="$compile_command $arg" - finalize_command="$finalize_command $arg" - fi - - oldlibs= - # calculate the name of the file, without its directory - outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` - libobjs_save="$libobjs" - - if test -n "$shlibpath_var"; then - # get the directories listed in $shlibpath_var - eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` - else - shlib_search_path= - fi - eval sys_lib_search_path=\"$sys_lib_search_path_spec\" - eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" - - output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` - if test "X$output_objdir" = "X$output"; then - output_objdir="$objdir" - else - output_objdir="$output_objdir/$objdir" - fi - # Create the object directory. - if test ! -d "$output_objdir"; then - $show "$mkdir $output_objdir" - $run $mkdir $output_objdir - status=$? - if test "$status" -ne 0 && test ! -d "$output_objdir"; then - exit $status - fi - fi - - # Determine the type of output - case $output in - "") - $echo "$modename: you must specify an output file" 1>&2 - $echo "$help" 1>&2 - exit 1 - ;; - *.$libext) linkmode=oldlib ;; - *.lo | *.$objext) linkmode=obj ;; - *.la) linkmode=lib ;; - *) linkmode=prog ;; # Anything else should be a program. - esac - - case $host in - *cygwin* | *mingw* | *pw32*) - # don't eliminate duplcations in $postdeps and $predeps - duplicate_compiler_generated_deps=yes - ;; - *) - duplicate_compiler_generated_deps=$duplicate_deps - ;; - esac - specialdeplibs= - - libs= - # Find all interdependent deplibs by searching for libraries - # that are linked more than once (e.g. -la -lb -la) - for deplib in $deplibs; do - if test "X$duplicate_deps" = "Xyes" ; then - case "$libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; - esac - fi - libs="$libs $deplib" - done - - if test "$linkmode" = lib; then - libs="$predeps $libs $compiler_lib_search_path $postdeps" - - # Compute libraries that are listed more than once in $predeps - # $postdeps and mark them as special (i.e., whose duplicates are - # not to be eliminated). - pre_post_deps= - if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then - for pre_post_dep in $predeps $postdeps; do - case "$pre_post_deps " in - *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; - esac - pre_post_deps="$pre_post_deps $pre_post_dep" - done - fi - pre_post_deps= - fi - - deplibs= - newdependency_libs= - newlib_search_path= - need_relink=no # whether we're linking any uninstalled libtool libraries - notinst_deplibs= # not-installed libtool libraries - notinst_path= # paths that contain not-installed libtool libraries - case $linkmode in - lib) - passes="conv link" - for file in $dlfiles $dlprefiles; do - case $file in - *.la) ;; - *) - $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 - exit 1 - ;; - esac - done - ;; - prog) - compile_deplibs= - finalize_deplibs= - alldeplibs=no - newdlfiles= - newdlprefiles= - passes="conv scan dlopen dlpreopen link" - ;; - *) passes="conv" - ;; - esac - for pass in $passes; do - if test "$linkmode,$pass" = "lib,link" || - test "$linkmode,$pass" = "prog,scan"; then - libs="$deplibs" - deplibs= - fi - if test "$linkmode" = prog; then - case $pass in - dlopen) libs="$dlfiles" ;; - dlpreopen) libs="$dlprefiles" ;; - link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; - esac - fi - if test "$pass" = dlopen; then - # Collect dlpreopened libraries - save_deplibs="$deplibs" - deplibs= - fi - for deplib in $libs; do - lib= - found=no - case $deplib in - -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) - if test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - deplibs="$deplib $deplibs" - fi - continue - ;; - -l*) - if test "$linkmode" != lib && test "$linkmode" != prog; then - $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 - continue - fi - if test "$pass" = conv; then - deplibs="$deplib $deplibs" - continue - fi - name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` - for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do - for search_ext in .la $shrext .so .a; do - # Search the libtool library - lib="$searchdir/lib${name}${search_ext}" - if test -f "$lib"; then - if test "$search_ext" = ".la"; then - found=yes - else - found=no - fi - break 2 - fi - done - done - if test "$found" != yes; then - # deplib doesn't seem to be a libtool library - if test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - deplibs="$deplib $deplibs" - test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" - fi - continue - else # deplib is a libtool library - # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, - # We need to do some special things here, and not later. - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $deplib "*) - if (${SED} -e '2q' $lib | - grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - library_names= - old_library= - case $lib in - */* | *\\*) . $lib ;; - *) . ./$lib ;; - esac - for l in $old_library $library_names; do - ll="$l" - done - if test "X$ll" = "X$old_library" ; then # only static version available - found=no - ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` - test "X$ladir" = "X$lib" && ladir="." - lib=$ladir/$old_library - if test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - deplibs="$deplib $deplibs" - test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" - fi - continue - fi - fi - ;; - *) ;; - esac - fi - fi - ;; # -l - -L*) - case $linkmode in - lib) - deplibs="$deplib $deplibs" - test "$pass" = conv && continue - newdependency_libs="$deplib $newdependency_libs" - newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` - ;; - prog) - if test "$pass" = conv; then - deplibs="$deplib $deplibs" - continue - fi - if test "$pass" = scan; then - deplibs="$deplib $deplibs" - newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` - else - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - fi - ;; - *) - $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 - ;; - esac # linkmode - continue - ;; # -L - -R*) - if test "$pass" = link; then - dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` - # Make sure the xrpath contains only unique directories. - case "$xrpath " in - *" $dir "*) ;; - *) xrpath="$xrpath $dir" ;; - esac - fi - deplibs="$deplib $deplibs" - continue - ;; - *.la) lib="$deplib" ;; - *.$libext) - if test "$pass" = conv; then - deplibs="$deplib $deplibs" - continue - fi - case $linkmode in - lib) - if test "$deplibs_check_method" != pass_all; then - $echo - $echo "*** Warning: Trying to link with static lib archive $deplib." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which you do not appear to have" - $echo "*** because the file extensions .$libext of this argument makes me believe" - $echo "*** that it is just a static archive that I should not used here." - else - $echo - $echo "*** Warning: Linking the shared library $output against the" - $echo "*** static library $deplib is not portable!" - deplibs="$deplib $deplibs" - fi - continue - ;; - prog) - if test "$pass" != link; then - deplibs="$deplib $deplibs" - else - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - fi - continue - ;; - esac # linkmode - ;; # *.$libext - *.lo | *.$objext) - if test "$pass" = conv; then - deplibs="$deplib $deplibs" - elif test "$linkmode" = prog; then - if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then - # If there is no dlopen support or we're linking statically, - # we need to preload. - newdlprefiles="$newdlprefiles $deplib" - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - newdlfiles="$newdlfiles $deplib" - fi - fi - continue - ;; - %DEPLIBS%) - alldeplibs=yes - continue - ;; - esac # case $deplib - if test "$found" = yes || test -f "$lib"; then : - else - $echo "$modename: cannot find the library \`$lib'" 1>&2 - exit 1 - fi - - # Check to see that this really is a libtool archive. - if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : - else - $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 - exit 1 - fi - - ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` - test "X$ladir" = "X$lib" && ladir="." - - dlname= - dlopen= - dlpreopen= - libdir= - library_names= - old_library= - # If the library was installed with an old release of libtool, - # it will not redefine variables installed, or shouldnotlink - installed=yes - shouldnotlink=no - - # Read the .la file - case $lib in - */* | *\\*) . $lib ;; - *) . ./$lib ;; - esac - - if test "$linkmode,$pass" = "lib,link" || - test "$linkmode,$pass" = "prog,scan" || - { test "$linkmode" != prog && test "$linkmode" != lib; }; then - test -n "$dlopen" && dlfiles="$dlfiles $dlopen" - test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" - fi - - if test "$pass" = conv; then - # Only check for convenience libraries - deplibs="$lib $deplibs" - if test -z "$libdir"; then - if test -z "$old_library"; then - $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 - exit 1 - fi - # It is a libtool convenience library, so add in its objects. - convenience="$convenience $ladir/$objdir/$old_library" - old_convenience="$old_convenience $ladir/$objdir/$old_library" - tmp_libs= - for deplib in $dependency_libs; do - deplibs="$deplib $deplibs" - if test "X$duplicate_deps" = "Xyes" ; then - case "$tmp_libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; - esac - fi - tmp_libs="$tmp_libs $deplib" - done - elif test "$linkmode" != prog && test "$linkmode" != lib; then - $echo "$modename: \`$lib' is not a convenience library" 1>&2 - exit 1 - fi - continue - fi # $pass = conv - - - # Get the name of the library we link against. - linklib= - for l in $old_library $library_names; do - linklib="$l" - done - if test -z "$linklib"; then - $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 - exit 1 - fi - - # This library was specified with -dlopen. - if test "$pass" = dlopen; then - if test -z "$libdir"; then - $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 - exit 1 - fi - if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then - # If there is no dlname, no dlopen support or we're linking - # statically, we need to preload. We also need to preload any - # dependent libraries so libltdl's deplib preloader doesn't - # bomb out in the load deplibs phase. - dlprefiles="$dlprefiles $lib $dependency_libs" - else - newdlfiles="$newdlfiles $lib" - fi - continue - fi # $pass = dlopen - - # We need an absolute path. - case $ladir in - [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; - *) - abs_ladir=`cd "$ladir" && pwd` - if test -z "$abs_ladir"; then - $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 - $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 - abs_ladir="$ladir" - fi - ;; - esac - laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` - - # Find the relevant object directory and library name. - if test "X$installed" = Xyes; then - if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then - $echo "$modename: warning: library \`$lib' was moved." 1>&2 - dir="$ladir" - absdir="$abs_ladir" - libdir="$abs_ladir" - else - dir="$libdir" - absdir="$libdir" - fi - else - dir="$ladir/$objdir" - absdir="$abs_ladir/$objdir" - # Remove this search path later - notinst_path="$notinst_path $abs_ladir" - fi # $installed = yes - name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` - - # This library was specified with -dlpreopen. - if test "$pass" = dlpreopen; then - if test -z "$libdir"; then - $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 - exit 1 - fi - # Prefer using a static library (so that no silly _DYNAMIC symbols - # are required to link). - if test -n "$old_library"; then - newdlprefiles="$newdlprefiles $dir/$old_library" - # Otherwise, use the dlname, so that lt_dlopen finds it. - elif test -n "$dlname"; then - newdlprefiles="$newdlprefiles $dir/$dlname" - else - newdlprefiles="$newdlprefiles $dir/$linklib" - fi - fi # $pass = dlpreopen - - if test -z "$libdir"; then - # Link the convenience library - if test "$linkmode" = lib; then - deplibs="$dir/$old_library $deplibs" - elif test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$dir/$old_library $compile_deplibs" - finalize_deplibs="$dir/$old_library $finalize_deplibs" - else - deplibs="$lib $deplibs" # used for prog,scan pass - fi - continue - fi - - - if test "$linkmode" = prog && test "$pass" != link; then - newlib_search_path="$newlib_search_path $ladir" - deplibs="$lib $deplibs" - - linkalldeplibs=no - if test "$link_all_deplibs" != no || test -z "$library_names" || - test "$build_libtool_libs" = no; then - linkalldeplibs=yes - fi - - tmp_libs= - for deplib in $dependency_libs; do - case $deplib in - -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test - esac - # Need to link against all dependency_libs? - if test "$linkalldeplibs" = yes; then - deplibs="$deplib $deplibs" - else - # Need to hardcode shared library paths - # or/and link against static libraries - newdependency_libs="$deplib $newdependency_libs" - fi - if test "X$duplicate_deps" = "Xyes" ; then - case "$tmp_libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; - esac - fi - tmp_libs="$tmp_libs $deplib" - done # for deplib - continue - fi # $linkmode = prog... - - if test "$linkmode,$pass" = "prog,link"; then - if test -n "$library_names" && - { test "$prefer_static_libs" = no || test -z "$old_library"; }; then - # We need to hardcode the library path - if test -n "$shlibpath_var"; then - # Make sure the rpath contains only unique directories. - case "$temp_rpath " in - *" $dir "*) ;; - *" $absdir "*) ;; - *) temp_rpath="$temp_rpath $dir" ;; - esac - fi - - # Hardcode the library path. - # Skip directories that are in the system default run-time - # search path. - case " $sys_lib_dlsearch_path " in - *" $absdir "*) ;; - *) - case "$compile_rpath " in - *" $absdir "*) ;; - *) compile_rpath="$compile_rpath $absdir" - esac - ;; - esac - case " $sys_lib_dlsearch_path " in - *" $libdir "*) ;; - *) - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" - esac - ;; - esac - fi # $linkmode,$pass = prog,link... - - if test "$alldeplibs" = yes && - { test "$deplibs_check_method" = pass_all || - { test "$build_libtool_libs" = yes && - test -n "$library_names"; }; }; then - # We only need to search for static libraries - continue - fi - fi - - link_static=no # Whether the deplib will be linked statically - if test -n "$library_names" && - { test "$prefer_static_libs" = no || test -z "$old_library"; }; then - if test "$installed" = no; then - notinst_deplibs="$notinst_deplibs $lib" - need_relink=yes - fi - # This is a shared library - - # Warn about portability, can't link against -module's on some systems (darwin) - if test "$shouldnotlink" = yes && test "$pass" = link ; then - $echo - if test "$linkmode" = prog; then - $echo "*** Warning: Linking the executable $output against the loadable module" - else - $echo "*** Warning: Linking the shared library $output against the loadable module" - fi - $echo "*** $linklib is not portable!" - fi - if test "$linkmode" = lib && - test "$hardcode_into_libs" = yes; then - # Hardcode the library path. - # Skip directories that are in the system default run-time - # search path. - case " $sys_lib_dlsearch_path " in - *" $absdir "*) ;; - *) - case "$compile_rpath " in - *" $absdir "*) ;; - *) compile_rpath="$compile_rpath $absdir" - esac - ;; - esac - case " $sys_lib_dlsearch_path " in - *" $libdir "*) ;; - *) - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" - esac - ;; - esac - fi - - if test -n "$old_archive_from_expsyms_cmds"; then - # figure out the soname - set dummy $library_names - realname="$2" - shift; shift - libname=`eval \\$echo \"$libname_spec\"` - # use dlname if we got it. it's perfectly good, no? - if test -n "$dlname"; then - soname="$dlname" - elif test -n "$soname_spec"; then - # bleh windows - case $host in - *cygwin* | mingw*) - major=`expr $current - $age` - versuffix="-$major" - ;; - esac - eval soname=\"$soname_spec\" - else - soname="$realname" - fi - - # Make a new name for the extract_expsyms_cmds to use - soroot="$soname" - soname=`$echo $soroot | ${SED} -e 's/^.*\///'` - newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" - - # If the library has no export list, then create one now - if test -f "$output_objdir/$soname-def"; then : - else - $show "extracting exported symbol list from \`$soname'" - save_ifs="$IFS"; IFS='~' - cmds=$extract_expsyms_cmds - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - fi - - # Create $newlib - if test -f "$output_objdir/$newlib"; then :; else - $show "generating import library for \`$soname'" - save_ifs="$IFS"; IFS='~' - cmds=$old_archive_from_expsyms_cmds - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - fi - # make sure the library variables are pointing to the new library - dir=$output_objdir - linklib=$newlib - fi # test -n "$old_archive_from_expsyms_cmds" - - if test "$linkmode" = prog || test "$mode" != relink; then - add_shlibpath= - add_dir= - add= - lib_linked=yes - case $hardcode_action in - immediate | unsupported) - if test "$hardcode_direct" = no; then - add="$dir/$linklib" - case $host in - *-*-sco3.2v5* ) add_dir="-L$dir" ;; - *-*-darwin* ) - # if the lib is a module then we can not link against it, someone - # is ignoring the new warnings I added - if /usr/bin/file -L $add 2> /dev/null | grep "bundle" >/dev/null ; then - $echo "** Warning, lib $linklib is a module, not a shared library" - if test -z "$old_library" ; then - $echo - $echo "** And there doesn't seem to be a static archive available" - $echo "** The link will probably fail, sorry" - else - add="$dir/$old_library" - fi - fi - esac - elif test "$hardcode_minus_L" = no; then - case $host in - *-*-sunos*) add_shlibpath="$dir" ;; - esac - add_dir="-L$dir" - add="-l$name" - elif test "$hardcode_shlibpath_var" = no; then - add_shlibpath="$dir" - add="-l$name" - else - lib_linked=no - fi - ;; - relink) - if test "$hardcode_direct" = yes; then - add="$dir/$linklib" - elif test "$hardcode_minus_L" = yes; then - add_dir="-L$dir" - # Try looking first in the location we're being installed to. - if test -n "$inst_prefix_dir"; then - case "$libdir" in - [\\/]*) - add_dir="$add_dir -L$inst_prefix_dir$libdir" - ;; - esac - fi - add="-l$name" - elif test "$hardcode_shlibpath_var" = yes; then - add_shlibpath="$dir" - add="-l$name" - else - lib_linked=no - fi - ;; - *) lib_linked=no ;; - esac - - if test "$lib_linked" != yes; then - $echo "$modename: configuration error: unsupported hardcode properties" - exit 1 - fi - - if test -n "$add_shlibpath"; then - case :$compile_shlibpath: in - *":$add_shlibpath:"*) ;; - *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; - esac - fi - if test "$linkmode" = prog; then - test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" - test -n "$add" && compile_deplibs="$add $compile_deplibs" - else - test -n "$add_dir" && deplibs="$add_dir $deplibs" - test -n "$add" && deplibs="$add $deplibs" - if test "$hardcode_direct" != yes && \ - test "$hardcode_minus_L" != yes && \ - test "$hardcode_shlibpath_var" = yes; then - case :$finalize_shlibpath: in - *":$libdir:"*) ;; - *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; - esac - fi - fi - fi - - if test "$linkmode" = prog || test "$mode" = relink; then - add_shlibpath= - add_dir= - add= - # Finalize command for both is simple: just hardcode it. - if test "$hardcode_direct" = yes; then - add="$libdir/$linklib" - elif test "$hardcode_minus_L" = yes; then - add_dir="-L$libdir" - add="-l$name" - elif test "$hardcode_shlibpath_var" = yes; then - case :$finalize_shlibpath: in - *":$libdir:"*) ;; - *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; - esac - add="-l$name" - elif test "$hardcode_automatic" = yes; then - if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then - add="$inst_prefix_dir$libdir/$linklib" - else - add="$libdir/$linklib" - fi - else - # We cannot seem to hardcode it, guess we'll fake it. - add_dir="-L$libdir" - # Try looking first in the location we're being installed to. - if test -n "$inst_prefix_dir"; then - case "$libdir" in - [\\/]*) - add_dir="$add_dir -L$inst_prefix_dir$libdir" - ;; - esac - fi - add="-l$name" - fi - - if test "$linkmode" = prog; then - test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" - test -n "$add" && finalize_deplibs="$add $finalize_deplibs" - else - test -n "$add_dir" && deplibs="$add_dir $deplibs" - test -n "$add" && deplibs="$add $deplibs" - fi - fi - elif test "$linkmode" = prog; then - # Here we assume that one of hardcode_direct or hardcode_minus_L - # is not unsupported. This is valid on all known static and - # shared platforms. - if test "$hardcode_direct" != unsupported; then - test -n "$old_library" && linklib="$old_library" - compile_deplibs="$dir/$linklib $compile_deplibs" - finalize_deplibs="$dir/$linklib $finalize_deplibs" - else - compile_deplibs="-l$name -L$dir $compile_deplibs" - finalize_deplibs="-l$name -L$dir $finalize_deplibs" - fi - elif test "$build_libtool_libs" = yes; then - # Not a shared library - if test "$deplibs_check_method" != pass_all; then - # We're trying link a shared library against a static one - # but the system doesn't support it. - - # Just print a warning and add the library to dependency_libs so - # that the program can be linked against the static library. - $echo - $echo "*** Warning: This system can not link to static lib archive $lib." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which you do not appear to have." - if test "$module" = yes; then - $echo "*** But as you try to build a module library, libtool will still create " - $echo "*** a static module, that should work as long as the dlopening application" - $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." - if test -z "$global_symbol_pipe"; then - $echo - $echo "*** However, this would only work if libtool was able to extract symbol" - $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" - $echo "*** not find such a program. So, this module is probably useless." - $echo "*** \`nm' from GNU binutils and a full rebuild may help." - fi - if test "$build_old_libs" = no; then - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - fi - else - convenience="$convenience $dir/$old_library" - old_convenience="$old_convenience $dir/$old_library" - deplibs="$dir/$old_library $deplibs" - link_static=yes - fi - fi # link shared/static library? - - if test "$linkmode" = lib; then - if test -n "$dependency_libs" && - { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || - test "$link_static" = yes; }; then - # Extract -R from dependency_libs - temp_deplibs= - for libdir in $dependency_libs; do - case $libdir in - -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` - case " $xrpath " in - *" $temp_xrpath "*) ;; - *) xrpath="$xrpath $temp_xrpath";; - esac;; - *) temp_deplibs="$temp_deplibs $libdir";; - esac - done - dependency_libs="$temp_deplibs" - fi - - newlib_search_path="$newlib_search_path $absdir" - # Link against this library - test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" - # ... and its dependency_libs - tmp_libs= - for deplib in $dependency_libs; do - newdependency_libs="$deplib $newdependency_libs" - if test "X$duplicate_deps" = "Xyes" ; then - case "$tmp_libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; - esac - fi - tmp_libs="$tmp_libs $deplib" - done - - if test "$link_all_deplibs" != no; then - # Add the search paths of all dependency libraries - for deplib in $dependency_libs; do - case $deplib in - -L*) path="$deplib" ;; - *.la) - dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` - test "X$dir" = "X$deplib" && dir="." - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; - *) - absdir=`cd "$dir" && pwd` - if test -z "$absdir"; then - $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 - absdir="$dir" - fi - ;; - esac - if grep "^installed=no" $deplib > /dev/null; then - path="$absdir/$objdir" - else - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` - if test -z "$libdir"; then - $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 - exit 1 - fi - if test "$absdir" != "$libdir"; then - $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 - fi - path="$absdir" - fi - depdepl= - case $host in - *-*-darwin*) - # we do not want to link against static libs, but need to link against shared - eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` - if test -n "$deplibrary_names" ; then - for tmp in $deplibrary_names ; do - depdepl=$tmp - done - if test -f "$path/$depdepl" ; then - depdepl="$path/$depdepl" - fi - # do not add paths which are already there - case " $newlib_search_path " in - *" $path "*) ;; - *) newlib_search_path="$newlib_search_path $path";; - esac - fi - path="" - ;; - *) - path="-L$path" - ;; - esac - - ;; - -l*) - case $host in - *-*-darwin*) - # Again, we only want to link against shared libraries - eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` - for tmp in $newlib_search_path ; do - if test -f "$tmp/lib$tmp_libs.dylib" ; then - eval depdepl="$tmp/lib$tmp_libs.dylib" - break - fi - done - path="" - ;; - *) continue ;; - esac - ;; - *) continue ;; - esac - case " $deplibs " in - *" $depdepl "*) ;; - *) deplibs="$deplibs $depdepl" ;; - esac - case " $deplibs " in - *" $path "*) ;; - *) deplibs="$deplibs $path" ;; - esac - done - fi # link_all_deplibs != no - fi # linkmode = lib - done # for deplib in $libs - dependency_libs="$newdependency_libs" - if test "$pass" = dlpreopen; then - # Link the dlpreopened libraries before other libraries - for deplib in $save_deplibs; do - deplibs="$deplib $deplibs" - done - fi - if test "$pass" != dlopen; then - if test "$pass" != conv; then - # Make sure lib_search_path contains only unique directories. - lib_search_path= - for dir in $newlib_search_path; do - case "$lib_search_path " in - *" $dir "*) ;; - *) lib_search_path="$lib_search_path $dir" ;; - esac - done - newlib_search_path= - fi - - if test "$linkmode,$pass" != "prog,link"; then - vars="deplibs" - else - vars="compile_deplibs finalize_deplibs" - fi - for var in $vars dependency_libs; do - # Add libraries to $var in reverse order - eval tmp_libs=\"\$$var\" - new_libs= - for deplib in $tmp_libs; do - # FIXME: Pedantically, this is the right thing to do, so - # that some nasty dependency loop isn't accidentally - # broken: - #new_libs="$deplib $new_libs" - # Pragmatically, this seems to cause very few problems in - # practice: - case $deplib in - -L*) new_libs="$deplib $new_libs" ;; - -R*) ;; - *) - # And here is the reason: when a library appears more - # than once as an explicit dependence of a library, or - # is implicitly linked in more than once by the - # compiler, it is considered special, and multiple - # occurrences thereof are not removed. Compare this - # with having the same library being listed as a - # dependency of multiple other libraries: in this case, - # we know (pedantically, we assume) the library does not - # need to be listed more than once, so we keep only the - # last copy. This is not always right, but it is rare - # enough that we require users that really mean to play - # such unportable linking tricks to link the library - # using -Wl,-lname, so that libtool does not consider it - # for duplicate removal. - case " $specialdeplibs " in - *" $deplib "*) new_libs="$deplib $new_libs" ;; - *) - case " $new_libs " in - *" $deplib "*) ;; - *) new_libs="$deplib $new_libs" ;; - esac - ;; - esac - ;; - esac - done - tmp_libs= - for deplib in $new_libs; do - case $deplib in - -L*) - case " $tmp_libs " in - *" $deplib "*) ;; - *) tmp_libs="$tmp_libs $deplib" ;; - esac - ;; - *) tmp_libs="$tmp_libs $deplib" ;; - esac - done - eval $var=\"$tmp_libs\" - done # for var - fi - # Last step: remove runtime libs from dependency_libs (they stay in deplibs) - tmp_libs= - for i in $dependency_libs ; do - case " $predeps $postdeps $compiler_lib_search_path " in - *" $i "*) - i="" - ;; - esac - if test -n "$i" ; then - tmp_libs="$tmp_libs $i" - fi - done - dependency_libs=$tmp_libs - done # for pass - if test "$linkmode" = prog; then - dlfiles="$newdlfiles" - dlprefiles="$newdlprefiles" - fi - - case $linkmode in - oldlib) - if test -n "$deplibs"; then - $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 - fi - - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 - fi - - if test -n "$rpath"; then - $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 - fi - - if test -n "$xrpath"; then - $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 - fi - - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 - fi - - if test -n "$export_symbols" || test -n "$export_symbols_regex"; then - $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 - fi - - # Now set the variables for building old libraries. - build_libtool_libs=no - oldlibs="$output" - objs="$objs$old_deplibs" - ;; - - lib) - # Make sure we only generate libraries of the form `libNAME.la'. - case $outputname in - lib*) - name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` - eval shared_ext=\"$shrext\" - eval libname=\"$libname_spec\" - ;; - *) - if test "$module" = no; then - $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - if test "$need_lib_prefix" != no; then - # Add the "lib" prefix for modules if required - name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` - eval shared_ext=\"$shrext\" - eval libname=\"$libname_spec\" - else - libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` - fi - ;; - esac - - if test -n "$objs"; then - if test "$deplibs_check_method" != pass_all; then - $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 - exit 1 - else - $echo - $echo "*** Warning: Linking the shared library $output against the non-libtool" - $echo "*** objects $objs is not portable!" - libobjs="$libobjs $objs" - fi - fi - - if test "$dlself" != no; then - $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 - fi - - set dummy $rpath - if test "$#" -gt 2; then - $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 - fi - install_libdir="$2" - - oldlibs= - if test -z "$rpath"; then - if test "$build_libtool_libs" = yes; then - # Building a libtool convenience library. - # Some compilers have problems with a `.al' extension so - # convenience libraries should have the same extension an - # archive normally would. - oldlibs="$output_objdir/$libname.$libext $oldlibs" - build_libtool_libs=convenience - build_old_libs=yes - fi - - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 - fi - else - - # Parse the version information argument. - save_ifs="$IFS"; IFS=':' - set dummy $vinfo 0 0 0 - IFS="$save_ifs" - - if test -n "$8"; then - $echo "$modename: too many parameters to \`-version-info'" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - # convert absolute version numbers to libtool ages - # this retains compatibility with .la files and attempts - # to make the code below a bit more comprehensible - - case $vinfo_number in - yes) - number_major="$2" - number_minor="$3" - number_revision="$4" - # - # There are really only two kinds -- those that - # use the current revision as the major version - # and those that subtract age and use age as - # a minor version. But, then there is irix - # which has an extra 1 added just for fun - # - case $version_type in - darwin|linux|osf|windows) - current=`expr $number_major + $number_minor` - age="$number_minor" - revision="$number_revision" - ;; - freebsd-aout|freebsd-elf|sunos) - current="$number_major" - revision="$number_minor" - age="0" - ;; - irix|nonstopux) - current=`expr $number_major + $number_minor - 1` - age="$number_minor" - revision="$number_minor" - ;; - esac - ;; - no) - current="$2" - revision="$3" - age="$4" - ;; - esac - - # Check that each of the things are valid numbers. - case $current in - 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; - *) - $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit 1 - ;; - esac - - case $revision in - 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; - *) - $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit 1 - ;; - esac - - case $age in - 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; - *) - $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit 1 - ;; - esac - - if test "$age" -gt "$current"; then - $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 - $echo "$modename: \`$vinfo' is not valid version information" 1>&2 - exit 1 - fi - - # Calculate the version variables. - major= - versuffix= - verstring= - case $version_type in - none) ;; - - darwin) - # Like Linux, but with the current version available in - # verstring for coding it into the library header - major=.`expr $current - $age` - versuffix="$major.$age.$revision" - # Darwin ld doesn't like 0 for these options... - minor_current=`expr $current + 1` - verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" - ;; - - freebsd-aout) - major=".$current" - versuffix=".$current.$revision"; - ;; - - freebsd-elf) - major=".$current" - versuffix=".$current"; - ;; - - irix | nonstopux) - major=`expr $current - $age + 1` - - case $version_type in - nonstopux) verstring_prefix=nonstopux ;; - *) verstring_prefix=sgi ;; - esac - verstring="$verstring_prefix$major.$revision" - - # Add in all the interfaces that we are compatible with. - loop=$revision - while test "$loop" -ne 0; do - iface=`expr $revision - $loop` - loop=`expr $loop - 1` - verstring="$verstring_prefix$major.$iface:$verstring" - done - - # Before this point, $major must not contain `.'. - major=.$major - versuffix="$major.$revision" - ;; - - linux) - major=.`expr $current - $age` - versuffix="$major.$age.$revision" - ;; - - osf) - major=.`expr $current - $age` - versuffix=".$current.$age.$revision" - verstring="$current.$age.$revision" - - # Add in all the interfaces that we are compatible with. - loop=$age - while test "$loop" -ne 0; do - iface=`expr $current - $loop` - loop=`expr $loop - 1` - verstring="$verstring:${iface}.0" - done - - # Make executables depend on our current version. - verstring="$verstring:${current}.0" - ;; - - sunos) - major=".$current" - versuffix=".$current.$revision" - ;; - - windows) - # Use '-' rather than '.', since we only want one - # extension on DOS 8.3 filesystems. - major=`expr $current - $age` - versuffix="-$major" - ;; - - *) - $echo "$modename: unknown library version type \`$version_type'" 1>&2 - $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 - exit 1 - ;; - esac - - # Clear the version info if we defaulted, and they specified a release. - if test -z "$vinfo" && test -n "$release"; then - major= - case $version_type in - darwin) - # we can't check for "0.0" in archive_cmds due to quoting - # problems, so we reset it completely - verstring= - ;; - *) - verstring="0.0" - ;; - esac - if test "$need_version" = no; then - versuffix= - else - versuffix=".0.0" - fi - fi - - # Remove version info from name if versioning should be avoided - if test "$avoid_version" = yes && test "$need_version" = no; then - major= - versuffix= - verstring="" - fi - - # Check to see if the archive will have undefined symbols. - if test "$allow_undefined" = yes; then - if test "$allow_undefined_flag" = unsupported; then - $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 - build_libtool_libs=no - build_old_libs=yes - fi - else - # Don't allow undefined symbols. - allow_undefined_flag="$no_undefined_flag" - fi - fi - - if test "$mode" != relink; then - # Remove our outputs, but don't remove object files since they - # may have been created when compiling PIC objects. - removelist= - tempremovelist=`$echo "$output_objdir/*"` - for p in $tempremovelist; do - case $p in - *.$objext) - ;; - $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) - if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 - then - continue - fi - removelist="$removelist $p" - ;; - *) ;; - esac - done - if test -n "$removelist"; then - $show "${rm}r $removelist" - $run ${rm}r $removelist - fi - fi - - # Now set the variables for building old libraries. - if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then - oldlibs="$oldlibs $output_objdir/$libname.$libext" - - # Transform .lo files to .o files. - oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` - fi - - # Eliminate all temporary directories. - for path in $notinst_path; do - lib_search_path=`$echo "$lib_search_path " | ${SED} -e 's% $path % %g'` - deplibs=`$echo "$deplibs " | ${SED} -e 's% -L$path % %g'` - dependency_libs=`$echo "$dependency_libs " | ${SED} -e 's% -L$path % %g'` - done - - if test -n "$xrpath"; then - # If the user specified any rpath flags, then add them. - temp_xrpath= - for libdir in $xrpath; do - temp_xrpath="$temp_xrpath -R$libdir" - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" ;; - esac - done - if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then - dependency_libs="$temp_xrpath $dependency_libs" - fi - fi - - # Make sure dlfiles contains only unique files that won't be dlpreopened - old_dlfiles="$dlfiles" - dlfiles= - for lib in $old_dlfiles; do - case " $dlprefiles $dlfiles " in - *" $lib "*) ;; - *) dlfiles="$dlfiles $lib" ;; - esac - done - - # Make sure dlprefiles contains only unique files - old_dlprefiles="$dlprefiles" - dlprefiles= - for lib in $old_dlprefiles; do - case "$dlprefiles " in - *" $lib "*) ;; - *) dlprefiles="$dlprefiles $lib" ;; - esac - done - - if test "$build_libtool_libs" = yes; then - if test -n "$rpath"; then - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) - # these systems don't actually have a c library (as such)! - ;; - *-*-rhapsody* | *-*-darwin1.[012]) - # Rhapsody C library is in the System framework - deplibs="$deplibs -framework System" - ;; - *-*-netbsd*) - # Don't link with libc until the a.out ld.so is fixed. - ;; - *-*-openbsd* | *-*-freebsd*) - # Do not include libc due to us having libc/libc_r. - test "X$arg" = "X-lc" && continue - ;; - *) - # Add libc to deplibs on all other systems if necessary. - if test "$build_libtool_need_lc" = "yes"; then - deplibs="$deplibs -lc" - fi - ;; - esac - fi - - # Transform deplibs into only deplibs that can be linked in shared. - name_save=$name - libname_save=$libname - release_save=$release - versuffix_save=$versuffix - major_save=$major - # I'm not sure if I'm treating the release correctly. I think - # release should show up in the -l (ie -lgmp5) so we don't want to - # add it in twice. Is that correct? - release="" - versuffix="" - major="" - newdeplibs= - droppeddeps=no - case $deplibs_check_method in - pass_all) - # Don't check for shared/static. Everything works. - # This might be a little naive. We might want to check - # whether the library exists or not. But this is on - # osf3 & osf4 and I'm not really sure... Just - # implementing what was already the behavior. - newdeplibs=$deplibs - ;; - test_compile) - # This code stresses the "libraries are programs" paradigm to its - # limits. Maybe even breaks it. We compile a program, linking it - # against the deplibs as a proxy for the library. Then we can check - # whether they linked in statically or dynamically with ldd. - $rm conftest.c - cat > conftest.c <<EOF - int main() { return 0; } -EOF - $rm conftest - $LTCC -o conftest conftest.c $deplibs - if test "$?" -eq 0 ; then - ldd_output=`ldd conftest` - for i in $deplibs; do - name="`expr $i : '-l\(.*\)'`" - # If $name is empty we are operating on a -L argument. - if test "$name" != "" && test "$name" -ne "0"; then - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $i "*) - newdeplibs="$newdeplibs $i" - i="" - ;; - esac - fi - if test -n "$i" ; then - libname=`eval \\$echo \"$libname_spec\"` - deplib_matches=`eval \\$echo \"$library_names_spec\"` - set dummy $deplib_matches - deplib_match=$2 - if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then - newdeplibs="$newdeplibs $i" - else - droppeddeps=yes - $echo - $echo "*** Warning: dynamic linker does not accept needed library $i." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which I believe you do not have" - $echo "*** because a test_compile did reveal that the linker did not use it for" - $echo "*** its dynamic dependency list that programs get resolved with at runtime." - fi - fi - else - newdeplibs="$newdeplibs $i" - fi - done - else - # Error occurred in the first compile. Let's try to salvage - # the situation: Compile a separate program for each library. - for i in $deplibs; do - name="`expr $i : '-l\(.*\)'`" - # If $name is empty we are operating on a -L argument. - if test "$name" != "" && test "$name" != "0"; then - $rm conftest - $LTCC -o conftest conftest.c $i - # Did it work? - if test "$?" -eq 0 ; then - ldd_output=`ldd conftest` - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $i "*) - newdeplibs="$newdeplibs $i" - i="" - ;; - esac - fi - if test -n "$i" ; then - libname=`eval \\$echo \"$libname_spec\"` - deplib_matches=`eval \\$echo \"$library_names_spec\"` - set dummy $deplib_matches - deplib_match=$2 - if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then - newdeplibs="$newdeplibs $i" - else - droppeddeps=yes - $echo - $echo "*** Warning: dynamic linker does not accept needed library $i." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which you do not appear to have" - $echo "*** because a test_compile did reveal that the linker did not use this one" - $echo "*** as a dynamic dependency that programs can get resolved with at runtime." - fi - fi - else - droppeddeps=yes - $echo - $echo "*** Warning! Library $i is needed by this library but I was not able to" - $echo "*** make it link in! You will probably need to install it or some" - $echo "*** library that it depends on before this library will be fully" - $echo "*** functional. Installing it before continuing would be even better." - fi - else - newdeplibs="$newdeplibs $i" - fi - done - fi - ;; - file_magic*) - set dummy $deplibs_check_method - file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` - for a_deplib in $deplibs; do - name="`expr $a_deplib : '-l\(.*\)'`" - # If $name is empty we are operating on a -L argument. - if test "$name" != "" && test "$name" != "0"; then - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $a_deplib "*) - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - ;; - esac - fi - if test -n "$a_deplib" ; then - libname=`eval \\$echo \"$libname_spec\"` - for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do - potential_libs=`ls $i/$libname[.-]* 2>/dev/null` - for potent_lib in $potential_libs; do - # Follow soft links. - if ls -lLd "$potent_lib" 2>/dev/null \ - | grep " -> " >/dev/null; then - continue - fi - # The statement above tries to avoid entering an - # endless loop below, in case of cyclic links. - # We might still enter an endless loop, since a link - # loop can be closed while we follow links, - # but so what? - potlib="$potent_lib" - while test -h "$potlib" 2>/dev/null; do - potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` - case $potliblink in - [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; - *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; - esac - done - if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ - | ${SED} 10q \ - | $EGREP "$file_magic_regex" > /dev/null; then - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - break 2 - fi - done - done - fi - if test -n "$a_deplib" ; then - droppeddeps=yes - $echo - $echo "*** Warning: linker path does not have real file for library $a_deplib." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which you do not appear to have" - $echo "*** because I did check the linker path looking for a file starting" - if test -z "$potlib" ; then - $echo "*** with $libname but no candidates were found. (...for file magic test)" - else - $echo "*** with $libname and none of the candidates passed a file format test" - $echo "*** using a file magic. Last file checked: $potlib" - fi - fi - else - # Add a -L argument. - newdeplibs="$newdeplibs $a_deplib" - fi - done # Gone through all deplibs. - ;; - match_pattern*) - set dummy $deplibs_check_method - match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` - for a_deplib in $deplibs; do - name="`expr $a_deplib : '-l\(.*\)'`" - # If $name is empty we are operating on a -L argument. - if test -n "$name" && test "$name" != "0"; then - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $a_deplib "*) - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - ;; - esac - fi - if test -n "$a_deplib" ; then - libname=`eval \\$echo \"$libname_spec\"` - for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do - potential_libs=`ls $i/$libname[.-]* 2>/dev/null` - for potent_lib in $potential_libs; do - potlib="$potent_lib" # see symlink-check above in file_magic test - if eval $echo \"$potent_lib\" 2>/dev/null \ - | ${SED} 10q \ - | $EGREP "$match_pattern_regex" > /dev/null; then - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - break 2 - fi - done - done - fi - if test -n "$a_deplib" ; then - droppeddeps=yes - $echo - $echo "*** Warning: linker path does not have real file for library $a_deplib." - $echo "*** I have the capability to make that library automatically link in when" - $echo "*** you link to this library. But I can only do this if you have a" - $echo "*** shared version of the library, which you do not appear to have" - $echo "*** because I did check the linker path looking for a file starting" - if test -z "$potlib" ; then - $echo "*** with $libname but no candidates were found. (...for regex pattern test)" - else - $echo "*** with $libname and none of the candidates passed a file format test" - $echo "*** using a regex pattern. Last file checked: $potlib" - fi - fi - else - # Add a -L argument. - newdeplibs="$newdeplibs $a_deplib" - fi - done # Gone through all deplibs. - ;; - none | unknown | *) - newdeplibs="" - tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ - -e 's/ -[LR][^ ]*//g'` - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - for i in $predeps $postdeps ; do - # can't use Xsed below, because $i might contain '/' - tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` - done - fi - if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ - | grep . >/dev/null; then - $echo - if test "X$deplibs_check_method" = "Xnone"; then - $echo "*** Warning: inter-library dependencies are not supported in this platform." - else - $echo "*** Warning: inter-library dependencies are not known to be supported." - fi - $echo "*** All declared inter-library dependencies are being dropped." - droppeddeps=yes - fi - ;; - esac - versuffix=$versuffix_save - major=$major_save - release=$release_save - libname=$libname_save - name=$name_save - - case $host in - *-*-rhapsody* | *-*-darwin1.[012]) - # On Rhapsody replace the C library is the System framework - newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` - ;; - esac - - if test "$droppeddeps" = yes; then - if test "$module" = yes; then - $echo - $echo "*** Warning: libtool could not satisfy all declared inter-library" - $echo "*** dependencies of module $libname. Therefore, libtool will create" - $echo "*** a static module, that should work as long as the dlopening" - $echo "*** application is linked with the -dlopen flag." - if test -z "$global_symbol_pipe"; then - $echo - $echo "*** However, this would only work if libtool was able to extract symbol" - $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" - $echo "*** not find such a program. So, this module is probably useless." - $echo "*** \`nm' from GNU binutils and a full rebuild may help." - fi - if test "$build_old_libs" = no; then - oldlibs="$output_objdir/$libname.$libext" - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - else - $echo "*** The inter-library dependencies that have been dropped here will be" - $echo "*** automatically added whenever a program is linked with this library" - $echo "*** or is declared to -dlopen it." - - if test "$allow_undefined" = no; then - $echo - $echo "*** Since this library must not contain undefined symbols," - $echo "*** because either the platform does not support them or" - $echo "*** it was explicitly requested with -no-undefined," - $echo "*** libtool will only create a static version of it." - if test "$build_old_libs" = no; then - oldlibs="$output_objdir/$libname.$libext" - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - fi - fi - fi - # Done checking deplibs! - deplibs=$newdeplibs - fi - - # All the library-specific variables (install_libdir is set above). - library_names= - old_library= - dlname= - - # Test again, we may have decided not to build it any more - if test "$build_libtool_libs" = yes; then - if test "$hardcode_into_libs" = yes; then - # Hardcode the library paths - hardcode_libdirs= - dep_rpath= - rpath="$finalize_rpath" - test "$mode" != relink && rpath="$compile_rpath$rpath" - for libdir in $rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - dep_rpath="$dep_rpath $flag" - fi - elif test -n "$runpath_var"; then - case "$perm_rpath " in - *" $libdir "*) ;; - *) perm_rpath="$perm_rpath $libdir" ;; - esac - fi - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - if test -n "$hardcode_libdir_flag_spec_ld"; then - eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" - else - eval dep_rpath=\"$hardcode_libdir_flag_spec\" - fi - fi - if test -n "$runpath_var" && test -n "$perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $perm_rpath; do - rpath="$rpath$dir:" - done - eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" - fi - test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" - fi - - shlibpath="$finalize_shlibpath" - test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" - if test -n "$shlibpath"; then - eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" - fi - - # Get the real and link names of the library. - eval shared_ext=\"$shrext\" - eval library_names=\"$library_names_spec\" - set dummy $library_names - realname="$2" - shift; shift - - if test -n "$soname_spec"; then - eval soname=\"$soname_spec\" - else - soname="$realname" - fi - if test -z "$dlname"; then - dlname=$soname - fi - - lib="$output_objdir/$realname" - for link - do - linknames="$linknames $link" - done - - # Use standard objects if they are pic - test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then - $show "generating symbol list for \`$libname.la'" - export_symbols="$output_objdir/$libname.exp" - $run $rm $export_symbols - cmds=$export_symbols_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - if len=`expr "X$cmd" : ".*"` && - test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then - $show "$cmd" - $run eval "$cmd" || exit $? - skipped_export=false - else - # The command line is too long to execute in one step. - $show "using reloadable object file for export list..." - skipped_export=: - fi - done - IFS="$save_ifs" - if test -n "$export_symbols_regex"; then - $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" - $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' - $show "$mv \"${export_symbols}T\" \"$export_symbols\"" - $run eval '$mv "${export_symbols}T" "$export_symbols"' - fi - fi - fi - - if test -n "$export_symbols" && test -n "$include_expsyms"; then - $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' - fi - - tmp_deplibs= - for test_deplib in $deplibs; do - case " $convenience " in - *" $test_deplib "*) ;; - *) - tmp_deplibs="$tmp_deplibs $test_deplib" - ;; - esac - done - deplibs="$tmp_deplibs" - - if test -n "$convenience"; then - if test -n "$whole_archive_flag_spec"; then - save_libobjs=$libobjs - eval libobjs=\"\$libobjs $whole_archive_flag_spec\" - else - gentop="$output_objdir/${outputname}x" - $show "${rm}r $gentop" - $run ${rm}r "$gentop" - $show "$mkdir $gentop" - $run $mkdir "$gentop" - status=$? - if test "$status" -ne 0 && test ! -d "$gentop"; then - exit $status - fi - generated="$generated $gentop" - - for xlib in $convenience; do - # Extract the objects. - case $xlib in - [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; - *) xabs=`pwd`"/$xlib" ;; - esac - xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` - xdir="$gentop/$xlib" - - $show "${rm}r $xdir" - $run ${rm}r "$xdir" - $show "$mkdir $xdir" - $run $mkdir "$xdir" - status=$? - if test "$status" -ne 0 && test ! -d "$xdir"; then - exit $status - fi - # We will extract separately just the conflicting names and we will no - # longer touch any unique names. It is faster to leave these extract - # automatically by $AR in one run. - $show "(cd $xdir && $AR x $xabs)" - $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? - if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then - : - else - $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 - $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 - $AR t "$xabs" | sort | uniq -cd | while read -r count name - do - i=1 - while test "$i" -le "$count" - do - # Put our $i before any first dot (extension) - # Never overwrite any file - name_to="$name" - while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" - do - name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` - done - $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" - $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? - i=`expr $i + 1` - done - done - fi - - libobjs="$libobjs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` - done - fi - fi - - if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then - eval flag=\"$thread_safe_flag_spec\" - linker_flags="$linker_flags $flag" - fi - - # Make a backup of the uninstalled library when relinking - if test "$mode" = relink; then - $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? - fi - - # Do each of the archive commands. - if test "$module" = yes && test -n "$module_cmds" ; then - if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then - eval test_cmds=\"$module_expsym_cmds\" - cmds=$module_expsym_cmds - else - eval test_cmds=\"$module_cmds\" - cmds=$module_cmds - fi - else - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - eval test_cmds=\"$archive_expsym_cmds\" - cmds=$archive_expsym_cmds - else - eval test_cmds=\"$archive_cmds\" - cmds=$archive_cmds - fi - fi - - if test "X$skipped_export" != "X:" && len=`expr "X$test_cmds" : ".*"` && - test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then - : - else - # The command line is too long to link in one step, link piecewise. - $echo "creating reloadable object files..." - - # Save the value of $output and $libobjs because we want to - # use them later. If we have whole_archive_flag_spec, we - # want to use save_libobjs as it was before - # whole_archive_flag_spec was expanded, because we can't - # assume the linker understands whole_archive_flag_spec. - # This may have to be revisited, in case too many - # convenience libraries get linked in and end up exceeding - # the spec. - if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then - save_libobjs=$libobjs - fi - save_output=$output - - # Clear the reloadable object creation command queue and - # initialize k to one. - test_cmds= - concat_cmds= - objlist= - delfiles= - last_robj= - k=1 - output=$output_objdir/$save_output-${k}.$objext - # Loop over the list of objects to be linked. - for obj in $save_libobjs - do - eval test_cmds=\"$reload_cmds $objlist $last_robj\" - if test "X$objlist" = X || - { len=`expr "X$test_cmds" : ".*"` && - test "$len" -le "$max_cmd_len"; }; then - objlist="$objlist $obj" - else - # The command $test_cmds is almost too long, add a - # command to the queue. - if test "$k" -eq 1 ; then - # The first file doesn't have a previous command to add. - eval concat_cmds=\"$reload_cmds $objlist $last_robj\" - else - # All subsequent reloadable object files will link in - # the last one created. - eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" - fi - last_robj=$output_objdir/$save_output-${k}.$objext - k=`expr $k + 1` - output=$output_objdir/$save_output-${k}.$objext - objlist=$obj - len=1 - fi - done - # Handle the remaining objects by creating one last - # reloadable object file. All subsequent reloadable object - # files will link in the last one created. - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" - - if ${skipped_export-false}; then - $show "generating symbol list for \`$libname.la'" - export_symbols="$output_objdir/$libname.exp" - $run $rm $export_symbols - libobjs=$output - # Append the command to create the export file. - eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" - fi - - # Set up a command to remove the reloadale object files - # after they are used. - i=0 - while test "$i" -lt "$k" - do - i=`expr $i + 1` - delfiles="$delfiles $output_objdir/$save_output-${i}.$objext" - done - - $echo "creating a temporary reloadable object file: $output" - - # Loop through the commands generated above and execute them. - save_ifs="$IFS"; IFS='~' - for cmd in $concat_cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - - libobjs=$output - # Restore the value of output. - output=$save_output - - if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then - eval libobjs=\"\$libobjs $whole_archive_flag_spec\" - fi - # Expand the library linking commands again to reset the - # value of $libobjs for piecewise linking. - - # Do each of the archive commands. - if test "$module" = yes && test -n "$module_cmds" ; then - if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then - cmds=$module_expsym_cmds - else - cmds=$module_cmds - fi - else - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - cmds=$archive_expsym_cmds - else - cmds=$archive_cmds - fi - fi - - # Append the command to remove the reloadable object files - # to the just-reset $cmds. - eval cmds=\"\$cmds~\$rm $delfiles\" - fi - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - - # Restore the uninstalled library and exit - if test "$mode" = relink; then - $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? - exit 0 - fi - - # Create links to the real library. - for linkname in $linknames; do - if test "$realname" != "$linkname"; then - $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" - $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? - fi - done - - # If -module or -export-dynamic was specified, set the dlname. - if test "$module" = yes || test "$export_dynamic" = yes; then - # On all known operating systems, these are identical. - dlname="$soname" - fi - fi - ;; - - obj) - if test -n "$deplibs"; then - $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 - fi - - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 - fi - - if test -n "$rpath"; then - $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 - fi - - if test -n "$xrpath"; then - $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 - fi - - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 - fi - - case $output in - *.lo) - if test -n "$objs$old_deplibs"; then - $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 - exit 1 - fi - libobj="$output" - obj=`$echo "X$output" | $Xsed -e "$lo2o"` - ;; - *) - libobj= - obj="$output" - ;; - esac - - # Delete the old objects. - $run $rm $obj $libobj - - # Objects from convenience libraries. This assumes - # single-version convenience libraries. Whenever we create - # different ones for PIC/non-PIC, this we'll have to duplicate - # the extraction. - reload_conv_objs= - gentop= - # reload_cmds runs $LD directly, so let us get rid of - # -Wl from whole_archive_flag_spec - wl= - - if test -n "$convenience"; then - if test -n "$whole_archive_flag_spec"; then - eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" - else - gentop="$output_objdir/${obj}x" - $show "${rm}r $gentop" - $run ${rm}r "$gentop" - $show "$mkdir $gentop" - $run $mkdir "$gentop" - status=$? - if test "$status" -ne 0 && test ! -d "$gentop"; then - exit $status - fi - generated="$generated $gentop" - - for xlib in $convenience; do - # Extract the objects. - case $xlib in - [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; - *) xabs=`pwd`"/$xlib" ;; - esac - xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` - xdir="$gentop/$xlib" - - $show "${rm}r $xdir" - $run ${rm}r "$xdir" - $show "$mkdir $xdir" - $run $mkdir "$xdir" - status=$? - if test "$status" -ne 0 && test ! -d "$xdir"; then - exit $status - fi - # We will extract separately just the conflicting names and we will no - # longer touch any unique names. It is faster to leave these extract - # automatically by $AR in one run. - $show "(cd $xdir && $AR x $xabs)" - $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? - if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then - : - else - $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 - $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 - $AR t "$xabs" | sort | uniq -cd | while read -r count name - do - i=1 - while test "$i" -le "$count" - do - # Put our $i before any first dot (extension) - # Never overwrite any file - name_to="$name" - while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" - do - name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` - done - $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" - $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? - i=`expr $i + 1` - done - done - fi - - reload_conv_objs="$reload_objs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` - done - fi - fi - - # Create the old-style object. - reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test - - output="$obj" - cmds=$reload_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - - # Exit if we aren't doing a library object file. - if test -z "$libobj"; then - if test -n "$gentop"; then - $show "${rm}r $gentop" - $run ${rm}r $gentop - fi - - exit 0 - fi - - if test "$build_libtool_libs" != yes; then - if test -n "$gentop"; then - $show "${rm}r $gentop" - $run ${rm}r $gentop - fi - - # Create an invalid libtool object if no PIC, so that we don't - # accidentally link it into a program. - # $show "echo timestamp > $libobj" - # $run eval "echo timestamp > $libobj" || exit $? - exit 0 - fi - - if test -n "$pic_flag" || test "$pic_mode" != default; then - # Only do commands if we really have different PIC objects. - reload_objs="$libobjs $reload_conv_objs" - output="$libobj" - cmds=$reload_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - fi - - if test -n "$gentop"; then - $show "${rm}r $gentop" - $run ${rm}r $gentop - fi - - exit 0 - ;; - - prog) - case $host in - *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; - esac - if test -n "$vinfo"; then - $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 - fi - - if test -n "$release"; then - $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 - fi - - if test "$preload" = yes; then - if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && - test "$dlopen_self_static" = unknown; then - $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." - fi - fi - - case $host in - *-*-rhapsody* | *-*-darwin1.[012]) - # On Rhapsody replace the C library is the System framework - compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` - finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` - ;; - esac - - case $host in - *darwin*) - # Don't allow lazy linking, it breaks C++ global constructors - if test "$tagname" = CXX ; then - compile_command="$compile_command ${wl}-bind_at_load" - finalize_command="$finalize_command ${wl}-bind_at_load" - fi - ;; - esac - - compile_command="$compile_command $compile_deplibs" - finalize_command="$finalize_command $finalize_deplibs" - - if test -n "$rpath$xrpath"; then - # If the user specified any rpath flags, then add them. - for libdir in $rpath $xrpath; do - # This is the magic to use -rpath. - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" ;; - esac - done - fi - - # Now hardcode the library paths - rpath= - hardcode_libdirs= - for libdir in $compile_rpath $finalize_rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - rpath="$rpath $flag" - fi - elif test -n "$runpath_var"; then - case "$perm_rpath " in - *" $libdir "*) ;; - *) perm_rpath="$perm_rpath $libdir" ;; - esac - fi - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) - case :$dllsearchpath: in - *":$libdir:"*) ;; - *) dllsearchpath="$dllsearchpath:$libdir";; - esac - ;; - esac - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - eval rpath=\" $hardcode_libdir_flag_spec\" - fi - compile_rpath="$rpath" - - rpath= - hardcode_libdirs= - for libdir in $finalize_rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval flag=\"$hardcode_libdir_flag_spec\" - rpath="$rpath $flag" - fi - elif test -n "$runpath_var"; then - case "$finalize_perm_rpath " in - *" $libdir "*) ;; - *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; - esac - fi - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - eval rpath=\" $hardcode_libdir_flag_spec\" - fi - finalize_rpath="$rpath" - - if test -n "$libobjs" && test "$build_old_libs" = yes; then - # Transform all the library objects into standard objects. - compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - fi - - dlsyms= - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - if test -n "$NM" && test -n "$global_symbol_pipe"; then - dlsyms="${outputname}S.c" - else - $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 - fi - fi - - if test -n "$dlsyms"; then - case $dlsyms in - "") ;; - *.c) - # Discover the nlist of each of the dlfiles. - nlist="$output_objdir/${outputname}.nm" - - $show "$rm $nlist ${nlist}S ${nlist}T" - $run $rm "$nlist" "${nlist}S" "${nlist}T" - - # Parse the name list into a source file. - $show "creating $output_objdir/$dlsyms" - - test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ -/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ -/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ - -#ifdef __cplusplus -extern \"C\" { -#endif - -/* Prevent the only kind of declaration conflicts we can make. */ -#define lt_preloaded_symbols some_other_symbol - -/* External symbol declarations for the compiler. */\ -" - - if test "$dlself" = yes; then - $show "generating symbol list for \`$output'" - - test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" - - # Add our own program objects to the symbol list. - progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - for arg in $progfiles; do - $show "extracting global C symbols from \`$arg'" - $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" - done - - if test -n "$exclude_expsyms"; then - $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' - $run eval '$mv "$nlist"T "$nlist"' - fi - - if test -n "$export_symbols_regex"; then - $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' - $run eval '$mv "$nlist"T "$nlist"' - fi - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - export_symbols="$output_objdir/$output.exp" - $run $rm $export_symbols - $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' - else - $run eval "${SED} -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' - $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' - $run eval 'mv "$nlist"T "$nlist"' - fi - fi - - for arg in $dlprefiles; do - $show "extracting global C symbols from \`$arg'" - name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` - $run eval '$echo ": $name " >> "$nlist"' - $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" - done - - if test -z "$run"; then - # Make sure we have at least an empty file. - test -f "$nlist" || : > "$nlist" - - if test -n "$exclude_expsyms"; then - $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T - $mv "$nlist"T "$nlist" - fi - - # Try sorting and uniquifying the output. - if grep -v "^: " < "$nlist" | - if sort -k 3 </dev/null >/dev/null 2>&1; then - sort -k 3 - else - sort +2 - fi | - uniq > "$nlist"S; then - : - else - grep -v "^: " < "$nlist" > "$nlist"S - fi - - if test -f "$nlist"S; then - eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' - else - $echo '/* NONE */' >> "$output_objdir/$dlsyms" - fi - - $echo >> "$output_objdir/$dlsyms" "\ - -#undef lt_preloaded_symbols - -#if defined (__STDC__) && __STDC__ -# define lt_ptr void * -#else -# define lt_ptr char * -# define const -#endif - -/* The mapping between symbol names and symbols. */ -const struct { - const char *name; - lt_ptr address; -} -lt_preloaded_symbols[] = -{\ -" - - eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" - - $echo >> "$output_objdir/$dlsyms" "\ - {0, (lt_ptr) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif\ -" - fi - - pic_flag_for_symtable= - case $host in - # compiling the symbol table file with pic_flag works around - # a FreeBSD bug that causes programs to crash when -lm is - # linked before any other PIC object. But we must not use - # pic_flag when linking with -static. The problem exists in - # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. - *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) - case "$compile_command " in - *" -static "*) ;; - *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; - esac;; - *-*-hpux*) - case "$compile_command " in - *" -static "*) ;; - *) pic_flag_for_symtable=" $pic_flag";; - esac - esac - - # Now compile the dynamic symbol file. - $show "(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" - $run eval '(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? - - # Clean up the generated files. - $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" - $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" - - # Transform the symbol file into the correct name. - compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` - finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` - ;; - *) - $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 - exit 1 - ;; - esac - else - # We keep going just in case the user didn't refer to - # lt_preloaded_symbols. The linker will fail if global_symbol_pipe - # really was required. - - # Nullify the symbol file. - compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` - finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` - fi - - if test "$need_relink" = no || test "$build_libtool_libs" != yes; then - # Replace the output file specification. - compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` - link_command="$compile_command$compile_rpath" - - # We have no uninstalled library dependencies, so finalize right now. - $show "$link_command" - $run eval "$link_command" - status=$? - - # Delete the generated files. - if test -n "$dlsyms"; then - $show "$rm $output_objdir/${outputname}S.${objext}" - $run $rm "$output_objdir/${outputname}S.${objext}" - fi - - exit $status - fi - - if test -n "$shlibpath_var"; then - # We should set the shlibpath_var - rpath= - for dir in $temp_rpath; do - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) - # Absolute path. - rpath="$rpath$dir:" - ;; - *) - # Relative path: add a thisdir entry. - rpath="$rpath\$thisdir/$dir:" - ;; - esac - done - temp_rpath="$rpath" - fi - - if test -n "$compile_shlibpath$finalize_shlibpath"; then - compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" - fi - if test -n "$finalize_shlibpath"; then - finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" - fi - - compile_var= - finalize_var= - if test -n "$runpath_var"; then - if test -n "$perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $perm_rpath; do - rpath="$rpath$dir:" - done - compile_var="$runpath_var=\"$rpath\$$runpath_var\" " - fi - if test -n "$finalize_perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $finalize_perm_rpath; do - rpath="$rpath$dir:" - done - finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " - fi - fi - - if test "$no_install" = yes; then - # We don't need to create a wrapper script. - link_command="$compile_var$compile_command$compile_rpath" - # Replace the output file specification. - link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` - # Delete the old output file. - $run $rm $output - # Link the executable and exit - $show "$link_command" - $run eval "$link_command" || exit $? - exit 0 - fi - - if test "$hardcode_action" = relink; then - # Fast installation is not supported - link_command="$compile_var$compile_command$compile_rpath" - relink_command="$finalize_var$finalize_command$finalize_rpath" - - $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 - $echo "$modename: \`$output' will be relinked during installation" 1>&2 - else - if test "$fast_install" != no; then - link_command="$finalize_var$compile_command$finalize_rpath" - if test "$fast_install" = yes; then - relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` - else - # fast_install is set to needless - relink_command= - fi - else - link_command="$compile_var$compile_command$compile_rpath" - relink_command="$finalize_var$finalize_command$finalize_rpath" - fi - fi - - # Replace the output file specification. - link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` - - # Delete the old output files. - $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname - - $show "$link_command" - $run eval "$link_command" || exit $? - - # Now create the wrapper script. - $show "creating $output" - - # Quote the relink command for shipping. - if test -n "$relink_command"; then - # Preserve any variables that may affect compiler behavior - for var in $variables_saved_for_relink; do - if eval test -z \"\${$var+set}\"; then - relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" - elif eval var_value=\$$var; test -z "$var_value"; then - relink_command="$var=; export $var; $relink_command" - else - var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` - relink_command="$var=\"$var_value\"; export $var; $relink_command" - fi - done - relink_command="(cd `pwd`; $relink_command)" - relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` - fi - - # Quote $echo for shipping. - if test "X$echo" = "X$SHELL $0 --fallback-echo"; then - case $0 in - [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";; - *) qecho="$SHELL `pwd`/$0 --fallback-echo";; - esac - qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` - else - qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` - fi - - # Only actually do things if our run command is non-null. - if test -z "$run"; then - # win32 will think the script is a binary if it has - # a .exe suffix, so we strip it off here. - case $output in - *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; - esac - # test for cygwin because mv fails w/o .exe extensions - case $host in - *cygwin*) - exeext=.exe - outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; - *) exeext= ;; - esac - case $host in - *cygwin* | *mingw* ) - cwrappersource=`$echo ${objdir}/lt-${output}.c` - cwrapper=`$echo ${output}.exe` - $rm $cwrappersource $cwrapper - trap "$rm $cwrappersource $cwrapper; exit 1" 1 2 15 - - cat > $cwrappersource <<EOF - -/* $cwrappersource - temporary wrapper executable for $objdir/$outputname - Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP - - The $output program cannot be directly executed until all the libtool - libraries that it depends on are installed. - - This wrapper executable should never be moved out of the build directory. - If it is, it will not operate correctly. - - Currently, it simply execs the wrapper *script* "/bin/sh $output", - but could eventually absorb all of the scripts functionality and - exec $objdir/$outputname directly. -*/ -EOF - cat >> $cwrappersource<<"EOF" -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <malloc.h> -#include <stdarg.h> -#include <assert.h> - -#if defined(PATH_MAX) -# define LT_PATHMAX PATH_MAX -#elif defined(MAXPATHLEN) -# define LT_PATHMAX MAXPATHLEN -#else -# define LT_PATHMAX 1024 -#endif - -#ifndef DIR_SEPARATOR -#define DIR_SEPARATOR '/' -#endif - -#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ - defined (__OS2__) -#define HAVE_DOS_BASED_FILE_SYSTEM -#ifndef DIR_SEPARATOR_2 -#define DIR_SEPARATOR_2 '\\' -#endif -#endif - -#ifndef DIR_SEPARATOR_2 -# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) -#else /* DIR_SEPARATOR_2 */ -# define IS_DIR_SEPARATOR(ch) \ - (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) -#endif /* DIR_SEPARATOR_2 */ - -#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) -#define XFREE(stale) do { \ - if (stale) { free ((void *) stale); stale = 0; } \ -} while (0) - -const char *program_name = NULL; - -void * xmalloc (size_t num); -char * xstrdup (const char *string); -char * basename (const char *name); -char * fnqualify(const char *path); -char * strendzap(char *str, const char *pat); -void lt_fatal (const char *message, ...); - -int -main (int argc, char *argv[]) -{ - char **newargz; - int i; - - program_name = (char *) xstrdup ((char *) basename (argv[0])); - newargz = XMALLOC(char *, argc+2); -EOF - - cat >> $cwrappersource <<EOF - newargz[0] = "$SHELL"; -EOF - - cat >> $cwrappersource <<"EOF" - newargz[1] = fnqualify(argv[0]); - /* we know the script has the same name, without the .exe */ - /* so make sure newargz[1] doesn't end in .exe */ - strendzap(newargz[1],".exe"); - for (i = 1; i < argc; i++) - newargz[i+1] = xstrdup(argv[i]); - newargz[argc+1] = NULL; -EOF - - cat >> $cwrappersource <<EOF - execv("$SHELL",newargz); -EOF - - cat >> $cwrappersource <<"EOF" -} - -void * -xmalloc (size_t num) -{ - void * p = (void *) malloc (num); - if (!p) - lt_fatal ("Memory exhausted"); - - return p; -} - -char * -xstrdup (const char *string) -{ - return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL -; -} - -char * -basename (const char *name) -{ - const char *base; - -#if defined (HAVE_DOS_BASED_FILE_SYSTEM) - /* Skip over the disk name in MSDOS pathnames. */ - if (isalpha (name[0]) && name[1] == ':') - name += 2; -#endif - - for (base = name; *name; name++) - if (IS_DIR_SEPARATOR (*name)) - base = name + 1; - return (char *) base; -} - -char * -fnqualify(const char *path) -{ - size_t size; - char *p; - char tmp[LT_PATHMAX + 1]; - - assert(path != NULL); - - /* Is it qualified already? */ -#if defined (HAVE_DOS_BASED_FILE_SYSTEM) - if (isalpha (path[0]) && path[1] == ':') - return xstrdup (path); -#endif - if (IS_DIR_SEPARATOR (path[0])) - return xstrdup (path); - - /* prepend the current directory */ - /* doesn't handle '~' */ - if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal ("getcwd failed"); - size = strlen(tmp) + 1 + strlen(path) + 1; /* +2 for '/' and '\0' */ - p = XMALLOC(char, size); - sprintf(p, "%s%c%s", tmp, DIR_SEPARATOR, path); - return p; -} - -char * -strendzap(char *str, const char *pat) -{ - size_t len, patlen; - - assert(str != NULL); - assert(pat != NULL); - - len = strlen(str); - patlen = strlen(pat); - - if (patlen <= len) - { - str += len - patlen; - if (strcmp(str, pat) == 0) - *str = '\0'; - } - return str; -} - -static void -lt_error_core (int exit_status, const char * mode, - const char * message, va_list ap) -{ - fprintf (stderr, "%s: %s: ", program_name, mode); - vfprintf (stderr, message, ap); - fprintf (stderr, ".\n"); - - if (exit_status >= 0) - exit (exit_status); -} - -void -lt_fatal (const char *message, ...) -{ - va_list ap; - va_start (ap, message); - lt_error_core (EXIT_FAILURE, "FATAL", message, ap); - va_end (ap); -} -EOF - # we should really use a build-platform specific compiler - # here, but OTOH, the wrappers (shell script and this C one) - # are only useful if you want to execute the "real" binary. - # Since the "real" binary is built for $host, then this - # wrapper might as well be built for $host, too. - $run $LTCC -s -o $cwrapper $cwrappersource - ;; - esac - $rm $output - trap "$rm $output; exit 1" 1 2 15 - - $echo > $output "\ -#! $SHELL - -# $output - temporary wrapper script for $objdir/$outputname -# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP -# -# The $output program cannot be directly executed until all the libtool -# libraries that it depends on are installed. -# -# This wrapper script should never be moved out of the build directory. -# If it is, it will not operate correctly. - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -Xsed='${SED} -e 1s/^X//' -sed_quote_subst='$sed_quote_subst' - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi - -relink_command=\"$relink_command\" - -# This environment variable determines our operation mode. -if test \"\$libtool_install_magic\" = \"$magic\"; then - # install mode needs the following variable: - notinst_deplibs='$notinst_deplibs' -else - # When we are sourced in execute mode, \$file and \$echo are already set. - if test \"\$libtool_execute_magic\" != \"$magic\"; then - echo=\"$qecho\" - file=\"\$0\" - # Make sure echo works. - if test \"X\$1\" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift - elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then - # Yippee, \$echo works! - : - else - # Restart under the correct shell, and then maybe \$echo will work. - exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} - fi - fi\ -" - $echo >> $output "\ - - # Find the directory that this script lives in. - thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` - test \"x\$thisdir\" = \"x\$file\" && thisdir=. - - # Follow symbolic links until we get to the real thisdir. - file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` - while test -n \"\$file\"; do - destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` - - # If there was a directory component, then change thisdir. - if test \"x\$destdir\" != \"x\$file\"; then - case \"\$destdir\" in - [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; - *) thisdir=\"\$thisdir/\$destdir\" ;; - esac - fi - - file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` - file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` - done - - # Try to get the absolute directory name. - absdir=\`cd \"\$thisdir\" && pwd\` - test -n \"\$absdir\" && thisdir=\"\$absdir\" -" - - if test "$fast_install" = yes; then - $echo >> $output "\ - program=lt-'$outputname'$exeext - progdir=\"\$thisdir/$objdir\" - - if test ! -f \"\$progdir/\$program\" || \\ - { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ - test \"X\$file\" != \"X\$progdir/\$program\"; }; then - - file=\"\$\$-\$program\" - - if test ! -d \"\$progdir\"; then - $mkdir \"\$progdir\" - else - $rm \"\$progdir/\$file\" - fi" - - $echo >> $output "\ - - # relink executable if necessary - if test -n \"\$relink_command\"; then - if relink_command_output=\`eval \$relink_command 2>&1\`; then : - else - $echo \"\$relink_command_output\" >&2 - $rm \"\$progdir/\$file\" - exit 1 - fi - fi - - $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || - { $rm \"\$progdir/\$program\"; - $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } - $rm \"\$progdir/\$file\" - fi" - else - $echo >> $output "\ - program='$outputname' - progdir=\"\$thisdir/$objdir\" -" - fi - - $echo >> $output "\ - - if test -f \"\$progdir/\$program\"; then" - - # Export our shlibpath_var if we have one. - if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then - $echo >> $output "\ - # Add our own library path to $shlibpath_var - $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" - - # Some systems cannot cope with colon-terminated $shlibpath_var - # The second colon is a workaround for a bug in BeOS R4 sed - $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` - - export $shlibpath_var -" - fi - - # fixup the dll searchpath if we need to. - if test -n "$dllsearchpath"; then - $echo >> $output "\ - # Add the dll search path components to the executable PATH - PATH=$dllsearchpath:\$PATH -" - fi - - $echo >> $output "\ - if test \"\$libtool_execute_magic\" != \"$magic\"; then - # Run the actual program with our arguments. -" - case $host in - # Backslashes separate directories on plain windows - *-*-mingw | *-*-os2*) - $echo >> $output "\ - exec \$progdir\\\\\$program \${1+\"\$@\"} -" - ;; - - *) - $echo >> $output "\ - exec \$progdir/\$program \${1+\"\$@\"} -" - ;; - esac - $echo >> $output "\ - \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" - exit 1 - fi - else - # The program doesn't exist. - \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 - \$echo \"This script is just a wrapper for \$program.\" 1>&2 - $echo \"See the $PACKAGE documentation for more information.\" 1>&2 - exit 1 - fi -fi\ -" - chmod +x $output - fi - exit 0 - ;; - esac - - # See if we need to build an old-fashioned archive. - for oldlib in $oldlibs; do - - if test "$build_libtool_libs" = convenience; then - oldobjs="$libobjs_save" - addlibs="$convenience" - build_libtool_libs=no - else - if test "$build_libtool_libs" = module; then - oldobjs="$libobjs_save" - build_libtool_libs=no - else - oldobjs="$old_deplibs $non_pic_objects" - fi - addlibs="$old_convenience" - fi - - if test -n "$addlibs"; then - gentop="$output_objdir/${outputname}x" - $show "${rm}r $gentop" - $run ${rm}r "$gentop" - $show "$mkdir $gentop" - $run $mkdir "$gentop" - status=$? - if test "$status" -ne 0 && test ! -d "$gentop"; then - exit $status - fi - generated="$generated $gentop" - - # Add in members from convenience archives. - for xlib in $addlibs; do - # Extract the objects. - case $xlib in - [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; - *) xabs=`pwd`"/$xlib" ;; - esac - xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` - xdir="$gentop/$xlib" - - $show "${rm}r $xdir" - $run ${rm}r "$xdir" - $show "$mkdir $xdir" - $run $mkdir "$xdir" - status=$? - if test "$status" -ne 0 && test ! -d "$xdir"; then - exit $status - fi - # We will extract separately just the conflicting names and we will no - # longer touch any unique names. It is faster to leave these extract - # automatically by $AR in one run. - $show "(cd $xdir && $AR x $xabs)" - $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? - if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then - : - else - $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 - $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 - $AR t "$xabs" | sort | uniq -cd | while read -r count name - do - i=1 - while test "$i" -le "$count" - do - # Put our $i before any first dot (extension) - # Never overwrite any file - name_to="$name" - while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" - do - name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` - done - $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" - $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? - i=`expr $i + 1` - done - done - fi - - oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` - done - fi - - # Do each command in the archive commands. - if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then - cmds=$old_archive_from_new_cmds - else - eval cmds=\"$old_archive_cmds\" - - if len=`expr "X$cmds" : ".*"` && - test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then - cmds=$old_archive_cmds - else - # the command line is too long to link in one step, link in parts - $echo "using piecewise archive linking..." - save_RANLIB=$RANLIB - RANLIB=: - objlist= - concat_cmds= - save_oldobjs=$oldobjs - # GNU ar 2.10+ was changed to match POSIX; thus no paths are - # encoded into archives. This makes 'ar r' malfunction in - # this piecewise linking case whenever conflicting object - # names appear in distinct ar calls; check, warn and compensate. - if (for obj in $save_oldobjs - do - $echo "X$obj" | $Xsed -e 's%^.*/%%' - done | sort | sort -uc >/dev/null 2>&1); then - : - else - $echo "$modename: warning: object name conflicts; overriding AR_FLAGS to 'cq'" 1>&2 - $echo "$modename: warning: to ensure that POSIX-compatible ar will work" 1>&2 - AR_FLAGS=cq - fi - # Is there a better way of finding the last object in the list? - for obj in $save_oldobjs - do - last_oldobj=$obj - done - for obj in $save_oldobjs - do - oldobjs="$objlist $obj" - objlist="$objlist $obj" - eval test_cmds=\"$old_archive_cmds\" - if len=`expr "X$test_cmds" : ".*"` && - test "$len" -le "$max_cmd_len"; then - : - else - # the above command should be used before it gets too long - oldobjs=$objlist - if test "$obj" = "$last_oldobj" ; then - RANLIB=$save_RANLIB - fi - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" - objlist= - fi - done - RANLIB=$save_RANLIB - oldobjs=$objlist - if test "X$oldobjs" = "X" ; then - eval cmds=\"\$concat_cmds\" - else - eval cmds=\"\$concat_cmds~\$old_archive_cmds\" - fi - fi - fi - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - eval cmd=\"$cmd\" - IFS="$save_ifs" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - done - - if test -n "$generated"; then - $show "${rm}r$generated" - $run ${rm}r$generated - fi - - # Now create the libtool archive. - case $output in - *.la) - old_library= - test "$build_old_libs" = yes && old_library="$libname.$libext" - $show "creating $output" - - # Preserve any variables that may affect compiler behavior - for var in $variables_saved_for_relink; do - if eval test -z \"\${$var+set}\"; then - relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" - elif eval var_value=\$$var; test -z "$var_value"; then - relink_command="$var=; export $var; $relink_command" - else - var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` - relink_command="$var=\"$var_value\"; export $var; $relink_command" - fi - done - # Quote the link command for shipping. - relink_command="(cd `pwd`; $SHELL $0 $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" - relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` - if test "$hardcode_automatic" = yes ; then - relink_command= - fi - # Only create the output if not a dry run. - if test -z "$run"; then - for installed in no yes; do - if test "$installed" = yes; then - if test -z "$install_libdir"; then - break - fi - output="$output_objdir/$outputname"i - # Replace all uninstalled libtool libraries with the installed ones - newdependency_libs= - for deplib in $dependency_libs; do - case $deplib in - *.la) - name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` - if test -z "$libdir"; then - $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 - exit 1 - fi - newdependency_libs="$newdependency_libs $libdir/$name" - ;; - *) newdependency_libs="$newdependency_libs $deplib" ;; - esac - done - dependency_libs="$newdependency_libs" - newdlfiles= - for lib in $dlfiles; do - name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` - if test -z "$libdir"; then - $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 - exit 1 - fi - newdlfiles="$newdlfiles $libdir/$name" - done - dlfiles="$newdlfiles" - newdlprefiles= - for lib in $dlprefiles; do - name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` - if test -z "$libdir"; then - $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 - exit 1 - fi - newdlprefiles="$newdlprefiles $libdir/$name" - done - dlprefiles="$newdlprefiles" - else - newdlfiles= - for lib in $dlfiles; do - case $lib in - [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; - *) abs=`pwd`"/$lib" ;; - esac - newdlfiles="$newdlfiles $abs" - done - dlfiles="$newdlfiles" - newdlprefiles= - for lib in $dlprefiles; do - case $lib in - [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; - *) abs=`pwd`"/$lib" ;; - esac - newdlprefiles="$newdlprefiles $abs" - done - dlprefiles="$newdlprefiles" - fi - $rm $output - # place dlname in correct position for cygwin - tdlname=$dlname - case $host,$output,$installed,$module,$dlname in - *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; - esac - $echo > $output "\ -# $outputname - a libtool library file -# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# The name that we can dlopen(3). -dlname='$tdlname' - -# Names of this library. -library_names='$library_names' - -# The name of the static archive. -old_library='$old_library' - -# Libraries that this one depends upon. -dependency_libs='$dependency_libs' - -# Version information for $libname. -current=$current -age=$age -revision=$revision - -# Is this an already installed library? -installed=$installed - -# Should we warn about portability when linking against -modules? -shouldnotlink=$module - -# Files to dlopen/dlpreopen -dlopen='$dlfiles' -dlpreopen='$dlprefiles' - -# Directory that this library needs to be installed in: -libdir='$install_libdir'" - if test "$installed" = no && test "$need_relink" = yes; then - $echo >> $output "\ -relink_command=\"$relink_command\"" - fi - done - fi - - # Do a symbolic link so that the libtool archive can be found in - # LD_LIBRARY_PATH before the program is installed. - $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" - $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? - ;; - esac - exit 0 - ;; - - # libtool install mode - install) - modename="$modename: install" - - # There may be an optional sh(1) argument at the beginning of - # install_prog (especially on Windows NT). - if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || - # Allow the use of GNU shtool's install command. - $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then - # Aesthetically quote it. - arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) - arg="\"$arg\"" - ;; - esac - install_prog="$arg " - arg="$1" - shift - else - install_prog= - arg="$nonopt" - fi - - # The real first argument should be the name of the installation program. - # Aesthetically quote it. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) - arg="\"$arg\"" - ;; - esac - install_prog="$install_prog$arg" - - # We need to accept at least all the BSD install flags. - dest= - files= - opts= - prev= - install_type= - isdir=no - stripme= - for arg - do - if test -n "$dest"; then - files="$files $dest" - dest="$arg" - continue - fi - - case $arg in - -d) isdir=yes ;; - -f) prev="-f" ;; - -g) prev="-g" ;; - -m) prev="-m" ;; - -o) prev="-o" ;; - -s) - stripme=" -s" - continue - ;; - -*) ;; - - *) - # If the previous option needed an argument, then skip it. - if test -n "$prev"; then - prev= - else - dest="$arg" - continue - fi - ;; - esac - - # Aesthetically quote the argument. - arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` - case $arg in - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) - arg="\"$arg\"" - ;; - esac - install_prog="$install_prog $arg" - done - - if test -z "$install_prog"; then - $echo "$modename: you must specify an install program" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - if test -n "$prev"; then - $echo "$modename: the \`$prev' option requires an argument" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - if test -z "$files"; then - if test -z "$dest"; then - $echo "$modename: no file or destination specified" 1>&2 - else - $echo "$modename: you must specify a destination" 1>&2 - fi - $echo "$help" 1>&2 - exit 1 - fi - - # Strip any trailing slash from the destination. - dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` - - # Check to see that the destination is a directory. - test -d "$dest" && isdir=yes - if test "$isdir" = yes; then - destdir="$dest" - destname= - else - destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` - test "X$destdir" = "X$dest" && destdir=. - destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` - - # Not a directory, so check to see that there is only one file specified. - set dummy $files - if test "$#" -gt 2; then - $echo "$modename: \`$dest' is not a directory" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - fi - case $destdir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - for file in $files; do - case $file in - *.lo) ;; - *) - $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 - $echo "$help" 1>&2 - exit 1 - ;; - esac - done - ;; - esac - - # This variable tells wrapper scripts just to set variables rather - # than running their programs. - libtool_install_magic="$magic" - - staticlibs= - future_libdirs= - current_libdirs= - for file in $files; do - - # Do each installation. - case $file in - *.$libext) - # Do the static libraries later. - staticlibs="$staticlibs $file" - ;; - - *.la) - # Check to see that this really is a libtool archive. - if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : - else - $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - library_names= - old_library= - relink_command= - # If there is no directory component, then add one. - case $file in - */* | *\\*) . $file ;; - *) . ./$file ;; - esac - - # Add the libdir to current_libdirs if it is the destination. - if test "X$destdir" = "X$libdir"; then - case "$current_libdirs " in - *" $libdir "*) ;; - *) current_libdirs="$current_libdirs $libdir" ;; - esac - else - # Note the libdir as a future libdir. - case "$future_libdirs " in - *" $libdir "*) ;; - *) future_libdirs="$future_libdirs $libdir" ;; - esac - fi - - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ - test "X$dir" = "X$file/" && dir= - dir="$dir$objdir" - - if test -n "$relink_command"; then - # Determine the prefix the user has applied to our future dir. - inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` - - # Don't allow the user to place us outside of our expected - # location b/c this prevents finding dependent libraries that - # are installed to the same prefix. - # At present, this check doesn't affect windows .dll's that - # are installed into $libdir/../bin (currently, that works fine) - # but it's something to keep an eye on. - if test "$inst_prefix_dir" = "$destdir"; then - $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 - exit 1 - fi - - if test -n "$inst_prefix_dir"; then - # Stick the inst_prefix_dir data into the link command. - relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` - else - relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"` - fi - - $echo "$modename: warning: relinking \`$file'" 1>&2 - $show "$relink_command" - if $run eval "$relink_command"; then : - else - $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 - exit 1 - fi - fi - - # See the names of the shared library. - set dummy $library_names - if test -n "$2"; then - realname="$2" - shift - shift - - srcname="$realname" - test -n "$relink_command" && srcname="$realname"T - - # Install the shared library and build the symlinks. - $show "$install_prog $dir/$srcname $destdir/$realname" - $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? - if test -n "$stripme" && test -n "$striplib"; then - $show "$striplib $destdir/$realname" - $run eval "$striplib $destdir/$realname" || exit $? - fi - - if test "$#" -gt 0; then - # Delete the old symlinks, and create new ones. - for linkname - do - if test "$linkname" != "$realname"; then - $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" - $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" - fi - done - fi - - # Do each command in the postinstall commands. - lib="$destdir/$realname" - cmds=$postinstall_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - fi - - # Install the pseudo-library for information purposes. - name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - instname="$dir/$name"i - $show "$install_prog $instname $destdir/$name" - $run eval "$install_prog $instname $destdir/$name" || exit $? - - # Maybe install the static library, too. - test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" - ;; - - *.lo) - # Install (i.e. copy) a libtool object. - - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile="$destdir/$destname" - else - destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - destfile="$destdir/$destfile" - fi - - # Deduce the name of the destination old-style object file. - case $destfile in - *.lo) - staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` - ;; - *.$objext) - staticdest="$destfile" - destfile= - ;; - *) - $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 - $echo "$help" 1>&2 - exit 1 - ;; - esac - - # Install the libtool object if requested. - if test -n "$destfile"; then - $show "$install_prog $file $destfile" - $run eval "$install_prog $file $destfile" || exit $? - fi - - # Install the old object if enabled. - if test "$build_old_libs" = yes; then - # Deduce the name of the old-style object file. - staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` - - $show "$install_prog $staticobj $staticdest" - $run eval "$install_prog \$staticobj \$staticdest" || exit $? - fi - exit 0 - ;; - - *) - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile="$destdir/$destname" - else - destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - destfile="$destdir/$destfile" - fi - - # If the file is missing, and there is a .exe on the end, strip it - # because it is most likely a libtool script we actually want to - # install - stripped_ext="" - case $file in - *.exe) - if test ! -f "$file"; then - file=`$echo $file|${SED} 's,.exe$,,'` - stripped_ext=".exe" - fi - ;; - esac - - # Do a test to see if this is really a libtool program. - case $host in - *cygwin*|*mingw*) - wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` - ;; - *) - wrapper=$file - ;; - esac - if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then - notinst_deplibs= - relink_command= - - # To insure that "foo" is sourced, and not "foo.exe", - # finese the cygwin/MSYS system by explicitly sourcing "foo." - # which disallows the automatic-append-.exe behavior. - case $build in - *cygwin* | *mingw*) wrapperdot=${wrapper}. ;; - *) wrapperdot=${wrapper} ;; - esac - # If there is no directory component, then add one. - case $file in - */* | *\\*) . ${wrapperdot} ;; - *) . ./${wrapperdot} ;; - esac - - # Check the variables that should have been set. - if test -z "$notinst_deplibs"; then - $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 - exit 1 - fi - - finalize=yes - for lib in $notinst_deplibs; do - # Check to see that each library is installed. - libdir= - if test -f "$lib"; then - # If there is no directory component, then add one. - case $lib in - */* | *\\*) . $lib ;; - *) . ./$lib ;; - esac - fi - libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test - if test -n "$libdir" && test ! -f "$libfile"; then - $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 - finalize=no - fi - done - - relink_command= - # To insure that "foo" is sourced, and not "foo.exe", - # finese the cygwin/MSYS system by explicitly sourcing "foo." - # which disallows the automatic-append-.exe behavior. - case $build in - *cygwin* | *mingw*) wrapperdot=${wrapper}. ;; - *) wrapperdot=${wrapper} ;; - esac - # If there is no directory component, then add one. - case $file in - */* | *\\*) . ${wrapperdot} ;; - *) . ./${wrapperdot} ;; - esac - - outputname= - if test "$fast_install" = no && test -n "$relink_command"; then - if test "$finalize" = yes && test -z "$run"; then - tmpdir="/tmp" - test -n "$TMPDIR" && tmpdir="$TMPDIR" - tmpdir="$tmpdir/libtool-$$" - if $mkdir "$tmpdir" && chmod 700 "$tmpdir"; then : - else - $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 - continue - fi - file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` - outputname="$tmpdir/$file" - # Replace the output file specification. - relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` - - $show "$relink_command" - if $run eval "$relink_command"; then : - else - $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 - ${rm}r "$tmpdir" - continue - fi - file="$outputname" - else - $echo "$modename: warning: cannot relink \`$file'" 1>&2 - fi - else - # Install the binary that we compiled earlier. - file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` - fi - fi - - # remove .exe since cygwin /usr/bin/install will append another - # one anyways - case $install_prog,$host in - */usr/bin/install*,*cygwin*) - case $file:$destfile in - *.exe:*.exe) - # this is ok - ;; - *.exe:*) - destfile=$destfile.exe - ;; - *:*.exe) - destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` - ;; - esac - ;; - esac - $show "$install_prog$stripme $file $destfile" - $run eval "$install_prog\$stripme \$file \$destfile" || exit $? - test -n "$outputname" && ${rm}r "$tmpdir" - ;; - esac - done - - for file in $staticlibs; do - name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - - # Set up the ranlib parameters. - oldlib="$destdir/$name" - - $show "$install_prog $file $oldlib" - $run eval "$install_prog \$file \$oldlib" || exit $? - - if test -n "$stripme" && test -n "$old_striplib"; then - $show "$old_striplib $oldlib" - $run eval "$old_striplib $oldlib" || exit $? - fi - - # Do each command in the postinstall commands. - cmds=$old_postinstall_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || exit $? - done - IFS="$save_ifs" - done - - if test -n "$future_libdirs"; then - $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 - fi - - if test -n "$current_libdirs"; then - # Maybe just do a dry run. - test -n "$run" && current_libdirs=" -n$current_libdirs" - exec_cmd='$SHELL $0 $preserve_args --finish$current_libdirs' - else - exit 0 - fi - ;; - - # libtool finish mode - finish) - modename="$modename: finish" - libdirs="$nonopt" - admincmds= - - if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then - for dir - do - libdirs="$libdirs $dir" - done - - for libdir in $libdirs; do - if test -n "$finish_cmds"; then - # Do each command in the finish commands. - cmds=$finish_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" || admincmds="$admincmds - $cmd" - done - IFS="$save_ifs" - fi - if test -n "$finish_eval"; then - # Do the single finish_eval. - eval cmds=\"$finish_eval\" - $run eval "$cmds" || admincmds="$admincmds - $cmds" - fi - done - fi - - # Exit here if they wanted silent mode. - test "$show" = : && exit 0 - - $echo "----------------------------------------------------------------------" - $echo "Libraries have been installed in:" - for libdir in $libdirs; do - $echo " $libdir" - done - $echo - $echo "If you ever happen to want to link against installed libraries" - $echo "in a given directory, LIBDIR, you must either use libtool, and" - $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" - $echo "flag during linking and do at least one of the following:" - if test -n "$shlibpath_var"; then - $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" - $echo " during execution" - fi - if test -n "$runpath_var"; then - $echo " - add LIBDIR to the \`$runpath_var' environment variable" - $echo " during linking" - fi - if test -n "$hardcode_libdir_flag_spec"; then - libdir=LIBDIR - eval flag=\"$hardcode_libdir_flag_spec\" - - $echo " - use the \`$flag' linker flag" - fi - if test -n "$admincmds"; then - $echo " - have your system administrator run these commands:$admincmds" - fi - if test -f /etc/ld.so.conf; then - $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" - fi - $echo - $echo "See any operating system documentation about shared libraries for" - $echo "more information, such as the ld(1) and ld.so(8) manual pages." - $echo "----------------------------------------------------------------------" - exit 0 - ;; - - # libtool execute mode - execute) - modename="$modename: execute" - - # The first argument is the command name. - cmd="$nonopt" - if test -z "$cmd"; then - $echo "$modename: you must specify a COMMAND" 1>&2 - $echo "$help" - exit 1 - fi - - # Handle -dlopen flags immediately. - for file in $execute_dlfiles; do - if test ! -f "$file"; then - $echo "$modename: \`$file' is not a file" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - dir= - case $file in - *.la) - # Check to see that this really is a libtool archive. - if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : - else - $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - # Read the libtool library. - dlname= - library_names= - - # If there is no directory component, then add one. - case $file in - */* | *\\*) . $file ;; - *) . ./$file ;; - esac - - # Skip this library if it cannot be dlopened. - if test -z "$dlname"; then - # Warn if it was a shared library. - test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" - continue - fi - - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` - test "X$dir" = "X$file" && dir=. - - if test -f "$dir/$objdir/$dlname"; then - dir="$dir/$objdir" - else - $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 - exit 1 - fi - ;; - - *.lo) - # Just add the directory containing the .lo file. - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` - test "X$dir" = "X$file" && dir=. - ;; - - *) - $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 - continue - ;; - esac - - # Get the absolute pathname. - absdir=`cd "$dir" && pwd` - test -n "$absdir" && dir="$absdir" - - # Now add the directory to shlibpath_var. - if eval "test -z \"\$$shlibpath_var\""; then - eval "$shlibpath_var=\"\$dir\"" - else - eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" - fi - done - - # This variable tells wrapper scripts just to set shlibpath_var - # rather than running their programs. - libtool_execute_magic="$magic" - - # Check if any of the arguments is a wrapper script. - args= - for file - do - case $file in - -*) ;; - *) - # Do a test to see if this is really a libtool program. - if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - # If there is no directory component, then add one. - case $file in - */* | *\\*) . $file ;; - *) . ./$file ;; - esac - - # Transform arg to wrapped name. - file="$progdir/$program" - fi - ;; - esac - # Quote arguments (to preserve shell metacharacters). - file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` - args="$args \"$file\"" - done - - if test -z "$run"; then - if test -n "$shlibpath_var"; then - # Export the shlibpath_var. - eval "export $shlibpath_var" - fi - - # Restore saved environment variables - if test "${save_LC_ALL+set}" = set; then - LC_ALL="$save_LC_ALL"; export LC_ALL - fi - if test "${save_LANG+set}" = set; then - LANG="$save_LANG"; export LANG - fi - - # Now prepare to actually exec the command. - exec_cmd="\$cmd$args" - else - # Display what would be done. - if test -n "$shlibpath_var"; then - eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" - $echo "export $shlibpath_var" - fi - $echo "$cmd$args" - exit 0 - fi - ;; - - # libtool clean and uninstall mode - clean | uninstall) - modename="$modename: $mode" - rm="$nonopt" - files= - rmforce= - exit_status=0 - - # This variable tells wrapper scripts just to set variables rather - # than running their programs. - libtool_install_magic="$magic" - - for arg - do - case $arg in - -f) rm="$rm $arg"; rmforce=yes ;; - -*) rm="$rm $arg" ;; - *) files="$files $arg" ;; - esac - done - - if test -z "$rm"; then - $echo "$modename: you must specify an RM program" 1>&2 - $echo "$help" 1>&2 - exit 1 - fi - - rmdirs= - - origobjdir="$objdir" - for file in $files; do - dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` - if test "X$dir" = "X$file"; then - dir=. - objdir="$origobjdir" - else - objdir="$dir/$origobjdir" - fi - name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` - test "$mode" = uninstall && objdir="$dir" - - # Remember objdir for removal later, being careful to avoid duplicates - if test "$mode" = clean; then - case " $rmdirs " in - *" $objdir "*) ;; - *) rmdirs="$rmdirs $objdir" ;; - esac - fi - - # Don't error if the file doesn't exist and rm -f was used. - if (test -L "$file") >/dev/null 2>&1 \ - || (test -h "$file") >/dev/null 2>&1 \ - || test -f "$file"; then - : - elif test -d "$file"; then - exit_status=1 - continue - elif test "$rmforce" = yes; then - continue - fi - - rmfiles="$file" - - case $name in - *.la) - # Possibly a libtool archive, so verify it. - if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - . $dir/$name - - # Delete the libtool libraries and symlinks. - for n in $library_names; do - rmfiles="$rmfiles $objdir/$n" - done - test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" - test "$mode" = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" - - if test "$mode" = uninstall; then - if test -n "$library_names"; then - # Do each command in the postuninstall commands. - cmds=$postuninstall_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" - if test "$?" -ne 0 && test "$rmforce" != yes; then - exit_status=1 - fi - done - IFS="$save_ifs" - fi - - if test -n "$old_library"; then - # Do each command in the old_postuninstall commands. - cmds=$old_postuninstall_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval cmd=\"$cmd\" - $show "$cmd" - $run eval "$cmd" - if test "$?" -ne 0 && test "$rmforce" != yes; then - exit_status=1 - fi - done - IFS="$save_ifs" - fi - # FIXME: should reinstall the best remaining shared library. - fi - fi - ;; - - *.lo) - # Possibly a libtool object, so verify it. - if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - - # Read the .lo file - . $dir/$name - - # Add PIC object to the list of files to remove. - if test -n "$pic_object" \ - && test "$pic_object" != none; then - rmfiles="$rmfiles $dir/$pic_object" - fi - - # Add non-PIC object to the list of files to remove. - if test -n "$non_pic_object" \ - && test "$non_pic_object" != none; then - rmfiles="$rmfiles $dir/$non_pic_object" - fi - fi - ;; - - *) - if test "$mode" = clean ; then - noexename=$name - case $file in - *.exe) - file=`$echo $file|${SED} 's,.exe$,,'` - noexename=`$echo $name|${SED} 's,.exe$,,'` - # $file with .exe has already been added to rmfiles, - # add $file without .exe - rmfiles="$rmfiles $file" - ;; - esac - # Do a test to see if this is a libtool program. - if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then - relink_command= - . $dir/$noexename - - # note $name still contains .exe if it was in $file originally - # as does the version of $file that was added into $rmfiles - rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" - if test "$fast_install" = yes && test -n "$relink_command"; then - rmfiles="$rmfiles $objdir/lt-$name" - fi - if test "X$noexename" != "X$name" ; then - rmfiles="$rmfiles $objdir/lt-${noexename}.c" - fi - fi - fi - ;; - esac - $show "$rm $rmfiles" - $run $rm $rmfiles || exit_status=1 - done - objdir="$origobjdir" - - # Try to remove the ${objdir}s in the directories where we deleted files - for dir in $rmdirs; do - if test -d "$dir"; then - $show "rmdir $dir" - $run rmdir $dir >/dev/null 2>&1 - fi - done - - exit $exit_status - ;; - - "") - $echo "$modename: you must specify a MODE" 1>&2 - $echo "$generic_help" 1>&2 - exit 1 - ;; - esac - - if test -z "$exec_cmd"; then - $echo "$modename: invalid operation mode \`$mode'" 1>&2 - $echo "$generic_help" 1>&2 - exit 1 - fi -fi # test -z "$show_help" - -if test -n "$exec_cmd"; then - eval exec $exec_cmd - exit 1 -fi - -# We need to display help for each of the modes. -case $mode in -"") $echo \ -"Usage: $modename [OPTION]... [MODE-ARG]... - -Provide generalized library-building support services. - - --config show all configuration variables - --debug enable verbose shell tracing --n, --dry-run display commands without modifying any files - --features display basic configuration information and exit - --finish same as \`--mode=finish' - --help display this help message and exit - --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] - --quiet same as \`--silent' - --silent don't print informational messages - --tag=TAG use configuration variables from tag TAG - --version print version information - -MODE must be one of the following: - - clean remove files from the build directory - compile compile a source file into a libtool object - execute automatically set library path, then run a program - finish complete the installation of libtool libraries - install install libraries or executables - link create a library or an executable - uninstall remove libraries from an installed directory - -MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for -a more detailed description of MODE. - -Report bugs to <bug-libtool@gnu.org>." - exit 0 - ;; - -clean) - $echo \ -"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... - -Remove files from the build directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed -to RM. - -If FILE is a libtool library, object or program, all the files associated -with it are deleted. Otherwise, only FILE itself is deleted using RM." - ;; - -compile) - $echo \ -"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE - -Compile a source file into a libtool library object. - -This mode accepts the following additional options: - - -o OUTPUT-FILE set the output file name to OUTPUT-FILE - -prefer-pic try to building PIC objects only - -prefer-non-pic try to building non-PIC objects only - -static always build a \`.o' file suitable for static linking - -COMPILE-COMMAND is a command to be used in creating a \`standard' object file -from the given SOURCEFILE. - -The output file name is determined by removing the directory component from -SOURCEFILE, then substituting the C source code suffix \`.c' with the -library object suffix, \`.lo'." - ;; - -execute) - $echo \ -"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... - -Automatically set library path, then run a program. - -This mode accepts the following additional options: - - -dlopen FILE add the directory containing FILE to the library path - -This mode sets the library path environment variable according to \`-dlopen' -flags. - -If any of the ARGS are libtool executable wrappers, then they are translated -into their corresponding uninstalled binary, and any of their required library -directories are added to the library path. - -Then, COMMAND is executed, with ARGS as arguments." - ;; - -finish) - $echo \ -"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... - -Complete the installation of libtool libraries. - -Each LIBDIR is a directory that contains libtool libraries. - -The commands that this mode executes may require superuser privileges. Use -the \`--dry-run' option if you just want to see what would be executed." - ;; - -install) - $echo \ -"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... - -Install executables or libraries. - -INSTALL-COMMAND is the installation command. The first component should be -either the \`install' or \`cp' program. - -The rest of the components are interpreted as arguments to that command (only -BSD-compatible install options are recognized)." - ;; - -link) - $echo \ -"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... - -Link object files or libraries together to form another library, or to -create an executable program. - -LINK-COMMAND is a command using the C compiler that you would use to create -a program from several object files. - -The following components of LINK-COMMAND are treated specially: - - -all-static do not do any dynamic linking at all - -avoid-version do not add a version suffix if possible - -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime - -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols - -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) - -export-symbols SYMFILE - try to export only the symbols listed in SYMFILE - -export-symbols-regex REGEX - try to export only the symbols matching REGEX - -LLIBDIR search LIBDIR for required installed libraries - -lNAME OUTPUT-FILE requires the installed library libNAME - -module build a library that can dlopened - -no-fast-install disable the fast-install mode - -no-install link a not-installable executable - -no-undefined declare that a library does not refer to external symbols - -o OUTPUT-FILE create OUTPUT-FILE from the specified objects - -objectlist FILE Use a list of object files found in FILE to specify objects - -precious-files-regex REGEX - don't remove output files matching REGEX - -release RELEASE specify package release information - -rpath LIBDIR the created library will eventually be installed in LIBDIR - -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries - -static do not do any dynamic linking of libtool libraries - -version-info CURRENT[:REVISION[:AGE]] - specify library version info [each variable defaults to 0] - -All other options (arguments beginning with \`-') are ignored. - -Every other argument is treated as a filename. Files ending in \`.la' are -treated as uninstalled libtool libraries, other files are standard or library -object files. - -If the OUTPUT-FILE ends in \`.la', then a libtool library is created, -only library objects (\`.lo' files) may be specified, and \`-rpath' is -required, except when creating a convenience library. - -If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created -using \`ar' and \`ranlib', or on Windows using \`lib'. - -If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file -is created, otherwise an executable program is created." - ;; - -uninstall) - $echo \ -"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... - -Remove libraries from an installation directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed -to RM. - -If FILE is a libtool library, all the files associated with it are deleted. -Otherwise, only FILE itself is deleted using RM." - ;; - -*) - $echo "$modename: invalid operation mode \`$mode'" 1>&2 - $echo "$help" 1>&2 - exit 1 - ;; -esac - -$echo -$echo "Try \`$modename --help' for more information about other modes." - -exit 0 - -# The TAGs below are defined such that we never get into a situation -# in which we disable both kinds of libraries. Given conflicting -# choices, we go for a static library, that is the most portable, -# since we can't tell whether shared libraries were disabled because -# the user asked for that or because the platform doesn't support -# them. This is particularly important on AIX, because we don't -# support having both static and shared libraries enabled at the same -# time on that platform, so we default to a shared-only configuration. -# If a disable-shared tag is given, we'll fallback to a static-only -# configuration. But we'll never go from static-only to shared-only. - -# ### BEGIN LIBTOOL TAG CONFIG: disable-shared -build_libtool_libs=no -build_old_libs=yes -# ### END LIBTOOL TAG CONFIG: disable-shared - -# ### BEGIN LIBTOOL TAG CONFIG: disable-static -build_old_libs=`case $build_libtool_libs in yes) $echo no;; *) $echo yes;; esac` -# ### END LIBTOOL TAG CONFIG: disable-static - -# Local Variables: -# mode:shell-script -# sh-indentation:2 -# End: +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun configure. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003 +# Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<EOF +$* +EOF + exit 0 +fi + +# The name of this program. +progname=`$echo "$0" | ${SED} 's%^.*/%%'` +modename="$progname" + +# Constants. +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION=1.5.2 + +default_mode= +help="Try \`$progname --help' for more information." +magic="%%%MAGIC variable%%%" +mkdir="mkdir" +mv="mv -f" +rm="rm -f" + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g' +# test EBCDIC or ASCII +case `echo A|tr A '\301'` in + A) # EBCDIC based system + SP2NL="tr '\100' '\n'" + NL2SP="tr '\r\n' '\100\100'" + ;; + *) # Assume ASCII based system + SP2NL="tr '\040' '\012'" + NL2SP="tr '\015\012' '\040\040'" + ;; +esac + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +# We save the old values to restore during execute mode. +if test "${LC_ALL+set}" = set; then + save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL +fi +if test "${LANG+set}" = set; then + save_LANG="$LANG"; LANG=C; export LANG +fi + +# Make sure IFS has a sensible default +: ${IFS=" +"} + +if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + $echo "$modename: not configured to build any kind of library" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" + +##################################### +# Shell function definitions: +# This seems to be the best place for them + +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +win32_libid () { + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ + grep -E 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | \ + sed -n -e '1,100{/ I /{x;/import/!{s/^/import/;h;p;};x;};}'` + if test "X$win32_nmres" = "Ximport" ; then + win32_libid_type="x86 archive import" + else + win32_libid_type="x86 archive static" + fi + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $echo $win32_libid_type +} + +# End of Shell function definitions +##################################### + +# Parse our command line options once, thoroughly. +while test "$#" -gt 0 +do + arg="$1" + shift + + case $arg in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + execute_dlfiles) + execute_dlfiles="$execute_dlfiles $arg" + ;; + tag) + tagname="$arg" + preserve_args="${preserve_args}=$arg" + + # Check whether tagname contains only valid characters + case $tagname in + *[!-_A-Za-z0-9,/]*) + $echo "$progname: invalid tag name: $tagname" 1>&2 + exit 1 + ;; + esac + + case $tagname in + CC) + # Don't test for the "default" C tag, as we know, it's there, but + # not specially marked. + ;; + *) + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$0" > /dev/null; then + taglist="$taglist $tagname" + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $0`" + else + $echo "$progname: ignoring unknown tag $tagname" 1>&2 + fi + ;; + esac + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case $arg in + --help) + show_help=yes + ;; + + --version) + $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" + $echo + $echo "Copyright (C) 2003 Free Software Foundation, Inc." + $echo "This is free software; see the source for copying conditions. There is NO" + $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + exit 0 + ;; + + --config) + ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $0 + # Now print the configurations for the tags. + for tagname in $taglist; do + ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$0" + done + exit 0 + ;; + + --debug) + $echo "$progname: enabling shell trace mode" + set -x + preserve_args="$preserve_args $arg" + ;; + + --dry-run | -n) + run=: + ;; + + --features) + $echo "host: $host" + if test "$build_libtool_libs" = yes; then + $echo "enable shared libraries" + else + $echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $echo "enable static libraries" + else + $echo "disable static libraries" + fi + exit 0 + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --preserve-dup-deps) duplicate_deps="yes" ;; + + --quiet | --silent) + show=: + preserve_args="$preserve_args $arg" + ;; + + --tag) prevopt="--tag" prev=tag ;; + --tag=*) + set tag "$optarg" ${1+"$@"} + shift + prev=tag + preserve_args="$preserve_args --tag" + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 +fi + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 + $echo "*** Future versions of Libtool will require -mode=MODE be specified." 1>&2 + case $nonopt in + *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) + mode=link + for arg + do + case $arg in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case $mode in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + + for arg + do + case "$arg_mode" in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + if test -n "$libobj" ; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit 1 + fi + arg_mode=target + continue + ;; + + -static | -prefer-pic | -prefer-non-pic) + later="$later $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + lastarg="$lastarg $arg" + done + IFS="$save_ifs" + lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` + + # Add the arguments to base_compile. + base_compile="$base_compile $lastarg" + continue + ;; + + * ) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + case $lastarg in + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + lastarg="\"$lastarg\"" + ;; + esac + + base_compile="$base_compile $lastarg" + done # for arg + + case $arg_mode in + arg) + $echo "$modename: you must specify an argument for -Xcompile" + exit 1 + ;; + target) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit 1 + ;; + *) + # Get the name of the library object. + [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSifmso]' + case $libobj in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.ii) xform=ii ;; + *.class) xform=class ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + *.java) xform=java ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case $libobj in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit 1 + ;; + esac + + # Infer tagged configuration to use if any are available and + # if one wasn't chosen via the "--tag" command line option. + # Only attempt this if the compiler in the base compile + # command doesn't match the default compiler. + if test -n "$available_tags" && test -z "$tagname"; then + case $base_compile in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$0" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $0`" + case "$base_compile " in + "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + $echo "$modename: unable to infer tagged configuration" + $echo "$modename: specify a tag with \`--tag'" 1>&2 + exit 1 +# else +# $echo "$modename: using $tagname tagged configuration" + fi + ;; + esac + fi + + for arg in $later; do + case $arg in + -static) + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir= + else + xdir=$xdir/ + fi + lobj=${xdir}$objdir/$objname + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit 1" 1 2 15 + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit 1" 1 2 15 + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $run ln "$0" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + $echo $srcfile > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + + $run $rm "$libobj" "${libobj}T" + + # Create a libtool object file (analogous to a ".la" file), + # but don't create it if we're doing a dry run. + test -z "$run" && cat > ${libobj}T <<EOF +# $libobj - a libtool object file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +EOF + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $srcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $srcfile" + fi + + if test ! -d "${xdir}$objdir"; then + $show "$mkdir ${xdir}$objdir" + $run $mkdir ${xdir}$objdir + status=$? + if test "$status" -ne 0 && test ! -d "${xdir}$objdir"; then + exit $status + fi + fi + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + command="$command -o $lobj" + fi + + $run $rm "$lobj" "$output_obj" + + $show "$command" + if $run eval "$command"; then : + else + test -n "$output_obj" && $run $rm $removelist + exit 1 + fi + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + $show "$mv $output_obj $lobj" + if $run $mv $output_obj $lobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the PIC object to the libtool object file. + test -z "$run" && cat >> ${libobj}T <<EOF +pic_object='$objdir/$objname' + +EOF + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + else + # No PIC object so indicate it doesn't exist in the libtool + # object file. + test -z "$run" && cat >> ${libobj}T <<EOF +pic_object=none + +EOF + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $srcfile" + else + command="$base_compile $srcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + $run $rm "$obj" "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + $run $rm $removelist + exit 1 + fi + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the non-PIC object the libtool object file. + # Only append if the libtool object file exists. + test -z "$run" && cat >> ${libobj}T <<EOF +# Name of the non-PIC object. +non_pic_object='$objname' + +EOF + else + # Append the name of the non-PIC object the libtool object file. + # Only append if the libtool object file exists. + test -z "$run" && cat >> ${libobj}T <<EOF +# Name of the non-PIC object. +non_pic_object=none + +EOF + fi + + $run $mv "${libobj}T" "${libobj}" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + $run $rm "$lockfile" + fi + + exit 0 + ;; + + # libtool link mode + link | relink) + modename="$modename: link" + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args="$nonopt" + base_compile="$nonopt $@" + compile_command="$nonopt" + finalize_command="$nonopt" + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + + avoid_version=no + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + + # Infer tagged configuration to use if any are available and + # if one wasn't chosen via the "--tag" command line option. + # Only attempt this if the compiler in the base link + # command doesn't match the default compiler. + if test -n "$available_tags" && test -z "$tagname"; then + case $base_compile in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$0" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $0`" + case $base_compile in + "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*) + # The compiler in $compile_command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + $echo "$modename: unable to infer tagged configuration" + $echo "$modename: specify a tag with \`--tag'" 1>&2 + exit 1 +# else +# $echo "$modename: using $tagname tagged configuration" + fi + ;; + esac + fi + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -all-static | -static) + if test "X$arg" = "X-all-static"; then + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + else + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + fi + build_libtool_libs=no + build_old_libs=yes + prefer_static_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test + ;; + *) qarg=$arg ;; + esac + libtool_args="$libtool_args $qarg" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit 1 + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat $save_arg` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit 1 + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit 1 + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + done + else + $echo "$modename: link input file \`$save_arg' does not exist" + exit 1 + fi + arg=$save_arg + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit 1 + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + compile_command="$compile_command $wl$qarg" + finalize_command="$finalize_command $wl$qarg" + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: more than one -exported-symbols argument is not allowed" + exit 1 + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + ;; + esac + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 + exit 1 + fi + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + case :$dllsearchpath: in + *":$dir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-pw32* | *-*-beos*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-mingw* | *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs -framework System" + continue + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # gcc -m* arguments should be passed to the linker via $compiler_flags + # in order to pass architecture information to the linker + # (e.g. 32 vs 64-bit). This may also be accomplished via -Wl,-mfoo + # but this is not reliable with gcc because gcc may use -mfoo to + # select a different linker, different libraries, etc, while + # -Wl,-mfoo simply passes -mfoo to the linker. + -m*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + if test "$with_gcc" = "yes" ; then + compiler_flags="$compiler_flags $arg" + fi + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # The PATH hackery in wrapper scripts is required on Windows + # in order for the loader to find any dlls it needs. + $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 + $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit 1 + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Wl,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $wl$flag" + linker_flags="$linker_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit 1 + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit 1 + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done # argument parsing loop + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + # Create the object directory. + if test ! -d "$output_objdir"; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + status=$? + if test "$status" -ne 0 && test ! -d "$output_objdir"; then + exit $status + fi + fi + + # Determine the type of output + case $output in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + case $host in + *cygwin* | *mingw* | *pw32*) + # don't eliminate duplcations in $postdeps and $predeps + duplicate_compiler_generated_deps=yes + ;; + *) + duplicate_compiler_generated_deps=$duplicate_deps + ;; + esac + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if test "X$duplicate_deps" = "Xyes" ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + case $linkmode in + lib) + passes="conv link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 + exit 1 + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + for pass in $passes; do + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 + continue + fi + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` + for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do + for search_ext in .la $shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if (${SED} -e '2q' $lib | + grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + library_names= + old_library= + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + ;; + *) + $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + if test "$deplibs_check_method" != pass_all; then + $echo + $echo "*** Warning: Trying to link with static lib archive $deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because the file extensions .$libext of this argument makes me believe" + $echo "*** that it is just a static archive that I should not used here." + else + $echo + $echo "*** Warning: Linking the shared library $output against the" + $echo "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + if test "$found" = yes || test -f "$lib"; then : + else + $echo "$modename: cannot find the library \`$lib'" 1>&2 + exit 1 + fi + + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + + # Read the .la file + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit 1 + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + $echo "$modename: \`$lib' is not a convenience library" 1>&2 + exit 1 + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit 1 + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 + exit 1 + fi + if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + abs_ladir="$ladir" + fi + ;; + esac + laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + $echo "$modename: warning: library \`$lib' was moved." 1>&2 + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi # $installed = yes + name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 + exit 1 + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var"; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *" $absdir "*) ;; + *) temp_rpath="$temp_rpath $dir" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + # This is a shared library + + # Warn about portability, can't link against -module's on some systems (darwin) + if test "$shouldnotlink" = yes && test "$pass" = link ; then + $echo + if test "$linkmode" = prog; then + $echo "*** Warning: Linking the executable $output against the loadable module" + else + $echo "*** Warning: Linking the shared library $output against the loadable module" + fi + $echo "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + realname="$2" + shift; shift + libname=`eval \\$echo \"$libname_spec\"` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw*) + major=`expr $current - $age` + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + soname=`$echo $soroot | ${SED} -e 's/^.*\///'` + newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + $show "extracting exported symbol list from \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$extract_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + $show "generating import library for \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$old_archive_from_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5* ) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a module then we can not link against it, someone + # is ignoring the new warnings I added + if /usr/bin/file -L $add 2> /dev/null | grep "bundle" >/dev/null ; then + $echo "** Warning, lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $echo + $echo "** And there doesn't seem to be a static archive available" + $echo "** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case "$libdir" in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit 1 + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case "$libdir" in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $echo + $echo "*** Warning: This system can not link to static lib archive $lib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $echo "*** But as you try to build a module library, libtool will still create " + $echo "*** a static module, that should work as long as the dlopening application" + $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + convenience="$convenience $dir/$old_library" + old_convenience="$old_convenience $dir/$old_library" + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$deplib" && dir="." + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + fi + ;; + esac + if grep "^installed=no" $deplib > /dev/null; then + path="$absdir/$objdir" + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit 1 + fi + if test "$absdir" != "$libdir"; then + $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 + fi + path="$absdir" + fi + depdepl= + case $host in + *-*-darwin*) + # we do not want to link against static libs, but need to link against shared + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$path/$depdepl" ; then + depdepl="$path/$depdepl" + fi + # do not add paths which are already there + case " $newlib_search_path " in + *" $path "*) ;; + *) newlib_search_path="$newlib_search_path $path";; + esac + fi + path="" + ;; + *) + path="-L$path" + ;; + esac + + ;; + -l*) + case $host in + *-*-darwin*) + # Again, we only want to link against shared libraries + eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` + for tmp in $newlib_search_path ; do + if test -f "$tmp/lib$tmp_libs.dylib" ; then + eval depdepl="$tmp/lib$tmp_libs.dylib" + break + fi + done + path="" + ;; + *) continue ;; + esac + ;; + *) continue ;; + esac + case " $deplibs " in + *" $depdepl "*) ;; + *) deplibs="$deplibs $depdepl" ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$deplibs $path" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval shared_ext=\"$shrext\" + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval shared_ext=\"$shrext\" + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 + exit 1 + else + $echo + $echo "*** Warning: Linking the shared library $output against the non-libtool" + $echo "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + if test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test "$#" -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$2" + number_minor="$3" + number_revision="$4" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows) + current=`expr $number_major + $number_minor` + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + current=`expr $number_major + $number_minor - 1` + age="$number_minor" + revision="$number_minor" + ;; + esac + ;; + no) + current="$2" + revision="$3" + age="$4" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; + *) + $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case $revision in + 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; + *) + $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case $age in + 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;; + *) + $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + if test "$age" -gt "$current"; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + minor_current=`expr $current + 1` + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + irix | nonstopux) + major=`expr $current - $age + 1` + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=.`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + major=`expr $current - $age` + versuffix="-$major" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + fi + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$echo "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + if test -n "$removelist"; then + $show "${rm}r $removelist" + $run ${rm}r $removelist + fi + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + for path in $notinst_path; do + lib_search_path=`$echo "$lib_search_path " | ${SED} -e 's% $path % %g'` + deplibs=`$echo "$deplibs " | ${SED} -e 's% -L$path % %g'` + dependency_libs=`$echo "$dependency_libs " | ${SED} -e 's% -L$path % %g'` + done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs -framework System" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c <<EOF + int main() { return 0; } +EOF + $rm conftest + $LTCC -o conftest conftest.c $deplibs + if test "$?" -eq 0 ; then + ldd_output=`ldd conftest` + for i in $deplibs; do + name="`expr $i : '-l\(.*\)'`" + # If $name is empty we are operating on a -L argument. + if test "$name" != "" && test "$name" -ne "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $i "*) + newdeplibs="$newdeplibs $i" + i="" + ;; + esac + fi + if test -n "$i" ; then + libname=`eval \\$echo \"$libname_spec\"` + deplib_matches=`eval \\$echo \"$library_names_spec\"` + set dummy $deplib_matches + deplib_match=$2 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then + newdeplibs="$newdeplibs $i" + else + droppeddeps=yes + $echo + $echo "*** Warning: dynamic linker does not accept needed library $i." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which I believe you do not have" + $echo "*** because a test_compile did reveal that the linker did not use it for" + $echo "*** its dynamic dependency list that programs get resolved with at runtime." + fi + fi + else + newdeplibs="$newdeplibs $i" + fi + done + else + # Error occurred in the first compile. Let's try to salvage + # the situation: Compile a separate program for each library. + for i in $deplibs; do + name="`expr $i : '-l\(.*\)'`" + # If $name is empty we are operating on a -L argument. + if test "$name" != "" && test "$name" != "0"; then + $rm conftest + $LTCC -o conftest conftest.c $i + # Did it work? + if test "$?" -eq 0 ; then + ldd_output=`ldd conftest` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $i "*) + newdeplibs="$newdeplibs $i" + i="" + ;; + esac + fi + if test -n "$i" ; then + libname=`eval \\$echo \"$libname_spec\"` + deplib_matches=`eval \\$echo \"$library_names_spec\"` + set dummy $deplib_matches + deplib_match=$2 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then + newdeplibs="$newdeplibs $i" + else + droppeddeps=yes + $echo + $echo "*** Warning: dynamic linker does not accept needed library $i." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because a test_compile did reveal that the linker did not use this one" + $echo "*** as a dynamic dependency that programs can get resolved with at runtime." + fi + fi + else + droppeddeps=yes + $echo + $echo "*** Warning! Library $i is needed by this library but I was not able to" + $echo "*** make it link in! You will probably need to install it or some" + $echo "*** library that it depends on before this library will be fully" + $echo "*** functional. Installing it before continuing would be even better." + fi + else + newdeplibs="$newdeplibs $i" + fi + done + fi + ;; + file_magic*) + set dummy $deplibs_check_method + file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name="`expr $a_deplib : '-l\(.*\)'`" + # If $name is empty we are operating on a -L argument. + if test "$name" != "" && test "$name" != "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for file magic test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a file magic. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name="`expr $a_deplib : '-l\(.*\)'`" + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval $echo \"$potent_lib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a regex pattern. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` + done + fi + if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ + | grep . >/dev/null; then + $echo + if test "X$deplibs_check_method" = "Xnone"; then + $echo "*** Warning: inter-library dependencies are not supported in this platform." + else + $echo "*** Warning: inter-library dependencies are not known to be supported." + fi + $echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $echo + $echo "*** Warning: libtool could not satisfy all declared inter-library" + $echo "*** dependencies of module $libname. Therefore, libtool will create" + $echo "*** a static module, that should work as long as the dlopening" + $echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $echo "*** The inter-library dependencies that have been dropped here will be" + $echo "*** automatically added whenever a program is linked with this library" + $echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $echo + $echo "*** Since this library must not contain undefined symbols," + $echo "*** because either the platform does not support them or" + $echo "*** it was explicitly requested with -no-undefined," + $echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + if len=`expr "X$cmd" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + $show "$cmd" + $run eval "$cmd" || exit $? + skipped_export=false + else + # The command line is too long to execute in one step. + $show "using reloadable object file for export list..." + skipped_export=: + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "$mkdir $gentop" + $run $mkdir "$gentop" + status=$? + if test "$status" -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "$mkdir $xdir" + $run $mkdir "$xdir" + status=$? + if test "$status" -ne 0 && test ! -d "$xdir"; then + exit $status + fi + # We will extract separately just the conflicting names and we will no + # longer touch any unique names. It is faster to leave these extract + # automatically by $AR in one run. + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 + $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 + $AR t "$xabs" | sort | uniq -cd | while read -r count name + do + i=1 + while test "$i" -le "$count" + do + # Put our $i before any first dot (extension) + # Never overwrite any file + name_to="$name" + while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" + do + name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` + done + $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" + $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? + i=`expr $i + 1` + done + done + fi + + libobjs="$libobjs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && len=`expr "X$test_cmds" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise. + $echo "creating reloadable object files..." + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + delfiles= + last_robj= + k=1 + output=$output_objdir/$save_output-${k}.$objext + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + eval test_cmds=\"$reload_cmds $objlist $last_robj\" + if test "X$objlist" = X || + { len=`expr "X$test_cmds" : ".*"` && + test "$len" -le "$max_cmd_len"; }; then + objlist="$objlist $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" + fi + last_robj=$output_objdir/$save_output-${k}.$objext + k=`expr $k + 1` + output=$output_objdir/$save_output-${k}.$objext + objlist=$obj + len=1 + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + + if ${skipped_export-false}; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + libobjs=$output + # Append the command to create the export file. + eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" + fi + + # Set up a command to remove the reloadale object files + # after they are used. + i=0 + while test "$i" -lt "$k" + do + i=`expr $i + 1` + delfiles="$delfiles $output_objdir/$save_output-${i}.$objext" + done + + $echo "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + + # Append the command to remove the reloadable object files + # to the just-reset $cmds. + eval cmds=\"\$cmds~\$rm $delfiles\" + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? + exit 0 + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case $output in + *.lo) + if test -n "$objs$old_deplibs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit 1 + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${obj}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "$mkdir $gentop" + $run $mkdir "$gentop" + status=$? + if test "$status" -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "$mkdir $xdir" + $run $mkdir "$xdir" + status=$? + if test "$status" -ne 0 && test ! -d "$xdir"; then + exit $status + fi + # We will extract separately just the conflicting names and we will no + # longer touch any unique names. It is faster to leave these extract + # automatically by $AR in one run. + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 + $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 + $AR t "$xabs" | sort | uniq -cd | while read -r count name + do + i=1 + while test "$i" -le "$count" + do + # Put our $i before any first dot (extension) + # Never overwrite any file + name_to="$name" + while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" + do + name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` + done + $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" + $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? + i=`expr $i + 1` + done + done + fi + + reload_conv_objs="$reload_objs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit 0 + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $run eval "echo timestamp > $libobj" || exit $? + exit 0 + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit 0 + ;; + + prog) + case $host in + *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; + esac + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + case $host in + *darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + if test "$tagname" = CXX ; then + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + fi + ;; + esac + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + case :$dllsearchpath: in + *":$libdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case $dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$output.exp" + $run $rm $export_symbols + $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + else + $run eval "${SED} -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' + $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` + $run eval '$echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | + if sort -k 3 </dev/null >/dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + $echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[] = +{\ +" + + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit 1 + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $run $rm $output + # Link the executable and exit + $show "$link_command" + $run eval "$link_command" || exit $? + exit 0 + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $0 --fallback-echo"; then + case $0 in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";; + *) qecho="$SHELL `pwd`/$0 --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + cwrappersource=`$echo ${objdir}/lt-${output}.c` + cwrapper=`$echo ${output}.exe` + $rm $cwrappersource $cwrapper + trap "$rm $cwrappersource $cwrapper; exit 1" 1 2 15 + + cat > $cwrappersource <<EOF + +/* $cwrappersource - temporary wrapper executable for $objdir/$outputname + Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP + + The $output program cannot be directly executed until all the libtool + libraries that it depends on are installed. + + This wrapper executable should never be moved out of the build directory. + If it is, it will not operate correctly. + + Currently, it simply execs the wrapper *script* "/bin/sh $output", + but could eventually absorb all of the scripts functionality and + exec $objdir/$outputname directly. +*/ +EOF + cat >> $cwrappersource<<"EOF" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <malloc.h> +#include <stdarg.h> +#include <assert.h> + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef DIR_SEPARATOR +#define DIR_SEPARATOR '/' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +#define HAVE_DOS_BASED_FILE_SYSTEM +#ifndef DIR_SEPARATOR_2 +#define DIR_SEPARATOR_2 '\\' +#endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +const char *program_name = NULL; + +void * xmalloc (size_t num); +char * xstrdup (const char *string); +char * basename (const char *name); +char * fnqualify(const char *path); +char * strendzap(char *str, const char *pat); +void lt_fatal (const char *message, ...); + +int +main (int argc, char *argv[]) +{ + char **newargz; + int i; + + program_name = (char *) xstrdup ((char *) basename (argv[0])); + newargz = XMALLOC(char *, argc+2); +EOF + + cat >> $cwrappersource <<EOF + newargz[0] = "$SHELL"; +EOF + + cat >> $cwrappersource <<"EOF" + newargz[1] = fnqualify(argv[0]); + /* we know the script has the same name, without the .exe */ + /* so make sure newargz[1] doesn't end in .exe */ + strendzap(newargz[1],".exe"); + for (i = 1; i < argc; i++) + newargz[i+1] = xstrdup(argv[i]); + newargz[argc+1] = NULL; +EOF + + cat >> $cwrappersource <<EOF + execv("$SHELL",newargz); +EOF + + cat >> $cwrappersource <<"EOF" +} + +void * +xmalloc (size_t num) +{ + void * p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL +; +} + +char * +basename (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha (name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return (char *) base; +} + +char * +fnqualify(const char *path) +{ + size_t size; + char *p; + char tmp[LT_PATHMAX + 1]; + + assert(path != NULL); + + /* Is it qualified already? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha (path[0]) && path[1] == ':') + return xstrdup (path); +#endif + if (IS_DIR_SEPARATOR (path[0])) + return xstrdup (path); + + /* prepend the current directory */ + /* doesn't handle '~' */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + size = strlen(tmp) + 1 + strlen(path) + 1; /* +2 for '/' and '\0' */ + p = XMALLOC(char, size); + sprintf(p, "%s%c%s", tmp, DIR_SEPARATOR, path); + return p; +} + +char * +strendzap(char *str, const char *pat) +{ + size_t len, patlen; + + assert(str != NULL); + assert(pat != NULL); + + len = strlen(str); + patlen = strlen(pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp(str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char * mode, + const char * message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} +EOF + # we should really use a build-platform specific compiler + # here, but OTOH, the wrappers (shell script and this C one) + # are only useful if you want to execute the "real" binary. + # Since the "real" binary is built for $host, then this + # wrapper might as well be built for $host, too. + $run $LTCC -s -o $cwrapper $cwrappersource + ;; + esac + $rm $output + trap "$rm $output; exit 1" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $echo >> $output "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + $echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $echo \"\$relink_command_output\" >&2 + $rm \"\$progdir/\$file\" + exit 1 + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + $echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \$progdir\\\\\$program \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + exec \$progdir/\$program \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" + exit 1 + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + $echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" + chmod +x $output + fi + exit 0 + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "$mkdir $gentop" + $run $mkdir "$gentop" + status=$? + if test "$status" -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + # Add in members from convenience archives. + for xlib in $addlibs; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "$mkdir $xdir" + $run $mkdir "$xdir" + status=$? + if test "$status" -ne 0 && test ! -d "$xdir"; then + exit $status + fi + # We will extract separately just the conflicting names and we will no + # longer touch any unique names. It is faster to leave these extract + # automatically by $AR in one run. + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 + $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 + $AR t "$xabs" | sort | uniq -cd | while read -r count name + do + i=1 + while test "$i" -le "$count" + do + # Put our $i before any first dot (extension) + # Never overwrite any file + name_to="$name" + while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" + do + name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` + done + $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" + $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? + i=`expr $i + 1` + done + done + fi + + oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` + done + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + eval cmds=\"$old_archive_cmds\" + + if len=`expr "X$cmds" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + $echo "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + # GNU ar 2.10+ was changed to match POSIX; thus no paths are + # encoded into archives. This makes 'ar r' malfunction in + # this piecewise linking case whenever conflicting object + # names appear in distinct ar calls; check, warn and compensate. + if (for obj in $save_oldobjs + do + $echo "X$obj" | $Xsed -e 's%^.*/%%' + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: warning: object name conflicts; overriding AR_FLAGS to 'cq'" 1>&2 + $echo "$modename: warning: to ensure that POSIX-compatible ar will work" 1>&2 + AR_FLAGS=cq + fi + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + for obj in $save_oldobjs + do + oldobjs="$objlist $obj" + objlist="$objlist $obj" + eval test_cmds=\"$old_archive_cmds\" + if len=`expr "X$test_cmds" : ".*"` && + test "$len" -le "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + eval cmd=\"$cmd\" + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $0 $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + for lib in $dlfiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdlfiles="$newdlfiles $libdir/$name" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit 1 + fi + newdlprefiles="$newdlprefiles $libdir/$name" + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $rm $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $echo >> $output "\ +relink_command=\"$relink_command\"" + fi + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? + ;; + esac + exit 0 + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg="$nonopt" + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest="$arg" + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) prev="-f" ;; + -g) prev="-g" ;; + -m) prev="-m" ;; + -o) prev="-o" ;; + -s) + stripme=" -s" + continue + ;; + -*) ;; + + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest="$arg" + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit 1 + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test "$#" -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + library_names= + old_library= + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + if test "$inst_prefix_dir" = "$destdir"; then + $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 + exit 1 + fi + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + $echo "$modename: warning: relinking \`$file'" 1>&2 + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + exit 1 + fi + fi + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$srcname $destdir/$realname" + $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? + if test -n "$stripme" && test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run eval "$striplib $destdir/$realname" || exit $? + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + cmds=$postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit 0 + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + file=`$echo $file|${SED} 's,.exe$,,'` + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin*|*mingw*) + wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` + ;; + *) + wrapper=$file + ;; + esac + if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then + notinst_deplibs= + relink_command= + + # To insure that "foo" is sourced, and not "foo.exe", + # finese the cygwin/MSYS system by explicitly sourcing "foo." + # which disallows the automatic-append-.exe behavior. + case $build in + *cygwin* | *mingw*) wrapperdot=${wrapper}. ;; + *) wrapperdot=${wrapper} ;; + esac + # If there is no directory component, then add one. + case $file in + */* | *\\*) . ${wrapperdot} ;; + *) . ./${wrapperdot} ;; + esac + + # Check the variables that should have been set. + if test -z "$notinst_deplibs"; then + $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 + exit 1 + fi + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + relink_command= + # To insure that "foo" is sourced, and not "foo.exe", + # finese the cygwin/MSYS system by explicitly sourcing "foo." + # which disallows the automatic-append-.exe behavior. + case $build in + *cygwin* | *mingw*) wrapperdot=${wrapper}. ;; + *) wrapperdot=${wrapper} ;; + esac + # If there is no directory component, then add one. + case $file in + */* | *\\*) . ${wrapperdot} ;; + *) . ./${wrapperdot} ;; + esac + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir="/tmp" + test -n "$TMPDIR" && tmpdir="$TMPDIR" + tmpdir="$tmpdir/libtool-$$" + if $mkdir "$tmpdir" && chmod 700 "$tmpdir"; then : + else + $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 + continue + fi + file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyways + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` + ;; + esac + ;; + esac + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + if test -n "$stripme" && test -n "$old_striplib"; then + $show "$old_striplib $oldlib" + $run eval "$old_striplib $oldlib" || exit $? + fi + + # Do each command in the postinstall commands. + cmds=$old_postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $0 $preserve_args --finish$current_libdirs' + else + exit 0 + fi + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + cmds=$finish_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = : && exit 0 + + $echo "----------------------------------------------------------------------" + $echo "Libraries have been installed in:" + for libdir in $libdirs; do + $echo " $libdir" + done + $echo + $echo "If you ever happen to want to link against installed libraries" + $echo "in a given directory, LIBDIR, you must either use libtool, and" + $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + $echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + $echo " during execution" + fi + if test -n "$runpath_var"; then + $echo " - add LIBDIR to the \`$runpath_var' environment variable" + $echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $echo + $echo "See any operating system documentation about shared libraries for" + $echo "more information, such as the ld(1) and ld.so(8) manual pages." + $echo "----------------------------------------------------------------------" + exit 0 + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit 1 + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit 1 + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + if test "${save_LC_ALL+set}" = set; then + LC_ALL="$save_LC_ALL"; export LC_ALL + fi + if test "${save_LANG+set}" = set; then + LANG="$save_LANG"; export LANG + fi + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit 0 + fi + ;; + + # libtool clean and uninstall mode + clean | uninstall) + modename="$modename: $mode" + rm="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) rm="$rm $arg"; rmforce=yes ;; + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$file"; then + dir=. + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if (test -L "$file") >/dev/null 2>&1 \ + || (test -h "$file") >/dev/null 2>&1 \ + || test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + test "$mode" = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + + if test "$mode" = uninstall; then + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + cmds=$postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + cmds=$old_postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + # FIXME: should reinstall the best remaining shared library. + fi + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + + # Read the .lo file + . $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" \ + && test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" \ + && test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + file=`$echo $file|${SED} 's,.exe$,,'` + noexename=`$echo $name|${SED} 's,.exe$,,'` + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + relink_command= + . $dir/$noexename + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + $show "$rm $rmfiles" + $run $rm $rmfiles || exit_status=1 + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + $show "rmdir $dir" + $run rmdir $dir >/dev/null 2>&1 + fi + done + + exit $exit_status + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 + ;; + esac + + if test -z "$exec_cmd"; then + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 + fi +fi # test -z "$show_help" + +if test -n "$exec_cmd"; then + eval exec $exec_cmd + exit 1 +fi + +# We need to display help for each of the modes. +case $mode in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --tag=TAG use configuration variables from tag TAG + --version print version information + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE. + +Report bugs to <bug-libtool@gnu.org>." + exit 0 + ;; + +clean) + $echo \ +"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; +esac + +$echo +$echo "Try \`$modename --help' for more information about other modes." + +exit 0 + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) $echo no;; *) $echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: