diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index df3fb24e..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -custom: ['https://www.paypal.me/michaelhartlef'] diff --git a/.gitignore b/.gitignore index 4ff3eea8..cd2f5bda 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,10 @@ !/bin/themes !/bin/icons !/bin/templates +!/bin/data +!/bin/internal +!/bin/external +!/bin/macdeploy*.command .bmx diff --git a/README.md b/README.md index 6701eed8..cf97943a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,9 @@ ## Cerberus X -[![GitHub release](https://img.shields.io/github/release/KrautApps/cerberus.svg)]() -[![Github Releases](https://img.shields.io/github/downloads/KrautApps/cerberus/latest/total.svg)]() -[![Github All Releases](https://img.shields.io/github/downloads/KrautApps/cerberus/total.svg)]() [![Twitter Follow](https://img.shields.io/twitter/follow/cerberus_x17.svg?style=social)]() [![GitHub stars](https://img.shields.io/github/stars/KrautApps/cerberus.svg?style=social&label=Star)]() -![Cerberus X Logo](https://www.cerberus-x.com/community/styles/xenfracture/xenfracture/CBX_Logo_small.png) +![Cerberus X Logo](https://www.cerberus-x.com/downloads/cx_logo_small.png) ### Cerberus X is a game development language, made for hobbyists, indies and professionals. @@ -29,7 +26,7 @@ Cerberus X is based on Monkey X programming language created by [Mark Sibly](htt * https://www.cerberus-x.com/cxDocs/Home.html * Download pre-built **Cerberus X** for **Windows/Linux/Mac OS**: - * https://krautapps.itch.io/cerberus-x + * https://www.cerberus-x.com/community/resources/categories/cerberus-x.6/ ### License diff --git a/VERSIONS.TXT b/VERSIONS.TXT index 9d89207e..354b6164 100644 --- a/VERSIONS.TXT +++ b/VERSIONS.TXT @@ -1,57 +1,114 @@ +***** v2020-05-09 ***** + +FIX: [DOCS/brl] Fixed missing entry for the admob, cerberusstore, gamecenter, fielpath, filesystem, url, tween, pool, process and markdown modules. (Author: MikeHart) +FIX: [DOCS/brl.databuffer] Fixed some typos. (Author: MikeHart) +FIX: [DOCS/cerberus] Fixed missing entry for the deque module. (Author: MikeHart) +FIX: [DOCS/cerberus.stack] Fixed some typos. (Author: MikeHart) +FIX: [DOCS/os] Fixed description of the StripExt statement. (Author: MikeHart) +FIX: [mojo] Fixed padded usage in Font.Load:Font(url:String, flags:Int=Image.DefaultFlags) (Author: Rich) +FIX: [mojo2] Fixed padded usage in Font.Load:Font(url:String, flags:Int=Image.Filter ) (Author: Rich) +FIX: [mojo2] Fixed padded parameter in Image.LoadFrames:Image[]( path:String,cellWidth:Int,cellHeight:Int,padded:Bool=False,xhandle:Float=.5,yhandle:Float=.5,flags:Int=Image.Filter|Image.Mipmap,shader:Shader=Null ). (Author: Rich) +FIX: [examples] Fixed mak/bbgametest -> missing z parameter in MouseEvent call. (Author: MikeHart) +FIX: [examples] Fixed mak/dynamicimage -> faulty fullscreen switch. (Author: MikeHart) +Fix: [TRANSCC] Fixed TRANSCC not being able to install on an Android device when creating a release build on Linux and OSX. (Author: Phil7) +Fix: [TRANSCC] Fixed TRANSCC not reporting the correct line number in certain cases when preprocessor statements were used.. (Author: dawlane) + +MOD: [cerberusstore] updated the underlying code to support the newest Google version. (Author: Rich) +MOD: [DOCS/interpolate] Fixed and added some images. (Author: Holzchopf) +MOD: [mojo] Added filter param to Font.Load:Font(url:String, flags:Int=Image.DefaultFlags ) (Author: Rich) +MOD: [mojo2] Added filter param to Font.Load:Font(url:String, flags:Int=Image.Filter ) (Author: Rich) +MOD: [mojo/mojo2] Font.Load(url:String, flags:Int=... ) accept now .FNT files and don't add a .TXT anymore. (Author: MikeHart) +MOD: [TRANSCC] Changed TRANSCC in a way so modules can add Android libs and lift up versions more easily. (Author: Rich) +MOD: [TRANSCC] Data file filters are not being case sensitive anymore. (Author: MikeHart) +MOD: [rebuildall.ps1] Reworked the build script for using MS Visual C++ 2017 Community edition. (Author: dawlane) +MOD: [rebuildall.sh] Reworked the build script. (Author: dawlane) +MOD: [building.txt] Updated the information. (Author: dawlane) + +NEW: [cerberus.interpolate] Added InterpolateCustomLine:Float(dataY:Float[], pX:Float ). (Author: Rich) +NEW: [cerberus.interpolate] Added InterpolateBackEaseIn:Float(pY0:Float, pY1:Float, pX:Float). (Author: Rich) +NEW: [cerberus.interpolate] Added InterpolateBackEaseIn:Float(pY0:Float, pY1:Float, pX:Float). (Author: Rich) +NEW: [cerberus.interpolate] Added InterpolateBackEaseOut:Float(pY0:Float, pY1:Float, pX:Float). (Author: Rich) +NEW: [cerberus.interpolate] Added InterpolateBackEaseInOut:Float(pY0:Float, pY1:Float, pX:Float). (Author: Rich) +NEW: [cerberus.interpolate] Added InterpolateElasticEaseIn:Float(pY0:Float, pY1:Float, pX:Float). (Author: Rich) +NEW: [cerberus.interpolate] Added InterpolateElasticEaseOut:Float(pY0:Float, pY1:Float, pX:Float). (Author: Rich) +NEW: [cerberus.interpolate] Added InterpolateElasticEaseInOut:Float(pY0:Float, pY1:Float, pX:Float). (Author: Rich) +NEW: [cerberus.interpolate] Added InterpolateBounceEaseIn:Float(pY0:Float, pY1:Float, pX:Float). (Author: Rich) +NEW: [cerberus.interpolate] Added InterpolateBounceEaseOut:Float(pY0:Float, pY1:Float, pX:Float). (Author: Rich) +NEW: [cerberus.interpolate] Added InterpolateBounceEaseInOut:Float(pY0:Float, pY1:Float, pX:Float). (Author: Rich) +NEW: [brl.tween] Added a module to support easy tweening. (Author: Rich) +NEW: [TRANSCC] Added app icon creation right into TRANSCC. (Author: Rich) +NEW: [TRANSCC] Added the Include directive to add files/directories to the build folder (GLFW/STDCPP). (Author: MikeHart) +NEW: [IOS] Added #IOS_APP_ICON to set icon of the app. (Author: Rich) +NEW: [ANDROID] Added #ANDROID_APP_ICON to set icon of the app. (Author: Rich) +NEW: [FLASH] Added #FLASH_APP_ICON to set the favicon of the browser tab. (Author: Rich) +NEW: [HTML5] Added #HTML5_APP_ICON to set the favicon of the browser tab. (Author: Rich) +NEW: [HTML5] Added #HTML5_APP_TITLE to be able to set the title of the browser tab. (Author: MikeHart) +NEW: [HTML5] Added #HTML5_CANVAS_WIDTH and #HTML5_CANVAS_HEIGHT control the size of the html5 canvas. (Author: MikeHart) +NEW: [HTML5] Added #HTML5_APP_FILENAME to set the output filename. (Author: MikeHart) +NEW: [HTML5] Added #HTML5_CANVAS_RESIZE_MODE to be able to set the CANVAS resize mode. (Author: MikeHart) +NEW: [HTML5] Added #HTML5_CONSOLE_SHOW to be able to hide the splitter and console area. (Author: MikeHart) +NEW: [rebuildall_macos.sh] New script to build CX on OSX right from the github repository. (Author: dawlane) + +***** v2019-10-13b ***** + +MOD: [REQUESTER] Requester dialogs now work on Linux, thanks to tinyfiledialogs (Author: MikeHart) +FIX: [GLFW] Added missing stb_write_image.h file on Linux (Author: MikeHart) +FIX: [TED] Was still using the old PrefsDialog on Linux (Author: MikeHart) + ***** v2019-10-13 ***** -FIX: [ANDROID] change file permission of gradlew in template. (Author: Dawlane) -MOD: [ANDROID] added 64bit libs to the target, to support Googles changes in August 2019. -FIX: [TRANS] Fixed CopyFile for Linux to preserve file permissions. (Author: Dawlane) -FIX: [TED] Fixed symlinks opening a second file when DebugStop is used. (Author: Dawlane) -MOD: [TED] Another attempt at fixing the capitalization of the API. -MOD: [TED] Moved Open Project from the BUILD menu to the FILE menu. -MOD: [TED] Replaced Options dialog with a similar one like from Dawlane's version of TED. +FIX: [ANDROID] change file permission of gradlew in template. (Author: dawlane) +MOD: [ANDROID] added 64bit libs to the target, to support Googles changes in August 2019. (Author: MikeHart) +FIX: [TRANS] Fixed CopyFile for Linux to preserve file permissions. (Author: dawlane) +FIX: [TED] Fixed symlinks opening a second file when DebugStop is used. (Author: dawlane) +MOD: [TED] Another attempt at fixing the capitalization of the API. (Author: MikeHart) +MOD: [TED] Moved Open Project from the BUILD menu to the FILE menu. (Author: MikeHart) +MOD: [TED] Replaced Options dialog with a similar one like from dawlane's version of TED. (Author: dawlane) This dialog is much smaller and so can be displayed on small screens two. -FIX: [TED] CTRL+PgDown and CTRL+PgUP now works on Linux to switch between open code tabs. -MOD: [TRANS/GLFW] On Windows you can add an app icon (.ico file) now via the new #GLFW_APP_ICON preprocessor setting. -FIX: [OSX] Recompiled the launcher as a 64bit app, so it is compatible with OSX Catalina (10.15.x). +FIX: [TED] CTRL+PgDown and CTRL+PgUP now works on Linux to switch between open code tabs. (Author: MikeHart) +MOD: [TRANS/GLFW] On Windows you can add an app icon (.ico file) now via the new #GLFW_APP_ICON preprocessor setting. (Author: MikeHart) +FIX: [OSX] Recompiled the launcher as a 64bit app, so it is compatible with OSX Catalina (10.15.x). (Author: MikeHart) FIX: [MOJO1] Fixed missing usage of frame parameter in DrawImage9P. (Author: Rich) MOD: [WIN8/WINPHONE8] Depreciated these targets. If you need them, move them out of the targets/depreciated folder. -MOD: [TRANS/ANDROID] Reactivated logcat filtering. +MOD: [TRANS/ANDROID] Reactivated logcat filtering. (Author: MikeHart) NEW: [Examples/MOJO2] DrawPrimitives2 shows how to use the DrawPrimitives method to draw several images at once. ***** v2019-05-05 ***** -MOD: [ANDROID] Changed MIN_SDK back to 16 like it was before. -MOD: [DOCS] Added A-Z shortcuts on top of indexes. -MOD: [Trans/ANDROID] Release builds are installed automatically now. -FIX: [AGK] Fixed docs creation to be compatible with the latest MakeDocs. -FIX: [MAKEDOCS] Fixed brl.markdown bug. -FIX: [TED] Fixed fixed displaying an iframe element in the docs. (Author: Dawlane) -FIX: [TED] Fixed scaling issues when displaying images. -NEW: [TED] Added overwrite mode. Just press the insert key to toggle it. -NEW: [MOJO2] Added Image.LoadFrames:Image[]( path:String,cellWidth:Int,cellHeight:Int,padded:Bool=False,xhandle:Float=.5,yhandle:Float=.5,flags:Int=Image.Filter|Image.Mipmap,shader:Shader=Null ). -NEW: [MOJO.APP] Added SetDeviceWindowIcon( _path:String ). -NEW: [MOJO.APP] Added SetDeviceWindowTitle( _title:String ). -NEW: [MOJO.APP] Added SetDeviceWindowSize( _width:Int, _height:Int ). -NEW: [MOJO.APP] Added SetDeviceWindowPosition( _x:Int, _y:Int ). -NEW: [MOJO.APP] Added SetDeviceWindowSizeLimits:Void( _minWidth:Int, _minHeight:Int, _maxWidth:Int, _maxHeight:Int ) -NEW: [MOJO.INPUT] Added SetMousePos:Void( _x:Int, _y:Int ). -NEW: [MOJO.INPUT] Added SetClipboard:Void( _text:String ). -NEW: [MOJO.INPUT] Added GetClipboard:String(). -NEW: [CERBERUS.INTERPOLATE] New module. -NEW: [MOJO.COLOR] New module. +MOD: [ANDROID] Changed MIN_SDK back to 16 like it was before. (Author: MikeHart) +MOD: [DOCS] Added A-Z shortcuts on top of indexes. (Author: Holzchopf) +MOD: [Trans/ANDROID] Release builds are installed automatically now. (Author: MikeHart) +FIX: [AGK] Fixed docs creation to be compatible with the latest MakeDocs. (Author: MikeHart) +FIX: [MAKEDOCS] Fixed brl.markdown bug. (Author: Holzchopf) +FIX: [TED] Fixed fixed displaying an iframe element in the docs. (Author: dawlane) +FIX: [TED] Fixed scaling issues when displaying images. (Author: MikeHart) +NEW: [TED] Added overwrite mode. Just press the insert key to toggle it. (Author: MikeHart) +NEW: [MOJO2] Added Image.LoadFrames:Image[]( path:String,cellWidth:Int,cellHeight:Int,padded:Bool=False,xhandle:Float=.5,yhandle:Float=.5,flags:Int=Image.Filter|Image.Mipmap,shader:Shader=Null ). (Author: MikeHart) +NEW: [MOJO.APP] Added SetDeviceWindowIcon( _path:String ). (Author: MikeHart) +NEW: [MOJO.APP] Added SetDeviceWindowTitle( _title:String ). (Author: MikeHart) +NEW: [MOJO.APP] Added SetDeviceWindowSize( _width:Int, _height:Int ). (Author: MikeHart) +NEW: [MOJO.APP] Added SetDeviceWindowPosition( _x:Int, _y:Int ). (Author: MikeHart) +NEW: [MOJO.APP] Added SetDeviceWindowSizeLimits:Void( _minWidth:Int, _minHeight:Int, _maxWidth:Int, _maxHeight:Int ) (Author: MikeHart) +NEW: [MOJO.INPUT] Added SetMousePos:Void( _x:Int, _y:Int ). (Author: MikeHart) +NEW: [MOJO.INPUT] Added SetClipboard:Void( _text:String ). (Author: MikeHart) +NEW: [MOJO.INPUT] Added GetClipboard:String(). (Author: MikeHart) +NEW: [CERBERUS.INTERPOLATE] New module. (Author: Holzchopf) +NEW: [MOJO.COLOR] New module. (Author: Holzchopf) ***** v2018-12-30 ***** -FIX: [AGK_IOS] Fixed AGK_IOS target showing up on non OSX platforms. -FIX: [ANDROID] Fixed MIN_SDK, TARGET and TOOLS version. -FIX: [brl.requesters] Fixed RequestFile not working with a set path. -FIX: [TED] Fixed selecting a help topic in the toolbar didn't show up the help file directly. +FIX: [AGK_IOS] Fixed AGK_IOS target showing up on non OSX platforms. (Author: MikeHart) +FIX: [ANDROID] Fixed MIN_SDK, TARGET and TOOLS version. (Author: MikeHart) +FIX: [brl.requesters] Fixed RequestFile not working with a set path. (Author: MikeHart) +FIX: [TED] Fixed selecting a help topic in the toolbar didn't show up the help file directly. (Author: MikeHart) MOD: [example] Various changes to sample scripts (Author: Paul59) -FIX: [TED] Fixed "Open on Desktop" on Linux. (Author: Dawlane) -MOD: [TED] If text is selected in the editor, it will be pre set in the Find dialog. -MOD: [DOCS/MAKEDOCS] Numerous changes to the docs and MakeDocs itself. -FIX: [GLFW/GLFW-ANGLE] Fixed returning MouseZ resets MouseX and MouseY to zero. -MOD: [TED] Bigger changes so TED uses the QT5 webengine now and needs QT5.9.2 to compile. (Author: Dawlane) +FIX: [TED] Fixed "Open on Desktop" on Linux. (Author: dawlane) +MOD: [TED] If text is selected in the editor, it will be pre set in the Find dialog. (Author: MikeHart) +MOD: [DOCS/MAKEDOCS] Numerous changes to the docs and MakeDocs itself. (Author: Holzchopf) +FIX: [GLFW/GLFW-ANGLE] Fixed returning MouseZ resets MouseX and MouseY to zero. (Author: MikeHart) +MOD: [TED] Bigger changes so TED uses the QT5 webengine now and needs QT5.9.2 to compile. (Author: dawlane) ***** v2018-08-10 ***** diff --git a/bin/config.winnt.txt b/bin/config.winnt.txt index d8779162..1169c661 100644 --- a/bin/config.winnt.txt +++ b/bin/config.winnt.txt @@ -4,7 +4,7 @@ ' 'Can be overriden via transcc cmd line ' -MODPATH="${CERBERUSDIR}/modules;${CERBERUSDIR}/modules_ext" +MODPATH="${CERBERUSDIR}/modules;${CERBERUSDIR}/modules_ext;D:\CerberusX\CerberusModulesx" '-------------------- '-------------------- @@ -27,7 +27,7 @@ HTML_PLAYER="${CERBERUSDIR}\bin\cserver_winnt.exe" '***** DO NOT use mingw64-5.1.0 as it has a linker bug ***** '***** 64 bit mingw ***** -MINGW_PATH="D:\Applications\Compilers\TDM-GCC-64" +MINGW_PATH="D:\TDM-GCC-64" '-------------------- '-------------------- @@ -37,7 +37,7 @@ MINGW_PATH="D:\Applications\Compilers\TDM-GCC-64" ' 'The Java JDK is currently available here: http://www.oracle.com/technetwork/java/javase/downloads/index.html ' -JDK_PATH="d:\programme\JavaSDK" +JDK_PATH="D:\Program Files (x86)\Java\jdk1.8.0_172" '-------------------- '-------------------- @@ -45,7 +45,7 @@ JDK_PATH="d:\programme\JavaSDK" ' 'Must be set to a valid dir for ANDROID target support ' -ANDROID_PATH="d:\programme\AndroidSDK" +ANDROID_PATH="D:\Program Files\Android\Android Studio" '-------------------- '-------------------- @@ -53,7 +53,7 @@ ANDROID_PATH="d:\programme\AndroidSDK" ' 'Must be set to a valid dir for ANDROID NDK target support ' -ANDROID_NDK_PATH="d:\devtools\android-ndk-r9" +'ANDROID_NDK_PATH="D:\Program Files\Android\Android Studio\ndk-bundle" '-------------------- '-------------------- @@ -63,7 +63,7 @@ ANDROID_NDK_PATH="d:\devtools\android-ndk-r9" ' 'Ant is currently available here: http://ant.apache.org/bindownload.cgi ' -ANT_PATH="D:\Programme\apache-ant-1.9.7" +'ANT_PATH="D:\Programme\apache-ant-1.9.7" '-------------------- '-------------------- @@ -73,7 +73,7 @@ ANT_PATH="D:\Programme\apache-ant-1.9.7" ' 'Either HTML_PLAYER or FLASH_PLAYER must be set for FLASH target support. ' -FLEX_PATH="d:\devtools\flex-sdk" +'FLEX_PATH="c:\flex_sdk_4.6" 'for opening .swf files...cerberus will use HTML_PLAYER if this is not set. 'FLASH_PLAYER="...?..." '-------------------- @@ -83,7 +83,7 @@ FLEX_PATH="d:\devtools\flex-sdk" ' 'PSM_PATH must be set for PSM target support. ' -PSM_PATH="d:\devtools\PSM_SDK" +'PSM_PATH="d:\devtools\PSM_SDK" '-------------------- '-------------------- @@ -91,9 +91,7 @@ PSM_PATH="d:\devtools\PSM_SDK" ' 'Must be set for XNA and GLFW target support. ' -'MSBUILD_PATH="${PROGRAMFILES}\MSBuild\14.0\Bin\MSBuild.exe" -'MSBUILD_PATH="${PROGRAMFILES}\MSBuild\12.0\Bin\MSBuild.exe" -MSBUILD_PATH="${WINDIR}\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" +MSBUILD_PATH="${PROGRAMFILES(x86)}\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe" '-------------------- '-------------------- @@ -101,10 +99,9 @@ MSBUILD_PATH="${WINDIR}\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" ' 'Must be set for AGK support. ' -AGK_PATH="C:/Program Files (x86)/The Game Creators/AGK2" +AGK_PATH="D:\Program Files (x86)\The Game Creators\AGK2" ' '-------------------- '--->> BEGIN OF JUNGLE IDE GENERATED CONFIG -MINGW_PATH= "D:\Applications\Compilers\TDM-GCC-64" '--->> END OF JUNGLE IDE GENERATED CONFIG diff --git a/bin/data/mojo_font.png b/bin/data/mojo_font.png new file mode 100644 index 00000000..839650c4 Binary files /dev/null and b/bin/data/mojo_font.png differ diff --git a/bin/external/dont_delete.txt b/bin/external/dont_delete.txt new file mode 100644 index 00000000..e69de29b diff --git a/bin/internal/dont_delete.txt b/bin/internal/dont_delete.txt new file mode 100644 index 00000000..e69de29b diff --git a/bin/macdeployqt-5.9.2.command b/bin/macdeployqt-5.9.2.command new file mode 100755 index 00000000..090b4507 --- /dev/null +++ b/bin/macdeployqt-5.9.2.command @@ -0,0 +1,15 @@ +#!/bin/bash +# +# Little script to make Ted.app standalone +# +cd `dirname $0` +#cd ../../bin +#macdeployqt-4.8 Ted.app +/Users/michaelhartlef/Qt/5.9.2/clang_64/bin/macdeployqt Ted.app -verbose=2 -always-overwrite +cd Ted.app/Contents/PlugIns +rm -r -f audio +rm -r -f bearer +rm -r -f imageformats +rm -r -f mediaservice +rm -r -f printsupport +rm -r -f sqldrivers diff --git a/bin/themes/default/images/dock_close.png b/bin/themes/default/images/dock_close.png new file mode 100644 index 00000000..888c0865 Binary files /dev/null and b/bin/themes/default/images/dock_close.png differ diff --git a/bin/themes/default/images/dock_close_sel.png b/bin/themes/default/images/dock_close_sel.png new file mode 100644 index 00000000..e912573c Binary files /dev/null and b/bin/themes/default/images/dock_close_sel.png differ diff --git a/docs/cerberusdoc/Credits.cerberusdoc b/docs/cerberusdoc/Credits.cerberusdoc index ea2e7936..4db4b7f0 100644 --- a/docs/cerberusdoc/Credits.cerberusdoc +++ b/docs/cerberusdoc/Credits.cerberusdoc @@ -1,13 +1,15 @@ > Cerberus X credits -+ Language design and programming - Mark Sibly ++ Work on Cerberus X - dawlane, Holzchopf, muruba, Martin, MikeHart, Paul59, Phil7, PixelPaladin, Rich, Soap. -+ Documentation - Mark Sibly, James Boyd, Arthur Bikmullin. ++ Cerberus website - Michael Hartlef. -+ Cerberus website - Martin Leidel and Michael Hartlef. ++ Initial language design and programming of Monkey X - Mark Sibly + ++ Initial documentation of Monkey X - Mark Sibly, James Boyd, Arthur Bikmullin. Additional thanks to: -Muruba, dawlane, Soap, PixelPaladin, Holzchopf, Beaker, Richard Betson, EdzUp[GD], Warpy, MikeHart, msephton, Binary_Moon, Otus 3, CodeGit, skn3[ac], Tibit, Mathieu, Sledge, Difference, CyBeRGoth, _Skully, sknightly, Rhodesy, ziggy, Hujiklo, earok, Robert Cummings, TMK, Playniax. +adamredwoos, Beaker, Richard Betson, EdzUp[GD], Warpy, msephton, Binary_Moon, Otus 3, CodeGit, skn3[ac], Tibit, Mathieu, Sledge, Difference, CyBeRGoth, _Skully, sknightly, Rhodesy, ziggy, Hujiklo, earok, Robert Cummings, TMK, Playniax, nerobot, Rob Hewitt, En929, AutmnLeaf, TheMrCerebro, wick, Gerry Quinn, magic, Slotman, Ferdi, Coppercicle, JaviCervera. diff --git a/docs/cerberusdoc/Programming/App config settings.cerberusdoc b/docs/cerberusdoc/Programming/App config settings.cerberusdoc index 531a2620..0482a228 100644 --- a/docs/cerberusdoc/Programming/App config settings.cerberusdoc +++ b/docs/cerberusdoc/Programming/App config settings.cerberusdoc @@ -32,12 +32,20 @@ The following app config settings are currently supported: 'Html5 settings, defaults shown ' +#HTML5_APP_FILENAME="CerberusGame.html" 'Set the default name for the html outfile. +#HTML5_APP_ICON="" 'set the name of a ico/png file which will be used as a favicon. If not provided, Trans will use the standard favicon. + 'PNG files will be converted to ICO files. Without a filepath, Trans will look in the folder where your .cxs source file is located at. +#HTML5_APP_TITLE="CerberusGame" 'Set the title inside the browser tab. +#HTML5_CANVAS_WIDTH=640 'Set the width of the canvas. +#HTML5_CANVAS_HEIGHT=480 'Set the height of the canvas. +#HTML5_CANVAS_RESIZE_MODE=1 '0=locked, 1=stretch, 2=resize +#HTML5_CONSOLE_SHOW=True 'Set it to False to hide the splitter and console DIV in your file. #HTML5_WEBAUDIO_ENABLED=True 'Set to false to disable webaudio support for mojo audio, and to use older multimedia audio system instead. 'GLFW settings, defaults shown ' -#GLFW_USE_MINGW=True 'Set to false on Windows to use MSVC instead of MinGW to build glfw apps. Needs VS 2015 installed. -#GLFW_GCC_MSIZE_WINNT="32" 'When building glfw apps with mingw/gcc, controls whether 32 or 64 bit apps are generated. +#GLFW_USE_MINGW=True 'Set to false on Windows to use MSVC instead of MinGW to build glfw apps. Needs at least VS 2015 installed. +#GLFW_GCC_MSIZE_WINNT="64" 'When building glfw apps with mingw/gcc, controls whether 32 or 64 bit apps are generated. 'Set to "64" to force 64 bit builds on Windows (needs mingw64), or "" to use compiler default. #GLFW_GCC_MSIZE_LINUX="" 'Ditto for Linux. #GLFW_GCC_CC_OPTS="" 'Pass compiler options to GCC type compilers @@ -52,10 +60,10 @@ The following app config settings are currently supported: #GLFW_WINDOW_FULLSCREEN=False #GLFW_WINDOW_SAMPLES=0 'Set to number of samples for multisampling (glfw3 only). #GLFW_WINDOW_DECORATED=True 'Set to false to create a broderless window (glfw3 only). -#GLFW_VERSION=2 'Set to GLFW version, ie: 2 or 3. -#GLFW_APP_ICON="myIcon.ico" 'On Windows you can set the app and window icon via this setting. - 'If no path is provided, TRANSCC will assume the source path as its location. +#GLFW_APP_ICON="" 'Set the name of a ico/png file which will be used as th apps icon. If not provided, Trans will use the standard icon file. + 'PNG files will be converted to ICO files. Without a filepath, Trans will look in the folder where your .cxs source file is located at. + #GLFW_APP_LABEL="My App" 'Human readable label for app. 'Must be set for cerberus://internal to map to 'per user' app data dir. 'If not set (the default), cerberus://internal is shared by all users of app. @@ -65,18 +73,35 @@ The following app config settings are currently supported: #GLFW_APP_PUBLISHER="My Company" 'Optional human readable publisher name for app. Must be filesystem friendly. 'Not defined by default. +'FLASH settings, defaults shown +#FLASH_APP_ICON="" +#FLASH_RENDER_WHILE_SUSPENDED=False 'IOS settings, defaults shown ' #IOS_RETINA_ENABLED=True #IOS_ACCELEROMETER_ENABLED=True -#IOS_DISPLAY_LINK_ENABLED=False +#IOS_DISPLAY_LINK_ENABLED=True +#IOS_APP_ICON="" 'Android settings, defaults shown ' #ANDROID_APP_LABEL="Cerberus X Game" #ANDROID_APP_PACKAGE="com.Cerberus_X.cxgame" -#ANDROID_SCREEN_ORIENTATION="portrait" 'one of: user, portrait, landscape +#ANDROID_APP_ICON="" +#ANDROID_SCREEN_ORIENTATION="user" '"user", "portrait", "landscape" +#ANDROID_GAMEPAD_ENABLED=False + +#ANDROID_MIN_SDK_VERSION="16" +#ANDROID_TARGET_SDK_VERSION="28" +#ANDROID_BUILD_TOOLS_VERSION="28.0.3" +#ANDROID_GRADLE_VERSION="3.2.1" +#ANDROID_GRADLE_DISTRIBUTION="gradle-4.6-all.zip" +#ANDROID_REPOSITORIES="" +#ANDROID_JAVA_SOURCE_VERSION="VERSION_1_8" +#ANDROID_JAVA_TARGET_VERSION="VERSION_1_8" +#ANDROID_APPLICATION_EXTRAS="" + #ANDROID_VERSION_CODE="1" #ANDROID_VERSION_NAME="1.0" #ANDROID_NATIVE_GL_ENABLED=False 'for use with the opengl modules @@ -112,6 +137,7 @@ The following app config settings are currently supported: 'Misc ' #CC_OPTS="" 'additional gcc options for stdcpp target, eg: #CC_OPTS+="-DMyDefine" +#CC_LIBS="" 'Pass additional libraries to link against for GCC type compilers. diff --git a/docs/cerberusdoc/Programming/Keywords.cerberusdoc b/docs/cerberusdoc/Programming/Keywords.cerberusdoc index a3938ea8..2e0ede76 100644 --- a/docs/cerberusdoc/Programming/Keywords.cerberusdoc +++ b/docs/cerberusdoc/Programming/Keywords.cerberusdoc @@ -3,7 +3,7 @@ The identifiers below are language keywords and are reserved for use by the Cerberus X language; these keywords are case-insensitive. >> Module control -[[Strict]] | [[Import]] | [[Extern]] +[[Strict]] | [[Import]] | [[Extern]] | [[Include]] >> Declarations [[Const]] | [[Local]] | [[Global]] | [[Field]] | [[Alias]] | [[Enumerate]] diff --git a/docs/cerberusdoc/Programming/Keywords/Import.cerberusdoc b/docs/cerberusdoc/Programming/Keywords/Import.cerberusdoc index ff8c0add..e4d10a9e 100644 --- a/docs/cerberusdoc/Programming/Keywords/Import.cerberusdoc +++ b/docs/cerberusdoc/Programming/Keywords/Import.cerberusdoc @@ -17,7 +17,7 @@ To import another module, the Import keyword must be placed at the top of your s Cerberus X also supports cyclic imports, whereby modules can import each other, gaining access to each other's declarations. >> See also -[[Strict]]~n +[[Strict]] | [[Include]]~n [Language reference](Language reference#modules) >> Example diff --git a/docs/cerberusdoc/Programming/Keywords/Include.cerberusdoc b/docs/cerberusdoc/Programming/Keywords/Include.cerberusdoc new file mode 100644 index 00000000..b1ee66eb --- /dev/null +++ b/docs/cerberusdoc/Programming/Keywords/Include.cerberusdoc @@ -0,0 +1,46 @@ +> Directive Include + +Module include directive. + +>> Syntax + +Include "filename" + +>> Description + +A Cerberus X program can add files into the build folder for further addition during the compile process. +Contrary to the Import directive, these files are not injected into the translated code and the main.* file. +Currently only the C++ and Desktop target are supporting this directive. + +>> See also +[[Strict]] | [[Import]]~n +[Language reference](Language reference#modules) + + +>> Optional parameters (inside the string) + +*-out=* + +A target directory. Otherwise the content will be copied into the build folder. + +*-ext=* + +A list of separated file extensions. These will filter the file extensions, that are copied. + +*-sub* + +If including a directory, this parameter allows to include sub directories. + +>> Example + +*Add a single file:* + +
+Include "native/sokol_app.h -out=targetDir"
+
+ +*Add the content of a directory:* + +
+Include "native/ -ext=c;h -out=targetDir -sub"
+
\ No newline at end of file diff --git a/docs/cerberusdoc/Programming/Language reference.cerberusdoc b/docs/cerberusdoc/Programming/Language reference.cerberusdoc index f3a6b44d..650a2df4 100644 --- a/docs/cerberusdoc/Programming/Language reference.cerberusdoc +++ b/docs/cerberusdoc/Programming/Language reference.cerberusdoc @@ -245,7 +245,7 @@ The following identifiers are [[Keywords|Language keywords]] and are reserved fo
 Void Strict Public Private Property Bool Int Float String Array
-Object Mod Continue Exit Import Extern New Self Super Try Catch
+Object Mod Continue Exit Import Include Extern New Self Super Try Catch
 Eachin True False Not Extends Abstract Final Select Case Default
 Const Enumerate Local Global Field Method Function Class And Or Shl Shr
 End If Then Else ElseIf EndIf While Wend Repeat Until Forever 
diff --git a/docs/templates/cerberusx/data/cerberusx.png b/docs/templates/cerberusx/data/cerberusx.png
deleted file mode 100644
index 3f8fb04b..00000000
Binary files a/docs/templates/cerberusx/data/cerberusx.png and /dev/null differ
diff --git a/docs/templates/cerberusx/index_template.html b/docs/templates/cerberusx/index_template.html
deleted file mode 100644
index fc67a868..00000000
--- a/docs/templates/cerberusx/index_template.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
-

${INDEX}

-
- -
- ${FOR ITEMS} - - ${NEXT} -
- diff --git a/docs/templates/cerberusx/page_template.html b/docs/templates/cerberusx/page_template.html deleted file mode 100644 index b118b79d..00000000 --- a/docs/templates/cerberusx/page_template.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - - Cerberus X Documentation - - - -
-
- -
- - - - - - - - ${IF ICONLINKS} - - ${ENDIF} - - -
Cerberus X Documentation - ${FOR ICONLINKS} - - ${NEXT} -
- -
- - -
- - - -
-
- - ${CONTENT} - -
-
-
- - \ No newline at end of file diff --git a/docs/templates/cerberusx/page_template_with_footer.html b/docs/templates/cerberusx/page_template_with_footer.html deleted file mode 100644 index c143cbdc..00000000 --- a/docs/templates/cerberusx/page_template_with_footer.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - Cerberus X Documentation - - - -
-
- -
- Cerberus X Documentation -
- - -
- - - -
-
- - ${CONTENT} - -
- This module and associated documentation are released under the ZLib/libpng license: - - -

The zlib/libpng License - -

Copyright (c) 2013 Blitz Research Ltd - -

This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. - -

Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - -

1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. - -

2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - -

3. This notice may not be removed or altered from any source distribution. - -

- -
-
-
- - \ No newline at end of file diff --git a/docs/templates/cerberusx/pagestyle.css b/docs/templates/cerberusx/pagestyle.css deleted file mode 100644 index 2ae0f1a6..00000000 --- a/docs/templates/cerberusx/pagestyle.css +++ /dev/null @@ -1,2666 +0,0 @@ -.clearfix { - *zoom: 1; -} -.clearfix:before, -.clearfix:after { - display: table; - content: ""; - line-height: 0; -} -.clearfix:after { - clear: both; -} -.hide-text { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} -.input-block-level { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -nav, -section { - display: block; -} -audio, -canvas, -video { - display: inline-block; - *display: inline; - *zoom: 1; -} -audio:not([controls]) { - display: none; -} -html { - font-size: 100%; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} -a:focus { - outline: thin dotted #333; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -a:hover, -a:active { - outline: 0; -} -sub, -sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline; -} -sup { - top: -0.5em; -} -sub { - bottom: -0.25em; -} -img { - /* Responsive images (ensure images don't scale beyond their parents) */ - - max-width: 100%; - /* Part 1: Set a maxium relative to the parent */ - - width: auto\9; - /* IE7-8 need help adjusting responsive images */ - - height: auto; - /* Part 2: Scale the height according to the width, otherwise you get stretching */ - - vertical-align: middle; - border: 0; - -ms-interpolation-mode: bicubic; -} -#map_canvas img, -.google-maps img { - max-width: none; -} -button, -input, -select, -textarea { - margin: 0; - font-size: 100%; - vertical-align: middle; -} -button, -input { - *overflow: visible; - line-height: normal; -} -button::-moz-focus-inner, -input::-moz-focus-inner { - padding: 0; - border: 0; -} -button, -html input[type="button"], -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; - cursor: pointer; -} -label, -select, -button, -input[type="button"], -input[type="reset"], -input[type="submit"], -input[type="radio"], -input[type="checkbox"] { - cursor: pointer; -} -input[type="search"] { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - -webkit-appearance: textfield; -} -input[type="search"]::-webkit-search-decoration, -input[type="search"]::-webkit-search-cancel-button { - -webkit-appearance: none; -} -textarea { - overflow: auto; - vertical-align: top; -} -@media print { - * { - text-shadow: none !important; - color: #000 !important; - background: transparent !important; - box-shadow: none !important; - } - a, - a:visited { - text-decoration: underline; - } - a[href]:after { - content: " (" attr(href) ")"; - } - abbr[title]:after { - content: " (" attr(title) ")"; - } - .ir a:after, - a[href^="javascript:"]:after, - a[href^="#"]:after { - content: ""; - } - pre, - blockquote { - border: 1px solid #999; - page-break-inside: avoid; - } - thead { - display: table-header-group; - } - tr, - img { - page-break-inside: avoid; - } - img { - max-width: 100% !important; - } - @page { - margin: 0.5cm; - } - p, - h2, - h3 { - orphans: 3; - widows: 3; - } - h2, - h3 { - page-break-after: avoid; - } -} -body { - margin: 0; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 13px; - line-height: 20px; - color: #242220; - background-color: #333b3b; -} -a { - color: #be2f0d; - text-decoration: none; -} -a:hover, -a:focus { - color: #a6290b; - text-decoration: underline; -} -.img-rounded { - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; -} -.img-polaroid { - padding: 4px; - background-color: #fff; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, 0.2); - -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); - -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); -} -.img-circle { - -webkit-border-radius: 500px; - -moz-border-radius: 500px; - border-radius: 500px; -} -.row { - margin-left: -20px; - *zoom: 1; -} -.row:before, -.row:after { - display: table; - content: ""; - line-height: 0; -} -.row:after { - clear: both; -} -[class*="span"] { - float: left; - min-height: 1px; - margin-left: 20px; -} -.container, -.navbar-static-top .container, -.navbar-fixed-top .container, -.navbar-fixed-bottom .container { - width: 940px; -} -.span12 { - width: 940px; -} -.span11 { - width: 860px; -} -.span10 { - width: 780px; -} -.span9 { - width: 700px; -} -.span8 { - width: 620px; -} -.span7 { - width: 540px; -} -.span6 { - width: 460px; -} -.span5 { - width: 380px; -} -.span4 { - width: 300px; -} -.span3 { - width: 220px; -} -.span2 { - width: 140px; -} -.span1 { - width: 60px; -} -.offset12 { - margin-left: 980px; -} -.offset11 { - margin-left: 900px; -} -.offset10 { - margin-left: 820px; -} -.offset9 { - margin-left: 740px; -} -.offset8 { - margin-left: 660px; -} -.offset7 { - margin-left: 580px; -} -.offset6 { - margin-left: 500px; -} -.offset5 { - margin-left: 420px; -} -.offset4 { - margin-left: 340px; -} -.offset3 { - margin-left: 260px; -} -.offset2 { - margin-left: 180px; -} -.offset1 { - margin-left: 100px; -} -.row-fluid { - width: 100%; - *zoom: 1; -} -.row-fluid:before, -.row-fluid:after { - display: table; - content: ""; - line-height: 0; -} -.row-fluid:after { - clear: both; -} -.row-fluid [class*="span"] { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - float: left; - margin-left: 2.127659574468085%; - *margin-left: 2.074468085106383%; -} -.row-fluid [class*="span"]:first-child { - margin-left: 0; -} -.row-fluid .controls-row [class*="span"] + [class*="span"] { - margin-left: 2.127659574468085%; -} -.row-fluid .span12 { - width: 100%; - *width: 99.94680851063829%; -} -.row-fluid .span11 { - width: 91.48936170212765%; - *width: 91.43617021276594%; -} -.row-fluid .span10 { - width: 82.97872340425532%; - *width: 82.92553191489361%; -} -.row-fluid .span9 { - width: 74.46808510638297%; - *width: 74.41489361702126%; -} -.row-fluid .span8 { - width: 65.95744680851064%; - *width: 65.90425531914893%; -} -.row-fluid .span7 { - width: 57.44680851063829%; - *width: 57.39361702127659%; -} -.row-fluid .span6 { - width: 48.93617021276595%; - *width: 48.88297872340425%; -} -.row-fluid .span5 { - width: 40.42553191489362%; - *width: 40.37234042553192%; -} -.row-fluid .span4 { - width: 31.914893617021278%; - *width: 31.861702127659576%; -} -.row-fluid .span3 { - width: 23.404255319148934%; - *width: 23.351063829787233%; -} -.row-fluid .span2 { - width: 14.893617021276595%; - *width: 14.840425531914894%; -} -.row-fluid .span1 { - width: 6.382978723404255%; - *width: 6.329787234042553%; -} -.row-fluid .offset12 { - margin-left: 104.25531914893617%; - *margin-left: 104.14893617021275%; -} -.row-fluid .offset12:first-child { - margin-left: 102.12765957446808%; - *margin-left: 102.02127659574467%; -} -.row-fluid .offset11 { - margin-left: 95.74468085106382%; - *margin-left: 95.6382978723404%; -} -.row-fluid .offset11:first-child { - margin-left: 93.61702127659574%; - *margin-left: 93.51063829787232%; -} -.row-fluid .offset10 { - margin-left: 87.23404255319149%; - *margin-left: 87.12765957446807%; -} -.row-fluid .offset10:first-child { - margin-left: 85.1063829787234%; - *margin-left: 84.99999999999999%; -} -.row-fluid .offset9 { - margin-left: 78.72340425531914%; - *margin-left: 78.61702127659572%; -} -.row-fluid .offset9:first-child { - margin-left: 76.59574468085106%; - *margin-left: 76.48936170212764%; -} -.row-fluid .offset8 { - margin-left: 70.2127659574468%; - *margin-left: 70.10638297872339%; -} -.row-fluid .offset8:first-child { - margin-left: 68.08510638297872%; - *margin-left: 67.9787234042553%; -} -.row-fluid .offset7 { - margin-left: 61.70212765957446%; - *margin-left: 61.59574468085106%; -} -.row-fluid .offset7:first-child { - margin-left: 59.574468085106375%; - *margin-left: 59.46808510638297%; -} -.row-fluid .offset6 { - margin-left: 53.191489361702125%; - *margin-left: 53.085106382978715%; -} -.row-fluid .offset6:first-child { - margin-left: 51.063829787234035%; - *margin-left: 50.95744680851063%; -} -.row-fluid .offset5 { - margin-left: 44.68085106382979%; - *margin-left: 44.57446808510638%; -} -.row-fluid .offset5:first-child { - margin-left: 42.5531914893617%; - *margin-left: 42.4468085106383%; -} -.row-fluid .offset4 { - margin-left: 36.170212765957444%; - *margin-left: 36.06382978723405%; -} -.row-fluid .offset4:first-child { - margin-left: 34.04255319148936%; - *margin-left: 33.93617021276596%; -} -.row-fluid .offset3 { - margin-left: 27.659574468085104%; - *margin-left: 27.5531914893617%; -} -.row-fluid .offset3:first-child { - margin-left: 25.53191489361702%; - *margin-left: 25.425531914893618%; -} -.row-fluid .offset2 { - margin-left: 19.148936170212764%; - *margin-left: 19.04255319148936%; -} -.row-fluid .offset2:first-child { - margin-left: 17.02127659574468%; - *margin-left: 16.914893617021278%; -} -.row-fluid .offset1 { - margin-left: 10.638297872340425%; - *margin-left: 10.53191489361702%; -} -.row-fluid .offset1:first-child { - margin-left: 8.51063829787234%; - *margin-left: 8.404255319148938%; -} -[class*="span"].hide, -.row-fluid [class*="span"].hide { - display: none; -} -[class*="span"].pull-right, -.row-fluid [class*="span"].pull-right { - float: right; -} -.container { - margin-right: auto; - margin-left: auto; - *zoom: 1; -} -.container:before, -.container:after { - display: table; - content: ""; - line-height: 0; -} -.container:after { - clear: both; -} -.container-fluid { - padding-right: 20px; - padding-left: 20px; - *zoom: 1; -} -.container-fluid:before, -.container-fluid:after { - display: table; - content: ""; - line-height: 0; -} -.container-fluid:after { - clear: both; -} -p { - margin: 0 0 10px; -} -.lead { - margin-bottom: 20px; - font-size: 19.5px; - font-weight: 200; - line-height: 30px; -} -small { - font-size: 85%; -} -strong { - font-weight: bold; -} -em { - font-style: italic; -} -cite { - font-style: normal; -} -.muted { - color: #999999; -} -a.muted:hover, -a.muted:focus { - color: #808080; -} -.text-warning { - color: #c09853; -} -a.text-warning:hover, -a.text-warning:focus { - color: #a47e3c; -} -.text-error { - color: #b94a48; -} -a.text-error:hover, -a.text-error:focus { - color: #953b39; -} -.text-info { - color: #3a87ad; -} -a.text-info:hover, -a.text-info:focus { - color: #2d6987; -} -.text-success { - color: #468847; -} -a.text-success:hover, -a.text-success:focus { - color: #356635; -} -.text-left { - text-align: left; -} -.text-right { - text-align: right; -} -.text-center { - text-align: center; -} -h1, -h2, -h3, -h4, -h5, -h6 { - margin: 10px 0; - font-family: inherit; - font-weight: bold; - line-height: 20px; - color: inherit; - text-rendering: optimizelegibility; -} -h1 small, -h2 small, -h3 small, -h4 small, -h5 small, -h6 small { - font-weight: normal; - line-height: 1; - color: #999999; -} -h1, -h2, -h3 { - line-height: 40px; -} -h1 { - font-size: 35.75px; -} -h2 { - font-size: 29.25px; -} -h3 { - font-size: 22.75px; -} -h4 { - font-size: 16.25px; -} -h5 { - font-size: 13px; -} -h6 { - font-size: 11.049999999999999px; -} -h1 small { - font-size: 22.75px; -} -h2 small { - font-size: 16.25px; -} -h3 small { - font-size: 13px; -} -h4 small { - font-size: 13px; -} -.page-header { - padding-bottom: 9px; - margin: 20px 0 30px; - border-bottom: 1px solid #eeeeee; -} -ul, -ol { - padding: 0; - margin: 0 0 10px 25px; -} -ul ul, -ul ol, -ol ol, -ol ul { - margin-bottom: 0; -} -li { - line-height: 20px; -} -ul.unstyled, -ol.unstyled { - margin-left: 0; - list-style: none; -} -ul.inline, -ol.inline { - margin-left: 0; - list-style: none; -} -ul.inline > li, -ol.inline > li { - display: inline-block; - *display: inline; - /* IE7 inline-block hack */ - - *zoom: 1; - padding-left: 5px; - padding-right: 5px; -} -dl { - margin-bottom: 20px; -} -dt, -dd { - line-height: 20px; -} -dt { - font-weight: bold; -} -dd { - margin-left: 10px; -} -.dl-horizontal { - *zoom: 1; -} -.dl-horizontal:before, -.dl-horizontal:after { - display: table; - content: ""; - line-height: 0; -} -.dl-horizontal:after { - clear: both; -} -.dl-horizontal dt { - float: left; - width: 160px; - clear: left; - text-align: right; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.dl-horizontal dd { - margin-left: 180px; -} -hr { - margin: 20px 0; - border: 0; - border-top: 1px solid #eeeeee; - border-bottom: 1px solid #ffffff; -} -abbr[title], -abbr[data-original-title] { - cursor: help; - border-bottom: 1px dotted #999999; -} -abbr.initialism { - font-size: 90%; - text-transform: uppercase; -} -blockquote { - padding: 0 0 0 15px; - margin: 0 0 20px; - border-left: 5px solid #eeeeee; -} -blockquote p { - margin-bottom: 0; - font-size: 16.25px; - font-weight: 300; - line-height: 1.25; -} -blockquote small { - display: block; - line-height: 20px; - color: #999999; -} -blockquote small:before { - content: '\2014 \00A0'; -} -blockquote.pull-right { - float: right; - padding-right: 15px; - padding-left: 0; - border-right: 5px solid #eeeeee; - border-left: 0; -} -blockquote.pull-right p, -blockquote.pull-right small { - text-align: right; -} -blockquote.pull-right small:before { - content: ''; -} -blockquote.pull-right small:after { - content: '\00A0 \2014'; -} -q:before, -q:after, -blockquote:before, -blockquote:after { - content: ""; -} -address { - display: block; - margin-bottom: 20px; - font-style: normal; - line-height: 20px; -} -.well { - min-height: 20px; - padding: 19px; - margin-bottom: 20px; - background-color: #f5f5f5; - border: 1px solid #e3e3e3; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); -} -.well blockquote { - border-color: #ddd; - border-color: rgba(0, 0, 0, 0.15); -} -.well-large { - padding: 24px; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; -} -.well-small { - padding: 9px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; -} -.nav { - margin-left: 0; - margin-bottom: 20px; - list-style: none; -} -.nav > li > a { - display: block; -} -.nav > li > a:hover, -.nav > li > a:focus { - text-decoration: none; - background-color: #eeeeee; -} -.nav > li > a > img { - max-width: none; -} -.nav > .pull-right { - float: right; -} -.nav-header { - display: block; - padding: 3px 15px; - font-size: 11px; - font-weight: bold; - line-height: 20px; - color: #999999; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); - text-transform: uppercase; -} -.nav li + .nav-header { - margin-top: 9px; -} -.nav-list { - padding-left: 15px; - padding-right: 15px; - margin-bottom: 0; -} -.nav-list > li > a, -.nav-list .nav-header { - margin-left: -15px; - margin-right: -15px; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); -} -.nav-list > li > a { - padding: 3px 15px; -} -.nav-list > .active > a, -.nav-list > .active > a:hover, -.nav-list > .active > a:focus { - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); - background-color: #be2f0d; -} -.nav-list [class^="icon-"], -.nav-list [class*=" icon-"] { - margin-right: 2px; -} -.nav-list .divider { - *width: 100%; - height: 1px; - margin: 9px 1px; - *margin: -5px 0 5px; - overflow: hidden; - background-color: #e5e5e5; - border-bottom: 1px solid #ffffff; -} -.nav-tabs, -.nav-pills { - *zoom: 1; -} -.nav-tabs:before, -.nav-pills:before, -.nav-tabs:after, -.nav-pills:after { - display: table; - content: ""; - line-height: 0; -} -.nav-tabs:after, -.nav-pills:after { - clear: both; -} -.nav-tabs > li, -.nav-pills > li { - float: left; -} -.nav-tabs > li > a, -.nav-pills > li > a { - padding-right: 12px; - padding-left: 12px; - margin-right: 2px; - line-height: 14px; -} -.nav-tabs { - border-bottom: 1px solid #ddd; -} -.nav-tabs > li { - margin-bottom: -1px; -} -.nav-tabs > li > a { - padding-top: 8px; - padding-bottom: 8px; - line-height: 20px; - border: 1px solid transparent; - -webkit-border-radius: 4px 4px 0 0; - -moz-border-radius: 4px 4px 0 0; - border-radius: 4px 4px 0 0; -} -.nav-tabs > li > a:hover, -.nav-tabs > li > a:focus { - border-color: #eeeeee #eeeeee #dddddd; -} -.nav-tabs > .active > a, -.nav-tabs > .active > a:hover, -.nav-tabs > .active > a:focus { - color: #555555; - background-color: #d5d1bc; - border: 1px solid #ddd; - border-bottom-color: transparent; - cursor: default; -} -.nav-pills > li > a { - padding-top: 8px; - padding-bottom: 8px; - margin-top: 2px; - margin-bottom: 2px; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; -} -.nav-pills > .active > a, -.nav-pills > .active > a:hover, -.nav-pills > .active > a:focus { - color: #ffffff; - background-color: #be2f0d; -} -.nav-stacked > li { - float: none; -} -.nav-stacked > li > a { - margin-right: 0; -} -.nav-tabs.nav-stacked { - border-bottom: 0; -} -.nav-tabs.nav-stacked > li > a { - border: 1px solid #ddd; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} -.nav-tabs.nav-stacked > li:first-child > a { - -webkit-border-top-right-radius: 4px; - -moz-border-radius-topright: 4px; - border-top-right-radius: 4px; - -webkit-border-top-left-radius: 4px; - -moz-border-radius-topleft: 4px; - border-top-left-radius: 4px; -} -.nav-tabs.nav-stacked > li:last-child > a { - -webkit-border-bottom-right-radius: 4px; - -moz-border-radius-bottomright: 4px; - border-bottom-right-radius: 4px; - -webkit-border-bottom-left-radius: 4px; - -moz-border-radius-bottomleft: 4px; - border-bottom-left-radius: 4px; -} -.nav-tabs.nav-stacked > li > a:hover, -.nav-tabs.nav-stacked > li > a:focus { - border-color: #ddd; - z-index: 2; -} -.nav-pills.nav-stacked > li > a { - margin-bottom: 3px; -} -.nav-pills.nav-stacked > li:last-child > a { - margin-bottom: 1px; -} -.nav-tabs .dropdown-menu { - -webkit-border-radius: 0 0 6px 6px; - -moz-border-radius: 0 0 6px 6px; - border-radius: 0 0 6px 6px; -} -.nav-pills .dropdown-menu { - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; -} -.nav .dropdown-toggle .caret { - border-top-color: #be2f0d; - border-bottom-color: #be2f0d; - margin-top: 6px; -} -.nav .dropdown-toggle:hover .caret, -.nav .dropdown-toggle:focus .caret { - border-top-color: #a6290b; - border-bottom-color: #a6290b; -} -/* move down carets for tabs */ -.nav-tabs .dropdown-toggle .caret { - margin-top: 8px; -} -.nav .active .dropdown-toggle .caret { - border-top-color: #fff; - border-bottom-color: #fff; -} -.nav-tabs .active .dropdown-toggle .caret { - border-top-color: #555555; - border-bottom-color: #555555; -} -.nav > .dropdown.active > a:hover, -.nav > .dropdown.active > a:focus { - cursor: pointer; -} -.nav-tabs .open .dropdown-toggle, -.nav-pills .open .dropdown-toggle, -.nav > li.dropdown.open.active > a:hover, -.nav > li.dropdown.open.active > a:focus { - color: #ffffff; - background-color: #999999; - border-color: #999999; -} -.nav li.dropdown.open .caret, -.nav li.dropdown.open.active .caret, -.nav li.dropdown.open a:hover .caret, -.nav li.dropdown.open a:focus .caret { - border-top-color: #ffffff; - border-bottom-color: #ffffff; - opacity: 1; - filter: alpha(opacity=100); -} -.tabs-stacked .open > a:hover, -.tabs-stacked .open > a:focus { - border-color: #999999; -} -.tabbable { - *zoom: 1; -} -.tabbable:before, -.tabbable:after { - display: table; - content: ""; - line-height: 0; -} -.tabbable:after { - clear: both; -} -.tab-content { - overflow: auto; -} -.tabs-below > .nav-tabs, -.tabs-right > .nav-tabs, -.tabs-left > .nav-tabs { - border-bottom: 0; -} -.tab-content > .tab-pane, -.pill-content > .pill-pane { - display: none; -} -.tab-content > .active, -.pill-content > .active { - display: block; -} -.tabs-below > .nav-tabs { - border-top: 1px solid #ddd; -} -.tabs-below > .nav-tabs > li { - margin-top: -1px; - margin-bottom: 0; -} -.tabs-below > .nav-tabs > li > a { - -webkit-border-radius: 0 0 4px 4px; - -moz-border-radius: 0 0 4px 4px; - border-radius: 0 0 4px 4px; -} -.tabs-below > .nav-tabs > li > a:hover, -.tabs-below > .nav-tabs > li > a:focus { - border-bottom-color: transparent; - border-top-color: #ddd; -} -.tabs-below > .nav-tabs > .active > a, -.tabs-below > .nav-tabs > .active > a:hover, -.tabs-below > .nav-tabs > .active > a:focus { - border-color: transparent #ddd #ddd #ddd; -} -.tabs-left > .nav-tabs > li, -.tabs-right > .nav-tabs > li { - float: none; -} -.tabs-left > .nav-tabs > li > a, -.tabs-right > .nav-tabs > li > a { - min-width: 74px; - margin-right: 0; - margin-bottom: 3px; -} -.tabs-left > .nav-tabs { - float: left; - margin-right: 19px; - border-right: 1px solid #ddd; -} -.tabs-left > .nav-tabs > li > a { - margin-right: -1px; - -webkit-border-radius: 4px 0 0 4px; - -moz-border-radius: 4px 0 0 4px; - border-radius: 4px 0 0 4px; -} -.tabs-left > .nav-tabs > li > a:hover, -.tabs-left > .nav-tabs > li > a:focus { - border-color: #eeeeee #dddddd #eeeeee #eeeeee; -} -.tabs-left > .nav-tabs .active > a, -.tabs-left > .nav-tabs .active > a:hover, -.tabs-left > .nav-tabs .active > a:focus { - border-color: #ddd transparent #ddd #ddd; - *border-right-color: #ffffff; -} -.tabs-right > .nav-tabs { - float: right; - margin-left: 19px; - border-left: 1px solid #ddd; -} -.tabs-right > .nav-tabs > li > a { - margin-left: -1px; - -webkit-border-radius: 0 4px 4px 0; - -moz-border-radius: 0 4px 4px 0; - border-radius: 0 4px 4px 0; -} -.tabs-right > .nav-tabs > li > a:hover, -.tabs-right > .nav-tabs > li > a:focus { - border-color: #eeeeee #eeeeee #eeeeee #dddddd; -} -.tabs-right > .nav-tabs .active > a, -.tabs-right > .nav-tabs .active > a:hover, -.tabs-right > .nav-tabs .active > a:focus { - border-color: #ddd #ddd #ddd transparent; - *border-left-color: #ffffff; -} -.nav > .disabled > a { - color: #999999; -} -.nav > .disabled > a:hover, -.nav > .disabled > a:focus { - text-decoration: none; - background-color: transparent; - cursor: default; -} -.breadcrumb { - padding: 8px 15px; - margin: 0 0 20px; - list-style: none; - background-color: #f5f5f5; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -.breadcrumb > li { - display: inline-block; - *display: inline; - /* IE7 inline-block hack */ - - *zoom: 1; - text-shadow: 0 1px 0 #ffffff; -} -.breadcrumb > li > .divider { - padding: 0 5px; - color: #ccc; -} -.breadcrumb > .active { - color: #999999; -} -.pull-right { - float: right; -} -.pull-left { - float: left; -} -.hide { - display: none; -} -.show { - display: block; -} -.invisible { - visibility: hidden; -} -.affix { - position: fixed; -} -@-ms-viewport { - width: device-width; -} -.hidden { - display: none; - visibility: hidden; -} -.visible-phone { - display: none !important; -} -.visible-tablet { - display: none !important; -} -.hidden-desktop { - display: none !important; -} -.visible-desktop { - display: inherit !important; -} -@media (min-width: 768px) and (max-width: 979px) { - .hidden-desktop { - display: inherit !important; - } - .visible-desktop { - display: none !important ; - } - .visible-tablet { - display: inherit !important; - } - .hidden-tablet { - display: none !important; - } -} -@media (max-width: 767px) { - .hidden-desktop { - display: inherit !important; - } - .visible-desktop { - display: none !important; - } - .visible-phone { - display: inherit !important; - } - .hidden-phone { - display: none !important; - } -} -.visible-print { - display: none !important; -} -@media print { - .visible-print { - display: inherit !important; - } - .hidden-print { - display: none !important; - } -} -@media (min-width: 1200px) { - .row { - margin-left: -30px; - *zoom: 1; - } - .row:before, - .row:after { - display: table; - content: ""; - line-height: 0; - } - .row:after { - clear: both; - } - [class*="span"] { - float: left; - min-height: 1px; - margin-left: 30px; - } - .container, - .navbar-static-top .container, - .navbar-fixed-top .container, - .navbar-fixed-bottom .container { - width: 1170px; - } - .span12 { - width: 1170px; - } - .span11 { - width: 1070px; - } - .span10 { - width: 970px; - } - .span9 { - width: 870px; - } - .span8 { - width: 770px; - } - .span7 { - width: 670px; - } - .span6 { - width: 570px; - } - .span5 { - width: 470px; - } - .span4 { - width: 370px; - } - .span3 { - width: 270px; - } - .span2 { - width: 170px; - } - .span1 { - width: 70px; - } - .offset12 { - margin-left: 1230px; - } - .offset11 { - margin-left: 1130px; - } - .offset10 { - margin-left: 1030px; - } - .offset9 { - margin-left: 930px; - } - .offset8 { - margin-left: 830px; - } - .offset7 { - margin-left: 730px; - } - .offset6 { - margin-left: 630px; - } - .offset5 { - margin-left: 530px; - } - .offset4 { - margin-left: 430px; - } - .offset3 { - margin-left: 330px; - } - .offset2 { - margin-left: 230px; - } - .offset1 { - margin-left: 130px; - } - .row-fluid { - width: 100%; - *zoom: 1; - } - .row-fluid:before, - .row-fluid:after { - display: table; - content: ""; - line-height: 0; - } - .row-fluid:after { - clear: both; - } - .row-fluid [class*="span"] { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - float: left; - margin-left: 2.564102564102564%; - *margin-left: 2.5109110747408616%; - } - .row-fluid [class*="span"]:first-child { - margin-left: 0; - } - .row-fluid .controls-row [class*="span"] + [class*="span"] { - margin-left: 2.564102564102564%; - } - .row-fluid .span12 { - width: 100%; - *width: 99.94680851063829%; - } - .row-fluid .span11 { - width: 91.45299145299145%; - *width: 91.39979996362975%; - } - .row-fluid .span10 { - width: 82.90598290598291%; - *width: 82.8527914166212%; - } - .row-fluid .span9 { - width: 74.35897435897436%; - *width: 74.30578286961266%; - } - .row-fluid .span8 { - width: 65.81196581196582%; - *width: 65.75877432260411%; - } - .row-fluid .span7 { - width: 57.26495726495726%; - *width: 57.21176577559556%; - } - .row-fluid .span6 { - width: 48.717948717948715%; - *width: 48.664757228587014%; - } - .row-fluid .span5 { - width: 40.17094017094017%; - *width: 40.11774868157847%; - } - .row-fluid .span4 { - width: 31.623931623931625%; - *width: 31.570740134569924%; - } - .row-fluid .span3 { - width: 23.076923076923077%; - *width: 23.023731587561375%; - } - .row-fluid .span2 { - width: 14.52991452991453%; - *width: 14.476723040552828%; - } - .row-fluid .span1 { - width: 5.982905982905983%; - *width: 5.929714493544281%; - } - .row-fluid .offset12 { - margin-left: 105.12820512820512%; - *margin-left: 105.02182214948171%; - } - .row-fluid .offset12:first-child { - margin-left: 102.56410256410257%; - *margin-left: 102.45771958537915%; - } - .row-fluid .offset11 { - margin-left: 96.58119658119658%; - *margin-left: 96.47481360247316%; - } - .row-fluid .offset11:first-child { - margin-left: 94.01709401709402%; - *margin-left: 93.91071103837061%; - } - .row-fluid .offset10 { - margin-left: 88.03418803418803%; - *margin-left: 87.92780505546462%; - } - .row-fluid .offset10:first-child { - margin-left: 85.47008547008548%; - *margin-left: 85.36370249136206%; - } - .row-fluid .offset9 { - margin-left: 79.48717948717949%; - *margin-left: 79.38079650845607%; - } - .row-fluid .offset9:first-child { - margin-left: 76.92307692307693%; - *margin-left: 76.81669394435352%; - } - .row-fluid .offset8 { - margin-left: 70.94017094017094%; - *margin-left: 70.83378796144753%; - } - .row-fluid .offset8:first-child { - margin-left: 68.37606837606839%; - *margin-left: 68.26968539734497%; - } - .row-fluid .offset7 { - margin-left: 62.393162393162385%; - *margin-left: 62.28677941443899%; - } - .row-fluid .offset7:first-child { - margin-left: 59.82905982905982%; - *margin-left: 59.72267685033642%; - } - .row-fluid .offset6 { - margin-left: 53.84615384615384%; - *margin-left: 53.739770867430444%; - } - .row-fluid .offset6:first-child { - margin-left: 51.28205128205128%; - *margin-left: 51.175668303327875%; - } - .row-fluid .offset5 { - margin-left: 45.299145299145295%; - *margin-left: 45.1927623204219%; - } - .row-fluid .offset5:first-child { - margin-left: 42.73504273504273%; - *margin-left: 42.62865975631933%; - } - .row-fluid .offset4 { - margin-left: 36.75213675213675%; - *margin-left: 36.645753773413354%; - } - .row-fluid .offset4:first-child { - margin-left: 34.18803418803419%; - *margin-left: 34.081651209310785%; - } - .row-fluid .offset3 { - margin-left: 28.205128205128204%; - *margin-left: 28.0987452264048%; - } - .row-fluid .offset3:first-child { - margin-left: 25.641025641025642%; - *margin-left: 25.53464266230224%; - } - .row-fluid .offset2 { - margin-left: 19.65811965811966%; - *margin-left: 19.551736679396257%; - } - .row-fluid .offset2:first-child { - margin-left: 17.094017094017094%; - *margin-left: 16.98763411529369%; - } - .row-fluid .offset1 { - margin-left: 11.11111111111111%; - *margin-left: 11.004728132387708%; - } - .row-fluid .offset1:first-child { - margin-left: 8.547008547008547%; - *margin-left: 8.440625568285142%; - } - input, - textarea, - .uneditable-input { - margin-left: 0; - } - .controls-row [class*="span"] + [class*="span"] { - margin-left: 30px; - } - input.span12, - textarea.span12, - .uneditable-input.span12 { - width: 1156px; - } - input.span11, - textarea.span11, - .uneditable-input.span11 { - width: 1056px; - } - input.span10, - textarea.span10, - .uneditable-input.span10 { - width: 956px; - } - input.span9, - textarea.span9, - .uneditable-input.span9 { - width: 856px; - } - input.span8, - textarea.span8, - .uneditable-input.span8 { - width: 756px; - } - input.span7, - textarea.span7, - .uneditable-input.span7 { - width: 656px; - } - input.span6, - textarea.span6, - .uneditable-input.span6 { - width: 556px; - } - input.span5, - textarea.span5, - .uneditable-input.span5 { - width: 456px; - } - input.span4, - textarea.span4, - .uneditable-input.span4 { - width: 356px; - } - input.span3, - textarea.span3, - .uneditable-input.span3 { - width: 256px; - } - input.span2, - textarea.span2, - .uneditable-input.span2 { - width: 156px; - } - input.span1, - textarea.span1, - .uneditable-input.span1 { - width: 56px; - } - .thumbnails { - margin-left: -30px; - } - .thumbnails > li { - margin-left: 30px; - } - .row-fluid .thumbnails { - margin-left: 0; - } -} -@media (min-width: 768px) and (max-width: 979px) { - .row { - margin-left: -20px; - *zoom: 1; - } - .row:before, - .row:after { - display: table; - content: ""; - line-height: 0; - } - .row:after { - clear: both; - } - [class*="span"] { - float: left; - min-height: 1px; - margin-left: 20px; - } - .container, - .navbar-static-top .container, - .navbar-fixed-top .container, - .navbar-fixed-bottom .container { - width: 724px; - } - .span12 { - width: 724px; - } - .span11 { - width: 662px; - } - .span10 { - width: 600px; - } - .span9 { - width: 538px; - } - .span8 { - width: 476px; - } - .span7 { - width: 414px; - } - .span6 { - width: 352px; - } - .span5 { - width: 290px; - } - .span4 { - width: 228px; - } - .span3 { - width: 166px; - } - .span2 { - width: 104px; - } - .span1 { - width: 42px; - } - .offset12 { - margin-left: 764px; - } - .offset11 { - margin-left: 702px; - } - .offset10 { - margin-left: 640px; - } - .offset9 { - margin-left: 578px; - } - .offset8 { - margin-left: 516px; - } - .offset7 { - margin-left: 454px; - } - .offset6 { - margin-left: 392px; - } - .offset5 { - margin-left: 330px; - } - .offset4 { - margin-left: 268px; - } - .offset3 { - margin-left: 206px; - } - .offset2 { - margin-left: 144px; - } - .offset1 { - margin-left: 82px; - } - .row-fluid { - width: 100%; - *zoom: 1; - } - .row-fluid:before, - .row-fluid:after { - display: table; - content: ""; - line-height: 0; - } - .row-fluid:after { - clear: both; - } - .row-fluid [class*="span"] { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - float: left; - margin-left: 2.7624309392265194%; - *margin-left: 2.709239449864817%; - } - .row-fluid [class*="span"]:first-child { - margin-left: 0; - } - .row-fluid .controls-row [class*="span"] + [class*="span"] { - margin-left: 2.7624309392265194%; - } - .row-fluid .span12 { - width: 100%; - *width: 99.94680851063829%; - } - .row-fluid .span11 { - width: 91.43646408839778%; - *width: 91.38327259903608%; - } - .row-fluid .span10 { - width: 82.87292817679558%; - *width: 82.81973668743387%; - } - .row-fluid .span9 { - width: 74.30939226519337%; - *width: 74.25620077583166%; - } - .row-fluid .span8 { - width: 65.74585635359117%; - *width: 65.69266486422946%; - } - .row-fluid .span7 { - width: 57.18232044198895%; - *width: 57.12912895262725%; - } - .row-fluid .span6 { - width: 48.61878453038674%; - *width: 48.56559304102504%; - } - .row-fluid .span5 { - width: 40.05524861878453%; - *width: 40.00205712942283%; - } - .row-fluid .span4 { - width: 31.491712707182323%; - *width: 31.43852121782062%; - } - .row-fluid .span3 { - width: 22.92817679558011%; - *width: 22.87498530621841%; - } - .row-fluid .span2 { - width: 14.3646408839779%; - *width: 14.311449394616199%; - } - .row-fluid .span1 { - width: 5.801104972375691%; - *width: 5.747913483013988%; - } - .row-fluid .offset12 { - margin-left: 105.52486187845304%; - *margin-left: 105.41847889972962%; - } - .row-fluid .offset12:first-child { - margin-left: 102.76243093922652%; - *margin-left: 102.6560479605031%; - } - .row-fluid .offset11 { - margin-left: 96.96132596685082%; - *margin-left: 96.8549429881274%; - } - .row-fluid .offset11:first-child { - margin-left: 94.1988950276243%; - *margin-left: 94.09251204890089%; - } - .row-fluid .offset10 { - margin-left: 88.39779005524862%; - *margin-left: 88.2914070765252%; - } - .row-fluid .offset10:first-child { - margin-left: 85.6353591160221%; - *margin-left: 85.52897613729868%; - } - .row-fluid .offset9 { - margin-left: 79.8342541436464%; - *margin-left: 79.72787116492299%; - } - .row-fluid .offset9:first-child { - margin-left: 77.07182320441989%; - *margin-left: 76.96544022569647%; - } - .row-fluid .offset8 { - margin-left: 71.2707182320442%; - *margin-left: 71.16433525332079%; - } - .row-fluid .offset8:first-child { - margin-left: 68.50828729281768%; - *margin-left: 68.40190431409427%; - } - .row-fluid .offset7 { - margin-left: 62.70718232044199%; - *margin-left: 62.600799341718584%; - } - .row-fluid .offset7:first-child { - margin-left: 59.94475138121547%; - *margin-left: 59.838368402492065%; - } - .row-fluid .offset6 { - margin-left: 54.14364640883978%; - *margin-left: 54.037263430116376%; - } - .row-fluid .offset6:first-child { - margin-left: 51.38121546961326%; - *margin-left: 51.27483249088986%; - } - .row-fluid .offset5 { - margin-left: 45.58011049723757%; - *margin-left: 45.47372751851417%; - } - .row-fluid .offset5:first-child { - margin-left: 42.81767955801105%; - *margin-left: 42.71129657928765%; - } - .row-fluid .offset4 { - margin-left: 37.01657458563536%; - *margin-left: 36.91019160691196%; - } - .row-fluid .offset4:first-child { - margin-left: 34.25414364640884%; - *margin-left: 34.14776066768544%; - } - .row-fluid .offset3 { - margin-left: 28.45303867403315%; - *margin-left: 28.346655695309746%; - } - .row-fluid .offset3:first-child { - margin-left: 25.69060773480663%; - *margin-left: 25.584224756083227%; - } - .row-fluid .offset2 { - margin-left: 19.88950276243094%; - *margin-left: 19.783119783707537%; - } - .row-fluid .offset2:first-child { - margin-left: 17.12707182320442%; - *margin-left: 17.02068884448102%; - } - .row-fluid .offset1 { - margin-left: 11.32596685082873%; - *margin-left: 11.219583872105325%; - } - .row-fluid .offset1:first-child { - margin-left: 8.56353591160221%; - *margin-left: 8.457152932878806%; - } - input, - textarea, - .uneditable-input { - margin-left: 0; - } - .controls-row [class*="span"] + [class*="span"] { - margin-left: 20px; - } - input.span12, - textarea.span12, - .uneditable-input.span12 { - width: 710px; - } - input.span11, - textarea.span11, - .uneditable-input.span11 { - width: 648px; - } - input.span10, - textarea.span10, - .uneditable-input.span10 { - width: 586px; - } - input.span9, - textarea.span9, - .uneditable-input.span9 { - width: 524px; - } - input.span8, - textarea.span8, - .uneditable-input.span8 { - width: 462px; - } - input.span7, - textarea.span7, - .uneditable-input.span7 { - width: 400px; - } - input.span6, - textarea.span6, - .uneditable-input.span6 { - width: 338px; - } - input.span5, - textarea.span5, - .uneditable-input.span5 { - width: 276px; - } - input.span4, - textarea.span4, - .uneditable-input.span4 { - width: 214px; - } - input.span3, - textarea.span3, - .uneditable-input.span3 { - width: 152px; - } - input.span2, - textarea.span2, - .uneditable-input.span2 { - width: 90px; - } - input.span1, - textarea.span1, - .uneditable-input.span1 { - width: 28px; - } -} -@media (max-width: 767px) { - body { - padding-left: 20px; - padding-right: 20px; - } - .navbar-fixed-top, - .navbar-fixed-bottom, - .navbar-static-top { - margin-left: -20px; - margin-right: -20px; - } - .container-fluid { - padding: 0; - } - .dl-horizontal dt { - float: none; - clear: none; - width: auto; - text-align: left; - } - .dl-horizontal dd { - margin-left: 0; - } - .container { - width: auto; - } - .row-fluid { - width: 100%; - } - .row, - .thumbnails { - margin-left: 0; - } - .thumbnails > li { - float: none; - margin-left: 0; - } - [class*="span"], - .uneditable-input[class*="span"], - .row-fluid [class*="span"] { - float: none; - display: block; - width: 100%; - margin-left: 0; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - } - .span12, - .row-fluid .span12 { - width: 100%; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - } - .row-fluid [class*="offset"]:first-child { - margin-left: 0; - } - .input-large, - .input-xlarge, - .input-xxlarge, - input[class*="span"], - select[class*="span"], - textarea[class*="span"], - .uneditable-input { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - } - .input-prepend input, - .input-append input, - .input-prepend input[class*="span"], - .input-append input[class*="span"] { - display: inline-block; - width: auto; - } - .controls-row [class*="span"] + [class*="span"] { - margin-left: 0; - } - .modal { - position: fixed; - top: 20px; - left: 20px; - right: 20px; - width: auto; - margin: 0; - } - .modal.fade { - top: -100px; - } - .modal.fade.in { - top: 20px; - } -} -@media (max-width: 480px) { - .nav-collapse { - -webkit-transform: translate3d(0, 0, 0); - } - .page-header h1 small { - display: block; - line-height: 20px; - } - input[type="checkbox"], - input[type="radio"] { - border: 1px solid #ccc; - } - .form-horizontal .control-label { - float: none; - width: auto; - padding-top: 0; - text-align: left; - } - .form-horizontal .controls { - margin-left: 0; - } - .form-horizontal .control-list { - padding-top: 0; - } - .form-horizontal .form-actions { - padding-left: 10px; - padding-right: 10px; - } - .media .pull-left, - .media .pull-right { - float: none; - display: block; - margin-bottom: 10px; - } - .media-object { - margin-right: 0; - margin-left: 0; - } - .modal { - top: 10px; - left: 10px; - right: 10px; - } - .modal-header .close { - padding: 10px; - margin: -10px; - } - .carousel-caption { - position: static; - } -} -@media (max-width: 979px) { - body { - padding-top: 0; - } - .navbar-fixed-top, - .navbar-fixed-bottom { - position: static; - } - .navbar-fixed-top { - margin-bottom: 20px; - } - .navbar-fixed-bottom { - margin-top: 20px; - } - .navbar-fixed-top .navbar-inner, - .navbar-fixed-bottom .navbar-inner { - padding: 5px; - } - .navbar .container { - width: auto; - padding: 0; - } - .navbar .brand { - padding-left: 10px; - padding-right: 10px; - margin: 0 0 0 -5px; - } - .nav-collapse { - clear: both; - } - .nav-collapse .nav { - float: none; - margin: 0 0 10px; - } - .nav-collapse .nav > li { - float: none; - } - .nav-collapse .nav > li > a { - margin-bottom: 2px; - } - .nav-collapse .nav > .divider-vertical { - display: none; - } - .nav-collapse .nav .nav-header { - color: #777777; - text-shadow: none; - } - .nav-collapse .nav > li > a, - .nav-collapse .dropdown-menu a { - padding: 9px 15px; - font-weight: bold; - color: #777777; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - } - .nav-collapse .btn { - padding: 4px 10px 4px; - font-weight: normal; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - } - .nav-collapse .dropdown-menu li + li a { - margin-bottom: 2px; - } - .nav-collapse .nav > li > a:hover, - .nav-collapse .nav > li > a:focus, - .nav-collapse .dropdown-menu a:hover, - .nav-collapse .dropdown-menu a:focus { - background-color: #f2f2f2; - } - .navbar-inverse .nav-collapse .nav > li > a, - .navbar-inverse .nav-collapse .dropdown-menu a { - color: #ffffff; - } - .navbar-inverse .nav-collapse .nav > li > a:hover, - .navbar-inverse .nav-collapse .nav > li > a:focus, - .navbar-inverse .nav-collapse .dropdown-menu a:hover, - .navbar-inverse .nav-collapse .dropdown-menu a:focus { - background-color: #95805f; - } - .nav-collapse.in .btn-group { - margin-top: 5px; - padding: 0; - } - .nav-collapse .dropdown-menu { - position: static; - top: auto; - left: auto; - float: none; - display: none; - max-width: none; - margin: 0 15px; - padding: 0; - background-color: transparent; - border: none; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; - -webkit-box-shadow: none; - -moz-box-shadow: none; - box-shadow: none; - } - .nav-collapse .open > .dropdown-menu { - display: block; - } - .nav-collapse .dropdown-menu:before, - .nav-collapse .dropdown-menu:after { - display: none; - } - .nav-collapse .dropdown-menu .divider { - display: none; - } - .nav-collapse .nav > li > .dropdown-menu:before, - .nav-collapse .nav > li > .dropdown-menu:after { - display: none; - } - .nav-collapse .navbar-form, - .nav-collapse .navbar-search { - float: none; - padding: 10px 15px; - margin: 10px 0; - border-top: 1px solid #f2f2f2; - border-bottom: 1px solid #f2f2f2; - -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1); - -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1); - box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1); - } - .navbar-inverse .nav-collapse .navbar-form, - .navbar-inverse .nav-collapse .navbar-search { - border-top-color: #95805f; - border-bottom-color: #95805f; - } - .navbar .nav-collapse .nav.pull-right { - float: none; - margin-left: 0; - } - .nav-collapse, - .nav-collapse.collapse { - overflow: hidden; - height: 0; - } - .navbar .btn-navbar { - display: block; - } - .navbar-static .navbar-inner { - padding-left: 10px; - padding-right: 10px; - } -} -@media (min-width: 980px) { - .nav-collapse.collapse { - height: auto !important; - overflow: visible !important; - } -} -p, -ul, -ol, -pre { - margin-top: 16px; - margin-bottom: 16px; -} -ul, -ol { - padding: 0; -} -h1, -h2, -h3, -h4, -h5, -h6 { - color: #352b1c; -} -h1 a, -h2 a, -h3 a, -h4 a, -h5 a, -h6 a { - color: #352b1c; -} -h1 a:hover, -h2 a:hover, -h3 a:hover, -h4 a:hover, -h5 a:hover, -h6 a:hover { - color: #352b1c; -} -hr { - margin-bottom: 13.333333333333334px; - border-bottom: none; -} -code, -pre, -div.pretty { - padding: 0 3px 2px; - font-family: monospace; - color: #242220; - font-size: 13px; -} -code { - padding: 0; - white-space: nowrap; -} -pre, -div.pretty { - display: block; - padding: 9.5px; - margin: 10px 0; - line-height: 20px; - background-color: #302f2d; - color: #e8bf6a; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -pre { - word-break: break-all; - word-wrap: break-word; - white-space: pre; - white-space: pre-wrap; -} -div.pretty code { - white-space: pre; - white-space: pre-wrap; -} -div.pretty code.d { - color: #6897bb; -} -div.pretty code.k { - color: #a9b7c6; -} -div.pretty code.i { - color: #e8bf6a; -} -div.pretty code.l { - color: #a4c157; -} -div.pretty code.r { - color: #bc9458; -} -.pre-scrollable { - max-height: 340px; - overflow-y: scroll; -} -canvas, -iframe { - margin: 0; - overflow: hidden; - padding: 5px; - border: 1px solid #ddd; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); - -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); -} -table { - max-width: 100%; - background-color: transparent; - border-collapse: collapse; - border-spacing: 0; -} -html { - overflow-y: scroll; -} -html, -body { - height: 100%; -} -.sheet { - padding: 0px 30px; - background: #ffffff; - min-height: 100%; - min-width: 652px !important; - -webkit-box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.3); - -moz-box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.3); - box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.3); -} -.breadcrumb { - text-transform: uppercase; - font-family: "din-condensed-web", "Trebuchet MS", Helvetica, sans-serif; - font-size: 12px; - padding: 0; - background: none; - -webkit-border-radius: none; - -moz-border-radius: none; - border-radius: none; -} -.breadcrumb a { - color: #52432b; -} -.breadcrumb .active { - color: #999999; -} -header.main { - padding-top: 22.5px; -} -header.main .title { - font-family: "futura-pt", "OpenSans", "Arial Black", Gadget, sans-serif; - font-size: 24px; - font-weight: bold; - line-height: 20px; - text-transform: uppercase; - margin: 10px 0; -} -header.main .title img { - margin-right: 10px; - margin-top: -7px; -} -nav.main { - text-transform: uppercase; - font-family: "din-condensed-web", "Trebuchet MS", Helvetica, sans-serif; -} -nav.main .nav { - background-color: #353535; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -nav.main .nav a { - margin: 0; - color: #ffffff; -} -nav.main .nav a:hover { - color: #f16801; - background: none; - -webkit-border-radius: none; - -moz-border-radius: none; - border-radius: none; -} -.content { - padding-bottom: 30px; -} -.content h1 { - text-transform: uppercase; - font-family: "futura-pt", "OpenSans", "Arial Black", Gadget, sans-serif; - font-size: 18.2px; - line-height: 20px; -} -.content h1 .name { - text-transform: none; -} -.content h1 code { - font-size: inherit; - text-transform: none; - padding: 0 8px; - color: #352b1c; -} -.content h2 { - font-size: 16.900000000000002px; - line-height: 25px; -} -.content h3 { - font-size: 14.3px; - line-height: 23px; -} -.content h4 { - font-size: 13px; -} -.content h5 { - font-size: 11.700000000000001px; -} -.content h5 { - font-size: 9.75px; -} -.content table { - width: auto; - margin-bottom: 20px; - border: 1px solid #dddddd; - border-collapse: separate; - border-left: 0; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -.content table th, -.content table td { - padding: 8px 15px 8px 10px; - line-height: 20px; - text-align: left; - vertical-align: top; - border-top: 1px solid #dddddd; - border-left: 1px solid #dddddd; -} -.content table th.span1, -.content table td.span1 { - float: none; - width: 44px; - margin-left: 0; -} -.content table th.span2, -.content table td.span2 { - float: none; - width: 124px; - margin-left: 0; -} -.content table th.span3, -.content table td.span3 { - float: none; - width: 204px; - margin-left: 0; -} -.content table th.span4, -.content table td.span4 { - float: none; - width: 284px; - margin-left: 0; -} -.content table th.span5, -.content table td.span5 { - float: none; - width: 364px; - margin-left: 0; -} -.content table th.span6, -.content table td.span6 { - float: none; - width: 444px; - margin-left: 0; -} -.content table th.span7, -.content table td.span7 { - float: none; - width: 524px; - margin-left: 0; -} -.content table th.span8, -.content table td.span8 { - float: none; - width: 604px; - margin-left: 0; -} -.content table th.span9, -.content table td.span9 { - float: none; - width: 684px; - margin-left: 0; -} -.content table th.span10, -.content table td.span10 { - float: none; - width: 764px; - margin-left: 0; -} -.content table th.span11, -.content table td.span11 { - float: none; - width: 844px; - margin-left: 0; -} -.content table th.span12, -.content table td.span12 { - float: none; - width: 924px; - margin-left: 0; -} -.content table th { - font-weight: bold; - vertical-align: bottom; - border-top: none; -} -.content table tr:nth-child(even) > td { - background-color: #f9f9f9; -} -.content .list-index { - word-wrap: break-word; -} -.content .scope-members-list .item { - margin-bottom: 32px; -} -.content .scope-members-list .item .name { - background-color: #fbfbfb; - color: #242220; - font-family: monospace; - margin-bottom: 13.333333333333334px; -} -.content .scope-members-list .item .description { - padding: 0 0 0 9px; -} -.content .scope-members-list .item .description p { - margin: 10px 0; - line-height: 16px; -} -.content .scope-members-list .item:last-child { - margin-bottom: 0; -} -.content .main-contents h2 { - font-weight: normal; - text-transform: uppercase; - font-size: 18.2px; - margin-bottom: 6px; -} -.content .main-contents hr { - margin-bottom: 10px; -} -.content .main-contents .item { - padding-left: 30px; - min-height: 110px; -} -.content .main-contents .item p { - font-style: italic; - color: #aca595; -} -.content table.scope-contents { - width: 100%; - border: none; -} -.content table.scope-contents tr td { - border: none; - border-bottom: 1px solid #eeeeee; - background: none; -} -.content table.scope-contents tr td ul { - font-family: monospace; -} -.content table.scope-contents tr:last-child td { - border-bottom: none; -} -.content table.scope-contents .name { - text-transform: uppercase; - font-size: 14px; -} -.content table.scope-contents ul { - margin-top: 0; -} -.content footer.main { - font-size: 12px; - line-height: 18.18181818181818px; - color: #4d4844; - background-color: #fcfcfc; - margin-top: 40px; - min-height: 20px; - padding: 20px; - border: 1px solid #eaeaea; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); - -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); -} -.content footer.main p { - margin-top: 13.333333333333334px; - margin-bottom: 13.333333333333334px; -} -.content footer.main p:last-child { - margin-bottom: 0; -} diff --git a/docs/templates/cerberusx/scope_template.html b/docs/templates/cerberusx/scope_template.html deleted file mode 100644 index 86b59a4f..00000000 --- a/docs/templates/cerberusx/scope_template.html +++ /dev/null @@ -1,359 +0,0 @@ - -

${KIND} ${IDENT}${TYPE}

- -${IF SUMMARY} -

${SUMMARY} - ${IF DESCRIPTION} More...${ENDIF}

-${ENDIF} - -
- - - ${IF EXTENDS} - - - - - ${ENDIF} - - ${IF IMPLEMENTS} - - - - - ${ENDIF} - - ${IF EXTENDED_BY} - - - - - ${ENDIF} - - ${IF IMPORTS} - - - - - ${ENDIF} - - ${IF CLASSES} - - - - - ${ENDIF} - - ${IF INTERFACES} - - - - - ${ENDIF} - - ${IF CONSTS} - - - - - ${ENDIF} - - ${IF GLOBALS} - - - - - ${ENDIF} - - ${IF FIELDS} - - - - - ${ENDIF} - - ${IF CTORS} - - - - - ${ENDIF} - - ${IF PROPERTIES} - - - - - ${ENDIF} - - ${IF METHODS} - - - - - ${ENDIF} - - ${IF FUNCTIONS} - - - - - ${ENDIF} - - ${IF INHERITED_PROPERTIES} - - - - - ${ENDIF} - - ${IF INHERITED_METHODS} - - - - - ${ENDIF} - - ${IF INHERITED_FUNCTIONS} - - - - - ${ENDIF} - -
Extends: -
    -
  • ${XEXTENDS}
  • -
-
Implements: -
    -
  • ${XIMPLEMENTS}
  • -
-
Extended by: -
    -
  • ${XEXTENDED_BY}
  • -
-
Imports: -
    - ${FOR IMPORTS} -
  • ${IDENT}
  • - ${NEXT} -
-
Classes: -
    - ${FOR CLASSES} -
  • ${IDENT}
  • - ${NEXT} -
-
Interfaces: -
    - ${FOR INTERFACES} -
  • ${IDENT}
  • - ${NEXT} -
-
Constants: -
    - ${FOR CONSTS} -
  • ${IDENT} : ${TYPE}
  • - ${NEXT} -
-
Globals: -
    - ${FOR GLOBALS} -
  • ${IDENT} : ${TYPE}
  • - ${NEXT} -
-
Fields: -
    - ${FOR FIELDS} -
  • ${IDENT} : ${TYPE}
  • - ${NEXT} -
-
Constructors: -
    - ${FOR CTORS} -
  • ${IDENT} ${TYPE}
  • - ${NEXT} -
-
Properties: -
    - ${FOR PROPERTIES} -
  • ${IDENT} : ${TYPE}
  • - ${NEXT} -
-
Methods: -
    - ${FOR METHODS} -
  • ${IDENT} : ${TYPE}
  • - ${NEXT} -
-
Functions: -
    - ${FOR FUNCTIONS} -
  • ${IDENT} : ${TYPE}
  • - ${NEXT} -
-
Inherited Properties: -
    - ${FOR INHERITED_PROPERTIES} -
  • ${IDENT} : ${TYPE}
  • - ${NEXT} -
-
Inherited Methods: -
    - ${FOR INHERITED_METHODS} -
  • ${IDENT} : ${TYPE}
  • - ${NEXT} -
-
Inherited Functions: -
    - ${FOR INHERITED_FUNCTIONS} -
  • ${IDENT} : ${TYPE}
  • - ${NEXT} -
-
- -${IF DESCRIPTION} - -

Detailed Discussion

- ${DESCRIPTION} - ${IF LINKS} -

See also ${LINKS}

- ${ENDIF} - ${IF EXAMPLE} -

Example ${EXAMPLE}

- ${ENDIF} -
-${ENDIF} - -${IF FIELDS} -

Field Documentation

-
- ${FOR FIELDS} -
- -
Field ${IDENT} : ${XTYPE}
-
-

${DESCRIPTION}

- ${IF LINKS} -

See also ${LINKS}

- ${ENDIF} - ${IF EXAMPLE} -

Example ${EXAMPLE}

- ${ENDIF} -
-
- ${NEXT} -
-
-${ENDIF} - -${IF GLOBALS} -

Global Documentation

-
- ${FOR GLOBALS} -
- -
Global ${IDENT} : ${XTYPE}
-
-

${DESCRIPTION}

- ${IF LINKS} -

See also ${LINKS}

- ${ENDIF} - ${IF EXAMPLE} -

Example ${EXAMPLE}

- ${ENDIF} -
-
- ${NEXT} -
-
-${ENDIF} - -${IF CTORS} -

Constructor Documentation

-
- ${FOR CTORS} -
- -
Method New ${XTYPE}
-
-

${DESCRIPTION}

- ${IF LINKS} -

See also ${LINKS}

- ${ENDIF} - ${IF EXAMPLE} -

Example ${EXAMPLE}

- ${ENDIF} -
-
- ${NEXT} -
-
-${ENDIF} - -${IF PROPERTIES} -

Property Documentation

-
- ${FOR PROPERTIES} -
- -
Method ${IDENT} : ${XTYPE} Property
-
-

${DESCRIPTION}

- ${IF LINKS} -

See also ${LINKS}

- ${ENDIF} - ${IF EXAMPLE} -

Example ${EXAMPLE}

- ${ENDIF} -
-
- ${NEXT} -
-
-${ENDIF} - -${IF METHODS} -

Method Documentation

-
- ${FOR METHODS} -
- -
Method ${IDENT} : ${XTYPE}
-
-

${DESCRIPTION}

- ${IF LINKS} -

See also ${LINKS}

- ${ENDIF} - ${IF EXAMPLE} -

Example ${EXAMPLE}

- ${ENDIF} -
-
- ${NEXT} -
-
-${ENDIF} - -${IF FUNCTIONS} -

Function Documentation

-
- ${FOR FUNCTIONS} -
- -
Function ${IDENT} : ${XTYPE}
-
-

${DESCRIPTION}

- ${IF LINKS} -

See also ${LINKS}

- ${ENDIF} - ${IF EXAMPLE} -

Example ${EXAMPLE}

- ${ENDIF} -
-
- ${NEXT} -
-
-${ENDIF} diff --git a/docs/templates/cerberusx3b/data/cerberusx.png b/docs/templates/cerberusx3b/data/cerberusx.png deleted file mode 100644 index 3f8fb04b..00000000 Binary files a/docs/templates/cerberusx3b/data/cerberusx.png and /dev/null differ diff --git a/docs/templates/cerberusx3b/index_template.html b/docs/templates/cerberusx3b/index_template.html deleted file mode 100644 index 9600721f..00000000 --- a/docs/templates/cerberusx3b/index_template.html +++ /dev/null @@ -1,12 +0,0 @@ - -

${INDEX}

- - - - ${FOR ITEMS} - - - - - ${NEXT} -
NameDescription
${IDENT} ${PARAMTYPES}
${IF SCOPE}in ${SCOPE}${ENDIF}${IF NOT SCOPE} ${ENDIF}
${SUMMARY}
diff --git a/docs/templates/cerberusx3b/page_template.html b/docs/templates/cerberusx3b/page_template.html deleted file mode 100644 index 210885c3..00000000 --- a/docs/templates/cerberusx3b/page_template.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - Cerberus X Documentation - - - -
-
-

- Cerberus X Documentation -

-${IF ICONLINKS} - -${FOR ICONLINKS} -${NEXT} - -${ENDIF} -
- - - -
- Home -${IF NAVLINKS}${FOR NAVLINKS} - ${IF LAST}${IDENT}${ENDIF}${IF NOT LAST}${IDENT}${ENDIF} -${NEXT}${ENDIF} -
- -
- -${CONTENT} - -
-
- - \ No newline at end of file diff --git a/docs/templates/cerberusx3b/pagestyle.css b/docs/templates/cerberusx3b/pagestyle.css deleted file mode 100644 index 186ce175..00000000 --- a/docs/templates/cerberusx3b/pagestyle.css +++ /dev/null @@ -1,403 +0,0 @@ -/************************ - shared definitions -************************/ -*{ - position: relative; - margin: 0; - padding: 0; -} -h1, h2, h3, h4, h5{ - font-family: sans-serif; - font-weight: 900; -} -a{ - text-decoration: none; - color: inherit; -} -a img{ - border: none; -} -code, pre{ - font-family: monospace; - font-size: 13px; /* fix for SHIT BROWSERS DOWNSCALING EFFING MONOSPACE FONTS */ - white-space: pre-wrap; -} -.main, .nav, .article, .section, .header, .footer{ - display: block; -} - -/************************ - page coarse layout -************************/ -html{ - /* - 100% = "16px", 81.25% = "13px" (old CX docs default) - Every other size depends on this, thus: - DO NOT CHANGE ! - */ - font-size: 81.25%; - line-height: 155%; -} -html, body{ - width: 100%; - background: #ffffff; - font-family: "Helvetica", "Arial", sans-serif; - color: #222222; -} -.page{ - box-sizing: border-box; - width: 100%; - padding: 1.5rem 2rem; -} - -/************************ - header -************************/ -.page>.header{ - font-size: 1.85rem; - line-height: 2em; -} -/* DOCS HEADER */ -.page>.header>h1{ - display: inline-block; - font-size: inherit; - text-transform: uppercase; -} -.page>.header>h1>a{ - display: inline-block; - vertical-align: middle; - margin-right: 0.5rem; -} -.page>.header>h1>a>img{ - vertical-align: top; -} -/* ICON LINKS */ -.page>.header>.icons{ - display: inline-flex; - flex-wrap: wrap; - float: right; -} -.page>.header>.icons>a{ - display: inline-block; - margin-left: 0.5rem; -} -.page>.header>.icons>a>img{ - vertical-align: middle; - max-width: 3rem; - max-height: 3rem; -} -.page>.header::after{ - display: block; - content: ''; - clear: both; -} - -/************************ - navigation -************************/ -/* MAIN NAVIGATION */ -.page>.nav{ - display: flex; - flex-wrap: wrap; - margin-top: 1rem; - border-radius: 0.4rem; - background: #333333; - font-size: 0.9rem; - text-transform: uppercase; - color: white; -} -.page>.nav>a{ - display: inline-block; - margin: 0 0.5rem; - padding: 0.5rem; -} -.page>.nav>a:hover{ - color: hsl(26, 100%, 45%); -} -/* LOCATION */ -.page>.location{ - display: flex; - flex-wrap: wrap; - margin-top: 1rem; - font-size: 0.9rem; - text-transform: uppercase; - color: #cccccc; -} -.page>.location>a{ - margin-right: 0.5rem; - color: black; -} -.page>.location>a:hover{ - color: hsl(26, 90%, 40%); -} -.page>.location>a::after{ - content: '/'; - margin-left: 0.5rem; - color: #cccccc; -} - -/************************ - contents -************************/ -.page>.main{ - margin-top: 2rem; -} -/* HEADINGS */ -.page>.main h1, -.page>.main h2, -.page>.main h3, -.page>.main h4, -.page>.main h5{ - margin: 3rem 0 1.5rem 0; - font-weight: bold; - color: #333333; -} -.page>.main h1{ - font-size: 1.4rem; - font-weight: 900; - text-transform: uppercase; -} -.page>.main h1 small{ - text-transform: none; -} -.page>.main h2{ - font-size: 1.3rem; -} -.page>.main h3{ - font-size: 1.1rem; -} -.page>.main hr{ - margin: 2rem 0; - height: 0.8rem; - border: none; - border-radius: 0.4rem; - background: #eeeeee; -} -/* SEMANTIC */ -.page>.main .article{ - margin: 3rem 0 1rem 0; -} -/* BLOCK CONTENTS */ -.page>.main p, -.page>.main ul, -.page>.main ol, -.page>.main table, -.page>.main div.pretty{ - margin: 0.8rem 0; -} -.page>.main ul, -.page>.main ol{ - margin-left: 2rem; -} -.page>.main iframe, -.page>.main canvas{ - box-sizing: border-box; - padding: 0.4rem; - border-radius: 0.4rem; - border: 1px solid #cccccc; -} -.page>.main .multicolumn{ - column-width: 15rem; - column-gap: 4rem; - column-rule: 1px solid #cccccc; -} -.page>.main pre{ - margin: 1rem 0; - padding: 0.6rem 1rem; - border-radius: 0.4rem; - border: 1px solid #cccccc; - background: #f5f5f5; -} -.page>.main img{ - max-width: 100%; -} -/* tables */ -.page>.main table{ - border-collapse: separate; - border-spacing: 0; - border-radius: 0.4rem; - border: 1px solid #cccccc; -} -.page>.main table tbody{ - border: inherit; -} -.page>.main table tr{ - border: inherit; -} -.page>.main table tr:nth-child(even){ - background-color: rgba(0,0,0, 0.04); -} -.page>.main table th, -.page>.main table td{ - padding: 0.6rem 1rem; - border: inherit; - border-right: none; - border-bottom: none; - text-align: left; - vertical-align: top; -} -.page>.main table th:first-child, -.page>.main table td:first-child{ - border-left: none; -} -.page>.main table th{ - border-top: none; - vertical-align: bottom; -} -/* INLINE CONTENTS */ -.page>.main a[href]{ - color: hsl(12, 90%, 40%); -} -.page>.main a[href]:hover{ - color: hsl(12, 90%, 30%); - text-decoration: underline; -} -.page>.main a[name]{ - position: absolute; - display: block; - top: -2rem; -} -.page>.main a.unresolved:after{ - content: '?'; - color: red; - font-weight: 900; - animation: blink 1s step-start infinite; -} -@keyframes blink{ - 50% {color: black;} -} - -/************************ - code blocks with syntax - highlighting -************************/ -div.pretty{ - font-family: monospace; - padding: 0.75rem; - background-color: #302f2d; - border-radius: 0.4rem; - color: #e8bf6a; - tab-size: 4; - -webkit-tab-size: 4; - -moz-tab-size: 4; - -ms-tab-size: 4; - overflow-x: auto; -} -div.pretty code{ - white-space: pre-wrap; -} -div.pretty code.d { - color: #6897bb; -} -div.pretty code.k { - color: #a9b7c6; -} -div.pretty code.i { - color: #e8bf6a; -} -div.pretty code.l { - color: #a4c157; -} -div.pretty code.r { - color: #bc9458; -} - -/************************ - scope documentation -************************/ -/* index */ -.page>.main table.index{ - width: 100%; - border-radius: 0; - border: none; - border-bottom: 1px solid #cccccc; - line-height: 1.3rem; - table-layout: fixed; -} -.page>.main table.index td{ - padding: 0.3rem 1rem; -} -.page>.main table.index th:first-child{ - width: 20rem; -} -.page>.main table.index th{ - padding: 1.5rem 1rem 0.3rem 1rem; - border-bottom: 1px solid #cccccc; - font-weight: normal; - text-transform: uppercase; -} -.page>.main table.index td>small{ - display: block; - top: -0.2em; - margin: -0.2em 0; - color: #999999; - font-size: 0.75em; -} -.page>.main table.index code small{ - color: #666666; -} - -.page>.main span.note{ - top: -1rem; - padding-left: 1rem; - font-size: 0.85em; -} - -.page>.main .declaration{ - font-weight: bold; - color: #666666; -} -.page>.main .declaration strong{ - color: #000000; -} -.page>.main .detail{ - top: 0.4rem; - font-size: 0.9rem; - text-transform: uppercase; -} -.page>.main .detail:before{ - display: inline-block; - width: 1.3rem; - font-size: 1rem; - font-weight: bold; - color: #999999; -} -.page>.main .detail.parameters:before{ - content: '\2ba9\20'; -} -.page>.main .detail.returns:before{ - content: '\2ba8\20'; -} -.page>.main .detail.links:before{ - content: '\2b67\20'; -} -.page>.main .detail.example:before{ - content: '\23f5\20'; -} - - -/* declarations */ -.page>.main .scope-decls{ - width: 100%; - border: none; -} -.page>.main .scope-decls tr{ - border: inherit; - border-bottom: 1px solid #cccccc; - background: none !important; -} -.page>.main .scope-decls tr:last-child{ - border-bottom: none; -} -.page>.main .scope-decls td{ - border: inherit; -} -.page>.main .scope-decls td:first-child{ - width: 14rem; - text-transform: uppercase; -} -.page>.main .scope-decls ul{ - margin: 0 0 1rem 0; - list-style: none; -} - diff --git a/docs/templates/cerberusx3b/scope_template.html b/docs/templates/cerberusx3b/scope_template.html deleted file mode 100644 index 5acc45a0..00000000 --- a/docs/templates/cerberusx3b/scope_template.html +++ /dev/null @@ -1,507 +0,0 @@ - -

${KIND} ${IDENT}${DECL}

- -${IF SUMMARY} -

- ${SUMMARY}${IF DESCRIPTION} More...${ENDIF} -

-${ENDIF} - -

Declarations

- -${IF IMPORTS} - - - ${FOR IMPORTS} - - - - - ${NEXT} -
Imports
${IDENT}${SUMMARY}
-${ENDIF} -${IF IMPORTED_BY} - - - - - -
Imported By
- ${FOR IMPORTED_BY} - ${IDENT}${IF NOT LAST} , ${ENDIF} - ${NEXT} -
- Please note that only documented modules are listed here, there might be undocumented modules that import this one. -${ENDIF} -${IF CLASSES} - - - ${FOR CLASSES} - - - - - ${NEXT} -
Classes
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF INTERFACES} - - - ${FOR INTERFACES} - - - - - ${NEXT} -
Interfaces
${IDENT}${SUMMARY}
-${ENDIF} -${IF EXTENDS} - - - ${FOR EXTENDS} - - - - - ${NEXT} -
Extends
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF EXTENDED_BY} - - - - - -
Extended By
- ${FOR EXTENDED_BY} - ${IDENT}${IF NOT LAST} , ${ENDIF} - ${NEXT} -
- Please note that only documented classes are listed here, there might be undocumented classes that extend this one. -${ENDIF} -${IF IMPLEMENTS} - - - ${FOR IMPLEMENTS} - - - - - ${NEXT} -
Implements
${IDENT}${SUMMARY}
-${ENDIF} -${IF IMPLEMENTED_BY} - - - - - -
Implemented By
- ${FOR IMPLEMENTED_BY} - ${IDENT}${IF NOT LAST} , ${ENDIF} - ${NEXT} -
- Please note that only documented classes are listed here, there might be undocumented classes that implement this interface. -${ENDIF} -${IF CONSTS} - - - ${FOR CONSTS} - - - - - ${NEXT} -
Constants
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF ENUMS} - - - ${FOR ENUMS} - - - - - ${NEXT} -
Enumerates
- ${FOR ENUM_ELEMENTS} - ${IDENT}${IF NOT LAST} , ${ENDIF} - ${NEXT} - ${SUMMARY}
-${ENDIF} -${IF GLOBALS} - - - ${FOR GLOBALS} - - - - - ${NEXT} -
Globals
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF FIELDS} - - - ${FOR FIELDS} - - - - - ${NEXT} -
Fields
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF PROPERTIES} - - - ${FOR PROPERTIES} - - - - - ${NEXT} -
Properties
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF CTORS} - - - ${FOR CTORS} - - - - - ${NEXT} -
Constructors
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF METHODS} - - - ${FOR METHODS} - - - - - ${NEXT} -
Methods
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF FUNCTIONS} - - - ${FOR FUNCTIONS} - - - - - ${NEXT} -
Functions
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF INHERITED_CONSTS} - - - ${FOR INHERITED_CONSTS} - - - - - ${NEXT} -
Inherited Constants
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF INHERITED_ENUMS} - - - ${FOR INHERITED_ENUMS} - - - - - ${NEXT} -
Inherited Enumerates
- ${FOR ENUM_ELEMENTS} - ${IDENT}${IF NOT LAST} , ${ENDIF} - ${NEXT} - ${SUMMARY}
-${ENDIF} -${IF INHERITED_GLOBALS} - - - ${FOR INHERITED_GLOBALS} - - - - - ${NEXT} -
Inherited Globals
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF INHERITED_FIELDS} - - - ${FOR INHERITED_FIELDS} - - - - - ${NEXT} -
Inherited Fields
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF INHERITED_PROPERTIES} - - - ${FOR INHERITED_PROPERTIES} - - - - - ${NEXT} -
Inherited Properties
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF INHERITED_CTORS} - - - ${FOR INHERITED_CTORS} - - - - - ${NEXT} -
Inherited Constructors
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF INHERITED_METHODS} - - - ${FOR INHERITED_METHODS} - - - - - ${NEXT} -
Inherited Methods
${IDENT}${DECL}${SUMMARY}
-${ENDIF} -${IF INHERITED_FUNCTIONS} - - - ${FOR INHERITED_FUNCTIONS} - - - - - ${NEXT} -
Inherited Functions
${IDENT}${DECL}${SUMMARY}
-${ENDIF} - -${IF DESCRIPTION} -
- -

Detailed Discussion

- ${DESCRIPTION} - ${IF LINKS} - See also - ${LINKS} - ${ENDIF} - ${IF EXAMPLE} - Example - ${EXAMPLE} - ${ENDIF} -
-
-${ENDIF} - -${IF CONSTS} -
-

Constants Documentation

- ${FOR CONSTS} -
- -
Const ${IDENT}${XDECL}
- ${DESCRIPTION} - ${IF LINKS} - See also - ${LINKS} - ${ENDIF} - ${IF EXAMPLE} - Example - ${EXAMPLE} - ${ENDIF} -
- ${NEXT} -
-
-${ENDIF} -${IF ENUMS} -
-

Enumerates Documentation

- ${FOR ENUMS} -
- ${FOR ENUM_ELEMENTS}${NEXT} -
Enumerate ${FOR ENUM_ELEMENTS}${IDENT}${IF XDECL}${XDECL}${ENDIF}${IF NOT LAST}, ${ENDIF}${NEXT}
- ${DESCRIPTION} - ${IF LINKS} - See also - ${LINKS} - ${ENDIF} - ${IF EXAMPLE} - Example - ${EXAMPLE} - ${ENDIF} -
- ${NEXT} -
-
-${ENDIF} -${IF GLOBALS} -
-

Globals Documentation

- ${FOR GLOBALS} -
- -
Global ${IDENT}${XDECL}
- ${DESCRIPTION} - ${IF LINKS} - See also - ${LINKS} - ${ENDIF} - ${IF EXAMPLE} - Example - ${EXAMPLE} - ${ENDIF} -
- ${NEXT} -
-
-${ENDIF} -${IF FIELDS} -
-

Fields Documentation

- ${FOR FIELDS} -
- -
Field ${IDENT}${XDECL}
- ${DESCRIPTION} - ${IF LINKS} - See also - ${LINKS} - ${ENDIF} - ${IF EXAMPLE} - Example - ${EXAMPLE} - ${ENDIF} -
- ${NEXT} -
-
-${ENDIF} -${IF PROPERTIES} -
-

Properties Documentation

- ${FOR PROPERTIES} -
- -
Method ${IDENT}${XDECL} Property
- ${DESCRIPTION} - ${IF PARAMETERS} - Parameters - ${PARAMETERS} - ${ENDIF} - ${IF RETURNS} - Returns - ${RETURNS} - ${ENDIF} - ${IF LINKS} - See also - ${LINKS} - ${ENDIF} - ${IF EXAMPLE} - Example - ${EXAMPLE} - ${ENDIF} -
- ${NEXT} -
-
-${ENDIF} -${IF CTORS} -
-

Constructors Documentation

- ${FOR CTORS} -
- -
Method ${IDENT}${XDECL}
- ${DESCRIPTION} - ${IF PARAMETERS} - Parameters - ${PARAMETERS} - ${ENDIF} - ${IF RETURNS} - Returns - ${RETURNS} - ${ENDIF} - ${IF LINKS} - See also - ${LINKS} - ${ENDIF} - ${IF EXAMPLE} - Example - ${EXAMPLE} - ${ENDIF} -
- ${NEXT} -
-
-${ENDIF} -${IF METHODS} -
-

Methods Documentation

- ${FOR METHODS} -
- -
Method ${IDENT}${XDECL}
- ${DESCRIPTION} - ${IF PARAMETERS} - Parameters - ${PARAMETERS} - ${ENDIF} - ${IF RETURNS} - Returns - ${RETURNS} - ${ENDIF} - ${IF LINKS} - See also - ${LINKS} - ${ENDIF} - ${IF EXAMPLE} - Example - ${EXAMPLE} - ${ENDIF} -
- ${NEXT} -
-
-${ENDIF} -${IF FUNCTIONS} -
-

Functions Documentation

- ${FOR FUNCTIONS} -
- -
Function ${IDENT}${XDECL}
- ${DESCRIPTION} - ${IF PARAMETERS} - Parameters - ${PARAMETERS} - ${ENDIF} - ${IF RETURNS} - Returns - ${RETURNS} - ${ENDIF} - ${IF LINKS} - See also - ${LINKS} - ${ENDIF} - ${IF EXAMPLE} - Example - ${EXAMPLE} - ${ENDIF} -
- ${NEXT} -
-
-${ENDIF} diff --git a/examples/mojo/mak/bbgametest/bbgametest.cxs b/examples/mojo/mak/bbgametest/bbgametest.cxs index aade66b9..19857e3e 100644 --- a/examples/mojo/mak/bbgametest/bbgametest.cxs +++ b/examples/mojo/mak/bbgametest/bbgametest.cxs @@ -30,8 +30,8 @@ Class GameDelegate Extends BBGameDelegate Print "KeyEvent: event="+event+", data="+data End - Method MouseEvent:Void( event:Int,data:Int,x:Float,y:Float ) - Print "MouseEvent: event="+event+", data="+data+", x="+x+", y="+y + Method MouseEvent:Void( event:Int,data:Int,x:Float,y:Float, z:Float ) + Print "MouseEvent: event="+event+", data="+data+", x="+x+", y="+y+", z="+z End Method TouchEvent:Void( event:Int,data:Int,x:Float,y:Float ) diff --git a/examples/mojo/mak/dynamicimage/dynamicimage.cxs b/examples/mojo/mak/dynamicimage/dynamicimage.cxs index f7fb2364..43209cf4 100644 --- a/examples/mojo/mak/dynamicimage/dynamicimage.cxs +++ b/examples/mojo/mak/dynamicimage/dynamicimage.cxs @@ -1,4 +1,3 @@ - 'Ok, looks a bit crap and doesn't make much sense, but it's just a test of offset, pitch, byte order etc... ' Import mojo @@ -21,9 +20,9 @@ Class MyApp Extends App If KeyHit( KEY_SPACE ) fullscreen=Not fullscreen If fullscreen - GlfwGame.GetGlfwGame().SetGlfwWindow( 1024,768,8,8,8,0,0,0,True ) + SetDeviceWindow( 1024, 768, 1 ) Else - GlfwGame.GetGlfwGame().SetGlfwWindow( 640,480,8,8,8,0,0,0,False ) + SetDeviceWindow( 640, 480, 4 ) Endif End #Endif diff --git a/examples/mojo2/tween/tween_example.cxs b/examples/mojo2/tween/tween_example.cxs new file mode 100644 index 00000000..f36e9726 --- /dev/null +++ b/examples/mojo2/tween/tween_example.cxs @@ -0,0 +1,169 @@ +Strict + +Import mojo2 +Import brl.tween + +'******************************************************************* +' Define the tweenExample that extends the App Class. +Class tweenExample Extends App + Field cnvs:Canvas + Field tw:Tween[6] + Field selected_tween:Int + Field tweens:String[] = ["LINEAR","BEZIER","CUSTOM","CURVE","BOUNCE (EASEOUT)","ELASTIC (EASEINOUT)"] + Field loop:Bool,yoyo:Bool + + Method OnCreate:Int() + SetUpdateRate(60) + cnvs = New Canvas + + ' linear tween + tw[0] = New Tween(Tween.LINEAR,2000) + tw[0].SetRange(100,540) + + ' cubic bezier tween + tw[1] = New Tween(Tween.BEZIER,2000) + tw[1].SetBezierPoints(0.2,0.6,0.7,1) + tw[1].SetRange(100,540) + + ' custom tween + tw[2] = New Tween(Tween.CUSTOM,2000) + tw[2].SetCustomData([0,0.1,0.9,0.8,0.4,0.7,1]) + tw[2].SetRange(100,540) + + ' curve tween + tw[3] = New Tween(Tween.CURVE,2000) + tw[3].SetCurve(0) + tw[3].SetRange(100,540) + + ' bounce tween + tw[4] = New Tween(Tween.BOUNCE,2000) + tw[4].SetEasing(Tween.EASEOUT) + tw[4].SetRange(100,540) + + ' elastic tween + tw[5] = New Tween(Tween.ELASTIC,2000) + tw[5].SetEasing(Tween.EASEINOUT) + tw[5].SetRange(100,540) + + loop = False + yoyo = False + selected_tween = 0 + tw[selected_tween].Start() + tw[selected_tween].SetLoop(loop) + tw[selected_tween].SetYoYo(yoyo) + + Return 0 + End + + Method OnUpdate:Int() + ' start tween again + If KeyHit(KEY_SPACE) Then tw[selected_tween].Start() + + ' change tween + If KeyHit(KEY_1) + selected_tween=(selected_tween+1) Mod tw.Length() + tw[selected_tween].Start() + tw[selected_tween].SetLoop(loop) + tw[selected_tween].SetYoYo(yoyo) + End + + ' randdom custom tween + If KeyHit(KEY_R) + Select selected_tween + Case 1 + tw[1].SetBezierPoints(0.25,Rnd(1),0.75,Rnd(1)) + Case 2 + CreateRandomTween() + Case 3 + tw[3].SetCurve(Rnd(1)) + End + tw[selected_tween].Start() + tw[selected_tween].SetLoop(loop) + tw[selected_tween].SetYoYo(yoyo) + End + + ' loop tween + If KeyHit(KEY_L) + loop = Not loop + tw[selected_tween].SetLoop(loop) + End + + ' yoyo tween + If KeyHit(KEY_Y) + yoyo = Not yoyo + tw[selected_tween].SetYoYo(yoyo) + End + + Return 0 + End + + Method CreateRandomTween:Void() + Local y:Float[Rnd(20)+3] + For Local i:Int = 0 Until y.Length() + y[i] = Rnd(1) + Next + tw[2].SetCustomData(y) + End + + Method OnRender:Int() + ' Clear the canvas with a black color. + cnvs.Clear (0,0.5,0) + + cnvs.SetColor 1,1,1 + cnvs.DrawText "Tween."+tweens[selected_tween],320,80,0.5,0.5 + + cnvs.SetColor 0,0.2,0 + cnvs.DrawRect 100,100,440,20 + + ' draw a circle using the Tween Range Value as the x co-ordinate + cnvs.SetColor 1,1,1 + cnvs.DrawOval tw[selected_tween].RangeValue()-10,100,20,20 + + DrawTween(220,180,200) + + cnvs.SetColor 1,1,1 + cnvs.DrawText "1 - Next Tween",10,400 + cnvs.DrawText "L - Toggle Looping",10,420 + cnvs.DrawText "Y - Toggle YoYoing",10,440 + cnvs.DrawText "SPACE - Restart Tween",330,400 + + Select selected_tween + Case 1,2,3 + cnvs.DrawText "R - Randomise Tween",330,420 + End + + cnvs.Flush + + Return 0 + End + + Method DrawTween:Void(x:Float,y:Float,size:Float) + cnvs.SetColor 1,1,1 + cnvs.DrawText "x",x+size+10,y+size,0.5,0.5 + cnvs.DrawText "y",x-1,y-10,0.5,0.5 + cnvs.DrawRect x-1,y,size+1,size+1 + + cnvs.SetColor 0,0.2,0 + cnvs.DrawRect x,y,size,size + + cnvs.SetColor 1,0,0 + Local tx:Float = x+tw[selected_tween].X()*size + Local ty:Float = y+size-tw[selected_tween].TweenValueAtX(tw[selected_tween].X())*size + cnvs.DrawLine x,ty,tx,ty + cnvs.DrawLine tx,ty,tx,y+size + + cnvs.SetColor 1,1,1 + Local prey:Float = tw[selected_tween].TweenValueAtX(0) + For Local i:Float = 1 Until size + cnvs.DrawLine x+i-1,y+size-prey*size,x+i,y+size-tw[selected_tween].TweenValueAtX(i/size)*size + prey = tw[selected_tween].TweenValueAtX(i/size) + Next + cnvs.SetColor 1,0,0 + cnvs.DrawOval tx-5,ty-5,10,10 + End +End + +Function Main:Int() + New tweenExample + Return 0 +End \ No newline at end of file diff --git a/license b/license index 331936ff..7341c363 100644 --- a/license +++ b/license @@ -1,7 +1,8 @@ The zlib/libpng License ======================= -Copyright (c) 2019 Michael Hartlef +Cerberus X - Copyright (c) 2020 Michael Hartlef +Monkey X - Copyright (c) 2013 Blitz Research Ltd This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of diff --git a/modules/brl/cerberusdoc/brl.cerberusdoc b/modules/brl/cerberusdoc/brl.cerberusdoc index 07809def..249f7e4b 100644 --- a/modules/brl/cerberusdoc/brl.cerberusdoc +++ b/modules/brl/cerberusdoc/brl.cerberusdoc @@ -1,8 +1,14 @@ # Module brl +# Import brl.admob + +# Import brl.cerberusstore + # Import brl.databuffer +# Import brl.gamecenter + # Import brl.stream # Import brl.datastream @@ -17,10 +23,29 @@ # Import brl.filestream +# Import brl.filepath + +# Import brl.filesystem + # Import brl.httprequest +# Import brl.url + # Import brl.requesters +# Import brl.tween + +# Import brl.pool + +# Import brl.process + +# Import brl.markdown + +# Import brl.json + + + + The brl module is a set of utility classes and functions. To import all modules in brl, simply add "Import brl" at the top of your program. diff --git a/modules/brl/cerberusdoc/databuffer.cerberusdoc b/modules/brl/cerberusdoc/databuffer.cerberusdoc index 2094b290..8c531f18 100644 --- a/modules/brl/cerberusdoc/databuffer.cerberusdoc +++ b/modules/brl/cerberusdoc/databuffer.cerberusdoc @@ -20,7 +20,7 @@ If @data is Null, the data load failed. Databuffer objects provide storage for arbitrary data. -Data may be written to a databufffer using one of the 'poke' methods, and read from a databuffer using one of the 'peek' methods. +Data may be written to a databuffer using one of the 'poke' methods, and read from a databuffer using one of the 'peek' methods. Parameters that specify buffer addresses or array indices for data transfers are not currently range checked. In general, you should always ensure that these are always valid, ie: >=0 And <=length of the buffer/array. Any transfer count parameters should always be >=0, but will always be clipped to make sure no overreads or overwrites occur. diff --git a/modules/brl/cerberusdoc/requesters.cerberusdoc b/modules/brl/cerberusdoc/requesters.cerberusdoc index 0d3fb039..5f3719e4 100644 --- a/modules/brl/cerberusdoc/requesters.cerberusdoc +++ b/modules/brl/cerberusdoc/requesters.cerberusdoc @@ -1,7 +1,7 @@ # Module brl.requesters -The requesters module allows you to use simple modal requesters with the glfw3 target on Mac and Windows only! +The requesters module allows you to use simple modal requesters with the glfw3 target. # Function Notify:Void( title:String,text:String,serious:Bool ) @@ -53,3 +53,7 @@ End # Function RequestDir:String( title:String,dir:String="" ) RequestDir activates a modal directory requester dialog. + +# Function RequestColor:Int( ) + +RequestColor returns the RGB value of a selected color. \ No newline at end of file diff --git a/modules/brl/cerberusdoc/tween.cerberusdoc b/modules/brl/cerberusdoc/tween.cerberusdoc new file mode 100644 index 00000000..df16fb08 --- /dev/null +++ b/modules/brl/cerberusdoc/tween.cerberusdoc @@ -0,0 +1,157 @@ + +# Module tween + +The tween module provides simple support for loops using the built in interpolation functions. +Some interpolation functions have easing in, easing out and easing in and out abilities. + +# Class tween.Tween + +The Tween class provides simple support for tweening with timing and loops. + +Each Tween will start at p(0,0) and end at p(1,1). A @CUSTOM interpolation is the only one that can overide p(0,y) and p(1,y). + +Example: +
+Strict
+Import mojo2
+Import tween
+
+Class myClass Extends App
+	Field canvas:Canvas
+	Field tw:Tween
+	
+	Method OnCreate:Int()
+		SetUpdateRate(60)
+		canvas = New Canvas
+		tw = New Tween(Tween.ELASTIC,2000)
+		tw.SetLoop(True)
+		tw.SetRange(0,300)
+		tw.SetEasing(Tween.EASEOUT)
+		tw.Start()
+		
+		Return 0
+	End
+
+	Method OnUpdate:Int()
+		Return 0
+	End
+
+	Method OnRender:Int()
+		canvas.Clear (0,0.5,0)	
+		canvas.DrawText( String("Cerberus X~nTweening").Split("~n")),DeviceWidth()/2,400-tw.RangeValue(),0.5,0.5
+		canvas.Flush
+
+		Return 0
+	End
+End
+
+Function Main:Int()
+	New myClass
+	Return 0
+End
+ + +# Method New(interpolation:Int, duration:Int) + +Setup a new Tween. + +* @interpolation can be either @Tween.@LINEAR, @Tween.@CUSTOM, @Tween.@BEZIER, @Tween.@CURVE, @Tween.@ELASTIC, @Tween.@BOUNCE, @Tween.@BACK +* @duration is the length of the tween in Milli-seconds + +For interpolation styles see [[cerberus.interpolate]] + +# Method RangeValue:Float() + +Get the value in the range of the current Tween. + +# Method RangeValueAtX:Float(x:Float) + +Get the value in the range of the Tween when x=@x. + +# Method RangeValueAtTime:Float(time:Float) + +Get the value in the range of the Tween when time=@time. + +Links: [[SetRange]] + +# Method SetRange:Void(startValue:Float, endValue:Float) + +Set the range of the values of the tween. @RangeValue will return values between @startValue and @endValue + +Links: [[RangeValue]] + +# Method TweenValue:Float() + +Return the current tween value. This is usually between 0 and 1. + +# Method TweenValueAtX:Float(x:Float) + +Returns the tween value when x is @x. @x must be between 0 and 1. This doesnt set the x posiiton of the tween. + +# Method TweenValueAtTime:Float(time:Float) + +Returns the tween value when time is @time. This doesnt set the time or duration. + +# Method Start:Void() + +Starts the current tween + +# Method Stop:Void() + +Stops the current tween + +# Method Resume:Void() + +Resumes the currently stopped tween + +# Method SetLoop:Void(flag:Bool) + +Sets looping action. + +Links: [[GetLoop]] + +# Method SetYoYo:Void(flag:Bool) + +Sets YoYo-ing. YoYo-ing will only wotk if looping is set to @True + +Links: [[GetYoYo]] + +# Method GetLoop:Bool() + +Returns @True if looping is set to True + +# Method GetYoYo:Bool() + +Returns @True if YoYo is set to True + +# Method X:Float() + +Returns the x value of the current tween. @x is from 0-1 + + +# Method SetEasing:Void(easing_mode:Int) + +Sets the easing mode for the Tween. + +@easing_mode can be @Tween.@EASEIN, @Tween.@EASEOUT, @Tween.@EASEINOUT + +Only the following tween modes have easing modes: @BOUNCE, @BACK, @ELASTIC + +# Method SetBezierPoints:Void(pXa:Float, pYA:Float, pXb:Float, pYb:Float) + +Sets the 2 control points for the Bezier curve. + +* Control point 1 = (@pXa, @pYa) +* Control point 2 = (@pXb, @pYb) + +# Method SetCustomData:Void(dataY:Float[]) + +Sets the y data for the custom interpolation. The Tween will pass through each @dataY point + +# Method SetCurve:Void(curveY:Float) + +Sets the curve iterpolation point so that the curve passes through p(0.5,@curveY) + +# Method SetDuration:Void(duration:Int) + +Sets a new duration for the tween. @duration is in Millisecs \ No newline at end of file diff --git a/modules/brl/cerberusstore.cxs b/modules/brl/cerberusstore.cxs index 04714010..92562fb4 100644 --- a/modules/brl/cerberusstore.cxs +++ b/modules/brl/cerberusstore.cxs @@ -8,7 +8,7 @@ Import asyncevent #LIBS+="StoreKit.framework" Import "native/cerberusstore.ios.cpp" #Elseif TARGET="android" -#SRCS+="${CD}/native/android_iab/src/com/android/vending/billing/IInAppBillingService.aidl" +#SRCS+="${CD}/native/android_iab/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl;" #ANDROID_MANIFEST_MAIN+="" Import "native/cerberusstore.android.java" #Else If TARGET="winrt" diff --git a/modules/brl/native/android_iab/src/com/android/vending/billing/IInAppBillingService.aidl b/modules/brl/native/android_iab/src/com/android/vending/billing/IInAppBillingService.aidl deleted file mode 100644 index 2a492f78..00000000 --- a/modules/brl/native/android_iab/src/com/android/vending/billing/IInAppBillingService.aidl +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.vending.billing; - -import android.os.Bundle; - -/** - * InAppBillingService is the service that provides in-app billing version 3 and beyond. - * This service provides the following features: - * 1. Provides a new API to get details of in-app items published for the app including - * price, type, title and description. - * 2. The purchase flow is synchronous and purchase information is available immediately - * after it completes. - * 3. Purchase information of in-app purchases is maintained within the Google Play system - * till the purchase is consumed. - * 4. An API to consume a purchase of an inapp item. All purchases of one-time - * in-app items are consumable and thereafter can be purchased again. - * 5. An API to get current purchases of the user immediately. This will not contain any - * consumed purchases. - * - * All calls will give a response code with the following possible values - * RESULT_OK = 0 - success - * RESULT_USER_CANCELED = 1 - user pressed back or canceled a dialog - * RESULT_BILLING_UNAVAILABLE = 3 - this billing API version is not supported for the type requested - * RESULT_ITEM_UNAVAILABLE = 4 - requested SKU is not available for purchase - * RESULT_DEVELOPER_ERROR = 5 - invalid arguments provided to the API - * RESULT_ERROR = 6 - Fatal error during the API action - * RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned - * RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned - */ -interface IInAppBillingService { - /** - * Checks support for the requested billing API version, package and in-app type. - * Minimum API version supported by this interface is 3. - * @param apiVersion the billing version which the app is using - * @param packageName the package name of the calling app - * @param type type of the in-app item being purchased "inapp" for one-time purchases - * and "subs" for subscription. - * @return RESULT_OK(0) on success, corresponding result code on failures - */ - int isBillingSupported(int apiVersion, String packageName, String type); - - /** - * Provides details of a list of SKUs - * Given a list of SKUs of a valid type in the skusBundle, this returns a bundle - * with a list JSON strings containing the productId, price, title and description. - * This API can be called with a maximum of 20 SKUs. - * @param apiVersion billing API version that the Third-party is using - * @param packageName the package name of the calling app - * @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST" - * @return Bundle containing the following key-value pairs - * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on - * failure as listed above. - * "DETAILS_LIST" with a StringArrayList containing purchase information - * in JSON format similar to: - * '{ "productId" : "exampleSku", "type" : "inapp", "price" : "$5.00", - * "title : "Example Title", "description" : "This is an example description" }' - */ - Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle); - - /** - * Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU, - * the type, a unique purchase token and an optional developer payload. - * @param apiVersion billing API version that the app is using - * @param packageName package name of the calling app - * @param sku the SKU of the in-app item as published in the developer console - * @param type the type of the in-app item ("inapp" for one-time purchases - * and "subs" for subscription). - * @param developerPayload optional argument to be sent back with the purchase information - * @return Bundle containing the following key-value pairs - * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on - * failure as listed above. - * "BUY_INTENT" - PendingIntent to start the purchase flow - * - * The Pending intent should be launched with startIntentSenderForResult. When purchase flow - * has completed, the onActivityResult() will give a resultCode of OK or CANCELED. - * If the purchase is successful, the result data will contain the following key-value pairs - * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on - * failure as listed above. - * "INAPP_PURCHASE_DATA" - String in JSON format similar to - * '{"orderId":"12999763169054705758.1371079406387615", - * "packageName":"com.example.app", - * "productId":"exampleSku", - * "purchaseTime":1345678900000, - * "purchaseToken" : "122333444455555", - * "developerPayload":"example developer payload" }' - * "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that - * was signed with the private key of the developer - * TODO: change this to app-specific keys. - */ - Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type, - String developerPayload); - - /** - * Returns the current SKUs owned by the user of the type and package name specified along with - * purchase information and a signature of the data to be validated. - * This will return all SKUs that have been purchased in V3 and managed items purchased using - * V1 and V2 that have not been consumed. - * @param apiVersion billing API version that the app is using - * @param packageName package name of the calling app - * @param type the type of the in-app items being requested - * ("inapp" for one-time purchases and "subs" for subscription). - * @param continuationToken to be set as null for the first call, if the number of owned - * skus are too many, a continuationToken is returned in the response bundle. - * This method can be called again with the continuation token to get the next set of - * owned skus. - * @return Bundle containing the following key-value pairs - * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on - * failure as listed above. - * "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs - * "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information - * "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures - * of the purchase information - * "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the - * next set of in-app purchases. Only set if the - * user has more owned skus than the current list. - */ - Bundle getPurchases(int apiVersion, String packageName, String type, String continuationToken); - - /** - * Consume the last purchase of the given SKU. This will result in this item being removed - * from all subsequent responses to getPurchases() and allow re-purchase of this item. - * @param apiVersion billing API version that the app is using - * @param packageName package name of the calling app - * @param purchaseToken token in the purchase information JSON that identifies the purchase - * to be consumed - * @return 0 if consumption succeeded. Appropriate error values for failures. - */ - int consumePurchase(int apiVersion, String packageName, String purchaseToken); -} diff --git a/targets/android/template/gradletemplate/app/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl b/modules/brl/native/android_iab/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl similarity index 100% rename from targets/android/template/gradletemplate/app/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl rename to modules/brl/native/android_iab/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl diff --git a/modules/brl/native/requesters.cpp b/modules/brl/native/requesters.cpp index df6794c0..b0ede69a 100644 --- a/modules/brl/native/requesters.cpp +++ b/modules/brl/native/requesters.cpp @@ -380,4 +380,73 @@ String bbRequestDir( String title,String dir ){ return str; } +#else + +#include +/* +String bbRequestFile2( String title,String filter,int save,String path ){ + + String ps; + if( save ){ + ps = tinyfd_saveFileDialog (OS_STR(title), OS_STR(path), 0, NULL, NULL); + }else{ + ps = tinyfd_openFileDialog (OS_STR(title), OS_STR(path), 0, NULL, NULL,0); + } + + return ps; +} +*/ + +void bbNotify( String title,String text,int serious ){ + + tinyfd_messageBox( OS_STR( title ),OS_STR( text ),"ok",serious ? "error" : "info",1 ); +} + +int bbConfirm( String title,String text,int serious ){ + + return tinyfd_messageBox( OS_STR( title ),OS_STR( text ),"okcancel",serious ? "error" : "info",1 ); +} + +int bbProceed( String title,String text,int serious ){ + + // Ok, no yesnocancal in tinyfd so we'll use kdialog... + + int result=tinyfd_messageBox( OS_STR( title ),OS_STR( text ),"yesnocancel",serious ? "error" : "info",1 ); + + return result==2 ? -1 : result; + +} + +String bbRequestFile( String title,String exts, int save,String path ){ + char const * ps; + if( path=="" ) path="."; + + if( save ){ + ps = tinyfd_saveFileDialog( OS_STR( title ),OS_STR( path ),0,0,0 ); + }else{ + ps = tinyfd_openFileDialog( OS_STR( title ),OS_STR( path ),0,0,0,0 ); + } + if (! ps) { + return ""; + }else{ + return ps; + } + +} + +String bbRequestDir( String title,String dir ){ + char const * ps; + + if( dir=="" ) dir="."; + + ps = tinyfd_selectFolderDialog( OS_STR( title ),OS_STR( dir ) ); + if (! ps) { + return ""; + }else{ + return ps; + } +} + + + #endif diff --git a/modules/brl/requesters.cxs b/modules/brl/requesters.cxs index 99becd4e..6addfdd4 100644 --- a/modules/brl/requesters.cxs +++ b/modules/brl/requesters.cxs @@ -1,5 +1,6 @@ -#If TARGET<>"glfw" Or (HOST<>"winnt" And HOST<>"macos") +'#If TARGET<>"glfw" Or (HOST<>"winnt" And HOST<>"macos") +#If TARGET<>"glfw" #Error "Requesters module unavailable on this target" #Endif @@ -7,11 +8,12 @@ Import "native/requesters.cpp" Extern + Function Notify:Void( title:String,text:String,serious:Bool=False )="bbNotify" Function Confirm:Bool( title:String,text:String,serious:Bool=False )="bbConfirm" -Function Proceed:Int( title:String,text:String,serious:Bool=false )="bbProceed" +Function Proceed:Int( title:String,text:String,serious:Bool=False )="bbProceed" Function RequestFile:String( title:String,extensions:String="",save:Bool=False,file:String="" )="bbRequestFile" diff --git a/modules/brl/tween.cxs b/modules/brl/tween.cxs new file mode 100644 index 00000000..baf2a148 --- /dev/null +++ b/modules/brl/tween.cxs @@ -0,0 +1,227 @@ +Strict + +Import mojo.app +Import cerberus.interpolate + +Class Tween + Public + Const LINEAR:=0 + Const BEZIER:=1 + Const CUSTOM:=2 + Const CURVE:=3 + Const SIN:=4 + Const FLATS:=5 + Const ELASTIC:=6 + Const BOUNCE:=7 + Const BACK:=8 + + Const EASEIN:=0 + Const EASEOUT:=1 + Const EASEINOUT:=2 + + Private + Field range_start:Int + Field range_end:Int + Field range:Float + + Field interpolation:Int + Field easing_mode:Int + + Field duration:Int + Field start_time:Int + Field old_time:Int + Field time:Int + + Field active:Bool + Field loop:Bool + Field yoyo:Bool + Field custom_data:Float[] + Field bezier_data:Float[6] + Field curve:Float + Field x:Float + Field value:Float + + Public + Method New(interpolation:Int,duration:Int) + Init(interpolation,duration) + End + + Method RangeValue:Float() + Return range_start + range * TweenValue() + End + + Method RangeValueAtX:Float(x:Float) + Return range_start + range * TweenValue(x) + End + + Method RangeValueAtTime:Float(time:Float) + Return range_start + range * TweenValue(time) + End + + Method SetRange:Void(startValue:Int,endValue:Int) + range_start = startValue + range_end = endValue + + range = endValue - startValue + End + + Method SetEasing:Void(easing:Int) + #If CONFIG="debug" + If interpolation<6 Then Print "No Easing mode for this interpolation" + #End + easing_mode = easing + End + + Method Start:Void() + start_time = Millisecs() + active = True + End + + Method Stop:Void() + old_time = Millisecs() + active = False + End + + Method Resume:Void() + If old_time = -1 + Start() + Else + start_time = Millisecs() - (old_time-start_time) + active = True + End + End + + Method SetLoop:Void(flag:Bool) + loop = flag + End + + Method GetLoop:Bool() + Return loop + End + + Method SetYoYo:Void(flag:Bool) + yoyo = flag + End + + Method GetYoYo:Bool() + Return yoyo + End + + Method X:Float() + x = time/Float(duration) + Return x + End + + Method TweenValue:Float() + Update() + Return value + End + + Method TweenValueAtX:Float(x:Float) + Return GetTween(x) + End + + Method TweenValueAtTime:Float(time:Float) + Return GetTween(time/Float(duration)) + End + + Method SetCustomData:Void(custom_data:Float[]) + Self.custom_data = custom_data + End + + Method SetBezierPoints:Void(pA:Float, pB:Float, pC:Float, pD:Float, pPrecision:Float = 0.0001) + bezier_data = [pA, pB, pC, pD, pPrecision] + End + + Method SetCurve:Void(pYA:Float) + curve = pYA + End + + Method SetDuration:Void(duration:Int) + Self.duration = duration + End + + Private + Method Init:Void(interpolation:Int,duration:Int) + Self.duration = duration + Self.interpolation = interpolation + + time = 0 + active = False + SetLoop(False) + SetYoYo(False) + + SetRange(0,1) + End + + Method Update:Void() + If active = False Then Return + time = Millisecs() - start_time + + If loop=True + If yoyo=True + time = time Mod (2*duration) + If time>duration + time = 2*duration - time + End + Else + time = time Mod duration + End + Else + If time>duration Then time=duration + End + + x = time/Float(duration) + value = GetTween(x) + End + + Method GetTween:Float(t:Float) + Select interpolation + Case LINEAR + Return InterpolateLin(0,1,t) + Case BEZIER + #If CONFIG="debug" + If bezier_data.Length()=0 Then Error("Bezier points not set. Use Tween.SetBezierPoints()") + #End + Return InterpolateCubicBezier(0,1,bezier_data[0],bezier_data[1],bezier_data[2],bezier_data[3],t,bezier_data[4]) + Case CUSTOM + #If CONFIG="debug" + If custom_data.Length()=0 Then Error("Custom data not set. Use Tween.SetCustomData()") + If custom_data.Length()=1 Then Error("Not enough custom point data. There must be at least 2 points") + #End + Return InterpolateCustomLine(custom_data,t) + Case CURVE + Return InterpolateCurve(0,1,curve,t) + Case SIN + Return InterpolateSin(0,1,t) + Case ELASTIC + Select easing_mode + Case EASEIN + Return InterpolateElasticEaseIn(0,1,t) + Case EASEOUT + Return InterpolateElasticEaseOut(0,1,t) + Case EASEINOUT + Return InterpolateElasticEaseInOut(0,1,t) + End + Case BOUNCE + Select easing_mode + Case EASEIN + Return InterpolateBounceEaseIn(0,1,t) + Case EASEOUT + Return InterpolateBounceEaseOut(0,1,t) + Case EASEINOUT + Return InterpolateBounceEaseInOut(0,1,t) + End + Case BACK + Select easing_mode + Case EASEIN + Return InterpolateBackEaseIn(0,1,t) + Case EASEOUT + Return InterpolateBackEaseOut(0,1,t) + Case EASEINOUT + Return InterpolateBackEaseInOut(0,1,t) + End + End + Return 0 + End +End \ No newline at end of file diff --git a/modules/cerberus/cerberusdoc/cerberus.cerberusdoc b/modules/cerberus/cerberusdoc/cerberus.cerberusdoc index 0f390868..622ae9db 100644 --- a/modules/cerberus/cerberusdoc/cerberus.cerberusdoc +++ b/modules/cerberus/cerberusdoc/cerberus.cerberusdoc @@ -3,6 +3,10 @@ # Import cerberus.boxes +# Import cerberus.deque + +# Import cerberus.interpolate + # Import cerberus.lang # Import cerberus.list @@ -13,8 +17,6 @@ # Import cerberus.random -# Import cerberus.interpolate - # Import cerberus.set # Import cerberus.stack diff --git a/modules/cerberus/cerberusdoc/interpolate.cerberusdoc b/modules/cerberus/cerberusdoc/interpolate.cerberusdoc index dffce294..83cb51b5 100644 --- a/modules/cerberus/cerberusdoc/interpolate.cerberusdoc +++ b/modules/cerberus/cerberusdoc/interpolate.cerberusdoc @@ -126,3 +126,155 @@ Parameters: Returns: Interpolated @y value at @x Links: [Live demo](./data/cerberus/interpolate/interpolate_applet.build/html5/CerberusGame.html) + +# Function InterpolateCustomLine:Float(dataY:Float[], x:Float) + +Interpolates on a sawtooth line through all the points in dataY[] spread evenly from `(0,@dataY[0])` to `(1,@dataY[n])` at @x. dataY must contain 2 or more points. + +![InterpolateCustomLine diagram](data/cerberus/interpolate/InterpolateCustomLine.png) + +Parameters: +* @dataY[] - an array of @y points +* @x - point to interpolate, ranging from 0 to 1 + +Returns: Interpolated @y value at @x + +Links: [Live demo](./data/cerberus/interpolate/interpolate_applet.build/html5/CerberusGame.html) + +# Function InterpolateElasticEaseIn:Float(y0:Float, y1:Float, x:Float) + +Interpolates on an elastic bouncing curve from `(0,@y0)` to `(1,@y1)` at @x. This eases in the bouncing. + +![InterpolateElasticEaseIn diagram](data/cerberus/interpolate/InterpolateElasticEaseIn.png) + +Parameters: +* @y0 - value at x=0.0 +* @y1 - value at x=1.0 +* @x - point to interpolate, ranging from 0 to 1 + +Returns: Interpolated @y value at @x + +Links: [Live demo](./data/cerberus/interpolate/interpolate_applet.build/html5/CerberusGame.html) + +# Function InterpolateElasticEaseOut:Float(y0:Float, y1:Float, x:Float) + +Interpolates on an elastic bouncing curve from `(0,@y0)` to `(1,@y1)` at @x. This eases out the bouncing. + +![InterpolateElasticEaseOut diagram](data/cerberus/interpolate/InterpolateElasticEaseOut.png) + +Parameters: +* @y0 - value at x=0.0 +* @y1 - value at x=1.0 +* @x - point to interpolate, ranging from 0 to 1 + +Returns: Interpolated @y value at @x + +Links: [Live demo](./data/cerberus/interpolate/interpolate_applet.build/html5/CerberusGame.html) + +# Function InterpolateElasticEaseInOut:Float(y0:Float, y1:Float, x:Float) + +Interpolates on an elastic bouncing curve from `(0,@y0)` to `(1,@y1)` at @x. This eases in and out the bouncing. + +![InterpolateElasticEaseInOut diagram](data/cerberus/interpolate/InterpolateElasticEaseInOut.png) + +Parameters: +* @y0 - value at x=0.0 +* @y1 - value at x=1.0 +* @x - point to interpolate, ranging from 0 to 1 + +Returns: Interpolated @y value at @x + +Links: [Live demo](./data/cerberus/interpolate/interpolate_applet.build/html5/CerberusGame.html) + +# Function InterpolateBackEaseIn:Float(y0:Float, y1:Float, x:Float) + +Interpolates on a pull back curve from `(0,@y0)` to `(1,@y1)` at @x. This eases in the pull back mechanism. + +![InterpolateBackEaseIn diagram](data/cerberus/interpolate/InterpolateBackEaseIn.png) + +Parameters: +* @y0 - value at x=0.0 +* @y1 - value at x=1.0 +* @x - point to interpolate, ranging from 0 to 1 + +Returns: Interpolated @y value at @x + +Links: [Live demo](./data/cerberus/interpolate/interpolate_applet.build/html5/CerberusGame.html) + + +# Function InterpolateBackEaseOut:Float(y0:Float, y1:Float, x:Float) + +Interpolates on a pull back curve from `(0,@y0)` to `(1,@y1)` at @x. This eases out the pull back mechanism. + +![InterpolateBackEaseOut diagram](data/cerberus/interpolate/InterpolateBackEaseOut.png) + +Parameters: +* @y0 - value at x=0.0 +* @y1 - value at x=1.0 +* @x - point to interpolate, ranging from 0 to 1 + +Returns: Interpolated @y value at @x + +Links: [Live demo](./data/cerberus/interpolate/interpolate_applet.build/html5/CerberusGame.html) + +# Function InterpolateBackEaseInOut:Float(y0:Float, y1:Float, x:Float) + +Interpolates on a pull back curve from `(0,@y0)` to `(1,@y1)` at @x. This eases in and out the pull back mechanism. + +![InterpolateBackEaseInOut diagram](data/cerberus/interpolate/InterpolateBackEaseInOut.png) + +Parameters: +* @y0 - value at x=0.0 +* @y1 - value at x=1.0 +* @x - point to interpolate, ranging from 0 to 1 + +Returns: Interpolated @y value at @x + +Links: [Live demo](./data/cerberus/interpolate/interpolate_applet.build/html5/CerberusGame.html) + +# Function InterpolateBounceEaseIn:Float(y0:Float, y1:Float, x:Float) + +Interpolates on a bouncing curve from `(0,@y0)` to `(1,@y1)` at @x. This eases in the bouncing. + +![InterpolateBounceEaseIn diagram](data/cerberus/interpolate/InterpolateBounceEaseIn.png) + +Parameters: +* @y0 - value at x=0.0 +* @y1 - value at x=1.0 +* @x - point to interpolate, ranging from 0 to 1 + +Returns: Interpolated @y value at @x + +Links: [Live demo](./data/cerberus/interpolate/interpolate_applet.build/html5/CerberusGame.html) + + +# Function InterpolateBounceEaseOut:Float(y0:Float, y1:Float, x:Float) + +Interpolates on a bouncing curve from `(0,@y0)` to `(1,@y1)` at @x. This eases out the bouncing. + +![InterpolateBounceEaseOut diagram](data/cerberus/interpolate/InterpolateBounceEaseOut.png) + +Parameters: +* @y0 - value at x=0.0 +* @y1 - value at x=1.0 +* @x - point to interpolate, ranging from 0 to 1 + +Returns: Interpolated @y value at @x + +Links: [Live demo](./data/cerberus/interpolate/interpolate_applet.build/html5/CerberusGame.html) + + +# Function InterpolateBounceEaseInOut:Float(y0:Float, y1:Float, x:Float) + +Interpolates on a bouncing curve from `(0,@y0)` to `(1,@y1)` at @x. This eases in and out the bouncing. + +![InterpolateBounceEaseIn diagram](data/cerberus/interpolate/InterpolateBounceEaseInOut.png) + +Parameters: +* @y0 - value at x=0.0 +* @y1 - value at x=1.0 +* @x - point to interpolate, ranging from 0 to 1 + +Returns: Interpolated @y value at @x + +Links: [Live demo](./data/cerberus/interpolate/interpolate_applet.build/html5/CerberusGame.html) diff --git a/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBackEaseIn.png b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBackEaseIn.png new file mode 100644 index 00000000..5dd5c13e Binary files /dev/null and b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBackEaseIn.png differ diff --git a/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBackEaseInOut.png b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBackEaseInOut.png new file mode 100644 index 00000000..769c428b Binary files /dev/null and b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBackEaseInOut.png differ diff --git a/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBackEaseOut.png b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBackEaseOut.png new file mode 100644 index 00000000..0468a33b Binary files /dev/null and b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBackEaseOut.png differ diff --git a/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBounceEaseIn.png b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBounceEaseIn.png new file mode 100644 index 00000000..1a6caf87 Binary files /dev/null and b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBounceEaseIn.png differ diff --git a/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBounceEaseInOut.png b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBounceEaseInOut.png new file mode 100644 index 00000000..1d06462c Binary files /dev/null and b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBounceEaseInOut.png differ diff --git a/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBounceEaseOut.png b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBounceEaseOut.png new file mode 100644 index 00000000..d398ea78 Binary files /dev/null and b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateBounceEaseOut.png differ diff --git a/modules/cerberus/cerberusdoc/interpolate.data/InterpolateCustom.png b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateCustom.png new file mode 100644 index 00000000..9fadd35b Binary files /dev/null and b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateCustom.png differ diff --git a/modules/cerberus/cerberusdoc/interpolate.data/InterpolateElasticEaseIn.png b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateElasticEaseIn.png new file mode 100644 index 00000000..1c27941e Binary files /dev/null and b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateElasticEaseIn.png differ diff --git a/modules/cerberus/cerberusdoc/interpolate.data/InterpolateElasticEaseInOut.png b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateElasticEaseInOut.png new file mode 100644 index 00000000..ebfade9b Binary files /dev/null and b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateElasticEaseInOut.png differ diff --git a/modules/cerberus/cerberusdoc/interpolate.data/InterpolateElasticEaseOut.png b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateElasticEaseOut.png new file mode 100644 index 00000000..7e424fea Binary files /dev/null and b/modules/cerberus/cerberusdoc/interpolate.data/InterpolateElasticEaseOut.png differ diff --git a/modules/cerberus/cerberusdoc/interpolate.data/interpolate_applet.build/html5/main.js b/modules/cerberus/cerberusdoc/interpolate.data/interpolate_applet.build/html5/main.js index 45959cd8..c10d577e 100644 --- a/modules/cerberus/cerberusdoc/interpolate.data/interpolate_applet.build/html5/main.js +++ b/modules/cerberus/cerberusdoc/interpolate.data/interpolate_applet.build/html5/main.js @@ -5,6 +5,7 @@ CFG_BRL_DATABUFFER_IMPLEMENTED="1"; CFG_BRL_GAMETARGET_IMPLEMENTED="1"; CFG_BRL_THREAD_IMPLEMENTED="1"; CFG_CD=""; +CFG_COLOR_USE_NORMALISED_COMPONENTS="1"; CFG_CONFIG="release"; CFG_GLFW_COPY_LIBS="openal32"; CFG_GLFW_GCC_LIB_OPTS="-lopenal32"; @@ -2864,6 +2865,9 @@ c_MyApp.prototype.p_Layout=function(){ bb_interpolate_applet_pointS1.p_SetScale(c_MyApp.m_framesize); bb_interpolate_applet_pointAB.p_SetScale(c_MyApp.m_framesize); bb_interpolate_applet_pointCD.p_SetScale(c_MyApp.m_framesize); + for(var t_i=0;t_i<6;t_i=t_i+1){ + bb_interpolate_applet_custom_points[t_i].p_SetScale(c_MyApp.m_framesize); + } c_MyApp.m_demox0=((c_MyApp.m_width/2)|0)+c_MyApp.m_framex0; c_MyApp.m_demoy0=c_MyApp.m_graphy0+c_MyApp.m_framey0; } @@ -2908,6 +2912,13 @@ c_MyApp.prototype.p_OnCreate=function(){ bb_interpolate_applet_pointCD.p_XBounds(0.0,1.0); bb_interpolate_applet_pointCD.p_YBounds(-0.5,1.5); bb_interpolate_applet_pointCD.p_Hide(); + for(var t_i=0;t_i<6;t_i=t_i+1){ + bb_interpolate_applet_custom_points[t_i]=c_ControlPoint.m_new.call(new c_ControlPoint); + bb_interpolate_applet_custom_points[t_i].p_Position(0.14285714285714285*(t_i+1),bb_interpolate_applet_custom_data[t_i+1]); + bb_interpolate_applet_custom_points[t_i].p_XBounds(0.14285714285714285*(t_i+1),0.14285714285714285*(t_i+1)); + bb_interpolate_applet_custom_points[t_i].p_YBounds(-0.5,1.5); + bb_interpolate_applet_custom_points[t_i].p_Hide(); + } bb_interpolate_applet_curfunc=bb_interpolate_applet_INTERPFUNCS[bb_interpolate_applet_curfuncidx]; bb_interpolate_applet_curfunc.p_Activate(); this.p_Layout(); @@ -2933,6 +2944,9 @@ c_MyApp.prototype.p_OnUpdate=function(){ bb_interpolate_applet_pointYA.p_Update(); bb_interpolate_applet_pointY0.p_Update(); bb_interpolate_applet_pointY1.p_Update(); + for(var t_i=0;t_i<6;t_i=t_i+1){ + bb_interpolate_applet_custom_points[t_i].p_Update(); + } if((bb_input_KeyHit(32))!=0){ bb_interpolate_applet_curfuncidx=(bb_interpolate_applet_curfuncidx+1) % bb_interpolate_applet_INTERPFUNCS.length; bb_interpolate_applet_curfunc=bb_interpolate_applet_INTERPFUNCS[bb_interpolate_applet_curfuncidx]; @@ -2941,12 +2955,15 @@ c_MyApp.prototype.p_OnUpdate=function(){ bb_interpolate_applet_pointS0.p_Hide(); bb_interpolate_applet_pointS1.p_Hide(); bb_interpolate_applet_pointYA.p_Hide(); + for(var t_i2=0;t_i2<6;t_i2=t_i2+1){ + bb_interpolate_applet_custom_points[t_i2].p_Hide(); + } bb_interpolate_applet_curfunc.p_Activate(); bb_interpolate_applet_anypointmoved=1; } var t_t=(bb_app_Millisecs() % (c_MyApp.m_DEMO_DURATION_MAX+2000)-1000); - for(var t_i=0;t_i<3;t_i=t_i+1){ - c_MyApp.m_demot[t_i]=bb_math_Clamp2(t_t/(c_MyApp.m_DEMO_DURATIONS[t_i]),0.0,1.0); + for(var t_i3=0;t_i3<3;t_i3=t_i3+1){ + c_MyApp.m_demot[t_i3]=bb_math_Clamp2(t_t/(c_MyApp.m_DEMO_DURATIONS[t_i3]),0.0,1.0); } if((bb_interpolate_applet_anypointmoved)!=0){ var t_ttxt=bb_interpolate_applet_curfunc.p_Label(); @@ -3019,6 +3036,9 @@ c_MyApp.prototype.p_OnRender=function(){ bb_interpolate_applet_pointYA.p_Draw(bb_interpolate_applet_cvMain); bb_interpolate_applet_pointS0.p_Draw(bb_interpolate_applet_cvMain); bb_interpolate_applet_pointS1.p_Draw(bb_interpolate_applet_cvMain); + for(var t_i=0;t_i<6;t_i=t_i+1){ + bb_interpolate_applet_custom_points[t_i].p_Draw(bb_interpolate_applet_cvMain); + } var t_x2=.0; var t_scl=.0; var t_s20=(c_MyApp.m_framesize)/20.0; @@ -3026,11 +3046,11 @@ c_MyApp.prototype.p_OnRender=function(){ bb_interpolate_applet_cvMain.p_Translate((c_MyApp.m_demox0),(c_MyApp.m_demoy0)); this.p_DrawFrameBorder(); bb_interpolate_applet_cvMain.p_SetColor3(2587588); - for(var t_i=0;t_i<3;t_i=t_i+1){ - t_scl=bb_interpolate_applet_curfunc.p_Interpolate(c_MyApp.m_demot[t_i]); + for(var t_i2=0;t_i2<3;t_i2=t_i2+1){ + t_scl=bb_interpolate_applet_curfunc.p_Interpolate(c_MyApp.m_demot[t_i2]); t_x2=(c_MyApp.m_framesize)*t_scl; - bb_interpolate_applet_cvMain.p_DrawCircle(t_x2,(4+4*t_i)*t_s20,t_s20,null); - bb_interpolate_applet_cvMain.p_DrawCircle((5+5*t_i)*t_s20,16.0*t_s20,2.0*t_s20*t_scl,null); + bb_interpolate_applet_cvMain.p_DrawCircle(t_x2,(4+4*t_i2)*t_s20,t_s20,null); + bb_interpolate_applet_cvMain.p_DrawCircle((5+5*t_i2)*t_s20,16.0*t_s20,2.0*t_s20*t_scl,null); } bb_interpolate_applet_cvMain.p_ResetMatrix(); bb_interpolate_applet_cvMain.p_SetColor(0.0,0.0,0.0); @@ -4183,163 +4203,84 @@ function bb_graphics_SetColor2(t_rgb){ } function c_Color(){ Object.call(this); - this.m__red=.0; - this.m__RgbIsUpToDate=false; - this.m__HsbIsUpToDate=false; + this.m_r=.0; + this.m_g=.0; + this.m_b=.0; + this.m__hue=.0; this.m__sat=.0; this.m__bri=.0; - this.m__grn=.0; - this.m__blu=.0; - this.m__hue=.0; -} -c_Color.prototype.p_red=function(t_pRed){ - this.m__red=bb_math_Clamp2(t_pRed,0.0,1.0); - this.m__RgbIsUpToDate=true; - this.m__HsbIsUpToDate=false; -} -c_Color.prototype.p_ToRgb=function(){ - if(this.m__sat==0.0){ - this.m__red=this.m__bri; - this.m__grn=this.m__bri; - this.m__blu=this.m__bri; - }else{ - if(this.m__bri==0.0){ - this.m__red=0.0; - this.m__grn=0.0; - this.m__blu=0.0; - }else{ - var t_hidx=((this.m__hue/60.0)|0); - var t_hfrac=this.m__hue/60.0-(t_hidx); - var t_ccj=this.m__bri*(1.0-this.m__sat); - var t_cck=this.m__bri*(1.0-this.m__sat*t_hfrac); - var t_ccl=this.m__bri*(1.0-this.m__sat*(1.0-t_hfrac)); - var t_1=t_hidx; - if(t_1==0){ - this.m__red=this.m__bri; - this.m__grn=t_ccl; - this.m__blu=t_ccj; - }else{ - if(t_1==1){ - this.m__red=t_cck; - this.m__grn=this.m__bri; - this.m__blu=t_ccj; - }else{ - if(t_1==2){ - this.m__red=t_ccj; - this.m__grn=this.m__bri; - this.m__blu=t_ccl; - }else{ - if(t_1==3){ - this.m__red=t_ccj; - this.m__grn=t_cck; - this.m__blu=this.m__bri; - }else{ - if(t_1==4){ - this.m__red=t_ccl; - this.m__grn=t_ccj; - this.m__blu=this.m__bri; - }else{ - if(t_1==5){ - this.m__red=this.m__bri; - this.m__grn=t_ccj; - this.m__blu=t_cck; - } - } - } - } - } - } - } - } - this.m__RgbIsUpToDate=true; -} -c_Color.prototype.p_red2=function(){ - if(!this.m__RgbIsUpToDate){ - this.p_ToRgb(); - } - return this.m__red; + this.m__HsbSyncRed=.0; + this.m__HsbSyncGrn=.0; + this.m__HsbSyncBlu=.0; } -c_Color.prototype.p_grn=function(t_pGrn){ - this.m__grn=bb_math_Clamp2(t_pGrn,0.0,1.0); - this.m__RgbIsUpToDate=true; - this.m__HsbIsUpToDate=false; +c_Color.prototype.p_Set2=function(t_pHex){ + this.m_r=(t_pHex>>16&255)/255.0; + this.m_g=(t_pHex>>8&255)/255.0; + this.m_b=(t_pHex&255)/255.0; } -c_Color.prototype.p_grn2=function(){ - if(!this.m__RgbIsUpToDate){ - this.p_ToRgb(); - } - return this.m__grn; -} -c_Color.prototype.p_blu=function(t_pBlu){ - this.m__blu=bb_math_Clamp2(t_pBlu,0.0,1.0); - this.m__RgbIsUpToDate=true; - this.m__HsbIsUpToDate=false; -} -c_Color.prototype.p_blu2=function(){ - if(!this.m__RgbIsUpToDate){ - this.p_ToRgb(); - } - return this.m__blu; -} -c_Color.prototype.p_Set2=function(t_pRed,t_pGrn,t_pBlu){ - this.m__red=bb_math_Clamp2(t_pRed,0.0,1.0); - this.m__grn=bb_math_Clamp2(t_pGrn,0.0,1.0); - this.m__blu=bb_math_Clamp2(t_pBlu,0.0,1.0); - this.m__RgbIsUpToDate=true; - this.m__HsbIsUpToDate=false; -} -c_Color.prototype.p_Set3=function(t_pHex){ - this.m__red=(t_pHex>>16&255)/255.0; - this.m__grn=(t_pHex>>8&255)/255.0; - this.m__blu=(t_pHex&255)/255.0; - this.m__RgbIsUpToDate=true; - this.m__HsbIsUpToDate=false; +c_Color.prototype.p_Set3=function(t_pRed,t_pGrn,t_pBlu){ + this.m_r=bb_math_Clamp2(t_pRed,0.0,1.0); + this.m_g=bb_math_Clamp2(t_pGrn,0.0,1.0); + this.m_b=bb_math_Clamp2(t_pBlu,0.0,1.0); } c_Color.prototype.p_Set4=function(t_pRgb){ - this.p_Set2(t_pRgb[0],t_pRgb[1],t_pRgb[2]); + this.m_r=bb_math_Clamp2(t_pRgb[0],0.0,1.0); + this.m_g=bb_math_Clamp2(t_pRgb[1],0.0,1.0); + this.m_b=bb_math_Clamp2(t_pRgb[2],0.0,1.0); } c_Color.prototype.p_Set5=function(t_pColor){ - this.p_Set3(bb_colornames_NamedHtmlColor(t_pColor)); + this.m_r=t_pColor.m_r; + this.m_g=t_pColor.m_g; + this.m_b=t_pColor.m_b; + this.m__hue=t_pColor.m__hue; + this.m__sat=t_pColor.m__sat; + this.m__bri=t_pColor.m__bri; + this.m__HsbSyncRed=t_pColor.m__HsbSyncRed; + this.m__HsbSyncGrn=t_pColor.m__HsbSyncGrn; + this.m__HsbSyncBlu=t_pColor.m__HsbSyncBlu; +} +c_Color.m_new=function(t_pRed,t_pGrn,t_pBlu){ + this.p_Set3(t_pRed,t_pGrn,t_pBlu); + return this; } -c_Color.m_new=function(){ - this.p_Set3(0); +c_Color.m_new2=function(t_pRgb){ + this.p_Set4(t_pRgb); return this; } -c_Color.m_new2=function(t_pHex){ - this.p_Set3(t_pHex); +c_Color.prototype.p_GetHex=function(){ + var t__r=((this.m_r*255.0)|0); + var t__g=((this.m_g*255.0)|0); + var t__b=((this.m_b*255.0)|0); + return t__r<<16|t__g<<8|t__b; +} +c_Color.prototype.p_ToInt=function(){ + return this.p_GetHex(); +} +c_Color.m_new3=function(t_pColor){ + this.p_Set5(t_pColor); return this; } -c_Color.m_new3=function(t_pRed,t_pGrn,t_pBlu){ - this.p_Set2(t_pRed,t_pGrn,t_pBlu); +c_Color.m_new4=function(t_pColorName){ + this.p_Set6(t_pColorName); return this; } -c_Color.m_new4=function(t_pColor){ - this.p_Set5(t_pColor); +c_Color.m_new5=function(t_pHex){ + this.p_Set2(t_pHex); return this; } -function bb_math_Clamp(t_n,t_min,t_max){ - if(t_nt_max){ - return t_max; - } - return t_n; +c_Color.prototype.p_Set6=function(t_pColorName){ + this.p_Set2(bb_colornames_NamedHtmlColor(t_pColorName)); } -function bb_math_Clamp2(t_n,t_min,t_max){ - if(t_nt_max){ - return t_max; - } - return t_n; +c_Color.m_new6=function(){ + this.p_Set2(0); + return this; } function bb_graphics_SetColor3(t_col){ - bb_graphics_context.m_color_r=t_col.p_red2()*255.0; - bb_graphics_context.m_color_g=t_col.p_grn2()*255.0; - bb_graphics_context.m_color_b=t_col.p_blu2()*255.0; + bb_graphics_context.m_color_r=t_col.m_r; + bb_graphics_context.m_color_g=t_col.m_g; + bb_graphics_context.m_color_b=t_col.m_b; bb_graphics_renderDevice.SetColor(bb_graphics_context.m_color_r,bb_graphics_context.m_color_g,bb_graphics_context.m_color_b); + bb_graphics_renderDevice.SetAlpha(bb_graphics_context.m_alpha); return 0; } function bb_graphics_SetAlpha(t_alpha){ @@ -4549,10 +4490,10 @@ c_DrawList.prototype.p_Reset=function(){ t_data[t_i].m_material=null; bb_graphics2_freeOps.p_Push7(t_data[t_i]); } - this.m__ops.p_Clear2(); + this.m__ops.p_Clear4(); this.m__op=bb_graphics2_nullOp; - this.m__casters.p_Clear2(); - this.m__casterVerts.p_Clear2(); + this.m__casters.p_Clear4(); + this.m__casterVerts.p_Clear4(); } c_DrawList.prototype.p_Flush=function(){ this.p_Render2(); @@ -4610,9 +4551,9 @@ c_DrawList.prototype.p_SetColor3=function(t_hex){ this.m__pmcolor=((this.m__alpha)|0)<<24|((this.m__color[2]*this.m__alpha)|0)<<16|((this.m__color[1]*this.m__alpha)|0)<<8|((this.m__color[0]*this.m__alpha)|0); } c_DrawList.prototype.p_SetColor4=function(t_col){ - this.m__color[0]=t_col.p_red2(); - this.m__color[1]=t_col.p_grn2(); - this.m__color[2]=t_col.p_blu2(); + this.m__color[0]=t_col.m_r; + this.m__color[1]=t_col.m_g; + this.m__color[2]=t_col.m_b; this.m__pmcolor=((this.m__alpha)|0)<<24|((this.m__color[2]*this.m__alpha)|0)<<16|((this.m__color[1]*this.m__alpha)|0)<<8|((this.m__color[0]*this.m__alpha)|0); } c_DrawList.prototype.p_BeginPrim=function(t_material,t_order){ @@ -5097,6 +5038,15 @@ c_Canvas.prototype.p_Clear=function(t_r,t_g,t_b,t_a){ gl.disable(3089); } } +c_Canvas.prototype.p_Clear2=function(t_col){ + this.p_Clear(t_col.m_r,t_col.m_g,t_col.m_b,1.0); +} +c_Canvas.prototype.p_Clear3=function(t_rgb){ + var t_r=(t_rgb>>16&255)/255.0; + var t_g=(t_rgb>>8&255)/255.0; + var t_b=(t_rgb&255)/255.0; + this.p_Clear(t_r,t_g,t_b,1.0); +} var bb_graphics2_inited=false; var bb_graphics2_vbosSeq=0; var bb_graphics2_rs_vbo=0; @@ -5589,7 +5539,7 @@ c_Map3.prototype.p_InsertFixup3=function(t_node){ this.m_root.m_color=1; return 0; } -c_Map3.prototype.p_Set6=function(t_key,t_value){ +c_Map3.prototype.p_Set7=function(t_key,t_value){ var t_node=this.m_root; var t_parent=null; var t_cmp=0; @@ -5621,7 +5571,7 @@ c_Map3.prototype.p_Set6=function(t_key,t_value){ return true; } c_Map3.prototype.p_Insert3=function(t_key,t_value){ - return this.p_Set6(t_key,t_value); + return this.p_Set7(t_key,t_value); } c_Map3.prototype.p_Keys=function(){ return c_MapKeys.m_new.call(new c_MapKeys,this); @@ -6464,7 +6414,7 @@ c_Texture.m_Color=function(t_color){ var t_data=c_DataBuffer.m_new.call(new c_DataBuffer,4,false); t_data.PokeInt(0,t_color); t_tex=c_Texture.m_new2.call(new c_Texture,1,1,4,12,(t_data)); - c_Texture.m__colors.p_Set7(t_color,t_tex); + c_Texture.m__colors.p_Set8(t_color,t_tex); return t_tex; } c_Texture.m_White=function(){ @@ -6543,7 +6493,7 @@ c_Material.prototype.p_SetTexture=function(t_param,t_texture){ } var t_old=this.m__textures.p_Get2(t_param); t_texture.p_Retain(); - this.m__textures.p_Set8(t_param,t_texture); + this.m__textures.p_Set9(t_param,t_texture); if((t_old)!=null){ t_old.p_Release(); } @@ -6647,13 +6597,13 @@ c_Material.prototype.p_SetVector=function(t_param,t_vector){ if(this.m__inited && !this.m__vectors.p_Contains2(t_param)){ return; } - this.m__vectors.p_Set10(t_param,t_vector); + this.m__vectors.p_Set11(t_param,t_vector); } c_Material.prototype.p_SetScalar=function(t_param,t_scalar){ if(this.m__inited && !this.m__scalars.p_Contains2(t_param)){ return; } - this.m__scalars.p_Set9(t_param,t_scalar); + this.m__scalars.p_Set10(t_param,t_scalar); } c_Material.prototype.p_Destroy=function(){ var t_=this.m__textures.p_ObjectEnumerator(); @@ -6773,7 +6723,7 @@ c_Map4.prototype.p_InsertFixup4=function(t_node){ this.m_root.m_color=1; return 0; } -c_Map4.prototype.p_Set7=function(t_key,t_value){ +c_Map4.prototype.p_Set8=function(t_key,t_value){ var t_node=this.m_root; var t_parent=null; var t_cmp=0; @@ -6965,7 +6915,7 @@ c_Map5.prototype.p_InsertFixup5=function(t_node){ this.m_root.m_color=1; return 0; } -c_Map5.prototype.p_Set8=function(t_key,t_value){ +c_Map5.prototype.p_Set9=function(t_key,t_value){ var t_node=this.m_root; var t_parent=null; var t_cmp=0; @@ -7443,7 +7393,7 @@ c_Map7.prototype.p_InsertFixup7=function(t_node){ this.m_root.m_color=1; return 0; } -c_Map7.prototype.p_Set9=function(t_key,t_value){ +c_Map7.prototype.p_Set10=function(t_key,t_value){ var t_node=this.m_root; var t_parent=null; var t_cmp=0; @@ -7618,7 +7568,7 @@ c_Map8.prototype.p_InsertFixup8=function(t_node){ this.m_root.m_color=1; return 0; } -c_Map8.prototype.p_Set10=function(t_key,t_value){ +c_Map8.prototype.p_Set11=function(t_key,t_value){ var t_node=this.m_root; var t_parent=null; var t_cmp=0; @@ -7730,7 +7680,7 @@ c_Stack3.prototype.p_Push8=function(t_values,t_offset,t_count){ c_Stack3.prototype.p_Push9=function(t_values,t_offset){ this.p_Push8(t_values,t_offset,t_values.length-t_offset); } -c_Stack3.prototype.p_Clear2=function(){ +c_Stack3.prototype.p_Clear4=function(){ for(var t_i=0;t_it_max){ + return t_max; + } + return t_n; +} +function bb_math_Clamp2(t_n,t_min,t_max){ + if(t_nt_max){ + return t_max; + } + return t_n; +} var bb_interpolate_applet_anypointmoved=0; function bb_input_KeyHit(t_key){ return bb_input_device.p_KeyHit(t_key); @@ -8891,6 +9039,158 @@ function bb_interpolate_InterpolateCubicBezier(t_pY0,t_pY1,t_pA,t_pB,t_pC,t_pD,t }while(!(t_runs==20)); return t_pY0+(3.0*t_pB-3.0*t_pY0)*t_t+(3.0*t_pY0-6.0*t_pB+3.0*t_pD)*t_t*t_t+(t_pY1+3.0*t_pB-3.0*t_pD-t_pY0)*t_t*t_t*t_t; } +function bb_interpolate_InterpolateCustomLine(t_dataY,t_pX){ + var t_steps=t_dataY.length-1; + if(t_steps<1){ + return 1.0; + } + var t_segment=((bb_math_Min2(t_pX*(t_steps),(t_steps)-1.0))|0); + var t_ratio=(t_pX-1.0/(t_steps)*(t_segment))/(1.0/(t_steps)); + return t_dataY[t_segment]+(t_dataY[t_segment+1]-t_dataY[t_segment])*t_ratio; +} +function bb_interpolate_InterpolateBackEaseIn(t_pY0,t_pY1,t_pX){ + var t_s=1.70158; + return t_pY0+t_pX*t_pX*((t_s+1.0)*t_pX-t_s)*(t_pY1-t_pY0); +} +function bb_interpolate_InterpolateBackEaseOut(t_pY0,t_pY1,t_pX){ + var t_s=1.70158; + t_pX=t_pX-1.0; + return t_pY0+(t_pX*t_pX*((t_s+1.0)*t_pX+t_s)+1.0)*(t_pY1-t_pY0); +} +function bb_interpolate_InterpolateBackEaseInOut(t_pY0,t_pY1,t_pX){ + var t_s=1.70158; + var t_s2=.0; + t_s2=t_s; + t_pX=t_pX*2.0; + t_s2*=1.525; + if(t_pX<1.0){ + return t_pY0+0.5*(t_pX*t_pX*((t_s2+1.0)*t_pX-t_s2))*(t_pY1-t_pY0); + } + t_pX=t_pX-2.0; + return t_pY0+0.5*(t_pX*t_pX*((t_s2+1.0)*t_pX+t_s2)+2.0)*(t_pY1-t_pY0); +} +function bb_interpolate_InterpolateBounceEaseIn(t_pY0,t_pY1,t_pX){ + t_pX=1.0-t_pX; + if(t_pX<0.3636363){ + return t_pY0+(1.0-7.5625*t_pX*t_pX)*(t_pY1-t_pY0); + }else{ + if(t_pX<0.7272727){ + t_pX-=0.5454545; + return t_pY0+(1.0-(7.5625*t_pX*t_pX+0.75))*(t_pY1-t_pY0); + }else{ + if(t_pX<0.9090909){ + t_pX-=0.8181818; + return t_pY0+(1.0-(7.5625*t_pX*t_pX+0.9375))*(t_pY1-t_pY0); + }else{ + t_pX-=0.9636363; + return t_pY0+(1.0-(7.5625*t_pX*t_pX+0.984375))*(t_pY1-t_pY0); + } + } + } +} +function bb_interpolate_InterpolateBounceEaseOut(t_pY0,t_pY1,t_pX){ + if(t_pX<0.3636363){ + return t_pY0+7.5625*t_pX*t_pX*(t_pY1-t_pY0); + }else{ + if(t_pX<0.7272727){ + t_pX-=0.5454545; + return t_pY0+(7.5625*t_pX*t_pX+0.75)*(t_pY1-t_pY0); + }else{ + if(t_pX<0.9090909){ + t_pX-=0.8181818; + return t_pY0+(7.5625*t_pX*t_pX+0.9375)*(t_pY1-t_pY0); + }else{ + t_pX-=0.9636363; + return t_pY0+(7.5625*t_pX*t_pX+0.984375)*(t_pY1-t_pY0); + } + } + } +} +function bb_interpolate_InterpolateBounceEaseInOut(t_pY0,t_pY1,t_pX){ + if(t_pX<0.5){ + t_pX=1.0-t_pX*2.0; + if(t_pX<0.3636363){ + return t_pY0+(1.0-7.5625*t_pX*t_pX)*0.5*(t_pY1-t_pY0); + }else{ + if(t_pX<0.7272727){ + t_pX-=0.5454545; + return t_pY0+(1.0-(7.5625*t_pX*t_pX+0.75))*0.5*(t_pY1-t_pY0); + }else{ + if(t_pX<0.9090909){ + t_pX-=0.8181818; + return t_pY0+(1.0-(7.5625*t_pX*t_pX+0.9375))*0.5*(t_pY1-t_pY0); + }else{ + t_pX-=0.9636363; + return t_pY0+(1.0-(7.5625*t_pX*t_pX+0.984375))*0.5*(t_pY1-t_pY0); + } + } + } + }else{ + t_pX=t_pX*2.0-1.0; + if(t_pX<0.3636363){ + return t_pY0+(7.5625*t_pX*t_pX*0.5+0.5)*(t_pY1-t_pY0); + }else{ + if(t_pX<0.7272727){ + t_pX-=0.5454545; + return t_pY0+((7.5625*t_pX*t_pX+0.75)*0.5+0.5)*(t_pY1-t_pY0); + }else{ + if(t_pX<0.9090909){ + t_pX-=0.8181818; + return t_pY0+((7.5625*t_pX*t_pX+0.9375)*0.5+0.5)*(t_pY1-t_pY0); + }else{ + t_pX-=0.9636363; + return t_pY0+((7.5625*t_pX*t_pX+0.984375)*0.5+0.5)*(t_pY1-t_pY0); + } + } + } + } +} +function bb_interpolate_InterpolateElasticEaseIn(t_pY0,t_pY1,t_pX){ + var t_p=.0; + var t_s=.0; + if(t_pX==0.0){ + return t_pY0; + } + if(t_pX==1.0){ + return t_pY1; + } + t_p=0.3; + t_s=t_p/4.0; + t_pX=t_pX-1.0; + return t_pY0-Math.pow(2.0,10.0*t_pX)*Math.sin(((t_pX-t_s)*6.2831853000000004/t_p*57.2957795)*D2R)*(t_pY1-t_pY0); +} +function bb_interpolate_InterpolateElasticEaseOut(t_pY0,t_pY1,t_pX){ + var t_p=.0; + var t_s=.0; + if(t_pX==0.0){ + return t_pY0; + } + if(t_pX==1.0){ + return t_pY1; + } + t_p=0.3; + t_s=t_p/4.0; + return t_pY0+(Math.pow(2.0,-10.0*t_pX)*Math.sin(((t_pX-t_s)*6.2831853000000004/t_p*57.2957795)*D2R)+1.0)*(t_pY1-t_pY0); +} +function bb_interpolate_InterpolateElasticEaseInOut(t_pY0,t_pY1,t_pX){ + var t_p=.0; + var t_s=.0; + if(t_pX==0.0){ + return t_pY0; + } + t_pX=t_pX*2.0; + if(t_pX==2.0){ + return t_pY1; + } + t_p=0.44999999999999996; + t_s=t_p/4.0; + if(t_pX<1.0){ + t_pX=t_pX-1.0; + return t_pY0+-0.5*(Math.pow(2.0,10.0*t_pX)*Math.sin(((t_pX-t_s)*6.2831853000000004/t_p*57.2957795)*D2R))*(t_pY1-t_pY0); + } + t_pX=t_pX-1.0; + return t_pY0+(Math.pow(2.0,-10.0*t_pX)*Math.sin(((t_pX-t_s)*6.2831853000000004/t_p*57.2957795)*D2R)*0.5+1.0)*(t_pY1-t_pY0); +} function bbInit(){ bb_app__app=null; bb_app__delegate=null; @@ -8955,7 +9255,9 @@ function bbInit(){ bb_interpolate_applet_pointS1=c_ControlPoint.m_new.call(new c_ControlPoint); bb_interpolate_applet_pointAB=c_ControlPoint.m_new.call(new c_ControlPoint); bb_interpolate_applet_pointCD=c_ControlPoint.m_new.call(new c_ControlPoint); - bb_interpolate_applet_INTERPFUNCS=[(c_InterpFuncLin.m_new.call(new c_InterpFuncLin)),(c_InterpFuncCurve.m_new.call(new c_InterpFuncCurve)),(c_InterpFuncSin.m_new.call(new c_InterpFuncSin)),(c_InterpFuncFit.m_new.call(new c_InterpFuncFit)),(c_InterpFuncFlats.m_new.call(new c_InterpFuncFlats)),(c_InterpFuncCubicBezier.m_new.call(new c_InterpFuncCubicBezier))]; + bb_interpolate_applet_custom_points=new_object_array(6); + bb_interpolate_applet_custom_data=[0.0,0.6,1.0,1.0,0.0,0.5,0.9,1.0]; + bb_interpolate_applet_INTERPFUNCS=[(c_InterpFuncLin.m_new.call(new c_InterpFuncLin)),(c_InterpFuncCurve.m_new.call(new c_InterpFuncCurve)),(c_InterpFuncSin.m_new.call(new c_InterpFuncSin)),(c_InterpFuncFit.m_new.call(new c_InterpFuncFit)),(c_InterpFuncFlats.m_new.call(new c_InterpFuncFlats)),(c_InterpFuncCubicBezier.m_new.call(new c_InterpFuncCubicBezier)),(c_InterpFuncCustomLine.m_new.call(new c_InterpFuncCustomLine)),(c_InterpFuncBackEaseIn.m_new.call(new c_InterpFuncBackEaseIn)),(c_InterpFuncBackEaseOut.m_new.call(new c_InterpFuncBackEaseOut)),(c_InterpFuncBackEaseInOut.m_new.call(new c_InterpFuncBackEaseInOut)),(c_InterpFuncBounceEaseIn.m_new.call(new c_InterpFuncBounceEaseIn)),(c_InterpFuncBounceEaseOut.m_new.call(new c_InterpFuncBounceEaseOut)),(c_InterpFuncBounceEaseInOut.m_new.call(new c_InterpFuncBounceEaseInOut)),(c_InterpFuncElasticEaseIn.m_new.call(new c_InterpFuncElasticEaseIn)),(c_InterpFuncElasticEaseOut.m_new.call(new c_InterpFuncElasticEaseOut)),(c_InterpFuncElasticEaseInOut.m_new.call(new c_InterpFuncElasticEaseInOut))]; bb_interpolate_applet_curfuncidx=0; bb_interpolate_applet_curfunc=null; c_MyApp.m_width=0; diff --git a/modules/cerberus/cerberusdoc/interpolate.data/interpolate_applet.cxs b/modules/cerberus/cerberusdoc/interpolate.data/interpolate_applet.cxs index e7f2f25f..dad618be 100644 --- a/modules/cerberus/cerberusdoc/interpolate.data/interpolate_applet.cxs +++ b/modules/cerberus/cerberusdoc/interpolate.data/interpolate_applet.cxs @@ -31,7 +31,17 @@ Global INTERPFUNCS:InterpFunc[] = [ InterpFunc(New InterpFuncLin), InterpFunc(New InterpFuncSin), InterpFunc(New InterpFuncFit), InterpFunc(New InterpFuncFlats), - InterpFunc(New InterpFuncCubicBezier)] + InterpFunc(New InterpFuncCubicBezier), + InterpFunc(New InterpFuncCustomLine), + InterpFunc(New InterpFuncBackEaseIn), + InterpFunc(New InterpFuncBackEaseOut), + InterpFunc(New InterpFuncBackEaseInOut), + InterpFunc(New InterpFuncBounceEaseIn), + InterpFunc(New InterpFuncBounceEaseOut), + InterpFunc(New InterpFuncBounceEaseInOut), + InterpFunc(New InterpFuncElasticEaseIn), + InterpFunc(New InterpFuncElasticEaseOut), + InterpFunc(New InterpFuncElasticEaseInOut)] Global curfuncidx:Int = 0 Global curfunc:InterpFunc @@ -46,10 +56,14 @@ Global pointS1 := New ControlPoint() ' cubic bezier points Global pointAB := New ControlPoint() Global pointCD := New ControlPoint() +' custom data +Global custom_data:Float[] = [0,0.6,1,1,0,0.5,0.9,1] +Global custom_points:ControlPoint[6] Global cvMain:Canvas ' track if any of the points moved Global anypointmoved:Int = True + ' main function @@ -71,7 +85,7 @@ Class MyApp Extends App Global demot:Float[3] Global DEMO_DURATIONS:Int[] = [500, 1000, 2000] Global DEMO_DURATION_MAX:Int - + Method OnCreate:Int() cvMain = New Canvas SetUpdateRate(60) @@ -113,10 +127,17 @@ Class MyApp Extends App pointCD.XBounds(0,1) pointCD.YBounds(-0.5,1.5) pointCD.Hide() + ' init custom data + For Local i:Int = 0 Until 6 + custom_points[i] = New ControlPoint() + custom_points[i].Position((1/7.0)*(i+1),custom_data[i+1]) + custom_points[i].XBounds((1/7.0)*(i+1),(1/7.0)*(i+1)) + custom_points[i].YBounds(-0.5,1.5) + custom_points[i].Hide() + Next '--- init tweening function attachments --- curfunc = INTERPFUNCS[ curfuncidx ] curfunc.Activate() - Layout() Return 0 End @@ -146,6 +167,9 @@ Class MyApp Extends App pointS1.SetScale( framesize ) pointAB.SetScale( framesize ) pointCD.SetScale( framesize ) + For Local i:Int = 0 Until 6 + custom_points[i].SetScale( framesize ) + Next ' demo stuff demox0 = width / 2 + framex0 demoy0 = graphy0 + framey0 @@ -169,6 +193,9 @@ Class MyApp Extends App pointYA.Update() pointY0.Update() pointY1.Update() + For Local i:Int = 0 Until 6 + custom_points[i].Update() + Next ' update function to use If KeyHit( KEY_SPACE ) Then curfuncidx = (curfuncidx + 1) Mod INTERPFUNCS.Length @@ -178,6 +205,9 @@ Class MyApp Extends App pointS0.Hide() pointS1.Hide() pointYA.Hide() + For Local i:Int = 0 Until 6 + custom_points[i].Hide() + Next curfunc.Activate() anypointmoved = True End @@ -245,6 +275,9 @@ Class MyApp Extends App pointYA.Draw(cvMain) pointS0.Draw(cvMain) pointS1.Draw(cvMain) + For Local i:Int = 0 Until 6 + custom_points[i].Draw(cvMain) + Next ' draw demo Local x:Float Local scl:Float @@ -320,6 +353,38 @@ Class InterpFuncLin Extends InterpFunc Method Activate:Void() End End +' InterpolateLin +Class InterpFuncCustomLine Extends InterpFunc + Method Interpolate:Float(pX:Float) + For Local i:Int = 1 Until 7 + custom_data[i] = custom_points[i-1].y + Next + custom_data[0] = pointY0.y + custom_data[7] = pointY1.y + + Return InterpolateCustomLine( custom_data, pX ) + End + Method Label:String() + Return "InterpolateCustomLine( ["+CustomDataString()+"], t )" + End + Method Activate:Void() + For Local i:Int = 0 Until 6 + custom_points[i].Show() + Next + End + Method CustomDataString:String() + Local data:String + + Local i:Int=0 + While i=0 and 1 then t=1 - If t < 0 then t=0 + If t > 1 Then t=1 + If t < 0 Then t=0 EndIf oldx = x ' abort after 20 runs to prevent infinite loops when AB/CD where badly set @@ -141,4 +141,144 @@ Function InterpolateCubicBezier:Float(pY0:Float, pY1:Float, pA:Float, pB:Float, Until runs=20 ' calculate y of cubic bezier spline and return Return pY0 + (3*pB - 3*pY0) * t + (3*pY0 - 6*pB + 3*pD) * t*t + (pY1 + 3*pB - 3*pD - pY0) * t*t*t -End \ No newline at end of file +End + +' interpolates across a custom range of points +Function InterpolateCustomLine:Float(dataY:Float[], pX:Float ) + Local steps:Int = dataY.Length()-1 + If steps <1 Then Return 1 + + Local segment:Int = Min(pX*steps,steps-1.0) + ' between segment and segment+1 + Local ratio:Float = (pX - 1.0/steps*segment) / (1.0/steps) + Return dataY[segment] + (dataY[segment+1]-dataY[segment])*ratio +End + +Function InterpolateBackEaseIn:Float(pY0:Float, pY1:Float, pX:Float) + Local s := 1.70158 + Return pY0 + (pX * pX * ((s + 1) * pX - s)) * (pY1-pY0) +End + +Function InterpolateBackEaseOut:Float(pY0:Float, pY1:Float, pX:Float) + Local s := 1.70158 + pX-=1 + Return pY0 + ((pX * pX * ((s + 1) * pX + s) + 1)) * (pY1-pY0) +End + +Function InterpolateBackEaseInOut:Float(pY0:Float, pY1:Float, pX:Float) + Local s:Float= 1.70158 + Local s2:Float + s2 = s + pX *= 2 + s2 *= 1.525 + If pX < 1 + Return pY0 + (0.5 * (pX * pX *((s2+1) * pX - s2))) * (pY1-pY0) + Endif + pX -= 2 + Return pY0 + (0.5 * (pX * pX * ((s2 + 1) * pX + s2) + 2)) * (pY1-pY0) +End + + +Function InterpolateElasticEaseIn:Float(pY0:Float, pY1:Float, pX:Float) + Local p:Float, s:Float + If pX = 0 Return pY0 + If pX = 1 Return pY1 + p = 0.3 + s = p / 4 + pX -= 1 + Return pY0 - ((Pow(2,10 * (pX)) * Sin(((pX - s) * (2 * PI) / p) * 57.2957795))) * (pY1-pY0) +End + +Function InterpolateElasticEaseOut:Float(pY0:Float, pY1:Float, pX:Float) + Local p:Float + Local s:Float + + If pX = 0 Return pY0 + If pX = 1 Return pY1 + p = 0.3 + s = p / 4 + Return pY0 + ((Pow(2,-10 * pX) * Sin(((pX - s) * (2 * PI) / p) * 57.2957795) + 1)) * (pY1-pY0) +End + +Function InterpolateElasticEaseInOut:Float(pY0:Float, pY1:Float, pX:Float) + Local p:Float + Local s:Float + + If pX = 0 Return pY0 + pX*=2 + If pX = 2 Return pY1 + p = (0.3 * 1.5) + s = p / 4 + If pX < 1 + pX -= 1 + Return pY0 + (-0.5 * (Pow(2,10 * pX) * Sin(((pX - s) * (2 * PI) / p) * 57.2957795))) * (pY1-pY0) + End + pX -= 1 + Return pY0 + (Pow(2,-10 * pX) * Sin(((pX - s) * (2 * PI) / p) * 57.2957795) * 0.5 + 1) * (pY1-pY0) +End + + + +Function InterpolateBounceEaseIn:Float(pY0:Float, pY1:Float, pX:Float) + pX = 1 - pX + If pX < 0.3636363 + Return pY0 + (1 - (7.5625 * pX * pX))*(pY1-pY0) + Else If pX < 0.7272727 + pX -= 0.5454545 + Return pY0 + (1 - (7.5625 * pX * pX + 0.75))*(pY1-pY0) + Else If pX < 0.9090909 + pX -= 0.8181818 + Return pY0 + (1 - (7.5625 * pX * pX + 0.9375))*(pY1-pY0) + Else + pX -= 0.9636363 + Return pY0 + (1 - (7.5625 * pX * pX + 0.984375))*(pY1-pY0) + Endif +End + +Function InterpolateBounceEaseOut:Float(pY0:Float, pY1:Float, pX:Float) + If pX < 0.3636363 + Return pY0 + ((7.5625 * pX * pX) )*(pY1-pY0) + Else If pX < 0.7272727 + pX -= 0.5454545 + Return pY0 + ((7.5625 * pX * pX + 0.75))*(pY1-pY0) + Else If pX < 0.9090909 + pX -= 0.8181818 + Return pY0 + ((7.5625 * pX * pX + 0.9375))*(pY1-pY0) + Else + pX -= 0.9636363 + Return pY0 + ((7.5625 * pX * pX + 0.984375))*(pY1-pY0) + Endif +End + +Function InterpolateBounceEaseInOut:Float(pY0:Float, pY1:Float, pX:Float) + If pX < 0.5 + pX = (1 - pX * 2) + If pX < 0.3636363 + Return pY0 + ((1 - (7.5625 * pX * pX)) * 0.5)*(pY1-pY0) + Else If pX < 0.7272727 + pX -= 0.5454545 + Return pY0 + ((1 - (7.5625 * pX * pX + 0.75)) * 0.5)*(pY1-pY0) + Else If pX < 0.9090909 + pX -= 0.8181818 + Return pY0 + ((1 - (7.5625 * pX * pX + 0.9375)) * 0.5)*(pY1-pY0) + Else + pX -= 0.9636363 + Return pY0 + ((1 - (7.5625 * pX * pX + 0.984375)) * 0.5)*(pY1-pY0) + Endif + Else + pX = (pX * 2 - 1) + If pX < 0.3636363 + Return pY0 + ((7.5625 * pX * pX) * 0.5 + 0.5)*(pY1-pY0) + Else If pX < 0.7272727 + pX -= 0.5454545 + Return pY0 + ((7.5625 * pX * pX + 0.75) * 0.5 + 0.5)*(pY1-pY0) + Else If pX < 0.9090909 + pX -= 0.8181818 + Return pY0 + ((7.5625 * pX * pX + 0.9375) * 0.5 + 0.5)*(pY1-pY0) + Else + pX -= 0.9636363 + Return pY0 + ((7.5625 * pX * pX + 0.984375) * 0.5 + 0.5)*(pY1-pY0) + Endif + Endif +End + diff --git a/modules/mojo/cerberusdoc/graphics.cerberusdoc b/modules/mojo/cerberusdoc/graphics.cerberusdoc index 2b11a357..4ffe7212 100644 --- a/modules/mojo/cerberusdoc/graphics.cerberusdoc +++ b/modules/mojo/cerberusdoc/graphics.cerberusdoc @@ -487,12 +487,14 @@ Load a fixed width font from @path. @firstChar represents the ASCII code of the first char. -# Function Load:Font(path:String) +# Function Load:Font(path:String, flags:Int=Image.DefaultFlags) Loads a bitmap font file created in tools like GlyphDesigner and alike. @path represents the filename of the texfile that defines the font and its individual glyphs. +@flags represents the Image filter that is applied at loading the image sheet. + # Class mojo.graphics.Image diff --git a/modules/mojo/graphics.cxs b/modules/mojo/graphics.cxs index 51bf582b..74ce873e 100644 --- a/modules/mojo/graphics.cxs +++ b/modules/mojo/graphics.cxs @@ -183,7 +183,7 @@ Class Font End '------------------------------------------ - Function Load:Font(url:String) + Function Load:Font(url:String, flags:Int=Image.DefaultFlags) Local iniText:String Local pageNum:Int = 0 Local idnum:Int = 0 @@ -207,12 +207,16 @@ Class Font path = path + pl[pi]+"/" Next Endif - Local ts:String = url.ToLower() - If (ts.Find(".txt") > 0) Then + 'Local ts:String = url.ToLower() + 'If (ts.Find(".txt") > 0) Then + If (url.Find(".txt") > 0) Or (url.Find(".fnt") > 0) Then iniText = app.LoadString(url) - Else - iniText = app.LoadString(url+".txt") + 'Else + ' iniText = app.LoadString(url+".txt") Endif +#If CONFIG="debug" + If iniText.Length = 0 Then Error("~n~nError in file graphics.cxs, Method Font.Load:Font(url:String, flags:Int=Image.DefaultFlags)~n~nCan not load font: "+url) +#End lines = iniText.Split(String.FromChar(13)+String.FromChar(10)) If lines.Length() < 2 then @@ -256,9 +260,9 @@ Class Font Endif filename = path+filename.Trim() - _pages[pageNum] = LoadImage(filename) + _pages[pageNum] = LoadImage(filename, 1, flags) #If CONFIG="debug" - If _pages[pageNum] = Null Then Error("~n~nError in file graphics.cxs, Method Font.Load:Font(url:String)~n~nCan not load page image: "+filename) + If _pages[pageNum] = Null Then Error("~n~nError in file graphics.cxs, Method Font.Load:Font(url:String, flags:Int=Image.DefaultFlags)~n~nCan not load page image: "+filename) #End pageNum = pageNum + 1 Endif diff --git a/modules/mojo2/cerberusdoc/graphics.cerberusdoc b/modules/mojo2/cerberusdoc/graphics.cerberusdoc index d51630ea..2b72cd67 100644 --- a/modules/mojo2/cerberusdoc/graphics.cerberusdoc +++ b/modules/mojo2/cerberusdoc/graphics.cerberusdoc @@ -307,12 +307,14 @@ Load a fixed width font from @path. @firstChar represents the ASCII code of the first char. -# Function Load:Font(path:String) +# Function Load:Font(path:String, flags:Int=Image.Filter) Loads a bitmap font file created in tools like GlyphDesigner and alike. @path represents the filename of the texfile that defines the font and its individual glyphs. +@flags represents the Image filter that is applied at loading the image sheet. + # Class ShadowCaster diff --git a/modules/mojo2/cerberusdoc/mojo2.cerberusdoc b/modules/mojo2/cerberusdoc/mojo2.cerberusdoc index f03da057..39a9b63b 100644 --- a/modules/mojo2/cerberusdoc/mojo2.cerberusdoc +++ b/modules/mojo2/cerberusdoc/mojo2.cerberusdoc @@ -1,10 +1,16 @@ # Module mojo2 +# Import mojo.app + +# Import mojo.audio + # Import mojo.color # Import mojo2.graphics +# Import mojo.input + # Import mojo2.renderer The mojo2 module is a new 2d rendering module for Cerberus. diff --git a/modules/mojo2/graphics.cxs b/modules/mojo2/graphics.cxs index e1e569c2..f68146b4 100644 --- a/modules/mojo2/graphics.cxs +++ b/modules/mojo2/graphics.cxs @@ -1234,7 +1234,11 @@ Class Image 'Local cellWidth:=material.Width/numFrames,cellHeight:=material.Height Local x:=0,width:=cellWidth - If padded x+=1;width-=2 + Local y:=0,height:=cellHeight + If padded + x+=1;width-=2 + y+=1;height-=2 + Endif Local tx:Int = material.Width/cellWidth Local ty:Int = material.Height/cellHeight @@ -1242,7 +1246,7 @@ Class Image Local i:Int = 0 For Local yi:Int = 0 To ty-1 For Local xi:Int = 0 To tx-1 - frames[i]=New Image( material,xi*cellWidth+x,yi*cellHeight,width,cellHeight,xhandle,yhandle ) + frames[i]=New Image( material,xi*cellWidth+x,yi*cellHeight+y,width,cellHeight,xhandle,yhandle ) i += 1 Next Next @@ -1377,7 +1381,7 @@ Class Font End '------------------------------------------ - Function Load:Font(url:String) + Function Load:Font(url:String, flags:Int=Image.Filter ) Local iniText:String Local pageNum:Int = 0 Local idnum:Int = 0 @@ -1401,13 +1405,16 @@ Class Font path = path + pl[pi]+"/" Next Endif - Local ts:String = url.ToLower() - If (ts.Find(".txt") > 0) Then + 'Local ts:String = url.ToLower() + 'If (ts.Find(".txt") > 0) Then + If (url.ToLower().Find(".txt") > 0) Or (url.ToLower().Find(".fnt") > 0) Then iniText = app.LoadString(url) - Else - iniText = app.LoadString(url+".txt") + 'Else + ' iniText = app.LoadString(url+".txt") Endif - +#If CONFIG="debug" + If iniText.Length() = 0 Then Error("~n~nError in file graphics.cxs, Method Font.Load:Font(url:String, flags:Int=Image.Filter)~n~nCan not load font: "+url) +#End lines = iniText.Split(String.FromChar(13)+String.FromChar(10)) If lines.Length() < 2 then lines = iniText.Split(String.FromChar(10)) @@ -1450,9 +1457,9 @@ Class Font Endif filename = path+filename.Trim() - _pages[pageNum] = Image.Load(filename) + _pages[pageNum] = Image.Load(filename,0.5,0.5,flags) #If CONFIG="debug" - If _pages[pageNum] = Null Then Error("~n~nError in file graphics.cxs, Method Font.Load:Font(url:String)~n~nCan not load page image: "+filename) + If _pages[pageNum] = Null Then Error("~n~nError in file graphics.cxs, Method Font.Load:Font(url:String, flags:Int=Image.Filter)~n~nCan not load page image: "+filename) #End pageNum = pageNum + 1 Endif diff --git a/modules/os/os.cerberusdoc b/modules/os/os.cerberusdoc index 2ec7dcb9..5b14e8b6 100644 --- a/modules/os/os.cerberusdoc +++ b/modules/os/os.cerberusdoc @@ -277,7 +277,7 @@ path - a file system path. # Function StripExt:String(path:String) -Extracts and returns the file extension of a file system path. +Removes the file type extension from a file system path. Parameters: diff --git a/modules/reflection/reflector.cxs b/modules/reflection/reflector.cxs index 850b65d2..ab5fbce2 100644 --- a/modules/reflection/reflector.cxs +++ b/modules/reflection/reflector.cxs @@ -628,7 +628,7 @@ Class Reflector Emit " End" Emit "End" - Local source:=output.Join( "~n" ) + Local source:=output.Join( "~n" )+"~n" ' Append a new line character to avoid EOF issues. Local attrs:=DECL_REFLECTOR diff --git a/modules/trans/blktrace.cxs b/modules/trans/blktrace.cxs new file mode 100644 index 00000000..11a556ce --- /dev/null +++ b/modules/trans/blktrace.cxs @@ -0,0 +1,246 @@ +' Module trans.blktrace +' +' Placed into the public domain 27/04/2020. +' No warranty implied; use at your own risk. + +'######################################################################### +' Classes to keep track of code block starts for use in tracing errors +' FILE VERSION 0.1 +' TODO: Modify the file preprocessor.cxs to make use of these classes +Import trans + +'######################################################################### +' Class definintion to contain the token and it's associated line number. +Class TraceRecord + Field _toke + Field _line + + Method New( toke,line ) + _toke=toke + _line=line + End + + Method Toke() + Return _toke + End + + Method Line() + Return _line + End + +End + +'############################################################################# +' Self contained class definition to keep track of the stgart of code blocks. +Class BlockTrace + + Global _Blocks:=New BlockTrace + + ' Identifier code for each type of code block + Const BLK_UNKNOWN:=0 + Const BLK_FOR:=1 + Const BLK_FUNCTION:=2 + Const BLK_METHOD:=3 + Const BLK_IF:=4 + Const BLK_REPEAT:=5 + Const BLK_WHILE:=6 + Const BLK_TRY:=6 + Const BLK_CLASS:=7 + Const BLK_INTERFACE:=8 + Const BLK_SELECT:=9 + + Field _record:=New List ' Work list to keep track of the current blocks. + Field _map:=New IntMap ' Map to keep a permanent track of all block type entry points. + + ' Internal method for adding a record to both the work list and permanent map. + Method AddRecord( record:TraceRecord ) + + Local token:=record.Toke + + If Not _map.Contains( token ) + Local newlist:=New IntList + newlist.AddLast( record.Line ) + _map.Add( token, newlist ) + Else + _map.Get( token ).AddLast( record.Line ) + Endif + + _record.AddLast( record ) + End + + ' Internal method to remove and return the last item on the work list. + Method RemoveRecord:TraceRecord() + If _record.IsEmpty Return Null ' Safe check. Return a Null if there is no item. + Return _record.RemoveLast + End + + ' Internal method to return the last item on the work list. + Method LastBlockItem:TraceRecord() + If _record.IsEmpty Return Null ' Safe check. Return a Null if there is no item. + Return _record.Last + End + + ' Internal method to build a list of line number for known block starts in the permanent map + ' to be sent back to the trace log function. + Method BlockLineList:IntList( token ) + Local blklines:=New IntList + Local lastblkline:Int + + ' Only add the last item line if there is one. + If LastBlockItem()<>Null lastblkline=LastBlockItem.Line() + + ' If the token passed is known, then only build a list for that token block. + If token>BLK_UNKNOWN + Local tokelines:=_map.Get( token ) + + ' Always add the last work list item if it exists. + If lastblkline>0 blklines.AddLast( lastblkline ) + For Local i:=Eachin tokelines + If i>lastblkline blklines.AddLast( i ) + Next + + ' If the token is not known, then construct a full + Else + ' Always add the last work list item if it exists. + If lastblkline>0 blklines.AddLast( lastblkline ) + + ' Read each key in the permanent map and iterate the list stored + ' to add to the list that will be used for the trace log. + For Local i:=Eachin _map.Keys + For Local j:=Eachin _map.Get( i ) + If j>lastblkline blklines.AddLast( j ) + Next + Next + + blklines.Sort + Endif + + Return blklines + End + + ' Internal method to print out a trace log. + Method Unwind( token ) + 'Local rows:=New StringStack + + Local blklines:=_Blocks.BlockLineList( token ).ToArray + Local path:=_errInfo[.. _errInfo.FindLast( "<" )] + + Print "~n~t------------ BLOCK TRACE ------------" + Print "FILE: "+path + Local i:=0 + + ' All lines should be output as rows of ten to cut down on the length of the console output. + While i=blklines.Length Exit + str+=blklines[i]+", " + i+=1 + col+=1 + Wend + Print "Statement Blocks at lines: "+str[..str.Length()-2] + Wend + + Print "" + + ' Return either the first line if there is one or zero. + If blklines.Length>0 Return blklines[0] Else Return 0 + End + + ' External function to get the last item stored on the work list. + Function LastRecordItem:TraceRecord() + Return _Blocks.LastBlockItem() + End + + ' External function to output a trace log by passing the block identifier code + ' that is of interest. + Function TraceLog( token=BLK_UNKNOWN ) + Return _Blocks.Unwind( token ) + End + + ' External function to output a trace log by passing the block identifier string + ' that is of interest. + Function TraceLog( token$="" ) + Return _Blocks.Unwind( Str2Code( token ) ) + End + + ' External function to return a block string identifier from a block code identifier. + Function Code2Str$( code ) + Select code + Case BLK_FOR + Return "For" + Case BLK_FUNCTION + Return "Function" + Case BLK_METHOD + Return "Method" + Case BLK_IF + Return "If" + Case BLK_REPEAT + Return "Repeat" + Case BLK_WHILE + Return "While" + Case BLK_TRY + Return "Try" + Case BLK_CLASS + Return "Class" + Case BLK_INTERFACE + Return "Try" + Case BLK_SELECT + Return "Select" + Default + Return "" + End + End + + ' External function to return a block code identifier from a block string identifier. + Function Str2Code( toke$ ) + Select toke.ToLower() + Case "for" + Return BLK_FOR + Case "function" + Return BLK_FUNCTION + Case "method" + Return BLK_METHOD + Case "if" + Return BLK_IF + Case "repeat" + Return BLK_REPEAT + Case "while" + Return BLK_WHILE + Case "try" + Return BLK_TRY + Case "class" + Return BLK_CLASS + Case "interface" + Return BLK_INTERFACE + Case "select" + Return BLK_SELECT + Default + Return BLK_UNKNOWN + End + End + + ' Reset both the work list and permanent map + Function Clear() + _Blocks._map.Clear + _Blocks._record.Clear + End + + ' External function to store both a block start token and it's line number by passing + ' the token's identifier code. + Function Push( toke, line ) + _Blocks.AddRecord( New TraceRecord( toke,line ) ) + End + + ' External function to store both a block start token and it's line number by passing + ' the token's identifier string. + Function Push( toke$, line ) + _Blocks.AddRecord( New TraceRecord( Str2Code( toke ),line ) ) + End + + ' External function to remove and return the last item on the work list. + Function Pop:TraceRecord() + Return _Blocks.RemoveRecord + End + +End \ No newline at end of file diff --git a/modules/trans/decl.cxs b/modules/trans/decl.cxs index b3727211..91239ad9 100644 --- a/modules/trans/decl.cxs +++ b/modules/trans/decl.cxs @@ -1471,6 +1471,7 @@ Class AppDecl Extends ScopeDecl Field allSemantedDecls:=New List 'top-level decls including externs Field fileImports:=New StringList + Field fileIncludes:=New StringList Method InsertModule( mdecl:ModuleDecl ) mdecl.scope=Self diff --git a/modules/trans/parser.cxs b/modules/trans/parser.cxs index 52244368..7a5d7956 100644 --- a/modules/trans/parser.cxs +++ b/modules/trans/parser.cxs @@ -3,7 +3,16 @@ ' Placed into the public domain 24/02/2011. ' No warranty implied; use at your own risk. +'###################################################################################################### +' This file scans the source file for syntax and builds a statement block ready for semantic analysis. +'###################################################################################################### +' NOTE: All comments should be viewed as a work-in-progress and my not be an accurate description of +' the internal workings of this file. + +' TODO: Commplete and check comments for accuracy. + Import trans +Import blktrace Global FILE_EXT_OLD$=".monkey" Global FILE_EXT$=".cxs" @@ -356,8 +365,9 @@ Class Parser Field _module:ModuleDecl Field _defattrs - Method SetErr() - If _toker.Path _errInfo=_toker.Path+"<"+_toker.Line+">" + Method SetErr( line=-1 ) + If line=-1 line=_toker.Line + If _toker.Path _errInfo=_toker.Path+"<"+line+">" End Method PushErr() @@ -368,6 +378,38 @@ Class Parser _errInfo=_errStack.RemoveLast() End + ' Check that the optional terminators are valid. + Method ParseBlockEnd( toke$, msg$="", log=False ) + SetErr + If Not CParse( toke ) And AtEos2=False And _tokeType<>TOKE_LINECOMMENT + If msg<>"" + If log BlockTrace.TraceLog( toke ) + Err msg + Endif + Return True + Endif + Return False + End + + ' End of file error reporting. + Method AtEOF( tokeID, msg$ ) + SetErr( BlockTrace.TraceLog( tokeID ) ) + Err "End-Of-File Reached. "+msg+" block not terminated correctly." + End + + ' End of file error reporting. String token version. + Method AtEOF( tokeID$, msg$ ) + SetErr( BlockTrace.TraceLog( tokeID ) ) + Err "End-Of-File Reached. "+msg+" block not terminated correctly." + End + + Method BackTrace:TraceRecord( tokeID ) + Local blk:=BlockTrace.TraceLog( tokeID ) + Local record:=BlockTrace.Pop + If record<>Null SetErr( record.Line ) + Return record + End + Method PushBlock( block:BlockDecl ) _blockStack.AddLast _block _errStack.AddLast _errInfo @@ -401,7 +443,7 @@ Class Parser Case TOKE_SYMBOL If _toke[0]=91 And _toke[_toke.Length-1]=93 ' If _toke[0]=Asc("[") And _toke[_toke.Length-1]=Asc("]") - _toke="[]" + _toke="[]" ' Set toke for empty array parsing. Endif End @@ -420,7 +462,7 @@ Class Parser Method Parse( toke$ ) If Not CParse( toke ) - Err "Syntax error - expecting '"+toke+"'." + Err "Syntax error - Expecting '"+toke+"'." Endif End @@ -428,6 +470,10 @@ Class Parser Return _toke="" Or _toke=";" Or _toke="~n" Or _toke="else" End + Method AtEos2() + Return _toke="" Or _toke=";" Or _toke="~n" + End + Method SkipEols() While CParse( "~n" ) Wend @@ -448,7 +494,7 @@ Class Parser Case "object","throwable" ' Default - If _tokeType<>TOKE_IDENT Err "Syntax error - expecting identifier." + If _tokeType<>TOKE_IDENT Err "Syntax error - Expecting identifier." End Local id$=_toke NextToke @@ -701,14 +747,27 @@ Class Parser Case TOKE_INTLIT expr=New ConstExpr( Type.intType,_toke ) NextToke + Case TOKE_FLOATLIT expr=New ConstExpr( Type.floatType,_toke ) NextToke + Case TOKE_STRINGLIT expr=New ConstExpr( Type.stringType,Dequote( _toke,"cerberus" ) ) NextToke + + ' In the case the parser should reach the end of the file and there is no known + ' open blocks. Provide a trace log and highlight the last known block that is still + ' on the record list. + Case TOKE_EOF + Local record:=BackTrace( BlockTrace.BLK_UNKNOWN ) + Err "End-Of-File. "+ + BlockTrace.Code2Str( record.Toke )+" block incorrectly terminated." + Default - Err "Syntax error - unexpected token '"+_toke+"'" + Local record:=BackTrace( BlockTrace.BLK_UNKNOWN ) + If record<>Null SetErr( _toker.Line ) Else SetErr + Err "Syntax error - Unexpected token '"+_toke+"'." End Select End Select @@ -882,9 +941,9 @@ Class Parser End Method ParseIfStmt( term$ ) - + Local lineStart=_toker.Line, tokeID=BlockTrace.BLK_IF CParse "if" - + Local expr:Expr=ParseExpr() CParse "then" @@ -898,12 +957,18 @@ Class Parser eatTerm=True Endif + BlockTrace.Push( tokeID, lineStart ) PushBlock thenBlock While _toke<>term + + ' If the EOF is reached, then the last block item is made as the error, giving a trace of all open blocks. + If _tokeType=TOKE_EOF AtEOF( tokeID, "Conditional" ) + Select _toke Case "endif" If term="end" Exit - Err "Syntax error - expecting 'End'." + SetErr( BlockTrace.TraceLog( tokeID ) ) + Err "Syntax error - Expecting conditional blocks to terminate with 'End', 'End If' or 'Endif'." Case "else","elseif" Local elif=_toke="elseif" NextToke @@ -920,10 +985,15 @@ Class Parser End Wend PopBlock + Local blkTrace:=BlockTrace.Pop If eatTerm NextToke - If term="end" CParse "if" + If term="end" + ' If the next token is not an 'If' statement, or one of the known Eos terminators. Then trhow an error. + ParseBlockEnd( "if", + "Syntax error - Expecting conditional blocks to terminate with 'End', 'Endif' Or 'End If'.", True ) + Endif Endif Local stmt:IfStmt=New IfStmt( expr,thenBlock,elseBlock ) @@ -932,39 +1002,65 @@ Class Parser End Method ParseWhileStmt() - + Local lineStart:=_toker.Line, tokeID:=BlockTrace.BLK_WHILE + + SetErr + Local errLine:=_errInfo Parse "while" Local expr:Expr=ParseExpr() Local block:BlockDecl=New BlockDecl( _block ) + BlockTrace.Push( tokeID,lineStart ) PushBlock block - While Not CParse( "wend" ) - If CParse( "end" ) - CParse "while" + + While True + ' Deal with the end of the file before touching the trace data. + If _tokeType=TOKE_EOF AtEOF( tokeID,"While/Wend/End While iterator" ) + + ' If the block terminator isn't 'Wend', then test for 'End' + ' If 'end' is found, then test to see if the following is 'While'. If not, then throw an error. + If Not CParse( "wend" ) + If CParse( "end" ) + If Not ParseBlockEnd( "while", "Syntax error - Expecting 'while' block to terminate with 'End' or 'End While'." ) Exit + Exit + Endif + Else + If Not AtEos2; SetErr; Err "Syntax error - Wend does not except a variable or expression." Exit Endif ParseStmt Wend PopBlock + Local blkTrace:=BlockTrace.Pop + Local stmt:WhileStmt=New WhileStmt( expr,block ) _block.AddStmt stmt End Method ParseRepeatStmt() - + Local lineStart:=_toker.Line, tokeID:=BlockTrace.BLK_REPEAT Parse "repeat" Local block:BlockDecl=New BlockDecl( _block ) + ' Store the trace and declaration blocks before iterate through the following tokens + ' until one of the iterator's exit tokes are met. + BlockTrace.Push( tokeID,lineStart ) PushBlock block - While _toke<>"until" And _toke<>"forever" + While _toke<>"until" And _toke<>"forever" And _tokeType<>TOKE_EOF ParseStmt Wend PopBlock + ' Deal with the end of the file before touching the trace data. + If _tokeType=TOKE_EOF AtEOF( tokeID, "Repeat/Until/Forever" ) + + Local blkTrace:=BlockTrace.Pop + + ' Depending on the block terminator, either parse the expression, or create a new forever expression. Local expr:Expr If CParse( "until" ) PushErr @@ -978,14 +1074,16 @@ Class Parser Local stmt:RepeatStmt=New RepeatStmt( block,expr ) _block.AddStmt stmt + End Method ParseForStmt() - + Local lineStart=_toker.Line, tokeID=BlockTrace.BLK_FOR + Parse "for" Local varid$,varty:Type,varlocal - + If CParse( "local" ) varlocal=True varid=ParseIdent() @@ -1003,16 +1101,54 @@ Class Parser Local expr:Expr=ParseExpr() Local block:BlockDecl=New BlockDecl( _block ) + BlockTrace.Push( tokeID, lineStart ) PushBlock block - While Not CParse( "next" ) - If CParse( "end" ) - CParse "for" + While True + + ' If the EOF is reached, then the last block item is made as the error, giving a trace of all open blocks. + If _tokeType=TOKE_EOF AtEOF( tokeID,"For/Next/End For" ) + + ' Check for block ends. As these blocks can have variables as part of their temination code, these are checked for. + If CParse( "next" ) + If _tokeType=TOKE_IDENT And ParseIdent()<>varid Err "Syntax error - Next variable name does not match For variable name" + + ' If the token is not and end of line character, then throw an error on which 'For' iterators are allowed. + If Not AtEos2() BlockTrace.TraceLog( tokeID ); Err "Syntax error - Expecting 'For' iterator to terminate with 'Next', 'End' or 'End For'." + Exit + + ' Not 'Next', so test for 'End' + Else If CParse( "end" ) + + ' If the current token isn't 'For', then assume that it's the iteration variable. + If _toke<>"for" + + ' Check for the iteration variable, if it's not, then throw an error. + If _tokeType=TOKE_IDENT And ParseIdent()<>varid + Err "Syntax error - Next variable name does not match For variable name" + Endif + + ' If the token is not and end of line character, then throw an error on which 'For' iterators are allowed. + If Not AtEos2() BlockTrace.TraceLog( tokeID ); Err "Syntax error - Expecting 'For' iterator to terminate with 'Next', 'End' or 'End For'." + + ' It is 'For', advance one token and assume that the next token will be the iteration variable + Else + NextToke + + ' Check for the iteration variable, if it's not, then throw an error. + If _tokeType=TOKE_IDENT And ParseIdent()<>varid + Err "Syntax error - Next variable name does not match For variable name" + Endif + + ' If the token is not and end of line character, then throw an error on which 'For' iterators are allowed. + If Not AtEos2() BlockTrace.TraceLog( tokeID ); Err "Syntax error - Expecting 'For' iterator to terminate with 'Next', 'End' or 'End For'." + Endif Exit Endif + ParseStmt - Wend - If _tokeType=TOKE_IDENT And ParseIdent()<>varid Err "Next variable name does not match For variable name" + Wend PopBlock + Local blkTrace:=BlockTrace.Pop() Local stmt:ForEachinStmt=New ForEachinStmt( varid,varty,varlocal,expr,block ) @@ -1055,16 +1191,55 @@ Class Parser Local block:BlockDecl=New BlockDecl( _block ) + BlockTrace.Push( tokeID, lineStart ) PushBlock block - While Not CParse( "next" ) - If CParse( "end" ) - CParse "for" + + While True + ' If the EOF is reached, then the last block item is made as the error, giving a trace of all open blocks. + If _tokeType=TOKE_EOF AtEOF( tokeID,"For/Next/End For" ) + + ' Check for block ends. As these blocks can have variables as part of their temination code, these are checked for. + If CParse( "next" ) + If _tokeType=TOKE_IDENT And ParseIdent()<>varid Err "Syntax error - Next variable name does not match For variable name" + + ' If the token is not and end of line character, then throw an error on which 'For' iterators are allowed. + If Not AtEos2() BlockTrace.TraceLog( tokeID ); Err "Syntax error - Expecting 'For' iterator to terminate with 'Next', 'End' or 'End For'." + Exit + + ' Not 'Next', so test for 'End' + Else If CParse( "end" ) + + ' If the current token isn't 'For', then assume that it's the iteration variable. + If _toke<>"for" + + ' Check for the iteration variable, if it's not, then throw an error. + If _tokeType=TOKE_IDENT And ParseIdent()<>varid + Err "Syntax error - Next variable name does not match For variable name" + Endif + + ' If the token is not and end of line character, then throw an error on which 'For' iterators are allowed. + If Not AtEos2() BlockTrace.TraceLog( tokeID ); Err "Syntax error - Expecting 'For' iterator to terminate with 'Next', 'End' or 'End For'." + + ' It is 'For', advance one token and assume that the next token will be the iteration variable + Else + NextToke + + ' Check for the iteration variable, if it's not, then throw an error. + If _tokeType=TOKE_IDENT And ParseIdent()<>varid + Err "Syntax error - Next variable name does not match For variable name" + Endif + + ' If the token is not and end of line character, then throw an error on which 'For' iterators are allowed. + If Not AtEos2() BlockTrace.TraceLog( tokeID ); Err "Syntax error - Expecting 'For' iterator to terminate with 'Next', 'End' or 'End For'." + Endif Exit Endif + ParseStmt Wend - If _tokeType=TOKE_IDENT And ParseIdent()<>varid Err "Next variable name does not match For variable name" + PopBlock + Local blkTrace:=BlockTrace.Pop() Local stmt:ForStmt=New ForStmt( init,expr,incr,block ) @@ -1089,13 +1264,20 @@ Class Parser End Method ParseTryStmt() + Local lineStart=_toker.Line, tokeID=BlockTrace.BLK_TRY Parse "try" Local block:=New BlockDecl( _block ) Local catches:=New Stack + BlockTrace.Push( tokeID,lineStart ) PushBlock block While _toke<>"end" + + ' If the EOF is reached, then the last block item is made as the error, giving a trace of all open blocks. + If _tokeType=TOKE_EOF AtEOF( tokeID,"Try/End Try" ) + + ' Process the catch block if found. If CParse( "catch" ) Local id:=ParseIdent() Parse ":" @@ -1105,15 +1287,19 @@ Class Parser catches.Push New CatchStmt( init,block ) PopBlock PushBlock block - Else + + Else ParseStmt Endif Wend + If Not catches.Length Err "Try block must have at least one catch block" PopBlock + Local record:=BlockTrace.Pop + NextToke - CParse "try" - + ParseBlockEnd( "try","Expecting 'Try' block must terminate with 'End' or 'End Try'." ) + _block.AddStmt New TryStmt( block,catches.ToArray() ) End @@ -1125,11 +1311,13 @@ Class Parser Method ParseSelectStmt() Parse "select" - + Local lineStart=_toker.Line, tokeID=BlockTrace.BLK_SELECT Local expr:=ParseExpr() Local block:BlockDecl=_block - + + BlockTrace.Push( tokeID,lineStart ) + _selTmpId+=1 Local tmpId:=String( _selTmpId ) '1,2,3... block.AddStmt New DeclStmt( tmpId,Null,expr ) @@ -1141,6 +1329,8 @@ Class Parser While _toke<>"end" And _toke<>"default" SetErr + If _tokeType=TOKE_EOF Exit + Select _toke Case "~n" NextToke @@ -1176,7 +1366,7 @@ Class Parser block=elseBlock Default - Err "Syntax error - expecting 'Case', 'Default' or 'End'." + Err "Syntax error - Expecting 'Case', 'Default' or 'End'." End Select Wend @@ -1184,6 +1374,8 @@ Class Parser NextToke PushBlock block While _toke<>"end" + If _tokeType=TOKE_EOF Exit + SetErr Select _toke Case "case" @@ -1196,9 +1388,14 @@ Class Parser PopBlock Endif + ' If the EOF is reached, then the last block item is made as the error, giving a trace of all open blocks. + If _tokeType=TOKE_EOF AtEOF( tokeID, "Selec/Case" ) + SetErr Parse "end" - CParse "select" + ParseBlockEnd( "select", "Syntax error -"+ + "Expecting 'Select' block to terminate with 'End' or 'End Select'." ) + BlockTrace.Pop End Method ParseStmt() @@ -1254,7 +1451,7 @@ Class Parser expr=New FuncCallExpr( expr,ParseArgs( True ) ) Else If FuncCallExpr( expr) Or InvokeSuperExpr( expr ) Or NewObjectExpr( expr ) - + Else Err "Expression cannot be used as a statement." Endif @@ -1266,27 +1463,34 @@ Class Parser Method ParseDecl:Decl( toke$,attrs ) SetErr - Local id$=ParseIdent() - Local ty:Type - Local init:Expr + + Local id$=ParseIdent() ' If the token is of the TOKE_IDENT, then this will return the string identifier and advance to the next token. + Local ty:Type ' Holds any type evaluated. + Local init:Expr ' Holds any expression evaluated. + If attrs & DECL_EXTERN ty=ParseDeclType() + Else If CParse( ":=" ) init=ParseExpr() + Else ty=ParseDeclType() If CParse( "=" ) init=ParseExpr() + Else If CParse( "[" ) Local len:=ParseExpr() Parse "]" - While CParse( "[]" ) + While CParse( "[]" ) ' This is a token that the method Parser.NextToke applies for empty arrays. ty=ty.ArrayOf() Wend init=New NewArrayExpr( ty,len ) ty=ty.ArrayOf() + Else If toke<>"const" init=New ConstExpr( ty,"" ) + Else Err "Constants must be initialized." Endif @@ -1344,7 +1548,7 @@ Class Parser init=New ConstExpr(Type.intType, i) Else init=New BinaryMathExpr( "+",lastInit.Copy(),New ConstExpr(Type.intType, i) ) - End + Endif decl=New ConstDecl( id,attrs,Type.intType,init ) Else Parse "=" @@ -1358,7 +1562,7 @@ Class Parser declList.AddLast(decl) Else _block.AddStmt New DeclStmt( decl ) - End + Endif Until Not CParse(",") Return declList End @@ -1373,11 +1577,12 @@ Class Parser End Method ParseFuncDecl:FuncDecl( attrs ) - + Local lineStart=_toker.Line, tokeID=BlockTrace.BLK_FUNCTION SetErr If CParse( "method" ) attrs|=FUNC_METHOD + tokeID=BlockTrace.BLK_METHOD Else If Not CParse( "function" ) InternalErr Endif @@ -1451,37 +1656,55 @@ Class Parser Endif Endif - If funcDecl.IsExtern() Or funcDecl.IsAbstract() Return funcDecl + If funcDecl.IsExtern() Or funcDecl.IsAbstract() + Return funcDecl + Endif + BlockTrace.Push( tokeID, lineStart ) PushBlock funcDecl While _toke<>"end" ParseStmt Wend PopBlock - - NextToke - - If attrs & (FUNC_CTOR|FUNC_METHOD) - CParse "method" + Local blkTrace:=BlockTrace.Pop() + + ' If the last token parsed was 'end', then check to see in the next token is one of the + ' allowed keywords. + If _toke="end" + NextToke + + Local blkend:="function" + Local msg:="Syntax error - Expecting Function block to terminate with 'End' or 'End Function'." + + If attrs & (FUNC_CTOR|FUNC_METHOD) + blkend="method" + msg="Syntax error - Expecting Method block to terminate with 'End' Or 'End Method'." + Endif + + SetErr + ParseBlockEnd( blkend, msg ) Else - CParse "function" + NextToke Endif - + Return funcDecl End Method ParseClassDecl:ClassDecl( attrs ) - SetErr - Local toke:=_toke + + Local toke:=_toke, lineStart=_toker.Line, tokeID=BlockTrace.BLK_CLASS If CParse( "interface" ) If attrs & DECL_EXTERN Err "Interfaces cannot be extern." attrs|=CLASS_INTERFACE|DECL_ABSTRACT + tokeID=BlockTrace.BLK_INTERFACE Else If Not CParse( "class" ) InternalErr Endif + BlockTrace.Push( tokeID,lineStart ) + Local id$=ParseIdent() Local args:=New StringStack Local superTy:IdentType=Type.objectType @@ -1575,11 +1798,29 @@ Class Parser If (attrs & CLASS_INTERFACE) Err "Interfaces can only contain constants and methods." classDecl.InsertDecl ParseFuncDecl( decl_attrs|func_attrs ) Default - Err "Syntax error - expecting class member declaration." + ' In the case the parser should reach the end of the file and there is no known + ' open blocks. Provide a trace log and highlight the last known block that is still + ' on the record list. + If _tokeType=TOKE_EOF AtEOF( BlockTrace.BLK_UNKNOWN, "Code" ) + Err "Syntax error - Expecting class member declaration." End Select Forever - If toke CParse toke + If toke + ' Line end checks for class or interface + Local msg:="" + If toke="class" + msg="Syntax error - Expecting 'Class' to terminate with 'End' or 'End Class'." + Else If toke="interface" + msg="Syntax error - Expecting 'Interface' to terminate with 'End' or 'End Interface'." + Endif + + If msg<>"" + SetErr + ParseBlockEnd( toke, msg, True ) + End + Endif + Local recor:=BlockTrace.Pop Return classDecl End @@ -1630,9 +1871,12 @@ Class Parser Local attrs + BlockTrace.Clear + 'Parse header - imports etc. While _toke SetErr + Select _toke Case "~n" NextToke @@ -1651,6 +1895,16 @@ Class Parser Else ImportModule ParseModPath(),attrs Endif + Case "include" + NextToke + Local filepath:String = ParseStringLit() + Local iOpt:= filepath.Find(" ") + If iOpt > 1 + filepath = RealPath(filepath[..iOpt])+filepath[iOpt..] + Else + filepath = RealPath(filepath) + Endif + _app.fileIncludes.AddLast(filepath ) Case "friend" NextToke Local modpath:=ParseModPath() @@ -1733,7 +1987,7 @@ Class Parser Case "function" _module.InsertDecl ParseFuncDecl( attrs ) Default - Err "Syntax error - expecting declaration." + Err "Syntax error - Expecting declaration." End Select Wend diff --git a/modules/trans/preprocessor.cxs b/modules/trans/preprocessor.cxs index 42f53e86..af2495ff 100644 --- a/modules/trans/preprocessor.cxs +++ b/modules/trans/preprocessor.cxs @@ -1,6 +1,15 @@ - Import parser +'################################################################### +' This file scans the source file for module and preprocessor data. +'################################################################### +' NOTE: All comments should be viewed as a work-in-progress and my not be an accurate description of +' the internal workings of this file. + +' TODO: Change the block tracking method to use the one in the file 'blktrace.cxs'. +' TODO: Check comments for accuracy. +' The next three functions are used to evaluate tokens that are expressions. +' Evaluate the token an expression Function EvalExpr:Expr( toker:Toker ) Local buf:=New StringStack @@ -8,6 +17,7 @@ Function EvalExpr:Expr( toker:Toker ) buf.Push toker.Toke toker.NextToke Wend + Local source:=buf.Join( "" ) toker=New Toker( "",source ) @@ -17,13 +27,17 @@ Function EvalExpr:Expr( toker:Toker ) Return expr End +' Evaluate the token as boolean Function EvalBool:Bool( toker:Toker ) + If toker.Remarks() Return False ' If the remark flag is set then return false. + Local expr:=EvalExpr( toker ) If Not BoolType( expr.exprType ) expr=expr.Cast( Type.boolType,CAST_EXPLICIT ) If expr.Eval() Return True Return False End +' Evaluate the token an string/text Function EvalText:String( toker:Toker ) Local expr:=EvalExpr( toker ) @@ -41,198 +55,311 @@ Function EvalText:String( toker:Toker ) Return val End +'############################################################################################################################################ +' Description: The function scans the source file to process and preprocessor directives, modules and other types of configuration variables. +' FUNCTION PreProcess( path:String, mdecl:ModuleDecl=Null) +' path: The source file on disk to process +' mdec: A module declaration (see file modules/trans/decl.cxs) Function PreProcess$( path$,mdecl:ModuleDecl=Null ) - Local cnest,ifnest,line,source:=New StringStack + ' Set up internal variables for the function + ' The cnest variable has two jobs: + ' The first being the total nexting level depth. + ' The second is to keep skip blocks within conditionals by setting by 17. + ' This means that nesting level depths are only permitted upto 65535. Any thing past this will be unpredictable. + Local cnest,ifnest,line,source:=New StringStack, tracknesting:=New IntStack(), trace:=New IntStack() - PushEnv GetConfigScope() + PushEnv GetConfigScope() ' Preserver the current configuration scope. + ' Get the current directory and module path configuration variables. Local p_cd:=GetConfigVar( "CD" ) Local p_modpath:=GetConfigVar( "MODPATH" ) - SetConfigVar "CD",ExtractDir( RealPath( path ) ) - If mdecl SetConfigVar "MODPATH",mdecl.rmodpath Else SetConfigVar "MODPATH","" + SetConfigVar "CD",ExtractDir( RealPath( path ) ) ' Set the CD configuration variable will the real file path. - Local toker:=New Toker( path,LoadString( path ) ) + If mdecl SetConfigVar "MODPATH",mdecl.rmodpath Else SetConfigVar "MODPATH","" ' If there is a valid module declaration, then set the module path configuration variable, else start with an empty one. + + Local toker:=New Toker( path,LoadString( path ) ) ' Load in the source file from disk and point to the first item to tokenize toker.NextToke - Local attrs:=0 -' If mdecl mdecl.ImportModule "monkey",0 + Local attrs:=0 ' The attrs variable will determine if the imported module will be public (value of zero) or private value of DECL_PRIVATE. + '############################################################################################################################## + ' SCANNER/LEXER + ' Description: Get the tokens from the source file to parse and build another set of tokes for the parser to construct the AST Repeat - + + '####################### + ' SCAN FOR VALID TOKENS + ' Description: TODO If line source.Push "~n" While toker.Toke And toker.Toke<>"~n" And toker.TokeType<>TOKE_LINECOMMENT toker.NextToke Wend + If Not toker.Toke Exit toker.NextToke Endif line+=1 - _errInfo=toker.Path+"<"+toker.Line+">" + _errInfo=toker.Path+"<"+toker.Line+">" ' Store the file path and the current line number for use when there is an error. If toker.TokeType=TOKE_SPACE toker.NextToke + '####################################### + ' READ IN NON PREPROCESS DIRECTIVE CODE + ' If the token is not the hash symbol, then import any modules and pass through any non preprocessor directives statements. If toker.Toke<>"#" - If cnest=ifnest + + ' If both cnest and ifnest are equal. Proceed to process any module imports and code that is not a preprocessor directive. + If cnest=ifnest + Local line:="" - While toker.Toke And toker.Toke<>"~n" And toker.TokeType<>TOKE_LINECOMMENT - Local toke:=toker.Toke + ' Loop through the tokens as long as the token is not a newline escape, or a line comment. + While toker.Toke And toker.Toke<>"~n" And toker.TokeType<>TOKE_LINECOMMENT + + Local toke:=toker.Toke ' Get the current token string and advance to the next token toker.NextToke + ' If there is a valid module object, aka a source file etc. + ' Then set the public/private flag or add a module to import to the list. If mdecl Select toke.ToLower() - Case "public" - attrs=0 - Case "private" - attrs=DECL_PRIVATE - Case "import" - While toker.TokeType=TOKE_SPACE - toke+=toker.Toke - toker.NextToke - Wend - If toker.TokeType=TOKE_IDENT - Local modpath:=toker.Toke - While toker.NextToke="." - modpath+="." + Case "public" + attrs=0 + Case "private" + attrs=DECL_PRIVATE + Case "import" + While toker.TokeType=TOKE_SPACE + toke+=toker.Toke toker.NextToke - If toker.TokeType<>TOKE_IDENT Exit - modpath+=toker.Toke Wend - toke+=modpath -' Print "Import found: "+toke - mdecl.ImportModule modpath,attrs - Endif - End + + ' If the last token is a IDENT, then this is the start of a module scope + If toker.TokeType=TOKE_IDENT + + Local modpath:=toker.Toke ' Add the initial token as part of the module path. + + ' Loop through untill the token in not an IDENT or the scope operator. + While toker.NextToke="." + modpath+="." + toker.NextToke + If toker.TokeType<>TOKE_IDENT Exit + modpath+=toker.Toke + Wend + toke+=modpath + + mdecl.ImportModule modpath,attrs ' Call the import module with the path and public/private flag. + Endif + End Endif - line+=toke + line+=toke ' Add the token to the line that will be pushed onto the internal source data. Wend + If line source.Push line + Endif Continue Endif + '################################# + ' PROCESS PREPROCESSOR DIRECTIVES + ' Description: The last token will be a hash `#`, so the token is advanced by one to get the next one. + ' This token is then checked to see if it's one of the following preprocessor directives, + ' `rem`, `if`, `else`, `elseif`, `endif`, `end`, `print` and `error`. Any non predefined will be treated as + ' an environment variable. An error is throw if any attempt to change any of the following + ' predefined environment variables `HOST`, `LANG`, `CONFIG`, `TARGET` and `SAFEMODE`. + ' + ' Nesting of conditional preprocessor directives and remark blocks are tracked by cnest and ifnest. + ' Bit 17 of cnest is used it set cnest to a higher value. When both cnest and ifnest are the same value + ' and when a `else` or `elseif` statement is encountered. Bit 17 of cnest is set, this will force the scanner to ignore parsing statements + ' until either an `if`, `elseif`, `endif`, `end` is encountered, with `if` and `elseif` re-evaluating the parity of cnest and ifnest based on the outcome if the condition test. + ' + ' Each time a `rem`, `if` is encountered, then the current line is stored to the string stack `tracknesting` and removed when a `end`, or `endif` is encountered. + ' This and the string stack `trace`, which holds `else` and `elseif` preprocessors is used to generate an error if the current token is of the type End-Of-File + ' and there was no correct termination of a conditional or remark block. + ' This makes for a primative preprocess nesting trace to highlight all block rem/if/else/elseif starts. Local toke:=toker.NextToke + If toker.TokeType=TOKE_SPACE toke=toker.NextToke Local stm:=toke.ToLower() Local ty:=toker.TokeType() toker.NextToke - + + ' Make adjustments to the current statment if it is an `end` or `else` statment and the following is an `if` statment. If stm="end" Or stm="else" If toker.TokeType=TOKE_SPACE toker.NextToke - If toker.Toke.ToLower()="if" + + If toker.Toke.ToLower()="if" toker.NextToke stm+="if" Endif + Endif + ' Process the statement Select stm - Case "rem" - - ifnest+=1 - - Case "if" - - ifnest+=1 - - If cnest=ifnest-1 - If EvalBool( toker ) cnest=ifnest - Endif - - Case "else" - - If Not ifnest Err "#Else without #If" - - If cnest=ifnest - cnest|=$10000 - Else If cnest=ifnest-1 - cnest=ifnest - Endif - - Case "elseif" - - If Not ifnest Err "#ElseIf without #If" - - If cnest=ifnest - cnest|=$10000 - Else If cnest=ifnest-1 - If EvalBool( toker ) cnest=ifnest - Endif - - Case "end","endif" - - If Not ifnest Err "#End without #If or #Rem" - - ifnest-=1 - - If ifnest<(cnest & $ffff) cnest=ifnest - - Case "print" - - If cnest=ifnest - Print EvalText( toker ) - Endif - - Case "error" - - If cnest=ifnest - Err EvalText( toker ) - Endif + Case "rem" + + If Not Toker.Remarks() + Toker.RemarksOn() + ifnest+=1 + tracknesting.Push line ' Keep trace of the error line when a nesting value has been increased + trace.Push line ' Keep track of elseif statements for tracing if there is an open nesting block at the end of the file. + Endif + + Case "if" + + ifnest+=1 + + If cnest=ifnest-1 + If EvalBool( toker ) cnest=ifnest + Endif + + tracknesting.Push line ' Keep trace of the error line when a nesting value has been increased + trace.Push line ' Keep track of elseif statements for tracing if there is an open nesting block at the end of the file. + + Case "else" + + If Not ifnest Err "#Else without #If" + + If cnest=ifnest + cnest|=$10000 + Else If cnest=ifnest-1 + cnest=ifnest + Endif + + trace.Push line ' Keep track of elseif statements for tracing if there is an open nesting block at the end of the file. - Default - - If cnest=ifnest - If ty=TOKE_IDENT + Case "elseif" - If toker.TokeType=TOKE_SPACE toker.NextToke - Local op:=toker.Toke() - - Select op - Case "=","+=" - - Select toke - Case "HOST","LANG","CONFIG","TARGET","SAFEMODE" - Err "App config var '"+toke+"' cannot be modified" - End + If Not ifnest Err "#ElseIf without #If" + + If cnest=ifnest + cnest|=$10000 + Else If cnest=ifnest-1 + If EvalBool( toker ) cnest=ifnest + Endif + + trace.Push line ' Keep track of elseif statements for tracing if there is an open nesting block at the end of the file. + + Case "end","endif" + + If Not ifnest Err "#End without #If or #Rem" + + ifnest-=1 + + ' Trap the lower 16 bits (0-15) of the cnest value. This removes bit 17 and gives a nesting level range of 0-65535. + ' If the cnest value is still higher than the ifnest value, then the cnest value is set to the value in ifnest. + ' Any other preprocessor directve such as #else, #elseif, #endif or #end will throw an error on the next loop. + If ifnest<(cnest & $ffff) + cnest=ifnest + Endif + + If Not tracknesting.IsEmpty() tracknesting.Pop ' Keep trace of the error line when a nesting value has been decreased. + If Toker.Remarks() Toker.RemarksOff() ' Clear the remarks block flag. + + Case "print" + + If cnest=ifnest + Print EvalText( toker ) + Endif + + Case "error" + + If cnest=ifnest + Err EvalText( toker ) + Endif + + Default + + ' No predefined processor directives used, so check the token is of type IDENT to assign or adjust a user configuration variable. + If cnest=ifnest + + If ty=TOKE_IDENT - toker.NextToke + If toker.TokeType=TOKE_SPACE toker.NextToke - Select op - Case "=" - Local expr:=EvalExpr( toker ) - Local val:=expr.Eval() - If Not GetConfigVars().Contains( toke ) - If StringType( expr.exprType ) val=EvalConfigTags( val ) - SetConfigVar toke,val,expr.exprType - Endif - Case "+=" - Local val:=EvalText( toker ) - Local var:=GetConfigVar( toke ) - If BoolType( GetConfigVarType( toke ) ) - If var="1" var="True" Else var="False" - Endif - If var And Not val.StartsWith( ";" ) val=";"+val - SetConfigVar toke,var+val - End + Local op:=toker.Toke() - Default - Err "Expecting assignment operator." - End - Else - Err "Unrecognized preprocessor directive '"+toke+"'" - Endif + Select op + Case "=","+=" - Endif - End + Select toke + Case "HOST","LANG","CONFIG","TARGET","SAFEMODE" + Err "App config var '"+toke+"' cannot be modified" + End + + toker.NextToke + + Select op + Case "=" + Local expr:=EvalExpr( toker ) + Local val:=expr.Eval() + + If Not GetConfigVars().Contains( toke ) + If StringType( expr.exprType ) val=EvalConfigTags( val ) + SetConfigVar toke,val,expr.exprType + Endif + + Case "+=" + Local val:=EvalText( toker ) + Local var:=GetConfigVar( toke ) + + If BoolType( GetConfigVarType( toke ) ) + If var="1" var="True" Else var="False" + Endif + + If var And Not val.StartsWith( ";" ) val=";"+val + SetConfigVar toke,var+val + End + + Default + Err "Expecting assignment operator." + End + Else + Err "Unrecognized preprocessor directive '"+toke+"'" + Endif + + Endif + End + Forever + + ' Final check for the end of file + If toker.TokeType=TOKE_EOF + + ' If the tracknesting string stack is empty, then check to see if there were any rem/elseif/else statement pushed to the second trace stack. + ' And if there was, list them out. + If Not tracknesting.IsEmpty() + + ' List out any trace information + If Not trace.IsEmpty() + Print "~t~t-------------- Preprocessor Trace Log --------------" + Local s:=" : Starts here....." + For Local i:=0 Until trace.Length-1 + If i>0 s="" + Print _errInfo[.. _errInfo.FindLast("<")+1]+trace.Get(i)+">"+s + End + Print "" + Endif + + ' Safey check, if there is noting in the trace stack, then pop the last item off the tracknesting string stack, else use the trace string stack + If trace.IsEmpty() _errInfo=_errInfo[.. _errInfo.FindLast("<")]+"<"+tracknesting.Pop+">" Else _errInfo=_errInfo[.. _errInfo.FindLast("<")]+"<"+trace.Pop+">" + Err "End of file reached. Preprocessor Conditional or Remark block preprocess not closed." + Endif + + trace.Clear + tracknesting.Clear + Endif + ' Set the configuration variables. SetConfigVar "MODPATH",p_modpath SetConfigVar "CD",p_cd diff --git a/modules/trans/toker.cxs b/modules/trans/toker.cxs index 3ddb080e..89791f2c 100644 --- a/modules/trans/toker.cxs +++ b/modules/trans/toker.cxs @@ -4,6 +4,14 @@ ' Placed into the public domain 24/02/2011. ' No warranty implied; use at your own risk. +'################################################################################## +' This file scans the source file strings that are to be turned into parser tokens +'################################################################################## +' NOTE: All comments should be viewed as a work-in-progress and my not be an accurate description of +' the internal workings of this file. + +' TODO: Check comments for accuracy. + Import trans 'toke_type @@ -19,11 +27,15 @@ Const TOKE_SYMBOL=8 Const TOKE_LINECOMMENT=9 Const TOKE_INTLITEX=10 +Const REMARK_BLOCK=$01 +Const CONBLOCK=$02 + '***** Tokenizer ***** Class Toker Global _symbols:StringSet Global _keywords:StringSet + Global _tokenFlags Field _path$ Field _line @@ -33,7 +45,9 @@ Class Toker Field _tokeType Field _tokePos + ' Initialisation method to define the keywords and symbols to treat as command tokens Method _init() + If _keywords Return Const keywords:="void strict "+ @@ -64,6 +78,7 @@ Class Toker _symbols.Insert "~~=" End + ' Two constructors. One requiring a path and a source file. The other just needs a valid token object. Method New( path$,source$ ) _init _path=path @@ -74,7 +89,7 @@ Class Toker _tokeType=TOKE_EOF _tokePos=0 End - + Method New( toker:Toker ) _init _path=toker._path @@ -86,6 +101,7 @@ Class Toker _tokePos=toker._tokePos End + ' Retrieve the file path or line that the tonkenizer is currently working with. Method Path$() Return _path End @@ -94,44 +110,86 @@ Class Toker Return _line End + ' Process an character to determine what the toke will be. Method NextToke$() _toke="" + ' Check for end of source file and add a End-Of-File token If _tokePos=_length + _tokeType=TOKE_EOF Return _toke + Endif + ' Preload chr and str with the current character code and is string representation. Local chr:=TCHR() Local str:=TSTR() + + ' Preserve the current character position before advancing by one. + ' This will be the start of a token that is to be parsed. Local start:=_tokePos _tokePos+=1 + ' If the current character is a new line or empty string, then set the token type to a SYMBOL skip a line. If str="~n" + _tokeType=TOKE_SYMBOL _line+=1 + + ' If the character is a white space character, then set the token type to SPACE and advance the token character count. Else If IsSpace( chr ) + _tokeType=TOKE_SPACE + While _tokePos<_length And IsSpace( TCHR() ) And TSTR()<>"~n" _tokePos+=1 Wend + + ' If the character is the start of a line comment then process until the next new line character and set the token type to LINECOMMENT. + Else If str="'" + + _tokeType=TOKE_LINECOMMENT + + While _tokePos<_length And TSTR()<>"~n" + _tokePos+=1 + Wend + + ' If not at the end of the file, increase the line count and advance to the next character for the next token when the method is called again. + If _tokePos<_length + _tokePos+=1 + _line+=1 + Endif + + ' If the character is an underscore or an alpha-beta, then the next token will be either an IDENT or KEYWORD token type. Else If str="_" Or IsAlpha( chr ) _tokeType=TOKE_IDENT + While _tokePos<_length Local chr=_source[_tokePos] If chr<>95 And Not IsAlpha( chr ) And Not IsDigit( chr ) Exit -' If chr<>Asc("_") And Not IsAlpha( chr ) And Not IsDigit( chr ) Exit _tokePos+=1 Wend + _toke=_source[start.._tokePos] + + ' If the result is one of the predefined keywords, then set the type accordingly. If _keywords.Contains( _toke.ToLower() ) _tokeType=TOKE_KEYWORD + + ' If the next character is a digit or period, then the token will be integer or a floating point number. Else If IsDigit( chr ) Or str="." And IsDigit( TCHR() ) + _tokeType=TOKE_INTLIT If str="." _tokeType=TOKE_FLOATLIT + + ' Loop through to the first non digit character While IsDigit( TCHR() ) _tokePos+=1 Wend + + ' The token type is an INTLIT, then test to see if the character at the end is a peroid and the one after is another digit. + ' If they are, then set the token type to a FLOATLIT and loop the next characters until another non digit character is encountered. If _tokeType=TOKE_INTLIT And TSTR()="." And IsDigit( TCHR(1) ) _tokeType=TOKE_FLOATLIT _tokePos+=2 @@ -139,89 +197,176 @@ Class Toker _tokePos+=1 Wend Endif + + ' If the end character is the exponent of a number, then set the token type to FLOATLIT process any exponent symbols before looping to the end. If TSTR().ToLower()="e" + _tokeType=TOKE_FLOATLIT _tokePos+=1 + If TSTR()="+" Or TSTR()="-" _tokePos+=1 + While IsDigit( TCHR() ) _tokePos+=1 Wend + Endif + + ' If the next character is the binary digit character, then set the token type to INTLIT and loop through until a non binary digit is encountered. Else If str="%" And IsBinDigit( TCHR() ) + _tokeType=TOKE_INTLIT _tokePos+=1 + While IsBinDigit( TCHR() ) _tokePos+=1 Wend + + ' If the next character is the hexadecimal digit character, then set the token type to INTLIT and loop through until a non hexadecimal digit is encountered. Else If str="$" And IsHexDigit( TCHR() ) + _tokeType=TOKE_INTLIT _tokePos+=1 + While IsHexDigit( TCHR() ) _tokePos+=1 Wend + + ' If the next character is the quotation character, then set the token type to STRINGLIT and loop through until the closing quote or newline character is encountered. + ' If the remarks flag is set, then the token type should be set to LINECOMMENT Else If str="~q" + _tokeType=TOKE_STRINGLIT - While _tokePos<_length And TSTR()<>"~q" + + ' Loop through until either a closing quote is encountered. Or if the comments flag is set in the token flags, + ' then look for a newline escape sequence and the set token type to TOKE_LINECOMMENT. + While _tokePos<_length + + If Remarks() + _tokeType=TOKE_LINECOMMENT + + If TSTR="~n" + _line+=1 + Exit + Endif + + Else + + If TSTR="~q" Exit + Endif + _tokePos+=1 Wend - If _tokePos<_length _tokePos+=1 Else _tokeType=TOKE_STRINGLITEX + + If _tokePos<_length + _tokePos+=1 + Else + If Not Remarks() _tokeType=TOKE_STRINGLITEX + Endif + + ' If the next character is the grave accent character, then set the token type to STRINGLIT and loop through until the closing quote or newline character is encountered. + ' If the remarks flag is set, then the token type should be set to LINECOMMENT Else If str="`" + _tokeType=TOKE_INTLIT - While _tokePos<_length And TSTR()<>"`" - _tokePos+=1 - Wend - If _tokePos<_length _tokePos+=1 Else _tokeType=TOKE_INTLITEX - Else If str="'" - _tokeType=TOKE_LINECOMMENT - While _tokePos<_length And TSTR()<>"~n" + + ' Loop through until either a closing grave accent is encountered. Or if the comments flag is set in the token flags, + ' then look for a newline escape sequence and the set token type to TOKE_LINECOMMENT. + While _tokePos<_length + + If Remarks() + _tokeType=TOKE_LINECOMMENT + If TSTR="~n" + _line+=1 + Exit + Endif + Else + If TSTR="`" Exit + Endif _tokePos+=1 Wend + If _tokePos<_length _tokePos+=1 - _line+=1 + Else + If Not Remarks() _tokeType=TOKE_INTLITEX Endif + + ' If the character is on opening square bracket, then set the token type to SYMBOL and loop through the next set of characters until the closing square bracket. Else If str="[" + _tokeType=TOKE_SYMBOL + Local i + While _tokePos+i<_length + If TSTR(i)="]" _tokePos+=i+1 Exit Endif + If TSTR(i)="~n" Or Not IsSpace( TCHR(i) ) Exit + i+=1 Wend + + + ' Treat anything left as a token type of SYMBOL Else + _tokeType=TOKE_SYMBOL If _symbols.Contains( _source[_tokePos-1.._tokePos+1] ) _tokePos+=1 Endif + ' If no token was process in the nested conditional above, then set the token to whatever was left. + ' The token type should not have been set, so it will be a zero value, meaning that it will be a token type of EOF. If Not _toke _toke=_source[start.._tokePos] - + Return _toke End + ' Return the actual token string Method Toke$() Return _toke End + ' Return the token type Method TokeType() Return _tokeType End + ' Iterate over any whitespace character Method SkipSpace() While _tokeType=TOKE_SPACE NextToke Wend End + ' Exposed external functions to set the various flags. + ' Use these to set and unset the remark block flag. + Function RemarksOn() + _tokenFlags|=REMARK_BLOCK + End + + Function RemarksOff() + _tokenFlags&= ~REMARK_BLOCK + End + + ' Check to see the status of the REMARK BLOCK FLAG. + Function Remarks:Bool() + Return Bool(_tokenFlags & REMARK_BLOCK) + End + Private + ' Returns the character code at the current token position with offset if required. Method TCHR( i=0 ) i+=_tokePos If i<_length Return _source[i] End + ' Returns the character string at the current token position with offset if required. Method TSTR$( i=0 ) i+=_tokePos If i<_length Return _source[i..i+1] diff --git a/modules_ext/.gitignore b/modules_ext/.gitignore deleted file mode 100644 index f935021a..00000000 --- a/modules_ext/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!.gitignore diff --git a/src/BUILDING.txt b/src/BUILDING.txt index 649cd455..0a535f7b 100644 --- a/src/BUILDING.txt +++ b/src/BUILDING.txt @@ -1,71 +1,117 @@ Building instructions +Before you beging. You should check out one of the desktop sub forums for any issues and work arounds, or to ask questions. +https://www.cerberus-x.com/community/categories/desktop-targets.70/ + +NOTE: The CerberusX IDE requires that Qt 5.9.x be installed to your system. +The IDE does not work correctly with any version later than 5.9.9. And versions below 5.9 are not officially supported. + ======= LINUX ======= You should find all the developer packages in your distributions online repository. -E.G. for Ubuntu/Linux Mint -sudo apt-get -y install g++ libglu1-mesa-dev libopenal-dev libxi-dev libxrandr-dev -libxinerama-dev libxcursor-dev libxxf86vm-dev libx11-dev libgl1-mesa-dev +Unbuntu 18.04/Ubuntu 19.04 (packages should be the same for Linux Mint 18/19) +Cerberus standard development files for making applications +sudo apt-get install g++ libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev libopenal-dev libglu1-mesa-dev + +Cerberus IDE development files for Ubuntu 18.04/Linux Mint 18 Only (Uses Qt 5.9.5) +sudo apt-get install qtmultimedia5-dev qt5-default qtwebengine5-dev + +OpenSUSE 15 +Cerberus standard development files for making applications +sudo zypper in gcc-c++ Mesa-libGL-devel openal-soft-devel libXcursor-devel libXrandr-devel libXinerama-devel libXi-devel + +Cerberus IDE development files for OpenSUSE 15 Only (Uses Qt 5.9.4) +sudo zypper in libqt5-qtwebengine-devel libqt5-qtmultimedia-devel + +Fedora 29 +Cerberus standard development files for making applications +sudo dnf install gcc-c++ mesa-libGLU-devel libXi-devel libXcursor-devel libXrandr-devel libXinerama-devel openal-soft-devel + +Cerberus IDE development files for Fedora 29 Only (Uses Qt 5.11.2) and only listed here for reference or at some stage Ted is made to work with later versions of Qt. +sudo dnf install qt5-qtwebengine-devel qt5-qtmultimedia-devel +You should download the Qt SDK and install version 5.9.2. And follow Manual Install of Ted. + +Raspbery Pi: +Open Terminal window: +sudo raspi-config + +Navigate to: +7 - Advanced options >> A7 - GL Driver >> G1 - GL (Full KMS) OpenGL desktop driver with full KMS -Qt4 -sudo apt-get install libqt4-dev libqtwebkit-dev qt4-default +sudo apt-get -y install g++ libglu1-mesa-dev libopenal-dev libxi-dev libxrandr-dev libxinerama-dev libxcursor-dev libxxf86vm-dev libx11-dev libgl1-mesa-dev +sudo apt-get -y install libqt5webkit5-dev libqt5sensors5-dev qtlocation5-dev libxslt1-dev libsqlite3-dev libgstreamer-plugins-base0.10-dev qt5-default libicu-dev -Qt5 -sudo apt-get -y install libqt5webkit5-dev qtlocation5-dev qtsensors5-dev libxslt-dev -libsqlite3-dev libgstreamer-plugins-base0.10-dev qt5-default libicu-dev -Special not for 64 bit users of Debian/Ubuntu and their derivatives: -Please be aware that you will of course need the g++-multilib package installed to do the following. -It is posible to cross compile and test for 32 bit builds by linking the required development libraries like so +You will find a bash script called rebuildall.sh. +If you have installed the Qt SDK directly from https://www.qt.io/ +And you have installed them to your home directory as a directory called Qt, or created a symbolic link to the Qt SDK in your home directory. +Then the script will automatically use those files, with the default being 5.9.2 if installed. +You can pass the Qt version to use from the command line. -Debian -sudo ln -s /usr/lib/i386-linux-gnu/libGL.so.1 /usr/lib32/libGL.so +If you have installed the distributions Qt pacakage, then you may have to edit the script to the +name that the distribution is using for executing Qt 5's qmake. Each distribution commonly uses their own naming scheme. -Ubuntu -sudo ln -s /usr/lib/i386-linux-gnu/mesa/libGL.so.1 /usr/lib32/libGL.so -All -sudo ln -s /usr/lib/i386-linux-gnu/libopenal.so.1 /usr/lib32/libopenal.so -sudo ln -s /usr/lib/i386-linux-gnu/libX11.so.6 /usr/lib32/libX11.so -sudo ln -s /usr/lib/i386-linux-gnu/libXxf86vm.so.1 /usr/lib32/libXxf86vm.so -sudo ln -s /usr/lib/i386-linux-gnu/libXi.so.6 /usr/lib32/libXi.so -sudo ln -s /usr/lib/i386-linux-gnu/libXrandr.so.2 /usr/lib32/libXrandr.so -sudo ln -s /usr/lib/i386-linux-gnu/libXinerama.so.1 /usr/lib32/libXinerama.so -sudo ln -s /usr/lib/i386-linux-gnu/libXcursor.so.1 /usr/lib32/libXcursor.so +Open a bash shell and change directory to where this script is located. +Then type: +.\rebuildall.sh QTVER +NOTE: The parameter QTVER is the version of Qt to use if you have got the Qt SDK from https://www.qt.io/ +The default is to use Qt 5.9.2. -======= WINDOWS VISTA/WIN&/8/X ======= -You will require the Window version of GCC, either MinGW (http://www.mingw.org/) or TDM (http://tdm-gcc.tdragon.net/) -You will need Visual Studio 2013 and the corresponding Qt 5.5.1 SDK for Visual Studio 2013 to build Ted +IMPORTANT NOTE: +The GCC compiler that comes with later versions of Linux is setup to produce Position-Independent Executable's, also known as PIE. +The file browser/manager in most distributions currently will not launch these files directly and may never will. And launching a file via the file manager may be removed entirely in future releases. + +To run Cerberus you will have to open a bash shell and change directory to the Cerberus root directory and type: +./Cerberus + +For a much easier solution, see IMPORTANT NOTE at +https://www.cerberus-x.com/community/threads/install-requirements-for-linux-includes-raspbery-pi.741/#post-5728 + +======= WINDOWS 8 and 10 ======= +You will require the Window version of GCC, but please note that newer versions will have issues. +It is recommended that you use the 64 bit version of TDM GCC 4.7/5.1.0. + +To build the IDE for Cerberus, you will need to have Visual Studio 2017 installed. You will find a power-shell script called rebuildall.ps1 that should work on Win7+. -To use it open a power shell (not the noraml command shell) and type -.\rebuildall.ps1 -mingw "path_to_mingw_root_directory" -qtsdk "path_to_qtsdk_root_directory" -qtspec "qtspec_directory_for_compiler" -NOTE: This script requires that the execution policy for the current user be set to unrestricted. -to do this open a power shell as administrator and use: +NOTE: Before using this script make sure that the execution policy for the current user be set to unrestricted. +To do this open a power shell as administrator and use: get-executionpolicy -list set-executionpolicy -scope currentuser unrestricted If the file is still blocked use: unblock-file -path "full_path_to_this_script" -You should reset the execution policy back to it's original state e.g.: +You should reset the execution policy back to it's original state after using this script e.g.: set-executionpolicy -scope currentuser undefined -ALSO NOTE: +To use the script, open a power shell (not the noraml command shell) and change directory to where this script is located. +Then type: +.\rebuildall.ps1 -mingw "path_to_mingw_root_directory" -qtsdk "path_to_qtsdk_root_directory" + +NOTE: The parameters -mingw and -qtsdk are optional if you already have both paths set correctly in your system paths. The defaults are shown 'path_to_mingw_root_directory' would be for example: C:\MinGW 'path_to_qtsdk_root_directory' would be for example: -C:\Qt5\5.5\msvc2013_64 - -If you are using a different compiler, you need to tell qmake which pre-built binaries you wish to use. -These are located in the Qt SDK under the mkspecs directory -'qtspec_directory_for_compiler' would be for example -win32-msvc2013 for Visual Studio 2013 - -To build a debug version of Ted add -qtdbg 1 - -======= MAC OSX ======= -TO DO - +C:\Qt5\5.9.2\msvc2017_64 + +======= Mac OS X ======= +You will require XCode at least 8.2, the xcode command line tools and the Qt SDK versions (5.9.x). +As Apple do change their tools often, you should check out the latest documentation. +But in general, once you have XCode installed. You can usually find the place to download the tools in general/download/components. +You just have to go looking for them. Or you can install the command line tools by opening a terminal, found in Applications->Utilities. +And typing xcode-select --install. + +You will find a bash script called rebuildall_macos.sh. +If you have installed the Qt SDK directly from https://www.qt.io/ +And you have installed them to your home directory as a directory called Qt, or created a symbolic link to the Qt SDK in your home directory. +Then the script will automatically use those files, with the default being 5.9.2 if installed. +You can pass the Qt version to use from the command line. + +Then type: +.\rebuildall_macos.sh QTVER +NOTE: The parameter QTVER is the version of Qt to use if you have got the Qt SDK from https://www.qt.io/ +The default is to use Qt 5.9.2. \ No newline at end of file diff --git a/src/cserver/cserver.cxs b/src/cserver/cserver.cxs index 41874b8e..3f3d7b3c 100644 --- a/src/cserver/cserver.cxs +++ b/src/cserver/cserver.cxs @@ -1,5 +1,5 @@ Strict -#GLFW_USE_MINGW=false + #Rem ================================================================================ Cerberus X MiniServer, used for local testing of HTML5 games diff --git a/src/launcher/xcode/Cerberus.xcodeproj/project.pbxproj b/src/launcher/xcode/Cerberus.xcodeproj/project.pbxproj new file mode 100644 index 00000000..629b5838 --- /dev/null +++ b/src/launcher/xcode/Cerberus.xcodeproj/project.pbxproj @@ -0,0 +1,287 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 96693B3520C2ACD00061DD43 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 96693B3420C2ACD00061DD43 /* main.m */; }; + D5928CF02465A655005D9702 /* cerberus.icns in Resources */ = {isa = PBXBuildFile; fileRef = D5928CEE2465A4D6005D9702 /* cerberus.icns */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 96693B2D20C2ACD00061DD43 /* Cerberus.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = Cerberus.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 96693B3420C2ACD00061DD43 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 96693B3B20C2ACD00061DD43 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D5928CEE2465A4D6005D9702 /* cerberus.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = cerberus.icns; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 96693B2A20C2ACD00061DD43 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 96693B2420C2ACD00061DD43 = { + isa = PBXGroup; + children = ( + D5928CEE2465A4D6005D9702 /* cerberus.icns */, + 96693B2F20C2ACD00061DD43 /* Cerberus */, + 96693B2E20C2ACD00061DD43 /* Products */, + ); + sourceTree = ""; + }; + 96693B2E20C2ACD00061DD43 /* Products */ = { + isa = PBXGroup; + children = ( + 96693B2D20C2ACD00061DD43 /* Cerberus.app */, + ); + name = Products; + sourceTree = ""; + }; + 96693B2F20C2ACD00061DD43 /* Cerberus */ = { + isa = PBXGroup; + children = ( + 96693B3420C2ACD00061DD43 /* main.m */, + 96693B3B20C2ACD00061DD43 /* Info.plist */, + ); + name = Cerberus; + path = "cerberus-launcher"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 96693B2C20C2ACD00061DD43 /* Cerberus */ = { + isa = PBXNativeTarget; + buildConfigurationList = 96693B3E20C2ACD00061DD43 /* Build configuration list for PBXNativeTarget "Cerberus" */; + buildPhases = ( + 96693B2920C2ACD00061DD43 /* Sources */, + 96693B2A20C2ACD00061DD43 /* Frameworks */, + D5928CEF2465A648005D9702 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Cerberus; + productName = "cerberus-launcher"; + productReference = 96693B2D20C2ACD00061DD43 /* Cerberus.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 96693B2520C2ACD00061DD43 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1140; + ORGANIZATIONNAME = Krautapps; + TargetAttributes = { + 96693B2C20C2ACD00061DD43 = { + CreatedOnToolsVersion = 7.3; + }; + }; + }; + buildConfigurationList = 96693B2820C2ACD00061DD43 /* Build configuration list for PBXProject "Cerberus" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 96693B2420C2ACD00061DD43; + productRefGroup = 96693B2E20C2ACD00061DD43 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 96693B2C20C2ACD00061DD43 /* Cerberus */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + D5928CEF2465A648005D9702 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D5928CF02465A655005D9702 /* cerberus.icns in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 96693B2920C2ACD00061DD43 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 96693B3520C2ACD00061DD43 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 96693B3C20C2ACD00061DD43 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 96693B3D20C2ACD00061DD43 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + }; + name = Release; + }; + 96693B3F20C2ACD00061DD43 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "cerberus-launcher/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + PRODUCT_BUNDLE_IDENTIFIER = "com.krautapps.cerberus-launcher"; + PRODUCT_NAME = Cerberus; + }; + name = Debug; + }; + 96693B4020C2ACD00061DD43 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = "cerberus-launcher/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + PRODUCT_BUNDLE_IDENTIFIER = "com.krautapps.cerberus-launcher"; + PRODUCT_NAME = Cerberus; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 96693B2820C2ACD00061DD43 /* Build configuration list for PBXProject "Cerberus" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 96693B3C20C2ACD00061DD43 /* Debug */, + 96693B3D20C2ACD00061DD43 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 96693B3E20C2ACD00061DD43 /* Build configuration list for PBXNativeTarget "Cerberus" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 96693B3F20C2ACD00061DD43 /* Debug */, + 96693B4020C2ACD00061DD43 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 96693B2520C2ACD00061DD43 /* Project object */; +} diff --git a/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/xcuserdata/dawlane.xcuserdatad/UserInterfaceState.xcuserstate b/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/xcuserdata/dawlane.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 00000000..c067e8c7 Binary files /dev/null and b/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/xcuserdata/dawlane.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/xcuserdata/dawlane.xcuserdatad/WorkspaceSettings.xcsettings b/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/xcuserdata/dawlane.xcuserdatad/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..070be288 --- /dev/null +++ b/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/xcuserdata/dawlane.xcuserdatad/WorkspaceSettings.xcsettings @@ -0,0 +1,22 @@ + + + + + BuildLocationStyle + CustomLocation + CustomBuildIntermediatesPath + Build/Intermediates + CustomBuildLocationType + RelativeToWorkspace + CustomBuildProductsPath + Build/Products + DerivedDataCustomLocation + xcode + DerivedDataLocationStyle + WorkspaceRelativePath + IssueFilterStyle + ShowActiveSchemeOnly + LiveSourceIssuesEnabled + + + diff --git a/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/xcuserdata/michaelhartlef.xcuserdatad/UserInterfaceState.xcuserstate b/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/xcuserdata/michaelhartlef.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 00000000..3180aedd Binary files /dev/null and b/src/launcher/xcode/Cerberus.xcodeproj/project.xcworkspace/xcuserdata/michaelhartlef.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/src/launcher/xcode/Cerberus.xcodeproj/xcshareddata/xcschemes/Cerberus.xcscheme b/src/launcher/xcode/Cerberus.xcodeproj/xcshareddata/xcschemes/Cerberus.xcscheme new file mode 100644 index 00000000..b8e506da --- /dev/null +++ b/src/launcher/xcode/Cerberus.xcodeproj/xcshareddata/xcschemes/Cerberus.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/launcher/xcode/Cerberus.xcodeproj/xcuserdata/dawlane.xcuserdatad/xcschemes/Cerberus.xcscheme b/src/launcher/xcode/Cerberus.xcodeproj/xcuserdata/dawlane.xcuserdatad/xcschemes/Cerberus.xcscheme new file mode 100644 index 00000000..d8497ae6 --- /dev/null +++ b/src/launcher/xcode/Cerberus.xcodeproj/xcuserdata/dawlane.xcuserdatad/xcschemes/Cerberus.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/launcher/xcode/Cerberus.xcodeproj/xcuserdata/dawlane.xcuserdatad/xcschemes/xcschememanagement.plist b/src/launcher/xcode/Cerberus.xcodeproj/xcuserdata/dawlane.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..6ba0c578 --- /dev/null +++ b/src/launcher/xcode/Cerberus.xcodeproj/xcuserdata/dawlane.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + Cerberus.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 96693B2C20C2ACD00061DD43 + + primary + + + + + diff --git a/src/launcher/xcode/Cerberus.xcodeproj/xcuserdata/michaelhartlef.xcuserdatad/xcschemes/xcschememanagement.plist b/src/launcher/xcode/Cerberus.xcodeproj/xcuserdata/michaelhartlef.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..8d4304b3 --- /dev/null +++ b/src/launcher/xcode/Cerberus.xcodeproj/xcuserdata/michaelhartlef.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + Cerberus.xcscheme_^#shared#^_ + + orderHint + 0 + + + SuppressBuildableAutocreation + + 96693B2C20C2ACD00061DD43 + + primary + + + + + diff --git a/src/launcher/xcode/cerberus-launcher/Info.plist b/src/launcher/xcode/cerberus-launcher/Info.plist new file mode 100644 index 00000000..5358fcb5 --- /dev/null +++ b/src/launcher/xcode/cerberus-launcher/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + cerberus.icns + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSApplicationCategoryType + public.app-category.developer-tools + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSPrincipalClass + NSApplication + + diff --git a/src/launcher/xcode/cerberus-launcher/main.m b/src/launcher/xcode/cerberus-launcher/main.m new file mode 100644 index 00000000..b932c795 --- /dev/null +++ b/src/launcher/xcode/cerberus-launcher/main.m @@ -0,0 +1,51 @@ +// +// Mac OSX Cerberus Launcher v0.1 +// + +#include +#include +#include + +//#define APP_BUNDLE_ID "com.krautapps.Ted" + +// Output error data +void outlist(NSMutableArray *array){ + for(int i = 1;i -#include - -// C++ Cerberus runtime. -// -// Placed into the public domain 24/02/2011. -// No warranty implied; use at your own risk. - -//***** Cerberus Types ***** - -typedef wchar_t Char; -template class Array; -class String; -class Object; - -#if CFG_CPP_DOUBLE_PRECISION_FLOATS -typedef double Float; -#define FLOAT(X) X -#else -typedef float Float; -#define FLOAT(X) X##f -#endif - -void dbg_error( const char *p ); - -#if !_MSC_VER -#define sprintf_s sprintf -#define sscanf_s sscanf -#endif - -//***** GC Config ***** - -#if CFG_CPP_GC_DEBUG -#define DEBUG_GC 1 -#else -#define DEBUG_GC 0 -#endif - -// GC mode: -// -// 0 = disabled -// 1 = Incremental GC every OnWhatever -// 2 = Incremental GC every allocation -// -#ifndef CFG_CPP_GC_MODE -#define CFG_CPP_GC_MODE 1 -#endif - -//How many bytes alloced to trigger GC -// -#ifndef CFG_CPP_GC_TRIGGER -#define CFG_CPP_GC_TRIGGER 8*1024*1024 -#endif - -//GC_MODE 2 needs to track locals on a stack - this may need to be bumped if your app uses a LOT of locals, eg: is heavily recursive... -// -#ifndef CFG_CPP_GC_MAX_LOCALS -#define CFG_CPP_GC_MAX_LOCALS 8192 -#endif - -// ***** GC ***** - -#if _WIN32 - -int gc_micros(){ - static int f; - static LARGE_INTEGER pcf; - if( !f ){ - if( QueryPerformanceFrequency( &pcf ) && pcf.QuadPart>=1000000L ){ - pcf.QuadPart/=1000000L; - f=1; - }else{ - f=-1; - } - } - if( f>0 ){ - LARGE_INTEGER pc; - if( QueryPerformanceCounter( &pc ) ) return pc.QuadPart/pcf.QuadPart; - f=-1; - } - return 0;// timeGetTime()*1000; -} - -#elif __APPLE__ - -#include - -int gc_micros(){ - static int f; - static mach_timebase_info_data_t timeInfo; - if( !f ){ - mach_timebase_info( &timeInfo ); - timeInfo.denom*=1000L; - f=1; - } - return mach_absolute_time()*timeInfo.numer/timeInfo.denom; -} - -#else - -int gc_micros(){ - return 0; -} - -#endif - -#define gc_mark_roots gc_mark - -void gc_mark_roots(); - -struct gc_object; - -gc_object *gc_object_alloc( int size ); -void gc_object_free( gc_object *p ); - -struct gc_object{ - gc_object *succ; - gc_object *pred; - int flags; - - virtual ~gc_object(){ - } - - virtual void mark(){ - } - - void *operator new( size_t size ){ - return gc_object_alloc( size ); - } - - void operator delete( void *p ){ - gc_object_free( (gc_object*)p ); - } -}; - -gc_object gc_free_list; -gc_object gc_marked_list; -gc_object gc_unmarked_list; -gc_object gc_queued_list; //doesn't really need to be doubly linked... - -int gc_free_bytes; -int gc_marked_bytes; -int gc_alloced_bytes; -int gc_max_alloced_bytes; -int gc_new_bytes; -int gc_markbit=1; - -gc_object *gc_cache[8]; - -void gc_collect_all(); -void gc_mark_queued( int n ); - -#define GC_CLEAR_LIST( LIST ) ((LIST).succ=(LIST).pred=&(LIST)) - -#define GC_LIST_IS_EMPTY( LIST ) ((LIST).succ==&(LIST)) - -#define GC_REMOVE_NODE( NODE ){\ -(NODE)->pred->succ=(NODE)->succ;\ -(NODE)->succ->pred=(NODE)->pred;} - -#define GC_INSERT_NODE( NODE,SUCC ){\ -(NODE)->pred=(SUCC)->pred;\ -(NODE)->succ=(SUCC);\ -(SUCC)->pred->succ=(NODE);\ -(SUCC)->pred=(NODE);} - -void gc_init1(){ - GC_CLEAR_LIST( gc_free_list ); - GC_CLEAR_LIST( gc_marked_list ); - GC_CLEAR_LIST( gc_unmarked_list); - GC_CLEAR_LIST( gc_queued_list ); -} - -void gc_init2(){ - gc_mark_roots(); -} - -#if CFG_CPP_GC_MODE==2 - -int gc_ctor_nest; -gc_object *gc_locals[CFG_CPP_GC_MAX_LOCALS],**gc_locals_sp=gc_locals; - -struct gc_ctor{ - gc_ctor(){ ++gc_ctor_nest; } - ~gc_ctor(){ --gc_ctor_nest; } -}; - -struct gc_enter{ - gc_object **sp; - gc_enter():sp(gc_locals_sp){ - } - ~gc_enter(){ -#if DEBUG_GC - static int max_locals; - int n=gc_locals_sp-gc_locals; - if( n>max_locals ){ - max_locals=n; - printf( "max_locals=%i\n",n ); - } -#endif - gc_locals_sp=sp; - } -}; - -#define GC_CTOR gc_ctor _c; -#define GC_ENTER gc_enter _e; - -#else - -struct gc_ctor{ -}; -struct gc_enter{ -}; - -#define GC_CTOR -#define GC_ENTER - -#endif - -//Can be modified off thread! -static volatile int gc_ext_new_bytes; - -#if _MSC_VER -#define atomic_add(P,V) InterlockedExchangeAdd((volatile unsigned int*)P,V) //(*(P)+=(V)) -#define atomic_sub(P,V) InterlockedExchangeSubtract((volatile unsigned int*)P,V) //(*(P)-=(V)) -#else -#define atomic_add(P,V) __sync_fetch_and_add(P,V) -#define atomic_sub(P,V) __sync_fetch_and_sub(P,V) -#endif - -//Careful! May be called off thread! -// -void gc_ext_malloced( int size ){ - atomic_add( &gc_ext_new_bytes,size ); -} - -void gc_object_free( gc_object *p ){ - - int size=p->flags & ~7; - gc_free_bytes-=size; - - if( size<64 ){ - p->succ=gc_cache[size>>3]; - gc_cache[size>>3]=p; - }else{ - free( p ); - } -} - -void gc_flush_free( int size ){ - - int t=gc_free_bytes-size; - if( t<0 ) t=0; - - //ignore bytes freed by released strings - int new_bytes=gc_new_bytes; - - while( gc_free_bytes>t ){ - - gc_object *p=gc_free_list.succ; - - GC_REMOVE_NODE( p ); - -#if DEBUG_GC -// printf( "deleting @%p\n",p );fflush( stdout ); -// p->flags|=4; -// continue; -#endif - delete p; - } - - gc_new_bytes=new_bytes; -} - -gc_object *gc_object_alloc( int size ){ - - size=(size+7)&~7; - - gc_new_bytes+=size; - -#if CFG_CPP_GC_MODE==2 - - if( !gc_ctor_nest ){ - -#if DEBUG_GC - int ms=gc_micros(); -#endif - if( gc_new_bytes+gc_ext_new_bytes>(CFG_CPP_GC_TRIGGER) ){ - atomic_sub( &gc_ext_new_bytes,gc_ext_new_bytes ); - gc_collect_all(); - gc_new_bytes=0; - }else{ - gc_mark_queued( (long long)(gc_new_bytes)*(gc_alloced_bytes-gc_new_bytes)/(CFG_CPP_GC_TRIGGER)+gc_new_bytes ); - } - -#if DEBUG_GC - ms=gc_micros()-ms; - if( ms>=100 ) {printf( "gc time:%i\n",ms );fflush( stdout );} -#endif - } - -#endif - - gc_flush_free( size ); - - gc_object *p; - if( size<64 && (p=gc_cache[size>>3]) ){ - gc_cache[size>>3]=p->succ; - }else{ - p=(gc_object*)malloc( size ); - } - - p->flags=size|gc_markbit; - GC_INSERT_NODE( p,&gc_unmarked_list ); - - gc_alloced_bytes+=size; - if( gc_alloced_bytes>gc_max_alloced_bytes ) gc_max_alloced_bytes=gc_alloced_bytes; - -#if CFG_CPP_GC_MODE==2 - *gc_locals_sp++=p; -#endif - - return p; -} - -#if DEBUG_GC - -template gc_object *to_gc_object( T *t ){ - gc_object *p=dynamic_cast(t); - if( p && (p->flags & 4) ){ - printf( "gc error : object already deleted @%p\n",p );fflush( stdout ); - exit(-1); - } - return p; -} - -#else - -#define to_gc_object(t) dynamic_cast(t) - -#endif - -template T *gc_retain( T *t ){ -#if CFG_CPP_GC_MODE==2 - *gc_locals_sp++=to_gc_object( t ); -#endif - return t; -} - -template void gc_mark( T *t ){ - - gc_object *p=to_gc_object( t ); - - if( p && (p->flags & 3)==gc_markbit ){ - p->flags^=1; - GC_REMOVE_NODE( p ); - GC_INSERT_NODE( p,&gc_marked_list ); - gc_marked_bytes+=(p->flags & ~7); - p->mark(); - } -} - -template void gc_mark_q( T *t ){ - - gc_object *p=to_gc_object( t ); - - if( p && (p->flags & 3)==gc_markbit ){ - p->flags^=1; - GC_REMOVE_NODE( p ); - GC_INSERT_NODE( p,&gc_queued_list ); - } -} - -template void gc_assign( T *&lhs,V *rhs ){ - - gc_object *p=to_gc_object( rhs ); - - if( p && (p->flags & 3)==gc_markbit ){ - p->flags^=1; - GC_REMOVE_NODE( p ); - GC_INSERT_NODE( p,&gc_queued_list ); - } - lhs=rhs; -} - -void gc_mark_locals(){ - -#if CFG_CPP_GC_MODE==2 - for( gc_object **pp=gc_locals;pp!=gc_locals_sp;++pp ){ - gc_object *p=*pp; - if( p && (p->flags & 3)==gc_markbit ){ - p->flags^=1; - GC_REMOVE_NODE( p ); - GC_INSERT_NODE( p,&gc_marked_list ); - gc_marked_bytes+=(p->flags & ~7); - p->mark(); - } - } -#endif -} - -void gc_mark_queued( int n ){ - while( gc_marked_bytesflags & ~7); - p->mark(); - } -} - -void gc_validate_list( gc_object &list,const char *msg ){ - gc_object *node=list.succ; - while( node ){ - if( node==&list ) return; - if( !node->pred ) break; - if( node->pred->succ!=node ) break; - node=node->succ; - } - if( msg ){ - puts( msg );fflush( stdout ); - } - puts( "LIST ERROR!" ); - exit(-1); -} - -//returns reclaimed bytes -void gc_sweep(){ - - int reclaimed_bytes=gc_alloced_bytes-gc_marked_bytes; - - if( reclaimed_bytes ){ - - //append unmarked list to end of free list - gc_object *head=gc_unmarked_list.succ; - gc_object *tail=gc_unmarked_list.pred; - gc_object *succ=&gc_free_list; - gc_object *pred=succ->pred; - - head->pred=pred; - tail->succ=succ; - pred->succ=head; - succ->pred=tail; - - gc_free_bytes+=reclaimed_bytes; - } - - //move marked to unmarked. - if( GC_LIST_IS_EMPTY( gc_marked_list ) ){ - GC_CLEAR_LIST( gc_unmarked_list ); - }else{ - gc_unmarked_list.succ=gc_marked_list.succ; - gc_unmarked_list.pred=gc_marked_list.pred; - gc_unmarked_list.succ->pred=gc_unmarked_list.pred->succ=&gc_unmarked_list; - GC_CLEAR_LIST( gc_marked_list ); - } - - //adjust sizes - gc_alloced_bytes=gc_marked_bytes; - gc_marked_bytes=0; - gc_markbit^=1; -} - -void gc_collect_all(){ - -// puts( "Mark locals" ); - gc_mark_locals(); - -// puts( "Marked queued" ); - gc_mark_queued( 0x7fffffff ); - -// puts( "Sweep" ); - gc_sweep(); - -// puts( "Mark roots" ); - gc_mark_roots(); - -#if DEBUG_GC - gc_validate_list( gc_marked_list,"Validating gc_marked_list" ); - gc_validate_list( gc_unmarked_list,"Validating gc_unmarked_list" ); - gc_validate_list( gc_free_list,"Validating gc_free_list" ); -#endif - -} - -void gc_collect(){ - -#if CFG_CPP_GC_MODE==1 - -#if DEBUG_GC - int ms=gc_micros(); -#endif - - if( gc_new_bytes+gc_ext_new_bytes>(CFG_CPP_GC_TRIGGER) ){ - atomic_sub( &gc_ext_new_bytes,gc_ext_new_bytes ); - gc_collect_all(); - gc_new_bytes=0; - }else{ - gc_mark_queued( (long long)(gc_new_bytes)*(gc_alloced_bytes-gc_new_bytes)/(CFG_CPP_GC_TRIGGER)+gc_new_bytes ); - } - -#if DEBUG_GC - ms=gc_micros()-ms; -// if( ms>=100 ) {printf( "gc time:%i\n",ms );fflush( stdout );} - if( ms>10 ) {printf( "gc time:%i\n",ms );fflush( stdout );} -#endif - -#endif -} - -// ***** Array ***** - -template T *t_memcpy( T *dst,const T *src,int n ){ - memcpy( dst,src,n*sizeof(T) ); - return dst+n; -} - -template T *t_memset( T *dst,int val,int n ){ - memset( dst,val,n*sizeof(T) ); - return dst+n; -} - -template int t_memcmp( const T *x,const T *y,int n ){ - return memcmp( x,y,n*sizeof(T) ); -} - -template int t_strlen( const T *p ){ - const T *q=p++; - while( *q++ ){} - return q-p; -} - -template T *t_create( int n,T *p ){ - t_memset( p,0,n ); - return p+n; -} - -template T *t_create( int n,T *p,const T *q ){ - t_memcpy( p,q,n ); - return p+n; -} - -template void t_destroy( int n,T *p ){ -} - -template void gc_mark_elements( int n,T *p ){ -} - -template void gc_mark_elements( int n,T **p ){ - for( int i=0;i class Array{ -public: - Array():rep( &nullRep ){ - } - - //Uses default... -// Array( const Array &t )... - - Array( int length ):rep( Rep::alloc( length ) ){ - t_create( rep->length,rep->data ); - } - - Array( const T *p,int length ):rep( Rep::alloc(length) ){ - t_create( rep->length,rep->data,p ); - } - - ~Array(){ - } - - //Uses default... -// Array &operator=( const Array &t )... - - int Length()const{ - return rep->length; - } - - T &At( int index ){ - if( index<0 || index>=rep->length ) dbg_error( "Array index out of range" ); - return rep->data[index]; - } - - const T &At( int index )const{ - if( index<0 || index>=rep->length ) dbg_error( "Array index out of range" ); - return rep->data[index]; - } - - T &operator[]( int index ){ - return rep->data[index]; - } - - const T &operator[]( int index )const{ - return rep->data[index]; - } - - Array Slice( int from,int term )const{ - int len=rep->length; - if( from<0 ){ - from+=len; - if( from<0 ) from=0; - }else if( from>len ){ - from=len; - } - if( term<0 ){ - term+=len; - }else if( term>len ){ - term=len; - } - if( term<=from ) return Array(); - return Array( rep->data+from,term-from ); - } - - Array Slice( int from )const{ - return Slice( from,rep->length ); - } - - Array Resize( int newlen )const{ - if( newlen<=0 ) return Array(); - int n=rep->length; - if( newlendata; - q=t_create( n,q,rep->data ); - q=t_create( (newlen-n),q ); - return Array( p ); - } - -private: - struct Rep : public gc_object{ - int length; - T data[0]; - - Rep():length(0){ - flags=3; - } - - Rep( int length ):length(length){ - } - - ~Rep(){ - t_destroy( length,data ); - } - - void mark(){ - gc_mark_elements( length,data ); - } - - static Rep *alloc( int length ){ - if( !length ) return &nullRep; - void *p=gc_object_alloc( sizeof(Rep)+length*sizeof(T) ); - return ::new(p) Rep( length ); - } - - }; - Rep *rep; - - static Rep nullRep; - - template friend void gc_mark( Array t ); - template friend void gc_mark_q( Array t ); - template friend Array gc_retain( Array t ); - template friend void gc_assign( Array &lhs,Array rhs ); - template friend void gc_mark_elements( int n,Array *p ); - - Array( Rep *rep ):rep(rep){ - } -}; - -template typename Array::Rep Array::nullRep; - -template Array *t_create( int n,Array *p ){ - for( int i=0;i(); - return p; -} - -template Array *t_create( int n,Array *p,const Array *q ){ - for( int i=0;i void gc_mark( Array t ){ - gc_mark( t.rep ); -} - -template void gc_mark_q( Array t ){ - gc_mark_q( t.rep ); -} - -template Array gc_retain( Array t ){ -#if CFG_CPP_GC_MODE==2 - gc_retain( t.rep ); -#endif - return t; -} - -template void gc_assign( Array &lhs,Array rhs ){ - gc_mark( rhs.rep ); - lhs=rhs; -} - -template void gc_mark_elements( int n,Array *p ){ - for( int i=0;iretain(); - } - - String( int n ){ - char buf[256]; - sprintf_s( buf,"%i",n ); - rep=Rep::alloc( t_strlen(buf) ); - for( int i=0;ilength;++i ) rep->data[i]=buf[i]; - } - - String( Float n ){ - char buf[256]; - - //would rather use snprintf, but it's doing weird things in MingW. - // - sprintf_s( buf,"%.17lg",n ); - // - char *p; - for( p=buf;*p;++p ){ - if( *p=='.' || *p=='e' ) break; - } - if( !*p ){ - *p++='.'; - *p++='0'; - *p=0; - } - - rep=Rep::alloc( t_strlen(buf) ); - for( int i=0;ilength;++i ) rep->data[i]=buf[i]; - } - - String( Char ch,int length ):rep( Rep::alloc(length) ){ - for( int i=0;idata[i]=ch; - } - - String( const Char *p ):rep( Rep::alloc(t_strlen(p)) ){ - t_memcpy( rep->data,p,rep->length ); - } - - String( const Char *p,int length ):rep( Rep::alloc(length) ){ - t_memcpy( rep->data,p,rep->length ); - } - -#if __OBJC__ - String( NSString *nsstr ):rep( Rep::alloc([nsstr length]) ){ - unichar *buf=(unichar*)malloc( rep->length * sizeof(unichar) ); - [nsstr getCharacters:buf range:NSMakeRange(0,rep->length)]; - for( int i=0;ilength;++i ) rep->data[i]=buf[i]; - free( buf ); - } -#endif - -#if __cplusplus_winrt - String( Platform::String ^str ):rep( Rep::alloc(str->Length()) ){ - for( int i=0;ilength;++i ) rep->data[i]=str->Data()[i]; - } -#endif - - ~String(){ - rep->release(); - } - - template String( const C *p ):rep( Rep::alloc(t_strlen(p)) ){ - for( int i=0;ilength;++i ) rep->data[i]=p[i]; - } - - template String( const C *p,int length ):rep( Rep::alloc(length) ){ - for( int i=0;ilength;++i ) rep->data[i]=p[i]; - } - - String Copy()const{ - Rep *crep=Rep::alloc( rep->length ); - t_memcpy( crep->data,rep->data,rep->length ); - return String( crep ); - } - - int Length()const{ - return rep->length; - } - - const Char *Data()const{ - return rep->data; - } - - Char At( int index )const{ - if( index<0 || index>=rep->length ) dbg_error( "Character index out of range" ); - return rep->data[index]; - } - - Char operator[]( int index )const{ - return rep->data[index]; - } - - String &operator=( const String &t ){ - t.rep->retain(); - rep->release(); - rep=t.rep; - return *this; - } - - String &operator+=( const String &t ){ - return operator=( *this+t ); - } - - int Compare( const String &t )const{ - int n=rep->lengthlength ? rep->length : t.rep->length; - for( int i=0;idata[i])-(int)(t.rep->data[i]) ) return q; - } - return rep->length-t.rep->length; - } - - bool operator==( const String &t )const{ - return rep->length==t.rep->length && t_memcmp( rep->data,t.rep->data,rep->length )==0; - } - - bool operator!=( const String &t )const{ - return rep->length!=t.rep->length || t_memcmp( rep->data,t.rep->data,rep->length )!=0; - } - - bool operator<( const String &t )const{ - return Compare( t )<0; - } - - bool operator<=( const String &t )const{ - return Compare( t )<=0; - } - - bool operator>( const String &t )const{ - return Compare( t )>0; - } - - bool operator>=( const String &t )const{ - return Compare( t )>=0; - } - - String operator+( const String &t )const{ - if( !rep->length ) return t; - if( !t.rep->length ) return *this; - Rep *p=Rep::alloc( rep->length+t.rep->length ); - Char *q=p->data; - q=t_memcpy( q,rep->data,rep->length ); - q=t_memcpy( q,t.rep->data,t.rep->length ); - return String( p ); - } - - int Find( String find,int start=0 )const{ - if( start<0 ) start=0; - while( start+find.rep->length<=rep->length ){ - if( !t_memcmp( rep->data+start,find.rep->data,find.rep->length ) ) return start; - ++start; - } - return -1; - } - - int FindLast( String find )const{ - int start=rep->length-find.rep->length; - while( start>=0 ){ - if( !t_memcmp( rep->data+start,find.rep->data,find.rep->length ) ) return start; - --start; - } - return -1; - } - - int FindLast( String find,int start )const{ - if( start>rep->length-find.rep->length ) start=rep->length-find.rep->length; - while( start>=0 ){ - if( !t_memcmp( rep->data+start,find.rep->data,find.rep->length ) ) return start; - --start; - } - return -1; - } - - String Trim()const{ - int i=0,i2=rep->length; - while( idata[i]<=32 ) ++i; - while( i2>i && rep->data[i2-1]<=32 ) --i2; - if( i==0 && i2==rep->length ) return *this; - return String( rep->data+i,i2-i ); - } - - Array Split( String sep )const{ - - if( !sep.rep->length ){ - Array bits( rep->length ); - for( int i=0;ilength;++i ){ - bits[i]=String( (Char)(*this)[i],1 ); - } - return bits; - } - - int i=0,i2,n=1; - while( (i2=Find( sep,i ))!=-1 ){ - ++n; - i=i2+sep.rep->length; - } - Array bits( n ); - if( n==1 ){ - bits[0]=*this; - return bits; - } - i=0;n=0; - while( (i2=Find( sep,i ))!=-1 ){ - bits[n++]=Slice( i,i2 ); - i=i2+sep.rep->length; - } - bits[n]=Slice( i ); - return bits; - } - - String Join( Array bits )const{ - if( bits.Length()==0 ) return String(); - if( bits.Length()==1 ) return bits[0]; - int newlen=rep->length * (bits.Length()-1); - for( int i=0;ilength; - } - Rep *p=Rep::alloc( newlen ); - Char *q=p->data; - q=t_memcpy( q,bits[0].rep->data,bits[0].rep->length ); - for( int i=1;idata,rep->length ); - q=t_memcpy( q,bits[i].rep->data,bits[i].rep->length ); - } - return String( p ); - } - - String Replace( String find,String repl )const{ - int i=0,i2,newlen=0; - while( (i2=Find( find,i ))!=-1 ){ - newlen+=(i2-i)+repl.rep->length; - i=i2+find.rep->length; - } - if( !i ) return *this; - newlen+=rep->length-i; - Rep *p=Rep::alloc( newlen ); - Char *q=p->data; - i=0; - while( (i2=Find( find,i ))!=-1 ){ - q=t_memcpy( q,rep->data+i,i2-i ); - q=t_memcpy( q,repl.rep->data,repl.rep->length ); - i=i2+find.rep->length; - } - q=t_memcpy( q,rep->data+i,rep->length-i ); - return String( p ); - } - - String ToLower()const{ - for( int i=0;ilength;++i ){ - Char t=towlower( rep->data[i] ); - if( t==rep->data[i] ) continue; - Rep *p=Rep::alloc( rep->length ); - Char *q=p->data; - t_memcpy( q,rep->data,i ); - for( q[i++]=t;ilength;++i ){ - q[i]=towlower( rep->data[i] ); - } - return String( p ); - } - return *this; - } - - String ToUpper()const{ - for( int i=0;ilength;++i ){ - Char t=towupper( rep->data[i] ); - if( t==rep->data[i] ) continue; - Rep *p=Rep::alloc( rep->length ); - Char *q=p->data; - t_memcpy( q,rep->data,i ); - for( q[i++]=t;ilength;++i ){ - q[i]=towupper( rep->data[i] ); - } - return String( p ); - } - return *this; - } - - bool Contains( String sub )const{ - return Find( sub )!=-1; - } - - bool StartsWith( String sub )const{ - return sub.rep->length<=rep->length && !t_memcmp( rep->data,sub.rep->data,sub.rep->length ); - } - - bool EndsWith( String sub )const{ - return sub.rep->length<=rep->length && !t_memcmp( rep->data+rep->length-sub.rep->length,sub.rep->data,sub.rep->length ); - } - - String Slice( int from,int term )const{ - int len=rep->length; - if( from<0 ){ - from+=len; - if( from<0 ) from=0; - }else if( from>len ){ - from=len; - } - if( term<0 ){ - term+=len; - }else if( term>len ){ - term=len; - } - if( termdata+from,term-from ); - } - - String Slice( int from )const{ - return Slice( from,rep->length ); - } - - Array ToChars()const{ - Array chars( rep->length ); - for( int i=0;ilength;++i ) chars[i]=rep->data[i]; - return chars; - } - - int ToInt()const{ - char buf[64]; - return atoi( ToCString( buf,sizeof(buf) ) ); - } - - Float ToFloat()const{ - char buf[256]; - return atof( ToCString( buf,sizeof(buf) ) ); - } - - template class CString{ - struct Rep{ - int refs; - C data[1]; - }; - Rep *_rep; - static Rep _nul; - public: - template CString( const T *data,int length ){ - _rep=(Rep*)malloc( length*sizeof(C)+sizeof(Rep) ); - _rep->refs=1; - _rep->data[length]=0; - for( int i=0;idata[i]=(C)data[i]; - } - } - CString():_rep( new Rep ){ - _rep->refs=1; - } - CString( const CString &c ):_rep(c._rep){ - ++_rep->refs; - } - ~CString(){ - if( !--_rep->refs ) free( _rep ); - } - CString &operator=( const CString &c ){ - ++c._rep->refs; - if( !--_rep->refs ) free( _rep ); - _rep=c._rep; - return *this; - } - operator const C*()const{ - return _rep->data; - } - }; - - template CString ToCString()const{ - return CString( rep->data,rep->length ); - } - - template C *ToCString( C *p,int length )const{ - if( --length>rep->length ) length=rep->length; - for( int i=0;idata[i]; - p[length]=0; - return p; - } - -#if __OBJC__ - NSString *ToNSString()const{ - return [NSString stringWithCharacters:ToCString() length:rep->length]; - } -#endif - -#if __cplusplus_winrt - Platform::String ^ToWinRTString()const{ - return ref new Platform::String( rep->data,rep->length ); - } -#endif - CString ToUtf8()const{ - std::vector buf; - Save( buf ); - return CString( &buf[0],buf.size() ); - } - - bool Save( FILE *fp )const{ - std::vector buf; - Save( buf ); - return buf.size() ? fwrite( &buf[0],1,buf.size(),fp )==buf.size() : true; - } - - void Save( std::vector &buf )const{ - - Char *p=rep->data; - Char *e=p+rep->length; - - while( p>6) ); - buf.push_back( 0x80 | (c & 0x3f) ); - }else{ - buf.push_back( 0xe0 | (c>>12) ); - buf.push_back( 0x80 | ((c>>6) & 0x3f) ); - buf.push_back( 0x80 | (c & 0x3f) ); - } - } - } - - static String FromChars( Array chars ){ - int n=chars.Length(); - Rep *p=Rep::alloc( n ); - for( int i=0;idata[i]=chars[i]; - } - return String( p ); - } - - static String Load( FILE *fp ){ - unsigned char tmp[4096]; - std::vector buf; - for(;;){ - int n=fread( tmp,1,4096,fp ); - if( n>0 ) buf.insert( buf.end(),tmp,tmp+n ); - if( n!=4096 ) break; - } - return buf.size() ? String::Load( &buf[0],buf.size() ) : String(); - } - - static String Load( unsigned char *p,int n ){ - - _str_load_err=0; - - unsigned char *e=p+n; - std::vector chars; - - int t0=n>0 ? p[0] : -1; - int t1=n>1 ? p[1] : -1; - - if( t0==0xfe && t1==0xff ){ - p+=2; - while( p2 ? p[2] : -1; - if( t0==0xef && t1==0xbb && t2==0xbf ) p+=3; - unsigned char *q=p; - bool fail=false; - while( p=e || (p[0] & 0xc0)!=0x80 ){ - fail=true; - break; - } - c=((c & 0x1f)<<6) | (p[0] & 0x3f); - p+=1; - }else if( (c & 0xf0)==0xe0 ){ - if( p+1>=e || (p[0] & 0xc0)!=0x80 || (p[1] & 0xc0)!=0x80 ){ - fail=true; - break; - } - c=((c & 0x0f)<<12) | ((p[0] & 0x3f)<<6) | (p[1] & 0x3f); - p+=2; - }else{ - fail=true; - break; - } - } - chars.push_back( c ); - } - if( fail ){ - _str_load_err="Invalid UTF-8"; - return String( q,n ); - } - } - return chars.size() ? String( &chars[0],chars.size() ) : String(); - } - -private: - - struct Rep{ - int refs; - int length; - Char data[0]; - - Rep():refs(1),length(0){ - } - - Rep( int length ):refs(1),length(length){ - } - - void retain(){ - ++refs; - } - - void release(){ - if( --refs || this==&nullRep ) return; - gc_new_bytes-=sizeof(Rep)+length*sizeof(Char); - free( this ); - } - - static Rep *alloc( int length ){ - if( !length ) return &nullRep; - void *p=malloc( sizeof(Rep)+length*sizeof(Char) ); - gc_new_bytes+=sizeof(Rep)+length*sizeof(Char); - return new(p) Rep( length ); - } - }; - Rep *rep; - - static Rep nullRep; - - String( Rep *rep ):rep(rep){ - } -}; - -String::Rep String::nullRep; - -String *t_create( int n,String *p ){ - for( int i=0;i String dbg_type( T **p ){ - return "Object"; -} - -template String dbg_type( Array *p ){ - return dbg_type( &(*p)[0] )+"[]"; -} - -String dbg_value( bool *p ){ - return *p ? "True" : "False"; -} - -String dbg_value( int *p ){ - return String( *p ); -} - -String dbg_value( Float *p ){ - return String( *p ); -} - -String dbg_value( String *p ){ - String t=*p; - if( t.Length()>100 ) t=t.Slice( 0,100 )+"..."; - t=t.Replace( "\"","~q" ); - t=t.Replace( "\t","~t" ); - t=t.Replace( "\n","~n" ); - t=t.Replace( "\r","~r" ); - return String("\"")+t+"\""; -} - -template String dbg_value( T **t ){ - Object *p=dynamic_cast( *t ); - char buf[64]; - sprintf_s( buf,"%p",p ); - return String("@") + (buf[0]=='0' && buf[1]=='x' ? buf+2 : buf ); -} - -template String dbg_value( Array *p ){ - String t="["; - int n=(*p).Length(); - if( n>100 ) n=100; - for( int i=0;i String dbg_decl( const char *id,T *ptr ){ - return String( id )+":"+dbg_type(ptr)+"="+dbg_value(ptr)+"\n"; -} - -struct dbg_var_type{ - virtual String type( void *p )=0; - virtual String value( void *p )=0; -}; - -template struct dbg_var_type_t : public dbg_var_type{ - - String type( void *p ){ - return dbg_type( (T*)p ); - } - - String value( void *p ){ - return dbg_value( (T*)p ); - } - - static dbg_var_type_t info; -}; -template dbg_var_type_t dbg_var_type_t::info; - -struct dbg_blk{ - void **var_ptr; - - dbg_blk():var_ptr(dbg_var_ptr){ - if( dbg_stepmode=='l' ) --dbg_suspend; - } - - ~dbg_blk(){ - if( dbg_stepmode=='l' ) ++dbg_suspend; - dbg_var_ptr=var_ptr; - } -}; - -struct dbg_func : public dbg_blk{ - const char *id; - const char *info; - - dbg_func( const char *p ):id(p),info(dbg_info){ - *dbg_func_ptr++=this; - if( dbg_stepmode=='s' ) --dbg_suspend; - } - - ~dbg_func(){ - if( dbg_stepmode=='s' ) ++dbg_suspend; - --dbg_func_ptr; - dbg_info=info; - } -}; - -int dbg_print( String t ){ - static char *buf; - static int len; - int n=t.Length(); - if( n+100>len ){ - len=n+100; - free( buf ); - buf=(char*)malloc( len ); - } - buf[n]='\n'; - for( int i=0;ivar_ptr ){ - const char *id=(*func_ptr++)->id; - const char *info=func_ptr!=dbg_func_ptr ? (*func_ptr)->info : dbg_info; - fprintf( dbg_stream,"+%s;%s\n",id,info ); - } - void *vp=*var_ptr++; - const char *nm=(const char*)*var_ptr++; - dbg_var_type *ty=(dbg_var_type*)*var_ptr++; - dbg_print( String(nm)+":"+ty->type(vp)+"="+ty->value(vp) ); - } - while( func_ptr!=dbg_func_ptr ){ - const char *id=(*func_ptr++)->id; - const char *info=func_ptr!=dbg_func_ptr ? (*func_ptr)->info : dbg_info; - fprintf( dbg_stream,"+%s;%s\n",id,info ); - } -} - -String dbg_stacktrace(){ - if( !dbg_info || !dbg_info[0] ) return ""; - String str=String( dbg_info )+"\n"; - dbg_func **func_ptr=dbg_func_ptr; - if( func_ptr==dbg_func_buf ) return str; - while( --func_ptr!=dbg_func_buf ){ - str+=String( (*func_ptr)->info )+"\n"; - } - return str; -} - -void dbg_throw( const char *err ){ - dbg_exstack=dbg_stacktrace(); - throw err; -} - -void dbg_stop(){ - -#if TARGET_OS_IPHONE - dbg_throw( "STOP" ); -#endif - - fprintf( dbg_stream,"{{~~%s~~}}\n",dbg_info ); - dbg_callstack(); - dbg_print( "" ); - - for(;;){ - - char buf[256]; - char *e=fgets( buf,256,stdin ); - if( !e ) exit( -1 ); - - e=strchr( buf,'\n' ); - if( !e ) exit( -1 ); - - *e=0; - - Object *p; - - switch( buf[0] ){ - case '?': - break; - case 'r': //run - dbg_suspend=0; - dbg_stepmode=0; - return; - case 's': //step - dbg_suspend=1; - dbg_stepmode='s'; - return; - case 'e': //enter func - dbg_suspend=1; - dbg_stepmode='e'; - return; - case 'l': //leave block - dbg_suspend=0; - dbg_stepmode='l'; - return; - case '@': //dump object - p=0; - sscanf_s( buf+1,"%p",&p ); - if( p ){ - dbg_print( p->debug() ); - }else{ - dbg_print( "" ); - } - break; - case 'q': //quit! - exit( 0 ); - break; - default: - printf( "????? %s ?????",buf );fflush( stdout ); - exit( -1 ); - } - } -} - -void dbg_error( const char *err ){ - -#if TARGET_OS_IPHONE - dbg_throw( err ); -#endif - - for(;;){ - bbPrint( String("Cerberus Runtime Error : ")+err ); - bbPrint( dbg_stacktrace() ); - dbg_stop(); - } -} - -#define DBG_INFO(X) dbg_info=(X);if( dbg_suspend>0 ) dbg_stop(); - -#define DBG_ENTER(P) dbg_func _dbg_func(P); - -#define DBG_BLOCK() dbg_blk _dbg_blk; - -#define DBG_GLOBAL( ID,NAME ) //TODO! - -#define DBG_LOCAL( ID,NAME )\ -*dbg_var_ptr++=&ID;\ -*dbg_var_ptr++=(void*)NAME;\ -*dbg_var_ptr++=&dbg_var_type_t::info; - -//**** main **** - -int argc; -const char **argv; - -Float D2R=0.017453292519943295f; -Float R2D=57.29577951308232f; - -int bbPrint( String t ){ - - static std::vector buf; - buf.clear(); - t.Save( buf ); - buf.push_back( '\n' ); - buf.push_back( 0 ); - -#if __cplusplus_winrt //winrt? - -#if CFG_WINRT_PRINT_ENABLED - OutputDebugStringA( (const char*)&buf[0] ); -#endif - -#elif _WIN32 //windows? - - fputs( (const char*)&buf[0],stdout ); - fflush( stdout ); - -#elif __APPLE__ //macos/ios? - - fputs( (const char*)&buf[0],stdout ); - fflush( stdout ); - -#elif __linux //linux? - -#if CFG_ANDROID_NDK_PRINT_ENABLED - LOGI( (const char*)&buf[0] ); -#else - fputs( (const char*)&buf[0],stdout ); - fflush( stdout ); -#endif - -#endif - - return 0; -} - -class BBExitApp{ -}; - -int bbError( String err ){ - if( !err.Length() ){ -#if __cplusplus_winrt - throw BBExitApp(); -#else - exit( 0 ); -#endif - } - dbg_error( err.ToCString() ); - return 0; -} - -int bbDebugLog( String t ){ - bbPrint( t ); - return 0; -} - -int bbDebugStop(){ - dbg_stop(); - return 0; -} - -int bbInit(); -int bbMain(); - -#if _MSC_VER - -static void _cdecl seTranslator( unsigned int ex,EXCEPTION_POINTERS *p ){ - - switch( ex ){ - case EXCEPTION_ACCESS_VIOLATION:dbg_error( "Memory access violation" ); - case EXCEPTION_ILLEGAL_INSTRUCTION:dbg_error( "Illegal instruction" ); - case EXCEPTION_INT_DIVIDE_BY_ZERO:dbg_error( "Integer divide by zero" ); - case EXCEPTION_STACK_OVERFLOW:dbg_error( "Stack overflow" ); - } - dbg_error( "Unknown exception" ); -} - -#else - -void sighandler( int sig ){ - switch( sig ){ - case SIGSEGV:dbg_error( "Memory access violation" ); - case SIGILL:dbg_error( "Illegal instruction" ); - case SIGFPE:dbg_error( "Floating point exception" ); -#if !_WIN32 - case SIGBUS:dbg_error( "Bus error" ); -#endif - } - dbg_error( "Unknown signal" ); -} - -#endif - -//entry point call by target main()... -// -int bb_std_main( int argc,const char **argv ){ - - ::argc=argc; - ::argv=argv; - -#if _MSC_VER - - _set_se_translator( seTranslator ); - -#else - - signal( SIGSEGV,sighandler ); - signal( SIGILL,sighandler ); - signal( SIGFPE,sighandler ); -#if !_WIN32 - signal( SIGBUS,sighandler ); -#endif - -#endif - - if( !setlocale( LC_CTYPE,"en_US.UTF-8" ) ){ - setlocale( LC_CTYPE,"" ); - } - - gc_init1(); - - bbInit(); - - gc_init2(); - - bbMain(); - - return 0; -} - - -//***** game.h ***** - -struct BBGameEvent{ - enum{ - None=0, - KeyDown=1,KeyUp=2,KeyChar=3, - MouseDown=4,MouseUp=5,MouseMove=6, - TouchDown=7,TouchUp=8,TouchMove=9, - MotionAccel=10 - }; -}; - -class BBGameDelegate : public Object{ -public: - virtual void StartGame(){} - virtual void SuspendGame(){} - virtual void ResumeGame(){} - virtual void UpdateGame(){} - virtual void RenderGame(){} - virtual void KeyEvent( int event,int data ){} - virtual void MouseEvent( int event,int data,Float x,Float y, Float z ){} - virtual void TouchEvent( int event,int data,Float x,Float y ){} - virtual void MotionEvent( int event,int data,Float x,Float y,Float z ){} - virtual void DiscardGraphics(){} -}; - -struct BBDisplayMode : public Object{ - int width; - int height; - int depth; - int hertz; - int flags; - BBDisplayMode( int width=0,int height=0,int depth=0,int hertz=0,int flags=0 ):width(width),height(height),depth(depth),hertz(hertz),flags(flags){} -}; - -class BBGame{ -public: - BBGame(); - virtual ~BBGame(){} - - // ***** Extern ***** - static BBGame *Game(){ return _game; } - - virtual void SetDelegate( BBGameDelegate *delegate ); - virtual BBGameDelegate *Delegate(){ return _delegate; } - - virtual void SetKeyboardEnabled( bool enabled ); - virtual bool KeyboardEnabled(); - - virtual void SetUpdateRate( int updateRate ); - virtual int UpdateRate(); - - virtual bool Started(){ return _started; } - virtual bool Suspended(){ return _suspended; } - - virtual int Millisecs(); - virtual void GetDate( Array date ); - virtual int SaveState( String state ); - virtual String LoadState(); - virtual String LoadString( String path ); - virtual int CountJoysticks( bool update ); - virtual bool PollJoystick( int port,Array joyx,Array joyy,Array joyz,Array buttons ); - virtual void OpenUrl( String url ); - virtual void SetMouseVisible( bool visible ); - - virtual int GetDeviceWidth(){ return 0; } - virtual int GetDeviceHeight(){ return 0; } - virtual void SetDeviceWindow( int width,int height,int flags ){} - virtual Array GetDisplayModes(){ return Array(); } - virtual BBDisplayMode *GetDesktopMode(){ return 0; } - virtual void SetSwapInterval( int interval ){} - - // ***** Native ***** - virtual String PathToFilePath( String path ); - virtual FILE *OpenFile( String path,String mode ); - virtual unsigned char *LoadData( String path,int *plength ); - virtual unsigned char *LoadImageData( String path,int *width,int *height,int *depth ){ return 0; } - virtual unsigned char *LoadAudioData( String path,int *length,int *channels,int *format,int *hertz ){ return 0; } - - //***** Internal ***** - virtual void Die( ThrowableObject *ex ); - virtual void gc_collect(); - virtual void StartGame(); - virtual void SuspendGame(); - virtual void ResumeGame(); - virtual void UpdateGame(); - virtual void RenderGame(); - virtual void KeyEvent( int ev,int data ); - virtual void MouseEvent( int ev,int data,float x,float y, float z ); - virtual void TouchEvent( int ev,int data,float x,float y ); - virtual void MotionEvent( int ev,int data,float x,float y,float z ); - virtual void DiscardGraphics(); - -protected: - - static BBGame *_game; - - BBGameDelegate *_delegate; - bool _keyboardEnabled; - int _updateRate; - bool _started; - bool _suspended; -}; - -//***** game.cpp ***** - -BBGame *BBGame::_game; - -BBGame::BBGame(): -_delegate( 0 ), -_keyboardEnabled( false ), -_updateRate( 0 ), -_started( false ), -_suspended( false ){ - _game=this; -} - -void BBGame::SetDelegate( BBGameDelegate *delegate ){ - _delegate=delegate; -} - -void BBGame::SetKeyboardEnabled( bool enabled ){ - _keyboardEnabled=enabled; -} - -bool BBGame::KeyboardEnabled(){ - return _keyboardEnabled; -} - -void BBGame::SetUpdateRate( int updateRate ){ - _updateRate=updateRate; -} - -int BBGame::UpdateRate(){ - return _updateRate; -} - -int BBGame::Millisecs(){ - return 0; -} - -void BBGame::GetDate( Array date ){ - int n=date.Length(); - if( n>0 ){ - time_t t=time( 0 ); - -#if _MSC_VER - struct tm tii; - struct tm *ti=&tii; - localtime_s( ti,&t ); -#else - struct tm *ti=localtime( &t ); -#endif - - date[0]=ti->tm_year+1900; - if( n>1 ){ - date[1]=ti->tm_mon+1; - if( n>2 ){ - date[2]=ti->tm_mday; - if( n>3 ){ - date[3]=ti->tm_hour; - if( n>4 ){ - date[4]=ti->tm_min; - if( n>5 ){ - date[5]=ti->tm_sec; - if( n>6 ){ - date[6]=0; - } - } - } - } - } - } - } -} - -int BBGame::SaveState( String state ){ - if( FILE *f=OpenFile( "./.cerberusstate","wb" ) ){ - bool ok=state.Save( f ); - fclose( f ); - return ok ? 0 : -2; - } - return -1; -} - -String BBGame::LoadState(){ - if( FILE *f=OpenFile( "./.cerberusstate","rb" ) ){ - String str=String::Load( f ); - fclose( f ); - return str; - } - return ""; -} - -String BBGame::LoadString( String path ){ - if( FILE *fp=OpenFile( path,"rb" ) ){ - String str=String::Load( fp ); - fclose( fp ); - return str; - } - return ""; -} - -int BBGame::CountJoysticks( bool update ){ - return 0; -} - -bool BBGame::PollJoystick( int port,Array joyx,Array joyy,Array joyz,Array buttons ){ - return false; -} - -void BBGame::OpenUrl( String url ){ -} - -void BBGame::SetMouseVisible( bool visible ){ -} - -//***** C++ Game ***** - -String BBGame::PathToFilePath( String path ){ - return path; -} - -FILE *BBGame::OpenFile( String path,String mode ){ - path=PathToFilePath( path ); - if( path=="" ) return 0; - -#if __cplusplus_winrt - path=path.Replace( "/","\\" ); - FILE *f; - if( _wfopen_s( &f,path.ToCString(),mode.ToCString() ) ) return 0; - return f; -#elif _WIN32 - return _wfopen( path.ToCString(),mode.ToCString() ); -#else - return fopen( path.ToCString(),mode.ToCString() ); -#endif -} - -unsigned char *BBGame::LoadData( String path,int *plength ){ - - FILE *f=OpenFile( path,"rb" ); - if( !f ) return 0; - - const int BUF_SZ=4096; - std::vector tmps; - int length=0; - - for(;;){ - void *p=malloc( BUF_SZ ); - int n=fread( p,1,BUF_SZ,f ); - tmps.push_back( p ); - length+=n; - if( n!=BUF_SZ ) break; - } - fclose( f ); - - unsigned char *data=(unsigned char*)malloc( length ); - unsigned char *p=data; - - int sz=length; - for( int i=0;iBUF_SZ ? BUF_SZ : sz; - memcpy( p,tmps[i],n ); - free( tmps[i] ); - sz-=n; - p+=n; - } - - *plength=length; - - gc_ext_malloced( length ); - - return data; -} - -//***** INTERNAL ***** - -void BBGame::Die( ThrowableObject *ex ){ - bbPrint( "Cerberus Runtime Error : Uncaught Cerberus Exception" ); -#ifndef NDEBUG - bbPrint( ex->stackTrace ); -#endif - exit( -1 ); -} - -void BBGame::gc_collect(){ - gc_mark( _delegate ); - ::gc_collect(); -} - -void BBGame::StartGame(){ - - if( _started ) return; - _started=true; - - try{ - _delegate->StartGame(); - }catch( ThrowableObject *ex ){ - Die( ex ); - } - gc_collect(); -} - -void BBGame::SuspendGame(){ - - if( !_started || _suspended ) return; - _suspended=true; - - try{ - _delegate->SuspendGame(); - }catch( ThrowableObject *ex ){ - Die( ex ); - } - gc_collect(); -} - -void BBGame::ResumeGame(){ - - if( !_started || !_suspended ) return; - _suspended=false; - - try{ - _delegate->ResumeGame(); - }catch( ThrowableObject *ex ){ - Die( ex ); - } - gc_collect(); -} - -void BBGame::UpdateGame(){ - - if( !_started || _suspended ) return; - - try{ - _delegate->UpdateGame(); - }catch( ThrowableObject *ex ){ - Die( ex ); - } - gc_collect(); -} - -void BBGame::RenderGame(){ - - if( !_started ) return; - - try{ - _delegate->RenderGame(); - }catch( ThrowableObject *ex ){ - Die( ex ); - } - gc_collect(); -} - -void BBGame::KeyEvent( int ev,int data ){ - - if( !_started ) return; - - try{ - _delegate->KeyEvent( ev,data ); - }catch( ThrowableObject *ex ){ - Die( ex ); - } - gc_collect(); -} - -void BBGame::MouseEvent( int ev,int data,float x,float y, float z ){ - - if( !_started ) return; - - try{ - _delegate->MouseEvent( ev,data,x,y,z ); - }catch( ThrowableObject *ex ){ - Die( ex ); - } - gc_collect(); -} - -void BBGame::TouchEvent( int ev,int data,float x,float y ){ - - if( !_started ) return; - - try{ - _delegate->TouchEvent( ev,data,x,y ); - }catch( ThrowableObject *ex ){ - Die( ex ); - } - gc_collect(); -} - -void BBGame::MotionEvent( int ev,int data,float x,float y,float z ){ - - if( !_started ) return; - - try{ - _delegate->MotionEvent( ev,data,x,y,z ); - }catch( ThrowableObject *ex ){ - Die( ex ); - } - gc_collect(); -} - -void BBGame::DiscardGraphics(){ - - if( !_started ) return; - - try{ - _delegate->DiscardGraphics(); - }catch( ThrowableObject *ex ){ - Die( ex ); - } - gc_collect(); -} - -// Stdcpp trans.system runtime. -// -// Placed into the public domain 24/02/2011. -// No warranty implied; use as your own risk. - -#if _WIN32 - -#ifndef PATH_MAX -#define PATH_MAX MAX_PATH -#endif - -typedef WCHAR OS_CHAR; -typedef struct _stat stat_t; - -#define mkdir( X,Y ) _wmkdir( X ) -#define rmdir _wrmdir -#define remove _wremove -#define rename _wrename -#define stat _wstat -#define _fopen _wfopen -#define putenv _wputenv -#define getenv _wgetenv -#define system _wsystem -#define chdir _wchdir -#define getcwd _wgetcwd -#define realpath(X,Y) _wfullpath( Y,X,PATH_MAX ) //Note: first args SWAPPED to be posix-like! -#define opendir _wopendir -#define readdir _wreaddir -#define closedir _wclosedir -#define DIR _WDIR -#define dirent _wdirent - -#elif __APPLE__ - -typedef char OS_CHAR; -typedef struct stat stat_t; - -#define _fopen fopen - -#elif __linux - -/* -#include -#include -#include -*/ - -typedef char OS_CHAR; -typedef struct stat stat_t; - -#define _fopen fopen - -#endif - -static String _appPath; -static Array _appArgs; - -static String::CString C_STR( const String &t ){ - return t.ToCString(); -} - -static String::CString OS_STR( const String &t ){ - return t.ToCString(); -} - -String HostOS(){ -#if _WIN32 - return "winnt"; -#elif __APPLE__ - return "macos"; -#elif __linux - return "linux"; -#else - return ""; -#endif -} - -String RealPath( String path ){ - std::vector buf( PATH_MAX+1 ); - if( realpath( OS_STR( path ),&buf[0] ) ){} - buf[buf.size()-1]=0; - for( int i=0;i0 && i AppArgs(){ - if( _appArgs.Length() ) return _appArgs; - _appArgs=Array( argc ); - for( int i=0;i LoadDir( String path ){ - std::vector files; - -#if _WIN32 - - WIN32_FIND_DATAW filedata; - HANDLE handle=FindFirstFileW( OS_STR(path+"/*"),&filedata ); - if( handle!=INVALID_HANDLE_VALUE ){ - do{ - String f=filedata.cFileName; - if( f=="." || f==".." ) continue; - files.push_back( f ); - }while( FindNextFileW( handle,&filedata ) ); - FindClose( handle ); - }else{ -// printf( "FindFirstFileW for LoadDir(%s) failed\n",C_STR(path) ); - fflush( stdout ); - } - -#else - - if( DIR *dir=opendir( OS_STR(path) ) ){ - while( dirent *ent=readdir( dir ) ){ - String f=ent->d_name; - if( f=="." || f==".." ) continue; - files.push_back( f ); - } - closedir( dir ); - }else{ -// printf( "opendir for LoadDir(%s) failed\n",C_STR(path) ); - fflush( stdout ); - } - -#endif - - return files.size() ? Array( &files[0],files.size() ) : Array(); -} - -int CopyFile( String srcpath,String dstpath ){ - -#if _WIN32 - - if( CopyFileW( OS_STR(srcpath),OS_STR(dstpath),FALSE ) ) return 1; - return 0; - -#elif __APPLE__ - - // Would like to use COPY_ALL here, but it breaks trans on MacOS - produces weird 'pch out of date' error with copied projects. - // - // Ranlib strikes back! - // - if( copyfile( OS_STR(srcpath),OS_STR(dstpath),0,COPYFILE_DATA )>=0 ) return 1; - return 0; - -#else - - int err=-1; - if( FILE *srcp=_fopen( OS_STR( srcpath ),OS_STR( "rb" ) ) ){ - err=-2; - if( FILE *dstp=_fopen( OS_STR( dstpath ),OS_STR( "wb" ) ) ){ - err=0; - char buf[1024]; - while( int n=fread( buf,1,1024,srcp ) ){ - if( fwrite( buf,1,n,dstp )!=n ){ - err=-3; - break; - } - } - fclose( dstp ); - }else{ -// printf( "FOPEN 'wb' for CopyFile(%s,%s) failed\n",C_STR(srcpath),C_STR(dstpath) ); - fflush( stdout ); - } - fclose( srcp ); - }else{ -// printf( "FOPEN 'rb' for CopyFile(%s,%s) failed\n",C_STR(srcpath),C_STR(dstpath) ); - fflush( stdout ); - } - return err==0; - -#endif -} - -int ChangeDir( String path ){ - return chdir( OS_STR(path) ); -} - -String CurrentDir(){ - std::vector buf( PATH_MAX+1 ); - if( getcwd( &buf[0],buf.size() ) ){} - buf[buf.size()-1]=0; - return String( &buf[0] ); -} - -int CreateDir( String path ){ - mkdir( OS_STR( path ),0777 ); - return FileType(path)==2; -} - -int DeleteDir( String path ){ - rmdir( OS_STR(path) ); - return FileType(path)==0; -} - -int DeleteFile( String path ){ - remove( OS_STR(path) ); - return FileType(path)==0; -} - -int SetEnv( String name,String value ){ -#if _WIN32 - return putenv( OS_STR( name+"="+value ) ); -#else - if( value.Length() ) return setenv( OS_STR( name ),OS_STR( value ),1 ); - unsetenv( OS_STR( name ) ); - return 0; -#endif -} - -String GetEnv( String name ){ - if( OS_CHAR *p=getenv( OS_STR(name) ) ) return String( p ); - return ""; -} - -int Execute( String cmd ){ - -#if _WIN32 - - cmd=String("cmd /S /C \"")+cmd+"\""; - - PROCESS_INFORMATION pi={0}; - STARTUPINFOW si={sizeof(si)}; - - if( !CreateProcessW( 0,(WCHAR*)(const OS_CHAR*)OS_STR(cmd),0,0,1,CREATE_DEFAULT_ERROR_MODE,0,0,&si,&pi ) ) return -1; - - WaitForSingleObject( pi.hProcess,INFINITE ); - - int res=GetExitCodeProcess( pi.hProcess,(DWORD*)&res ) ? res : -1; - - CloseHandle( pi.hProcess ); - CloseHandle( pi.hThread ); - - return res; - -#else - - return system( OS_STR(cmd) ); - -#endif -} - -int ExitApp( int retcode ){ - exit( retcode ); - return 0; -} - -class c_ILinkResolver; -class c_IPrettifier; -class c_Makedocs; -class c_Stack; -class c_StringStack; -class c_List; -class c_StringList; -class c_Node; -class c_HeadNode; -class c_Enumerator; -class c_DocDecl; -class c_Stack2; -class c_DocDeclStack; -class c_Enumerator2; -class c_ApiDoccer; -class c_Toker; -class c_Parser; -class c_Set; -class c_StringSet; -class c_Map; -class c_StringMap; -class c_Node2; -class c_ThrowableString; -class c_Stack3; -class c_IntStack; -class c_BackwardsStack; -class c_BackwardsEnumerator; -class c_DocDoccer; -class c_Map2; -class c_StringMap2; -class c_Node3; -class c_Map3; -class c_StringMap3; -class c_Node4; -class c_Map4; -class c_StringMap4; -class c_Node5; -class c_NodeEnumerator; -class c_PageMaker; -class c_Stack4; -class c_Markdown; -class c_Stack5; -class c_StringObject; -class c_NodeEnumerator2; -class c_NodeEnumerator3; -class c_ILinkResolver : public virtual gc_interface{ - public: - virtual String p_ResolveLink(String,String)=0; -}; -class c_IPrettifier : public virtual gc_interface{ - public: - virtual String p_PrettifyLine(String)=0; - virtual String p_EndPrettyBlock()=0; - virtual String p_BeginPrettyBlock()=0; -}; -class c_Makedocs : public Object,public virtual c_ILinkResolver,public virtual c_IPrettifier{ - public: - c_StringStack* m_ignoremods; - String m_errinfofile; - int m_errinfoline; - int m_errinfochar; - String m_rootpath; - String m_templatename; - bool m_opt_printtree; - bool m_opt_printdocs; - String m_templatedir; - String m_modpaths; - String m_docpath; - c_DocDecl* m_rootdecl; - c_DocDecl* m_rootmodules; - c_DocDecl* m_rootdocs; - c_DocDecl* m_branch3rdparty; - c_ApiDoccer* m_apidoccer; - c_DocDoccer* m_docdoccer; - c_StringMap3* m_indexes; - c_DocDecl* m_curdecl; - String m_template; - c_PageMaker* m_pager; - c_Markdown* m_marker; - Array m_iconlinks_url; - Array m_iconlinks_icon; - c_IntStack* m_blocks; - c_Makedocs(); - void p_Message(String,String); - void p_Die(String); - void p_ParseAppArgs(); - int p__IsInCxRoot(); - void p_BrowseToCxRoot(); - void p_LoadTemplateName(); - void p_Warning(String); - void p_LoadModulesPath(); - void p_LoadDocPath(); - void p_CleanUpEarly(); - void p_CopyFile(String,String); - void p__AssertPath(String); - void p_CopyDir(String,String,bool); - void p_CopyTemplateData(); - void p_SetErrInfoFile(String); - void p_SetErrInfoLine(int); - void p_SetErrInfoChar(int); - void p_Error(String); - void p_ClearErrInfo(); - void p__CopyExamples(c_DocDecl*,c_DocDeclStack*); - void p__AssignExamples(c_DocDecl*); - void p__CompleteIdentifiers(c_DocDecl*,String,String); - void p__CompleteImports(); - void p__CompleteInherited(c_DocDecl*,c_DocDecl*); - void p__CompleteExtends(); - String p__SummaryFromDescription(String); - void p__CompleteSummaries(); - void p__CompleteExamples(); - void p_Complete(); - void p__MoveToIndex(String,c_DocDeclStack*); - void p__CreateIndex(String,c_DocDeclStack*,String); - void p__FillMasterIndex(c_DocDecl*,c_DocDeclStack*); - void p_CreateIndexes(); - String p_BuildDocLink(c_DocDecl*,c_DocDecl*); - void p_WriteDeclFiles(); - static int m_resolvecode; - String p_ResolveDocLink(String); - String p__ApplyPageTemplate(Array,Array,String); - void p__WritePage(String,String); - Array p__LinkUrlsFromIdents(Array); - void p_WriteDocs(); - void p_WriteExamples(); - c_Makedocs* m_new(); - String p_ResolveLink(String,String); - String p_BeginPrettyBlock(); - String p_EndPrettyBlock(); - String p_PrettifyLine(String); - void mark(); -}; -class c_Stack : public Object{ - public: - Array m_data; - int m_length; - c_Stack(); - c_Stack* m_new(); - c_Stack* m_new2(Array); - void p_Push(String); - void p_Push2(Array,int,int); - void p_Push3(Array,int); - virtual bool p_Equals(String,String); - bool p_Contains(String); - bool p_IsEmpty(); - String p_Get(int); - static String m_NIL; - String p_Pop(); - Array p_ToArray(); - void mark(); -}; -class c_StringStack : public c_Stack{ - public: - c_StringStack(); - c_StringStack* m_new(Array); - c_StringStack* m_new2(); - String p_Join(String); - bool p_Equals(String,String); - void mark(); -}; -String bb_os_ExtractDir(String); -class c_List : public Object{ - public: - c_Node* m__head; - c_List(); - c_List* m_new(); - c_Node* p_AddLast(String); - c_List* m_new2(Array); - bool p_IsEmpty(); - String p_RemoveFirst(); - virtual bool p_Equals(String,String); - c_Node* p_Find(String,c_Node*); - c_Node* p_Find2(String); - void p_RemoveFirst2(String); - int p_Count(); - c_Enumerator* p_ObjectEnumerator(); - Array p_ToArray(); - void mark(); -}; -class c_StringList : public c_List{ - public: - c_StringList(); - c_StringList* m_new(Array); - c_StringList* m_new2(); - bool p_Equals(String,String); - void mark(); -}; -class c_Node : public Object{ - public: - c_Node* m__succ; - c_Node* m__pred; - String m__data; - c_Node(); - c_Node* m_new(c_Node*,c_Node*,String); - c_Node* m_new2(); - int p_Remove(); - void mark(); -}; -class c_HeadNode : public c_Node{ - public: - c_HeadNode(); - c_HeadNode* m_new(); - void mark(); -}; -class c_Enumerator : public Object{ - public: - c_List* m__list; - c_Node* m__curr; - c_Enumerator(); - c_Enumerator* m_new(c_List*); - c_Enumerator* m_new2(); - bool p_HasNext(); - String p_NextObject(); - void mark(); -}; -Array bb_os_LoadDir(String,bool,bool); -int bb_os_DeleteDir(String,bool); -int bb_os_CopyDir(String,String,bool,bool); -class c_DocDecl : public Object{ - public: - c_DocDecl* m_parent; - int m_kind; - String m_ident; - int m_uid; - bool m_canbefound; - c_DocDeclStack* m_childs; - int m__lastsid; - c_DocDecl* m_target; - c_DocDecl(); - static int m__uid; - bool p_Canbefound(); - c_DocDecl* m_new(int,String); - c_DocDecl* m_new2(); - void p_Add(c_DocDecl*); - void p_Add2(c_Stack2*); - c_DocDecl* p_GetChild(int); - c_DocDecl* p_GetChild2(String); - c_DocDecl* p_GetChild3(String,int); - c_DocDeclStack* p_GetChilds(String,bool); - c_DocDeclStack* p_GetChilds2(int,bool); - c_DocDecl* p_GetScope(int); - static c_DocDecl* m__root; - static c_DocDecl* m__modroot; - static c_DocDeclStack* m__modules; - static c_DocDecl* m__docroot; - static c_DocDeclStack* m__documents; - static c_StringStack* m__primnames; - void p_PrepareFinder(); - String p_GetType(bool,bool); - String p_GetUniqueIdent(); - static c_StringMap2* m__primlinks; - static int m__searchid; - c_DocDecl* p__FindInHere(Array,int,String,int); - c_DocDecl* p__FoundDecl(c_DocDecl*,bool); - c_DocDecl* p_FindFromHere(String,int); - String p_GetIdent(); - String p_GetIdentWithParams(); - String p_GetTextOfChild(int); - void p_Sort(); - String p_GetKindName(); - String p_GetScopeIdent(); - String p_GetDocType(bool); - c_DocDecl* p__FindChild(String,String,int); - c_DocDecl* p_FindChild(String,int); - String p_GetGenType(); - String p_GetDocXType(); - String p_GetTargetIdent(); - String p_ToString(int); - void mark(); -}; -class c_Stack2 : public Object{ - public: - Array m_data; - int m_length; - c_Stack2(); - c_Stack2* m_new(); - c_Stack2* m_new2(Array); - void p_Push4(c_DocDecl*); - void p_Push5(Array,int,int); - void p_Push6(Array,int); - c_Enumerator2* p_ObjectEnumerator(); - static c_DocDecl* m_NIL; - void p_Length(int); - int p_Length2(); - Array p_ToArray(); - bool p_Equals2(c_DocDecl*,c_DocDecl*); - void p_RemoveEach(c_DocDecl*); - c_DocDecl* p_Get(int); - virtual int p_Compare(c_DocDecl*,c_DocDecl*); - bool p__Less(int,int,int); - void p__Swap(int,int); - bool p__Less2(int,c_DocDecl*,int); - bool p__Less3(c_DocDecl*,int,int); - void p__Sort(int,int,int); - virtual void p_Sort2(bool); - void mark(); -}; -class c_DocDeclStack : public c_Stack2{ - public: - c_DocDeclStack(); - c_DocDeclStack* m_new(); - void p_Sort2(bool); - int p_Compare(c_DocDecl*,c_DocDecl*); - void mark(); -}; -class c_Enumerator2 : public Object{ - public: - c_Stack2* m_stack; - int m_index; - c_Enumerator2(); - c_Enumerator2* m_new(c_Stack2*); - c_Enumerator2* m_new2(); - bool p_HasNext(); - c_DocDecl* p_NextObject(); - void mark(); -}; -int bb_math_Max(int,int); -Float bb_math_Max2(Float,Float); -class c_ApiDoccer : public Object{ - public: - c_Makedocs* m_maker; - int m_cursect; - c_DocDecl* m_curparagraph; - c_Parser* m_parser; - c_ApiDoccer(); - c_ApiDoccer* m_new(c_Makedocs*); - c_ApiDoccer* m_new2(); - void p_LoadExamples(String,c_DocDecl*); - void p_AppendDocContents(c_DocDecl*,String); - void p_Error(String); - void p_ParseDocFile(String,c_DocDecl*,String); - void p_CopyDocsData(String,String); - void p_ParseSourceFile(String,c_DocDecl*,String); - void p_ParseIn(String,c_DocDecl*,String); - void p_Parse(); - String p_StripParagraph(String); - void p_SetPagerStrings(c_PageMaker*,c_DocDecl*,bool); - void p_SetPagerList(c_PageMaker*,c_DocDecl*,int,String); - void p_SetPagerLists(c_PageMaker*,c_DocDecl*,Array,Array); - String p_ApplyModuleTemplate(c_DocDecl*,c_PageMaker*); - String p_ApplyClassTemplate(c_DocDecl*,c_PageMaker*); - void mark(); -}; -String bb_os_ExtractExt(String); -String bb_os_StripExt(String); -String bb_os_StripDir(String); -class c_Toker : public Object{ - public: - String m__path; - int m__line; - String m__source; - int m__length; - String m__toke; - int m__tokeType; - int m__tokePos; - c_Toker(); - static c_StringSet* m__keywords; - static c_StringSet* m__symbols; - int p__init(); - c_Toker* m_new(String,String); - c_Toker* m_new2(c_Toker*); - c_Toker* m_new3(); - int p_TCHR(int); - String p_TSTR(int); - String p_NextToke(); - void mark(); -}; -class c_Parser : public c_Toker{ - public: - c_Parser(); - c_Parser* m_new(String); - c_Parser* m_new2(); - c_Toker* p_Store(); - String p_NextSpace(); - String p_NextCdata(String); - void p_Pop(); - void p_Error(String); - void p_PopSpace(bool); - void p_Restore(c_Toker*); - bool p__PopToken(String,int,bool,bool,bool); - bool p_PopUntilToken(String,bool); - bool p_PopUntilToken2(int,bool); - bool p_PopToken(String,bool); - bool p_PopToken2(int,bool); - String p_SParseModpath(bool); - c_DocDecl* p_ParseModuleHeader(c_DocDecl*); - c_DocDecl* p_ParseImportDecl(c_DocDecl*); - c_DocDecl* p_GetModuleScope(c_DocDecl*); - String p_SParseClasspath(); - void p_PopLineBreak(); - c_Stack2* p_ParseTypeParameters(c_DocDecl*); - bool p_PopKeyword(String,bool); - String p_SParseExpression(); - c_DocDecl* p_ParseTypeArray(c_DocDecl*); - c_DocDecl* p_ParseType(c_DocDecl*); - c_Stack2* p_ParseTypeArguments(c_DocDecl*); - c_DocDecl* p_ParseClassExtends(c_DocDecl*); - c_Stack2* p_ParseClassImplements(c_DocDecl*,String); - c_Stack2* p_ParseInterfaceExtends(c_DocDecl*); - c_DocDecl* p_ParseClassDecl(c_DocDecl*,int); - c_DocDecl* p_GetClassScope(c_DocDecl*); - c_DocDecl* p_ParseTypeDecl(c_DocDecl*,int); - c_DocDecl* p_ParseInitialValue(c_DocDecl*); - c_DocDecl* p_ParseVariable(c_DocDecl*,int); - c_Stack2* p_ParseVariableSet(c_DocDecl*,int); - c_Stack2* p_ParseFunctionParameters(c_DocDecl*); - c_DocDecl* p_ParseFunctionDecl(c_DocDecl*,int); - c_DocDecl* p_ParseEnumDecl(c_DocDecl*,int); - c_DocDecl* p_ParseDecl(c_DocDecl*); - String p_NextRestOfLine(); - int p_GetCarretLine(); - int p_GetCarretChar(); - bool p_PopUntilKeyword(String,bool); - void mark(); -}; -class c_Set : public Object{ - public: - c_Map* m_map; - c_Set(); - c_Set* m_new(c_Map*); - c_Set* m_new2(); - int p_Insert(String); - bool p_Contains(String); - void mark(); -}; -class c_StringSet : public c_Set{ - public: - c_StringSet(); - c_StringSet* m_new(); - void mark(); -}; -class c_Map : public Object{ - public: - c_Node2* m_root; - c_Map(); - c_Map* m_new(); - virtual int p_Compare2(String,String)=0; - int p_RotateLeft(c_Node2*); - int p_RotateRight(c_Node2*); - int p_InsertFixup(c_Node2*); - bool p_Set(String,Object*); - bool p_Insert2(String,Object*); - c_Node2* p_FindNode(String); - bool p_Contains(String); - int p_Clear(); - Object* p_Get2(String); - void mark(); -}; -class c_StringMap : public c_Map{ - public: - c_StringMap(); - c_StringMap* m_new(); - int p_Compare2(String,String); - void mark(); -}; -class c_Node2 : public Object{ - public: - String m_key; - c_Node2* m_right; - c_Node2* m_left; - Object* m_value; - int m_color; - c_Node2* m_parent; - c_Node2(); - c_Node2* m_new(String,Object*,int,c_Node2*); - c_Node2* m_new2(); - void mark(); -}; -bool bb_stringutil_IsSpace(int); -bool bb_stringutil_IsAlpha(int); -bool bb_stringutil_IsDigit(int); -bool bb_stringutil_IsBinDigit(int); -bool bb_stringutil_IsHexDigit(int); -class c_ThrowableString : public ThrowableObject{ - public: - String m_str; - c_ThrowableString(); - c_ThrowableString* m_new(String); - c_ThrowableString* m_new2(); - String p_ToString2(); - void mark(); -}; -String bb_stringutil_UnifyLineEndings(String); -class c_Stack3 : public Object{ - public: - Array m_data; - int m_length; - c_Stack3(); - c_Stack3* m_new(); - c_Stack3* m_new2(Array); - c_BackwardsStack* p_Backwards(); - void p_Push7(int); - void p_Push8(Array,int,int); - void p_Push9(Array,int); - static int m_NIL; - int p_Pop(); - void p_Length(int); - int p_Length2(); - int p_Get(int); - void p_Clear(); - void mark(); -}; -class c_IntStack : public c_Stack3{ - public: - c_IntStack(); - c_IntStack* m_new(Array); - c_IntStack* m_new2(); - void mark(); -}; -class c_BackwardsStack : public Object{ - public: - c_Stack3* m_stack; - c_BackwardsStack(); - c_BackwardsStack* m_new(c_Stack3*); - c_BackwardsStack* m_new2(); - c_BackwardsEnumerator* p_ObjectEnumerator(); - void mark(); -}; -class c_BackwardsEnumerator : public Object{ - public: - c_Stack3* m_stack; - int m_index; - c_BackwardsEnumerator(); - c_BackwardsEnumerator* m_new(c_Stack3*); - c_BackwardsEnumerator* m_new2(); - bool p_HasNext(); - int p_NextObject(); - void mark(); -}; -class c_DocDoccer : public Object{ - public: - c_Makedocs* m_maker; - c_DocDoccer(); - c_DocDoccer* m_new(c_Makedocs*); - c_DocDoccer* m_new2(); - void p_DocIn(String,c_DocDecl*,String,bool); - void p_Doc(); - void p_Doc3rdParty(); - void mark(); -}; -class c_Map2 : public Object{ - public: - c_Node3* m_root; - c_Map2(); - c_Map2* m_new(); - virtual int p_Compare2(String,String)=0; - c_Node3* p_FindNode(String); - c_DocDecl* p_Get2(String); - int p_RotateLeft2(c_Node3*); - int p_RotateRight2(c_Node3*); - int p_InsertFixup2(c_Node3*); - bool p_Add3(String,c_DocDecl*); - c_Node3* p_FirstNode(); - c_NodeEnumerator3* p_ObjectEnumerator(); - void mark(); -}; -class c_StringMap2 : public c_Map2{ - public: - c_StringMap2(); - c_StringMap2* m_new(); - int p_Compare2(String,String); - void mark(); -}; -class c_Node3 : public Object{ - public: - String m_key; - c_Node3* m_right; - c_Node3* m_left; - c_DocDecl* m_value; - int m_color; - c_Node3* m_parent; - c_Node3(); - c_Node3* m_new(String,c_DocDecl*,int,c_Node3*); - c_Node3* m_new2(); - c_Node3* p_NextNode(); - c_DocDecl* p_Value(); - void mark(); -}; -class c_Map3 : public Object{ - public: - c_Node4* m_root; - c_Map3(); - c_Map3* m_new(); - virtual int p_Compare2(String,String)=0; - int p_RotateLeft3(c_Node4*); - int p_RotateRight3(c_Node4*); - int p_InsertFixup3(c_Node4*); - bool p_Add4(String,c_StringMap2*); - c_Node4* p_FirstNode(); - c_NodeEnumerator2* p_ObjectEnumerator(); - void mark(); -}; -class c_StringMap3 : public c_Map3{ - public: - c_StringMap3(); - c_StringMap3* m_new(); - int p_Compare2(String,String); - void mark(); -}; -class c_Node4 : public Object{ - public: - String m_key; - c_Node4* m_right; - c_Node4* m_left; - c_StringMap2* m_value; - int m_color; - c_Node4* m_parent; - c_Node4(); - c_Node4* m_new(String,c_StringMap2*,int,c_Node4*); - c_Node4* m_new2(); - c_Node4* p_NextNode(); - String p_Key(); - c_StringMap2* p_Value(); - void mark(); -}; -class c_Map4 : public Object{ - public: - c_Node5* m_root; - c_Map4(); - c_Map4* m_new(); - virtual int p_Compare2(String,String)=0; - c_Node5* p_FindNode(String); - bool p_Contains(String); - int p_RotateLeft4(c_Node5*); - int p_RotateRight4(c_Node5*); - int p_InsertFixup4(c_Node5*); - bool p_Add5(String,String); - bool p_Set2(String,String); - c_Node5* p_FirstNode(); - c_NodeEnumerator* p_ObjectEnumerator(); - void mark(); -}; -class c_StringMap4 : public c_Map4{ - public: - c_StringMap4(); - c_StringMap4* m_new(); - int p_Compare2(String,String); - void mark(); -}; -class c_Node5 : public Object{ - public: - String m_key; - c_Node5* m_right; - c_Node5* m_left; - String m_value; - int m_color; - c_Node5* m_parent; - c_Node5(); - c_Node5* m_new(String,String,int,c_Node5*); - c_Node5* m_new2(); - c_Node5* p_NextNode(); - String p_Key(); - String p_Value(); - void mark(); -}; -class c_NodeEnumerator : public Object{ - public: - c_Node5* m_node; - c_NodeEnumerator(); - c_NodeEnumerator* m_new(c_Node5*); - c_NodeEnumerator* m_new2(); - bool p_HasNext(); - c_Node5* p_NextObject(); - void mark(); -}; -class c_PageMaker : public Object{ - public: - String m__template; - c_StringMap* m__decls; - c_Stack4* m__scopes; - c_Stack5* m__lists; - c_IntStack* m__iters; - c_PageMaker(); - c_PageMaker* m_new(String); - c_PageMaker* m_new2(); - void p_Clear(); - void p_SetString(String,String); - void p_BeginList(String); - void p_AddItem(); - void p_EndList(); - Object* p_GetValue(String); - String p_GetString(String); - c_Stack4* p_GetList(String); - String p_MakePage(); - void mark(); -}; -class c_Stack4 : public Object{ - public: - Array m_data; - int m_length; - c_Stack4(); - c_Stack4* m_new(); - c_Stack4* m_new2(Array); - void p_Push10(c_StringMap*); - void p_Push11(Array,int,int); - void p_Push12(Array,int); - static c_StringMap* m_NIL; - void p_Clear(); - c_StringMap* p_Top(); - c_StringMap* p_Pop(); - void p_Length(int); - int p_Length2(); - c_StringMap* p_Get(int); - void mark(); -}; -class c_Markdown : public Object{ - public: - c_ILinkResolver* m__resolver; - c_IPrettifier* m__prettifier; - String m__blk; - c_Markdown(); - c_Markdown* m_new(c_ILinkResolver*,c_IPrettifier*); - c_Markdown* m_new2(); - String p_Prettify(String); - String p_SetBlock(String); - int p_Find3(String,String,int); - String p_ReplaceSpanTags(String,String,String); - String p_ReplacePrefixTags(String,String,String); - String p_ReplaceLinks(String); - String p_ReplaceEscs(String); - String p_SpanToHtml(String); - String p_LineToHtml(String); - String p_ToHtml(String); - void mark(); -}; -class c_Stack5 : public Object{ - public: - Array m_data; - int m_length; - c_Stack5(); - c_Stack5* m_new(); - c_Stack5* m_new2(Array); - static c_Stack4* m_NIL; - void p_Clear(); - void p_Push13(c_Stack4*); - void p_Push14(Array,int,int); - void p_Push15(Array,int); - c_Stack4* p_Top(); - c_Stack4* p_Pop(); - void mark(); -}; -class c_StringObject : public Object{ - public: - String m_value; - c_StringObject(); - c_StringObject* m_new(int); - c_StringObject* m_new2(Float); - c_StringObject* m_new3(String); - c_StringObject* m_new4(); - void mark(); -}; -String bb_stringutil_HtmlEscape(String); -int bb_math_Min(int,int); -Float bb_math_Min2(Float,Float); -class c_NodeEnumerator2 : public Object{ - public: - c_Node4* m_node; - c_NodeEnumerator2(); - c_NodeEnumerator2* m_new(c_Node4*); - c_NodeEnumerator2* m_new2(); - bool p_HasNext(); - c_Node4* p_NextObject(); - void mark(); -}; -class c_NodeEnumerator3 : public Object{ - public: - c_Node3* m_node; - c_NodeEnumerator3(); - c_NodeEnumerator3* m_new(c_Node3*); - c_NodeEnumerator3* m_new2(); - bool p_HasNext(); - c_Node3* p_NextObject(); - void mark(); -}; -int bbMain(); -c_Makedocs::c_Makedocs(){ - m_ignoremods=(new c_StringStack)->m_new2(); - m_errinfofile=String(); - m_errinfoline=0; - m_errinfochar=0; - m_rootpath=String(); - m_templatename=String(); - m_opt_printtree=false; - m_opt_printdocs=false; - m_templatedir=String(); - m_modpaths=String(); - m_docpath=String(); - m_rootdecl=0; - m_rootmodules=0; - m_rootdocs=0; - m_branch3rdparty=0; - m_apidoccer=0; - m_docdoccer=0; - m_indexes=0; - m_curdecl=0; - m_template=String(); - m_pager=0; - m_marker=0; - m_iconlinks_url=Array(); - m_iconlinks_icon=Array(); - m_blocks=0; -} -void c_Makedocs::p_Message(String t_pType,String t_pPrompt){ - String t_msg=String(); - if((m_errinfofile).Length()!=0){ - String t_errinfo=m_errinfofile; - if((m_errinfoline)!=0){ - t_errinfo=t_errinfo+(String(L", line ",7)+String(m_errinfoline)); - if((m_errinfochar)!=0){ - t_errinfo=t_errinfo+(String(L", char ",7)+String(m_errinfochar)); - } - } - t_msg=String(L"[",1)+t_pType+String(L" (",2)+t_errinfo+String(L")] ",3)+t_pPrompt; - }else{ - t_msg=String(L"[",1)+t_pType+String(L"] ",2)+t_pPrompt; - } - bbPrint(t_msg); -} -void c_Makedocs::p_Die(String t_pPrompt){ - p_Message(String(L"FATAL ERROR",11),t_pPrompt); - ExitApp(0); -} -void c_Makedocs::p_ParseAppArgs(){ - int t_i=1; - while(t_i t_ignored=t_ignparam.Split(String(L";",1)); - Array t_=t_ignored; - int t_2=0; - while(t_2p_Push(t_ign); - } - t_i+=1; - }else{ - p_Die(String(L"-ignore must be followed by module name",39)); - } - }else{ - if(t_1==String(L"-path",5)){ - if(t_i t_=t_config.Split(String(L"\n",1)); - int t_2=0; - while(t_2 t_bits=t_line.Split(String(L"=",1)); - if(t_bits.Length()!=2){ - continue; - } - if(t_bits[0]==String(L"MODPATH",7)){ - String t_val=t_bits[1]; - do{ - int t_i0=t_val.Find(String(L"${",2),0); - int t_i1=t_val.Find(String(L"}",1),0); - if(t_i0==-1 || t_i1==-1){ - break; - } - String t_ident=t_val.Slice(t_i0+2,t_i1); - String t_3=t_ident; - if(t_3==String(L"MONKEYDIR",9) || t_3==String(L"CERBERUSDIR",11)){ - t_ident=CurrentDir(); - }else{ - t_ident=GetEnv(t_ident); - } - t_val=t_val.Slice(0,t_i0)+t_ident+t_val.Slice(t_i1+1); - }while(!(false)); - if(t_val.StartsWith(String(L"\"",1)) && t_val.EndsWith(String(L"\"",1))){ - t_val=t_val.Slice(1,-1); - } - m_modpaths=t_val; - if(!((m_modpaths).Length()!=0)){ - p_Warning(String(L"MODPATH not set",15)); - } - break; - } - } - } - m_modpaths=m_modpaths.Replace(String(L"\\",1),String(L"/",1)); - m_modpaths=m_modpaths.Replace(String(L"|",1),String(L";",1)); -} -void c_Makedocs::p_LoadDocPath(){ - m_docpath=CurrentDir()+String(L"/",1)+String(L"docs/cerberusdoc",16); -} -void c_Makedocs::p_CleanUpEarly(){ - if(!m_opt_printdocs && !m_opt_printtree){ - bb_os_DeleteDir(String(L"docs/html",9),true); - CreateDir(String(L"docs/html",9)); - CreateDir(String(L"docs/html/data",14)); - CreateDir(String(L"docs/html/examples",18)); - } -} -void c_Makedocs::p_CopyFile(String t_pSrc,String t_pDst){ - if(!m_opt_printdocs && !m_opt_printtree){ - CopyFile(t_pSrc,t_pDst); - } -} -void c_Makedocs::p__AssertPath(String t_pDst){ - int t_p=-1; - String t_path=String(); - do{ - t_p=t_pDst.Find(String(L"/",1),t_p+1); - if(t_p==-1){ - t_path=t_pDst; - }else{ - t_path=t_pDst.Slice(0,t_p); - } - if(FileType(t_path)!=2){ - CreateDir(t_path); - } - }while(!(t_p==-1)); -} -void c_Makedocs::p_CopyDir(String t_pSrc,String t_pDst,bool t_pRecursive){ - if(!m_opt_printdocs && !m_opt_printtree){ - p__AssertPath(t_pDst); - bb_os_CopyDir(t_pSrc,t_pDst,t_pRecursive,false); - } -} -void c_Makedocs::p_CopyTemplateData(){ - Array t_=LoadDir(m_templatedir); - int t_2=0; - while(t_2p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_ex=t_->p_NextObject(); - String t_source=t_ex->p_GetChild(221)->m_ident; - t_source=String(L"
",5)+t_source+String(L"
",6); - c_DocDeclStack* t_decls=t_pScope->p_GetChilds(t_ex->m_ident,true); - if((t_decls)!=0){ - c_Enumerator2* t_2=t_decls->p_ObjectEnumerator(); - while(t_2->p_HasNext()){ - c_DocDecl* t_d=t_2->p_NextObject(); - int t_4=t_d->m_kind; - if(t_4==901 || t_4==301 || t_4==302 || t_4==310 || t_4==320 || t_4==321 || t_4==403 || t_4==405 || t_4==406 || t_4==410 || t_4==420 || t_4==421 || t_4==423){ - if(!((t_d->p_GetChild(801))!=0)){ - t_d->p_Add((new c_DocDecl)->m_new(801,t_source)); - } - }else{ - if(t_4==601){ - if(!((t_d->m_parent->p_GetChild(801))!=0)){ - t_d->m_parent->p_Add((new c_DocDecl)->m_new(801,t_source)); - } - } - } - } - } - } -} -void c_Makedocs::p__AssignExamples(c_DocDecl* t_pScope){ - if((t_pScope->m_childs)!=0){ - c_Enumerator2* t_=t_pScope->m_childs->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_c=t_->p_NextObject(); - if(t_c->m_kind==901 || t_c->m_kind==900){ - c_DocDeclStack* t_examples=t_c->p_GetChilds2(220,false); - if((t_examples)!=0){ - p__CopyExamples(t_c,t_examples); - } - p__AssignExamples(t_c); - } - } - } -} -void c_Makedocs::p__CompleteIdentifiers(c_DocDecl* t_pDecl,String t_pScope,String t_pModPath){ - String t_uident=String(); - if((t_pScope).Length()!=0){ - t_uident=t_pScope+String(L".",1); - } - if((t_pModPath).Length()!=0){ - t_uident=t_pModPath+String(L".",1)+t_uident; - } - bool t_completechilds=false; - int t_5=t_pDecl->m_kind; - if(t_5==310 || t_5==403 || t_5==406 || t_5==405 || t_5==410){ - t_pDecl->p_Add((new c_DocDecl)->m_new(201,t_uident)); - String t_txt=String(); - c_DocDeclStack* t_params=t_pDecl->p_GetChilds2(600,false); - if((t_params)!=0){ - c_Enumerator2* t_=t_params->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_p=t_->p_NextObject(); - if((t_txt).Length()!=0){ - t_txt=t_txt+String(L",",1); - } - t_txt=t_txt+t_p->p_GetType(false,true); - } - } - t_pDecl->p_Add((new c_DocDecl)->m_new(202,String(L"(",1)+t_txt+String(L")",1))); - }else{ - if(t_5==901 || t_5==900){ - t_pModPath=t_pDecl->p_GetUniqueIdent(); - t_completechilds=true; - }else{ - if(t_5==301 || t_5==302){ - t_pDecl->p_Add((new c_DocDecl)->m_new(201,t_uident)); - t_pScope=t_pDecl->m_ident; - t_completechilds=true; - }else{ - if(t_5==100 || t_5==102 || t_5==101){ - t_completechilds=true; - }else{ - if(t_5==320 || t_5==322 || t_5==321 || t_5==420 || t_5==422 || t_5==421 || t_5==423){ - t_pDecl->p_Add((new c_DocDecl)->m_new(201,t_uident)); - } - } - } - } - } - if(((t_pDecl->m_childs)!=0) && t_completechilds){ - c_Enumerator2* t_2=t_pDecl->m_childs->p_ObjectEnumerator(); - while(t_2->p_HasNext()){ - c_DocDecl* t_c=t_2->p_NextObject(); - p__CompleteIdentifiers(t_c,t_pScope,t_pModPath); - } - } -} -void c_Makedocs::p__CompleteImports(){ - c_DocDeclStack* t_imps=m_rootmodules->p_GetChilds2(300,true); - if((t_imps)!=0){ - c_Enumerator2* t_=t_imps->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_i=t_->p_NextObject(); - c_DocDecl* t_decl=0; - t_decl=m_rootmodules->p_FindFromHere(t_i->m_ident,901); - if((t_decl)!=0){ - t_i->m_target=t_decl; - c_DocDecl* t_d=(new c_DocDecl)->m_new(700,t_i->m_parent->p_GetUniqueIdent()); - t_d->m_target=t_i->m_parent; - t_decl->p_Add(t_d); - } - } - } -} -void c_Makedocs::p__CompleteInherited(c_DocDecl* t_pFrom,c_DocDecl* t_pTo){ - if(!((t_pFrom->p_GetChild(499))!=0)){ - t_pFrom->p_Add((new c_DocDecl)->m_new(499,String())); - c_DocDeclStack* t_exts=t_pFrom->p_GetChilds2(401,false); - if((t_exts)!=0){ - c_Enumerator2* t_=t_exts->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_e=t_->p_NextObject(); - p__CompleteInherited(t_e,t_pFrom); - } - } - } - if((t_pFrom->m_childs)!=0){ - c_Enumerator2* t_2=t_pFrom->m_childs->p_ObjectEnumerator(); - while(t_2->p_HasNext()){ - c_DocDecl* t_c=t_2->p_NextObject(); - int t_kind=0; - int t_6=t_c->m_kind; - if(t_6==406){ - t_kind=456; - }else{ - if(t_6==403){ - t_kind=453; - }else{ - if(t_6==405){ - t_kind=455; - }else{ - if(t_6==410){ - t_kind=460; - }else{ - if(t_6==420){ - t_kind=470; - }else{ - if(t_6==422){ - t_kind=472; - }else{ - if(t_6==421){ - t_kind=471; - }else{ - if(t_6==423){ - t_kind=473; - } - } - } - } - } - } - } - } - if(((t_kind)!=0) && !((t_pTo->p_GetChild3(t_c->m_ident,t_c->m_kind))!=0)){ - c_DocDecl* t_decl=(new c_DocDecl)->m_new(t_kind,t_c->m_ident); - t_decl->m_target=t_c; - t_pTo->p_Add(t_decl); - } - } - } -} -void c_Makedocs::p__CompleteExtends(){ - c_DocDeclStack* t_exts=m_rootmodules->p_GetChilds2(401,true); - c_DocDeclStack* t_imps=m_rootmodules->p_GetChilds2(402,true); - if((t_exts)!=0){ - c_Enumerator2* t_=t_exts->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_e=t_->p_NextObject(); - c_DocDecl* t_decl=0; - t_decl=t_e->m_parent->m_parent->p_FindFromHere(t_e->m_ident,301); - if(!((t_decl)!=0)){ - t_decl=t_e->m_parent->m_parent->p_FindFromHere(t_e->m_ident,302); - } - if((t_decl)!=0){ - t_e->m_target=t_decl; - c_DocDecl* t_d=(new c_DocDecl)->m_new(701,t_e->m_parent->p_GetUniqueIdent()); - t_d->m_target=t_e->m_parent; - t_decl->p_Add(t_d); - p__CompleteInherited(t_decl,t_e->m_parent); - } - } - } - if((t_imps)!=0){ - c_Enumerator2* t_2=t_imps->p_ObjectEnumerator(); - while(t_2->p_HasNext()){ - c_DocDecl* t_i=t_2->p_NextObject(); - c_DocDecl* t_decl2=0; - t_decl2=t_i->m_parent->m_parent->p_FindFromHere(t_i->m_ident,302); - if((t_decl2)!=0){ - t_i->m_target=t_decl2; - c_DocDecl* t_d2=(new c_DocDecl)->m_new(702,t_i->m_parent->p_GetUniqueIdent()); - t_d2->m_target=t_i->m_parent; - t_decl2->p_Add(t_d2); - } - } - } -} -String c_Makedocs::p__SummaryFromDescription(String t_pDescription){ - Array t_lines=t_pDescription.Replace(String(L"\r",1),String(L"\n",1)).Split(String(L"\n",1)); - String t_summary=String(); - Array t_=t_lines; - int t_2=0; - while(t_2",1))){ - int t_i=0; - while(t_ip_GetChilds2(800,true); - c_DocDeclStack* t_contents=m_rootdecl->p_GetChilds2(805,true); - if(((t_descs)!=0) && ((t_contents)!=0)){ - t_descs->p_Push6(t_contents->p_ToArray(),0); - }else{ - if((t_contents)!=0){ - t_descs=t_contents; - } - } - if((t_descs)!=0){ - c_Enumerator2* t_=t_descs->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_d=t_->p_NextObject(); - String t_summary=p__SummaryFromDescription(t_d->m_ident); - if(t_summary.StartsWith(String(L"* ",2))){ - t_summary=t_summary.Slice(2); - } - if(t_summary.StartsWith(String(L"+ ",2))){ - t_summary=t_summary.Slice(2); - } - if(t_summary.StartsWith(String(L"| ",2))){ - t_summary=t_summary.Slice(2); - } - c_DocDecl* t_decl=(new c_DocDecl)->m_new(850,t_summary); - t_d->m_parent->p_Add(t_decl); - } - } -} -void c_Makedocs::p__CompleteExamples(){ - c_DocDeclStack* t_examples=m_rootmodules->p_GetChilds2(801,true); - if((t_examples)!=0){ - c_Enumerator2* t_=t_examples->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_ex=t_->p_NextObject(); - String t_str=t_ex->m_parent->p_GetUniqueIdent().Replace(String(L".",1),String(L"_",1)); - t_str=t_str+String(L".cxs",4); - t_ex->p_Add((new c_DocDecl)->m_new(222,t_str)); - } - } -} -void c_Makedocs::p_Complete(){ - m_rootdecl->p_PrepareFinder(); - p__AssignExamples(m_rootmodules); - p__CompleteIdentifiers(m_rootmodules,String(),String()); - p__CompleteImports(); - p__CompleteExtends(); - p__CompleteSummaries(); - p__CompleteExamples(); -} -void c_Makedocs::p__MoveToIndex(String t_pIndex,c_DocDeclStack* t_pStack){ - c_StringMap2* t_index=(new c_StringMap2)->m_new(); - if((t_pStack)!=0){ - c_Enumerator2* t_=t_pStack->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_d=t_->p_NextObject(); - String t_key=t_d->p_GetIdentWithParams(); - t_key=t_key+t_d->p_GetTextOfChild(201); - t_index->p_Add3(t_key.ToLower(),t_d); - } - } - m_indexes->p_Add4(t_pIndex,t_index); -} -void c_Makedocs::p__CreateIndex(String t_pIndex,c_DocDeclStack* t_pStack,String t_pSummary){ - c_DocDecl* t_decl=(new c_DocDecl)->m_new(903,t_pIndex); - String t_txt=t_pSummary; - if(!((t_txt).Length()!=0)){ - t_txt=t_pIndex; - } - t_decl->p_Add((new c_DocDecl)->m_new(850,t_txt)); - m_rootdocs->p_Add(t_decl); - p__MoveToIndex(t_pIndex,t_pStack); -} -void c_Makedocs::p__FillMasterIndex(c_DocDecl* t_pDecl,c_DocDeclStack* t_pStack){ - if((t_pDecl->m_childs)!=0){ - c_Enumerator2* t_=t_pDecl->m_childs->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_d=t_->p_NextObject(); - int t_7=t_d->m_kind; - if(t_7==902 || t_7==903 || t_7==901 || t_7==301 || t_7==302 || t_7==310 || t_7==320 || t_7==321 || t_7==403 || t_7==405 || t_7==406 || t_7==410 || t_7==420 || t_7==421 || t_7==423 || t_7==601){ - t_pStack->p_Push4(t_d); - p__FillMasterIndex(t_d,t_pStack); - }else{ - if(t_7==101 || t_7==102 || t_7==900 || t_7==322 || t_7==422){ - p__FillMasterIndex(t_d,t_pStack); - } - } - } - } -} -void c_Makedocs::p_CreateIndexes(){ - m_indexes=(new c_StringMap3)->m_new(); - c_DocDeclStack* t_idecls=m_rootdocs->p_GetChilds2(903,true); - if((t_idecls)!=0){ - c_Enumerator2* t_=t_idecls->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_idx=t_->p_NextObject(); - c_DocDeclStack* t_docs=t_idx->p_GetChilds2(902,false); - c_DocDeclStack* t_idxs=t_idx->p_GetChilds2(903,false); - if(((t_docs)!=0) && ((t_idxs)!=0)){ - t_docs->p_Push6(t_idxs->p_ToArray(),0); - }else{ - if((t_idxs)!=0){ - t_docs=t_idxs; - } - } - p__MoveToIndex(t_idx->p_GetUniqueIdent(),t_docs); - t_idx->p_Add((new c_DocDecl)->m_new(850,String(L"Index of ",9)+t_idx->p_GetIdent())); - } - } - c_DocDeclStack* t_modules=m_rootdecl->p_GetChilds2(901,true); - c_DocDeclStack* t_classes=m_rootdecl->p_GetChilds2(301,true); - c_DocDeclStack* t_interfaces=m_rootdecl->p_GetChilds2(302,true); - c_DocDeclStack* t_functions=m_rootdecl->p_GetChilds2(310,true); - p__CreateIndex(String(L"Modules",7),t_modules,String(L"All documented modules",22)); - p__CreateIndex(String(L"Classes",7),t_classes,String(L"All documented classes",22)); - p__CreateIndex(String(L"Interfaces",10),t_interfaces,String(L"All documented interfaces",25)); - p__CreateIndex(String(L"Functions",9),t_functions,String(L"All documented functions",24)); - c_DocDeclStack* t_master=(new c_DocDeclStack)->m_new(); - p__FillMasterIndex(m_rootdecl,t_master); - p__CreateIndex(String(L"Index",5),t_master,String(L"Everything",10)); -} -String c_Makedocs::p_BuildDocLink(c_DocDecl* t_pDecl,c_DocDecl* t_pScope){ - while((t_pScope)!=0){ - int t_9=t_pScope->m_kind; - if(t_9==301 || t_9==302 || t_9==901 || t_9==902 || t_9==903 || t_9==102 || t_9==101 || t_9==100){ - break; - } - t_pScope=t_pScope->m_parent; - } - String t_anchor=String(); - String t_document=String(); - c_DocDecl* t_bit=t_pDecl; - do{ - int t_10=t_bit->m_kind; - if(t_10==902 || t_10==903){ - c_DocDecl* t_pdecl2=t_bit->p_GetChild(201); - if((t_pdecl2)!=0){ - t_document=t_pdecl2->m_ident.Replace(String(L"/",1),String(L"_",1)); - } - t_document=t_document+t_bit->m_ident; - t_bit=m_rootdocs; - }else{ - if(t_10==901){ - t_document=t_bit->p_GetIdent()+t_document; - t_document=String(L"Modules_",8)+t_document; - t_bit=m_rootmodules; - }else{ - if(t_10==301 || t_10==302){ - t_document=String(L"_",1)+t_bit->m_ident+t_document; - }else{ - if(t_10==100 || t_10==101 || t_10==102){ - t_document=t_document+String(L".html",5); - break; - }else{ - if(t_10==322 || t_10==422 || t_10==472){ - }else{ - t_anchor=String(L"#",1)+t_bit->p_GetIdentWithParams(); - if(t_bit->m_parent==t_pScope){ - break; - } - } - } - } - } - } - t_bit=t_bit->m_parent; - }while(!(false)); - return t_document+t_anchor; -} -void c_Makedocs::p_WriteDeclFiles(){ - p_ClearErrInfo(); - m_curdecl=m_rootmodules; - c_DocDeclStack* t_alldecls=m_rootdecl->p_GetChilds2(0,true); - String t_txt=String(); - c_StringMap4* t_idx=(new c_StringMap4)->m_new(); - c_Enumerator2* t_=t_alldecls->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_d=t_->p_NextObject(); - int t_8=t_d->m_kind; - if(t_8==901 || t_8==301 || t_8==302 || t_8==310 || t_8==320 || t_8==321 || t_8==403 || t_8==405 || t_8==406 || t_8==410 || t_8==420 || t_8==421 || t_8==423 || t_8==601){ - if(!t_idx->p_Contains(t_d->m_ident)){ - t_idx->p_Add5(t_d->m_ident,p_BuildDocLink(t_d,0)); - }else{ - String t_str=String(L"Index.html#",11)+t_d->m_ident; - t_idx->p_Set2(t_d->m_ident,t_str); - } - }else{ - if(t_8==902){ - if(t_d->p_GetTextOfChild(201)==String(L"Programming/Keywords/",21)){ - t_idx->p_Add5(t_d->m_ident,p_BuildDocLink(t_d,0)); - } - } - } - } - c_NodeEnumerator* t_2=t_idx->p_ObjectEnumerator(); - while(t_2->p_HasNext()){ - c_Node5* t_d2=t_2->p_NextObject(); - t_txt=t_txt+(t_d2->p_Key()+String(L":",1)+t_d2->p_Value()+String(L"\n",1)); - } - SaveString(t_txt,String(L"docs/html/index.txt",19)); - t_txt=String(); - c_Enumerator2* t_3=t_alldecls->p_ObjectEnumerator(); - while(t_3->p_HasNext()){ - c_DocDecl* t_d3=t_3->p_NextObject(); - String t_ktxt=t_d3->p_GetKindName(); - if(t_ktxt!=String(L"Unspecified",11)){ - String t_str2=t_d3->p_GetScopeIdent()+t_d3->m_ident+t_d3->p_GetDocType(false).Replace(String(L" ",1),String()); - t_txt=t_txt+(t_ktxt+String(L" ",1)+t_str2); - t_txt=t_txt+(String(L";",1)+p_BuildDocLink(t_d3,0)); - t_txt=t_txt+String(L";",1); - t_txt=t_txt+String(L"\n",1); - } - } - SaveString(t_txt,String(L"docs/html/decls.txt",19)); -} -int c_Makedocs::m_resolvecode; -String c_Makedocs::p_ResolveDocLink(String t_pLink){ - if(!((t_pLink).Length()!=0)){ - m_resolvecode=-1; - p_Warning(String(L"empty link, please fix",22)); - return String(); - } - String t_link=t_pLink; - String t_anchor=String(); - if(t_link.Contains(String(L"#",1))){ - int t_p=t_link.Find(String(L"#",1),0); - t_anchor=t_link.Slice(t_p); - t_link=t_link.Slice(0,t_p); - } - c_DocDecl* t_dest=m_curdecl->p_FindFromHere(t_link,0); - if(!((t_dest)!=0)){ - t_dest=m_rootdecl->p_FindChild(t_link,0); - } - if((t_dest)!=0){ - m_resolvecode=0; - t_link=p_BuildDocLink(t_dest,m_curdecl); - }else{ - m_resolvecode=-1; - p_Warning(String(L"link destination not found: ",28)+t_link); - } - return t_link; -} -String c_Makedocs::p__ApplyPageTemplate(Array t_pLinkIdents,Array t_pLinkUrls,String t_pContents){ - m_pager->p_Clear(); - if((m_iconlinks_url).Length()!=0){ - m_pager->p_BeginList(String(L"ICONLINKS",9)); - for(int t_i=0;t_ip_AddItem(); - m_pager->p_SetString(String(L"URL",3),m_iconlinks_url[t_i]); - m_pager->p_SetString(String(L"ICON",4),m_iconlinks_icon[t_i]); - } - m_pager->p_EndList(); - } - if((t_pLinkIdents).Length()!=0){ - m_pager->p_BeginList(String(L"NAVLINKS",8)); - for(int t_i2=0;t_i2p_AddItem(); - m_pager->p_SetString(String(L"IDENT",5),t_pLinkIdents[t_i2]); - m_pager->p_SetString(String(L"URL",3),t_pLinkUrls[t_i2]); - } - m_pager->p_EndList(); - } - m_pager->p_SetString(String(L"CONTENT",7),t_pContents); - return m_pager->p_MakePage(); -} -void c_Makedocs::p__WritePage(String t_pFile,String t_pContents){ - if(!m_opt_printdocs && !m_opt_printtree){ - SaveString(t_pContents,String(L"docs/html/",10)+t_pFile); - }else{ - if(m_opt_printdocs){ - bbPrint(String(L">>> OUTPUT FOR FILE: ",21)+t_pFile); - bbPrint(t_pContents); - } - } -} -Array c_Makedocs::p__LinkUrlsFromIdents(Array t_pIdents){ - Array t_urls=Array(t_pIdents.Length()); - for(int t_i=0;t_im_new(m_template); - m_marker=(new c_Markdown)->m_new((this),(this)); - c_DocDeclStack* t_decls=m_rootdocs->p_GetChilds2(211,true); - p_ClearErrInfo(); - m_curdecl=m_rootdocs; - if((t_decls)!=0){ - int t_cnt=t_decls->p_Length2(); - m_iconlinks_url=Array(t_cnt); - m_iconlinks_icon=Array(t_cnt); - int t_i=0; - c_Enumerator2* t_=t_decls->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_d=t_->p_NextObject(); - m_iconlinks_url[t_i]=p_BuildDocLink(t_d->m_parent,0); - m_iconlinks_icon[t_i]=t_d->m_ident; - t_i+=1; - } - } - Array t_linkidents=Array(); - Array t_linkurls=Array(); - String t_page=String(); - String t_file=String(); - String t_content=String(); - String t_scopetemplate=LoadString(m_templatedir+String(L"/scope_template.html",20)); - c_PageMaker* t_scopepager=(new c_PageMaker)->m_new(t_scopetemplate); - c_DocDeclStack* t_modules=m_rootmodules->p_GetChilds2(901,true); - if((t_modules)!=0){ - c_Enumerator2* t_2=t_modules->p_ObjectEnumerator(); - while(t_2->p_HasNext()){ - c_DocDecl* t_m=t_2->p_NextObject(); - p_SetErrInfoFile(t_m->m_ident); - m_curdecl=t_m; - String t_3[]={String(L"Modules",7),t_m->p_GetIdent()}; - t_linkidents=Array(t_3,2); - String t_4[]={String(L"Modules.html",12),p_ResolveDocLink(t_m->m_ident)}; - t_linkurls=Array(t_4,2); - t_page=m_apidoccer->p_ApplyModuleTemplate(t_m,t_scopepager); - t_content=p__ApplyPageTemplate(t_linkidents,t_linkurls,t_page); - t_file=p_BuildDocLink(t_m,0); - p__WritePage(t_file,t_content); - if((t_m->m_childs)!=0){ - t_linkidents=t_linkidents.Resize(3); - t_linkurls=t_linkurls.Resize(3); - c_Enumerator2* t_5=t_m->m_childs->p_ObjectEnumerator(); - while(t_5->p_HasNext()){ - c_DocDecl* t_c=t_5->p_NextObject(); - if(t_c->m_kind==301 || t_c->m_kind==302){ - p_SetErrInfoFile(t_c->p_GetUniqueIdent()); - m_curdecl=t_c; - t_linkidents[2]=t_c->m_ident; - t_linkurls[2]=p_ResolveDocLink(t_c->p_GetUniqueIdent()); - t_page=m_apidoccer->p_ApplyClassTemplate(t_c,t_scopepager); - t_content=p__ApplyPageTemplate(t_linkidents,t_linkurls,t_page); - t_file=p_BuildDocLink(t_c,0); - p__WritePage(t_file,t_content); - } - } - } - } - } - c_DocDeclStack* t_docs=m_rootdocs->p_GetChilds2(902,true); - if((t_docs)!=0){ - c_Enumerator2* t_6=t_docs->p_ObjectEnumerator(); - while(t_6->p_HasNext()){ - c_DocDecl* t_d2=t_6->p_NextObject(); - p_SetErrInfoFile(t_d2->m_ident); - m_curdecl=t_d2; - if(t_d2->m_ident!=String(L"Home",4)){ - t_linkidents=t_d2->p_GetUniqueIdent().Split(String(L"/",1)); - t_linkurls=p__LinkUrlsFromIdents(t_linkidents); - }else{ - t_linkidents=Array(); - t_linkurls=Array(); - } - t_page=m_marker->p_ToHtml(t_d2->p_GetTextOfChild(805)); - t_content=p__ApplyPageTemplate(t_linkidents,t_linkurls,t_page); - t_file=p_BuildDocLink(t_d2,0); - p__WritePage(t_file,t_content); - } - } - String t_indextemplate=LoadString(m_templatedir+String(L"/index_template.html",20)); - c_PageMaker* t_indexpager=(new c_PageMaker)->m_new(t_indextemplate); - m_curdecl=m_rootdocs; - String t_txt=String(); - c_NodeEnumerator2* t_7=m_indexes->p_ObjectEnumerator(); - while(t_7->p_HasNext()){ - c_Node4* t_index=t_7->p_NextObject(); - p_SetErrInfoFile(t_index->p_Key()); - t_linkidents=t_index->p_Key().Split(String(L"/",1)); - t_linkurls=p__LinkUrlsFromIdents(t_linkidents); - String t_indexname=t_linkidents[t_linkidents.Length()-1]; - t_indexpager->p_Clear(); - t_indexpager->p_SetString(String(L"INDEX",5),t_indexname); - t_indexpager->p_BeginList(String(L"ITEMS",5)); - if((t_index->p_Value())!=0){ - c_NodeEnumerator3* t_8=t_index->p_Value()->p_ObjectEnumerator(); - while(t_8->p_HasNext()){ - c_Node3* t_item=t_8->p_NextObject(); - c_DocDecl* t_decl=t_item->p_Value(); - t_indexpager->p_AddItem(); - m_curdecl=t_decl; - m_apidoccer->p_SetPagerStrings(t_indexpager,t_decl,true); - } - } - t_indexpager->p_EndList(); - t_page=t_indexpager->p_MakePage(); - t_content=p__ApplyPageTemplate(t_linkidents,t_linkurls,t_page); - t_file=t_linkurls[t_linkurls.Length()-1]; - p__WritePage(t_file,t_content); - } -} -void c_Makedocs::p_WriteExamples(){ - if(m_opt_printdocs || m_opt_printtree){ - return; - } - p__AssertPath(String(L"docs/html/examples",18)); - c_DocDeclStack* t_examples=m_rootmodules->p_GetChilds2(801,true); - if((t_examples)!=0){ - c_Enumerator2* t_=t_examples->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_ex=t_->p_NextObject(); - String t_file=t_ex->p_GetTextOfChild(222); - String t_source=t_ex->m_ident; - int t_p0=t_source.Find(String(L"
",5),0);
-			int t_p1=t_source.Find(String(L"
",6),t_p0+5); - if(t_p0>=0 && t_p1>=0){ - t_source=t_source.Slice(t_p0+5,t_p1); - SaveString(t_source,String(L"docs/html/examples/",19)+t_file); - } - } - } -} -c_Makedocs* c_Makedocs::m_new(){ - bbPrint(String(L"Makedocs 2018-12-21",19)); - p_ParseAppArgs(); - p_BrowseToCxRoot(); - p_LoadTemplateName(); - p_LoadModulesPath(); - p_LoadDocPath(); - p_CleanUpEarly(); - p_CopyTemplateData(); - m_rootdecl=(new c_DocDecl)->m_new(100,String()); - m_rootmodules=(new c_DocDecl)->m_new(101,String()); - m_rootdocs=(new c_DocDecl)->m_new(102,String()); - m_rootdecl->p_Add(m_rootmodules); - m_rootdecl->p_Add(m_rootdocs); - m_branch3rdparty=(new c_DocDecl)->m_new(903,String(L"3rd Party Docs",14)); - m_branch3rdparty->p_Add((new c_DocDecl)->m_new(850,String(L"All 3rd Party Docs",18))); - m_rootdocs->p_Add(m_branch3rdparty); - bbPrint(String(L"parsing APIs...",15)); - m_apidoccer=(new c_ApiDoccer)->m_new(this); - m_apidoccer->p_Parse(); - bbPrint(String(L"parsing cerberusdocs...",23)); - m_docdoccer=(new c_DocDoccer)->m_new(this); - m_docdoccer->p_Doc(); - bbPrint(String(L"parsing 3rd party docs...",25)); - m_docdoccer->p_Doc3rdParty(); - bbPrint(String(L"completing decls...",19)); - p_Complete(); - p_CreateIndexes(); - m_rootdecl->p_Sort(); - bbPrint(String(L"writing decl files...",21)); - p_WriteDeclFiles(); - bbPrint(String(L"writing docs...",15)); - p_WriteDocs(); - bbPrint(String(L"writing examples...",19)); - p_WriteExamples(); - if(m_opt_printtree){ - bbPrint(m_rootdecl->p_ToString(0)); - } - bbPrint(String(L"done!",5)); - return this; -} -String c_Makedocs::p_ResolveLink(String t_pLink,String t_pAltText){ - if(t_pLink.StartsWith(String(L"",5))){ - String t_src=t_pLink.Slice(5); - String t_html=String(L"\"",6)+t_pAltText+String(L"\"",1));",3); - return t_html; - } - String t_link=t_pLink; - String t_alt=t_pAltText; - if(!((t_pAltText).Length()!=0)){ - t_alt=t_pLink; - } - if(t_pLink.StartsWith(String(L"http://",7)) || t_pLink.StartsWith(String(L"https://",8)) || t_pLink.StartsWith(String(L"#",1)) || t_pLink.StartsWith(String(L"../",3)) || t_pLink.StartsWith(String(L"./",2))){ - String t_html2=String(L"",2)+t_alt+String(L"",4); - return t_html2; - } - if(!((t_pAltText).Length()!=0)){ - int t_p=t_alt.FindLast(String(L"/",1)); - if(t_p>=0){ - t_alt=t_alt.Slice(t_p+1); - } - } - t_link=p_ResolveDocLink(t_link); - if(m_resolvecode<0){ - return String(L"",21)+t_alt+String(L"",4); - } - return String(L"",2)+t_alt+String(L"",4); -} -String c_Makedocs::p_BeginPrettyBlock(){ - m_blocks=(new c_IntStack)->m_new2(); - return String(L"
",20); -} -String c_Makedocs::p_EndPrettyBlock(){ - return String(L"
",6); -} -String c_Makedocs::p_PrettifyLine(String t_pText){ - c_Toker* t_toker=(new c_Toker)->m_new(String(L"docs",4),t_pText); - String t_css=String(L"d",1); - String t__css=String(); - String t_txt=String(); - String t_html=String(); - do{ - t_toker->p_NextToke(); - t_txt=t_toker->m__toke; - if(t_toker->m__tokeType==11 || t_toker->m__tokeType==0){ - break; - } - if(t_toker->m__toke==String(L"#",1)){ - t_toker->p_NextToke(); - if(t_toker->m__toke.ToLower()==String(L"rem",3)){ - t_css=String(L"r",1); - m_blocks->p_Push7(1); - }else{ - if(t_toker->m__toke.ToLower()==String(L"end",3)){ - if(m_blocks->p_Length2()>0){ - t_css=String(L"r",1); - m_blocks->p_Pop(); - }else{ - t_css=String(L"d",1); - } - }else{ - t_css=String(L"d",1); - } - } - t_txt=t_txt+t_toker->m__toke; - }else{ - if(m_blocks->p_Length2()>0){ - t_css=String(L"r",1); - }else{ - int t_11=t_toker->m__tokeType; - if(t_11==9){ - t_css=String(L"r",1); - if(t_txt.EndsWith(String(L"\n",1))){ - t_txt=t_txt.Slice(0,-1); - } - if(t_txt.EndsWith(String(L"\r\n",2))){ - t_txt=t_txt.Slice(0,-2); - } - if(t_txt.EndsWith(String(L"\r",1))){ - t_txt=t_txt.Slice(0,-1); - } - }else{ - if(t_11==3){ - t_css=String(L"k",1); - }else{ - if(t_11==2){ - t_css=String(L"i",1); - }else{ - if(t_11==4 || t_11==5 || t_11==6){ - t_css=String(L"l",1); - }else{ - if(t_11==8){ - t_css=String(L"d",1); - } - } - } - } - } - } - } - if(t_css!=t__css){ - if((t__css).Length()!=0){ - t_html=t_html+String(L"",7); - } - if((t_css).Length()!=0){ - t_html=t_html+(String(L"",2)); - } - } - t_html=t_html+bb_stringutil_HtmlEscape(t_txt); - t__css=t_css; - }while(!(false)); - if((t__css).Length()!=0){ - t_html=t_html+String(L"",7); - } - t_html=t_html+String(L"
",5); - return t_html; -} -void c_Makedocs::mark(){ - Object::mark(); -} -c_Stack::c_Stack(){ - m_data=Array(); - m_length=0; -} -c_Stack* c_Stack::m_new(){ - return this; -} -c_Stack* c_Stack::m_new2(Array t_data){ - this->m_data=t_data.Slice(0); - this->m_length=t_data.Length(); - return this; -} -void c_Stack::p_Push(String t_value){ - if(m_length==m_data.Length()){ - m_data=m_data.Resize(m_length*2+10); - } - m_data[m_length]=t_value; - m_length+=1; -} -void c_Stack::p_Push2(Array t_values,int t_offset,int t_count){ - for(int t_i=0;t_i t_values,int t_offset){ - p_Push2(t_values,t_offset,t_values.Length()-t_offset); -} -bool c_Stack::p_Equals(String t_lhs,String t_rhs){ - return t_lhs==t_rhs; -} -bool c_Stack::p_Contains(String t_value){ - for(int t_i=0;t_i c_Stack::p_ToArray(){ - Array t_t=Array(m_length); - for(int t_i=0;t_i t_data){ - c_Stack::m_new2(t_data); - return this; -} -c_StringStack* c_StringStack::m_new2(){ - c_Stack::m_new(); - return this; -} -String c_StringStack::p_Join(String t_separator){ - return t_separator.Join(p_ToArray()); -} -bool c_StringStack::p_Equals(String t_lhs,String t_rhs){ - return t_lhs==t_rhs; -} -void c_StringStack::mark(){ - c_Stack::mark(); -} -String bb_os_ExtractDir(String t_path){ - int t_i=t_path.FindLast(String(L"/",1)); - if(t_i==-1){ - t_i=t_path.FindLast(String(L"\\",1)); - } - if(t_i!=-1){ - return t_path.Slice(0,t_i); - } - return String(); -} -c_List::c_List(){ - m__head=((new c_HeadNode)->m_new()); -} -c_List* c_List::m_new(){ - return this; -} -c_Node* c_List::p_AddLast(String t_data){ - return (new c_Node)->m_new(m__head,m__head->m__pred,t_data); -} -c_List* c_List::m_new2(Array t_data){ - Array t_=t_data; - int t_2=0; - while(t_2m__succ==m__head; -} -String c_List::p_RemoveFirst(){ - String t_data=m__head->m__succ->m__data; - m__head->m__succ->p_Remove(); - return t_data; -} -bool c_List::p_Equals(String t_lhs,String t_rhs){ - return t_lhs==t_rhs; -} -c_Node* c_List::p_Find(String t_value,c_Node* t_start){ - while(t_start!=m__head){ - if(p_Equals(t_value,t_start->m__data)){ - return t_start; - } - t_start=t_start->m__succ; - } - return 0; -} -c_Node* c_List::p_Find2(String t_value){ - return p_Find(t_value,m__head->m__succ); -} -void c_List::p_RemoveFirst2(String t_value){ - c_Node* t_node=p_Find2(t_value); - if((t_node)!=0){ - t_node->p_Remove(); - } -} -int c_List::p_Count(){ - int t_n=0; - c_Node* t_node=m__head->m__succ; - while(t_node!=m__head){ - t_node=t_node->m__succ; - t_n+=1; - } - return t_n; -} -c_Enumerator* c_List::p_ObjectEnumerator(){ - return (new c_Enumerator)->m_new(this); -} -Array c_List::p_ToArray(){ - Array t_arr=Array(p_Count()); - int t_i=0; - c_Enumerator* t_=this->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - String t_t=t_->p_NextObject(); - t_arr[t_i]=t_t; - t_i+=1; - } - return t_arr; -} -void c_List::mark(){ - Object::mark(); -} -c_StringList::c_StringList(){ -} -c_StringList* c_StringList::m_new(Array t_data){ - c_List::m_new2(t_data); - return this; -} -c_StringList* c_StringList::m_new2(){ - c_List::m_new(); - return this; -} -bool c_StringList::p_Equals(String t_lhs,String t_rhs){ - return t_lhs==t_rhs; -} -void c_StringList::mark(){ - c_List::mark(); -} -c_Node::c_Node(){ - m__succ=0; - m__pred=0; - m__data=String(); -} -c_Node* c_Node::m_new(c_Node* t_succ,c_Node* t_pred,String t_data){ - m__succ=t_succ; - m__pred=t_pred; - m__succ->m__pred=this; - m__pred->m__succ=this; - m__data=t_data; - return this; -} -c_Node* c_Node::m_new2(){ - return this; -} -int c_Node::p_Remove(){ - m__succ->m__pred=m__pred; - m__pred->m__succ=m__succ; - return 0; -} -void c_Node::mark(){ - Object::mark(); -} -c_HeadNode::c_HeadNode(){ -} -c_HeadNode* c_HeadNode::m_new(){ - c_Node::m_new2(); - m__succ=(this); - m__pred=(this); - return this; -} -void c_HeadNode::mark(){ - c_Node::mark(); -} -c_Enumerator::c_Enumerator(){ - m__list=0; - m__curr=0; -} -c_Enumerator* c_Enumerator::m_new(c_List* t_list){ - m__list=t_list; - m__curr=t_list->m__head->m__succ; - return this; -} -c_Enumerator* c_Enumerator::m_new2(){ - return this; -} -bool c_Enumerator::p_HasNext(){ - while(m__curr->m__succ->m__pred!=m__curr){ - m__curr=m__curr->m__succ; - } - return m__curr!=m__list->m__head; -} -String c_Enumerator::p_NextObject(){ - String t_data=m__curr->m__data; - m__curr=m__curr->m__succ; - return t_data; -} -void c_Enumerator::mark(){ - Object::mark(); -} -Array bb_os_LoadDir(String t_path,bool t_recursive,bool t_hidden){ - c_StringList* t_dirs=(new c_StringList)->m_new2(); - c_StringList* t_files=(new c_StringList)->m_new2(); - t_dirs->p_AddLast(String()); - while(!t_dirs->p_IsEmpty()){ - String t_dir=t_dirs->p_RemoveFirst(); - Array t_=LoadDir(t_path+String(L"/",1)+t_dir); - int t_2=0; - while(t_2p_AddLast(t_f); - }else{ - if(t_1==2){ - if(t_recursive){ - t_dirs->p_AddLast(t_f); - }else{ - t_files->p_AddLast(t_f); - } - } - } - } - } - return t_files->p_ToArray(); -} -int bb_os_DeleteDir(String t_path,bool t_recursive){ - if(!t_recursive){ - return DeleteDir(t_path); - } - int t_4=FileType(t_path); - if(t_4==0){ - return 1; - }else{ - if(t_4==1){ - return 0; - } - } - Array t_=LoadDir(t_path); - int t_2=0; - while(t_2 t_files=LoadDir(t_srcpath); - int t_2=FileType(t_dstpath); - if(t_2==0){ - if(!((CreateDir(t_dstpath))!=0)){ - return 0; - } - }else{ - if(t_2==1){ - return 0; - } - } - Array t_=t_files; - int t_3=0; - while(t_3m_new(); - } - m_childs->p_Push4(t_pDecl); - t_pDecl->m_parent=this; -} -void c_DocDecl::p_Add2(c_Stack2* t_pDecls){ - c_Enumerator2* t_=t_pDecls->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_d=t_->p_NextObject(); - p_Add(t_d); - } -} -c_DocDecl* c_DocDecl::p_GetChild(int t_pKind){ - if((m_childs)!=0){ - c_Enumerator2* t_=m_childs->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_c=t_->p_NextObject(); - if(t_c->m_kind==t_pKind){ - return t_c; - } - } - } - return 0; -} -c_DocDecl* c_DocDecl::p_GetChild2(String t_pIdent){ - if((m_childs)!=0){ - c_Enumerator2* t_=m_childs->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_c=t_->p_NextObject(); - if(t_c->m_ident==t_pIdent){ - return t_c; - } - } - } - return 0; -} -c_DocDecl* c_DocDecl::p_GetChild3(String t_pIdent,int t_pKind){ - if((m_childs)!=0){ - c_Enumerator2* t_=m_childs->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_c=t_->p_NextObject(); - if(t_c->m_ident==t_pIdent && (t_pKind==0 || t_c->m_kind==t_pKind)){ - return t_c; - } - } - } - return 0; -} -c_DocDeclStack* c_DocDecl::p_GetChilds(String t_pIdent,bool t_pRecursive){ - if((m_childs)!=0){ - c_DocDeclStack* t_ret=(new c_DocDeclStack)->m_new(); - c_Enumerator2* t_=m_childs->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_c=t_->p_NextObject(); - if(t_c->m_ident==t_pIdent){ - t_ret->p_Push4(t_c); - } - if(t_pRecursive){ - c_DocDeclStack* t_cret=t_c->p_GetChilds(t_pIdent,true); - if((t_cret)!=0){ - t_ret->p_Push6(t_cret->p_ToArray(),0); - } - } - } - if((t_ret->p_Length2())!=0){ - return t_ret; - } - } - return 0; -} -c_DocDeclStack* c_DocDecl::p_GetChilds2(int t_pKind,bool t_pRecursive){ - if((m_childs)!=0){ - c_DocDeclStack* t_ret=(new c_DocDeclStack)->m_new(); - c_Enumerator2* t_=m_childs->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_c=t_->p_NextObject(); - if(t_pKind==0 || t_c->m_kind==t_pKind){ - t_ret->p_Push4(t_c); - } - if(t_pRecursive){ - c_DocDeclStack* t_cret=t_c->p_GetChilds2(t_pKind,true); - if((t_cret)!=0){ - t_ret->p_Push6(t_cret->p_ToArray(),0); - } - } - } - if((t_ret->p_Length2())!=0){ - return t_ret; - } - } - return 0; -} -c_DocDecl* c_DocDecl::p_GetScope(int t_pKind){ - c_DocDecl* t_decl=this; - while(t_decl->m_kind!=t_pKind){ - if((t_decl->m_parent)!=0){ - t_decl=t_decl->m_parent; - }else{ - return 0; - } - } - return t_decl; -} -c_DocDecl* c_DocDecl::m__root; -c_DocDecl* c_DocDecl::m__modroot; -c_DocDeclStack* c_DocDecl::m__modules; -c_DocDecl* c_DocDecl::m__docroot; -c_DocDeclStack* c_DocDecl::m__documents; -c_StringStack* c_DocDecl::m__primnames; -void c_DocDecl::p_PrepareFinder(){ - m__root=p_GetScope(100); - m__modroot=m__root->p_GetChild(101); - m__modules=m__modroot->p_GetChilds2(901,true); - m__docroot=m__root->p_GetChild(102); - m__documents=m__docroot->p_GetChilds2(902,true); - c_DocDeclStack* t_alsodocuments=m__docroot->p_GetChilds2(903,true); - if((t_alsodocuments)!=0){ - m__documents->p_Push6(t_alsodocuments->p_ToArray(),0); - } - String t_[]={String(L"Void",4),String(L"Bool",4),String(L"Int",3),String(L"Float",5),String(L"String",6)}; - m__primnames->p_Push3(Array(t_,5),0); -} -String c_DocDecl::p_GetType(bool t_pPutInLink,bool t_pMarkOptionals){ - String t_str=String(); - c_DocDecl* t_t=p_GetChild(500); - if((t_t)!=0){ - t_str=t_t->m_ident; - if(t_pPutInLink){ - c_DocDecl* t_gparam=0; - c_DocDecl* t_scope=p_GetScope(301); - if((t_scope)!=0){ - t_gparam=t_scope->p_GetChild3(t_str,400); - } - if(!((t_gparam)!=0)){ - t_str=String(L"[[",2)+t_str+String(L"]]",2); - } - } - t_str=t_str+t_t->p_GetType(t_pPutInLink,false); - } - c_DocDeclStack* t_args=p_GetChilds2(551,false); - if((t_args)!=0){ - String t_astr=String(); - c_Enumerator2* t_=t_args->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_a=t_->p_NextObject(); - if((t_astr).Length()!=0){ - t_astr=t_astr+String(L",",1); - } - t_astr=t_astr+(t_a->m_ident+t_a->p_GetType(t_pPutInLink,false)); - } - if(t_pPutInLink){ - t_str=t_str+(String(L"<",4)+t_astr+String(L">",4)); - }else{ - t_str=t_str+(String(L"<",1)+t_astr+String(L">",1)); - } - } - c_DocDecl* t_arr=p_GetChild(550); - while((t_arr)!=0){ - t_str=t_str+String(L"[]",2); - t_arr=t_arr->p_GetChild(550); - } - if(t_pMarkOptionals && ((t_t)!=0) && ((t_t->m_parent->p_GetChild(502))!=0)){ - t_str=String(L"[",1)+t_str+String(L"]",1); - } - return t_str; -} -String c_DocDecl::p_GetUniqueIdent(){ - String t__scope=String(); - String t__params=String(); - String t_str=String(); - if((m_childs)!=0){ - c_Enumerator2* t_=m_childs->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_c=t_->p_NextObject(); - if(t_c->m_kind==201){ - t__scope=t_c->m_ident; - if((t__params).Length()!=0){ - break; - } - }else{ - if(t_c->m_kind==202){ - t__params=t_c->m_ident; - if((t__scope).Length()!=0){ - break; - } - } - } - } - } - return t__scope+m_ident+t__params; -} -c_StringMap2* c_DocDecl::m__primlinks; -int c_DocDecl::m__searchid; -c_DocDecl* c_DocDecl::p__FindInHere(Array t_pIdentPath,int t_pLevel,String t_pParams,int t_pKind){ - if(t_pLevel==0){ - if(m__lastsid==m__searchid){ - return 0; - } - m__lastsid=m__searchid; - } - bool t_islastlevel=t_pLevel==t_pIdentPath.Length()-1; - String t__ident=t_pIdentPath[t_pLevel]; - if((m_childs)!=0){ - bool t_cbf=false; - c_Enumerator2* t_=m_childs->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_c=t_->p_NextObject(); - t_cbf=t_c->m_canbefound; - if(t_c->m_kind==900 && !t_islastlevel){ - t_cbf=true; - } - if(t_cbf){ - String t_cident=t_c->m_ident; - if(t_c->m_kind==901 || t_c->m_kind==900){ - int t_p0=t_cident.FindLast(String(L".",1)); - if(t_p0>=0){ - t_cident=t_cident.Slice(t_p0+1); - } - } - if(t_islastlevel){ - if(t_cident==t__ident && (t_pKind==0 || t_c->m_kind==t_pKind)){ - if((t_pParams).Length()!=0){ - c_DocDecl* t_p=t_c->p_GetChild(202); - if(!((t_p)!=0)){ - continue; - } - if(t_p->m_ident!=t_pParams){ - continue; - } - } - return t_c; - } - }else{ - if(t_cident==t__ident){ - return t_c->p__FindInHere(t_pIdentPath,t_pLevel+1,t_pParams,t_pKind); - } - } - } - } - } - return 0; -} -c_DocDecl* c_DocDecl::p__FoundDecl(c_DocDecl* t_pDecl,bool t_pAddToPrimLinks){ - if(t_pAddToPrimLinks){ - m__primlinks->p_Add3(t_pDecl->m_ident,t_pDecl); - } - return t_pDecl; -} -c_DocDecl* c_DocDecl::p_FindFromHere(String t_pIdent,int t_pKind){ - bool t_addtoprimlinks=false; - if(m__primnames->p_Contains(t_pIdent)){ - c_DocDecl* t_decl=m__primlinks->p_Get2(t_pIdent); - if((t_decl)!=0){ - return t_decl; - } - t_addtoprimlinks=true; - } - m__searchid+=1; - c_DocDecl* t_scope=0; - c_DocDecl* t_decl2=0; - c_DocDeclStack* t_decls=0; - Array t_idents=Array(); - String t_params=String(); - String t_docpathtomatch=String(); - if(t_pIdent.Contains(String(L"/",1))){ - t_idents=t_pIdent.Split(String(L"/",1)); - if(t_idents[0]==String()){ - t_idents=t_idents.Slice(1); - t_scope=m__docroot; - }else{ - t_scope=this; - } - }else{ - String t__ident=String(); - if(t_pIdent.Contains(String(L"(",1))){ - int t_p0=t_pIdent.Find(String(L"(",1),0); - t_params=t_pIdent.Slice(t_p0); - t__ident=t_pIdent.Slice(0,t_p0); - }else{ - t__ident=t_pIdent; - } - t_idents=t__ident.Split(String(L".",1)); - if(t_idents[0]==String()){ - t_idents=t_idents.Slice(1); - t_scope=m__modroot; - }else{ - t_scope=p_GetScope(301); - if(!((t_scope)!=0)){ - t_scope=p_GetScope(302); - } - if(!((t_scope)!=0)){ - t_scope=p_GetScope(901); - } - if(!((t_scope)!=0)){ - t_scope=m__modroot; - } - } - } - do{ - int t_4=t_scope->m_kind; - if(t_4==301 || t_4==302){ - t_decl2=t_scope->p__FindInHere(t_idents,0,t_params,t_pKind); - if((t_decl2)!=0){ - return p__FoundDecl(t_decl2,false); - } - t_decls=t_scope->p_GetChilds2(401,false); - if((t_decls)!=0){ - c_Enumerator2* t_=t_decls->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_d=t_->p_NextObject(); - if((t_d->m_target)!=0){ - t_decl2=t_d->m_target->p__FindInHere(t_idents,0,t_params,t_pKind); - if((t_decl2)!=0){ - return p__FoundDecl(t_decl2,false); - } - } - } - } - t_decls=t_scope->p_GetChilds2(402,false); - if((t_decls)!=0){ - c_Enumerator2* t_2=t_decls->p_ObjectEnumerator(); - while(t_2->p_HasNext()){ - c_DocDecl* t_d2=t_2->p_NextObject(); - if((t_d2->m_target)!=0){ - t_decl2=t_d2->m_target->p__FindInHere(t_idents,0,t_params,t_pKind); - if((t_decl2)!=0){ - return p__FoundDecl(t_decl2,false); - } - } - } - } - t_scope=t_scope->p_GetScope(901); - }else{ - if(t_4==901 || t_4==900){ - t_decl2=t_scope->p__FindInHere(t_idents,0,t_params,t_pKind); - if((t_decl2)!=0){ - return p__FoundDecl(t_decl2,false); - } - t_decls=t_scope->p_GetChilds2(300,false); - if((t_decls)!=0){ - c_Enumerator2* t_3=t_decls->p_ObjectEnumerator(); - while(t_3->p_HasNext()){ - c_DocDecl* t_d3=t_3->p_NextObject(); - if((t_d3->m_target)!=0){ - t_decl2=t_d3->m_target->p__FindInHere(t_idents,0,t_params,t_pKind); - if((t_decl2)!=0){ - return p__FoundDecl(t_decl2,false); - } - } - } - } - t_scope=t_scope->m_parent; - }else{ - if(t_4==101){ - t_decl2=t_scope->p__FindInHere(t_idents,0,t_params,t_pKind); - if((t_decl2)!=0){ - return p__FoundDecl(t_decl2,false); - } - t_decls=m__modules; - if((t_decls)!=0){ - c_Enumerator2* t_5=t_decls->p_ObjectEnumerator(); - while(t_5->p_HasNext()){ - c_DocDecl* t_d4=t_5->p_NextObject(); - t_decl2=t_d4->p__FindInHere(t_idents,0,t_params,t_pKind); - if((t_decl2)!=0){ - return p__FoundDecl(t_decl2,false); - } - } - } - t_scope=m__docroot; - }else{ - if(t_4==102){ - t_decl2=t_scope->p__FindInHere(t_idents,0,t_params,t_pKind); - if((t_decl2)!=0){ - return p__FoundDecl(t_decl2,t_addtoprimlinks); - } - t_decls=m__documents; - if((t_decls)!=0){ - c_Enumerator2* t_6=t_decls->p_ObjectEnumerator(); - while(t_6->p_HasNext()){ - c_DocDecl* t_d5=t_6->p_NextObject(); - t_decl2=t_d5->p__FindInHere(t_idents,0,t_params,t_pKind); - if((t_decl2)!=0){ - return p__FoundDecl(t_decl2,t_addtoprimlinks); - } - } - } - return 0; - }else{ - if(t_4==902 || t_4==903){ - t_decl2=t_scope->p__FindInHere(t_idents,0,t_params,t_pKind); - if((t_decl2)!=0){ - return p__FoundDecl(t_decl2,false); - } - t_scope=t_scope->m_parent; - }else{ - t_scope=m__docroot; - } - } - } - } - } - }while(!(false)); -} -String c_DocDecl::p_GetIdent(){ - return m_ident; -} -String c_DocDecl::p_GetIdentWithParams(){ - if((m_childs)!=0){ - c_Enumerator2* t_=m_childs->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_c=t_->p_NextObject(); - if(t_c->m_kind==202){ - return p_GetIdent()+t_c->m_ident; - } - } - } - return p_GetIdent(); -} -String c_DocDecl::p_GetTextOfChild(int t_pKind){ - c_DocDecl* t_d=p_GetChild(t_pKind); - if((t_d)!=0){ - return t_d->m_ident; - } - return String(); -} -void c_DocDecl::p_Sort(){ - if((m_childs)!=0){ - m_childs->p_Sort2(true); - } -} -String c_DocDecl::p_GetKindName(){ - int t_2=m_kind; - if(t_2==901){ - return String(L"Module",6); - }else{ - if(t_2==301){ - return String(L"Class",5); - }else{ - if(t_2==302){ - return String(L"Interface",9); - }else{ - if(t_2==310){ - return String(L"Function",8); - }else{ - if(t_2==320){ - return String(L"Const",5); - }else{ - if(t_2==321){ - return String(L"Global",6); - }else{ - if(t_2==403){ - return String(L"Method",6); - }else{ - if(t_2==405){ - return String(L"Property",8); - }else{ - if(t_2==406){ - return String(L"Method",6); - }else{ - if(t_2==410){ - return String(L"Function",8); - }else{ - if(t_2==420){ - return String(L"Const",5); - }else{ - if(t_2==421){ - return String(L"Global",6); - }else{ - if(t_2==423){ - return String(L"Field",5); - }else{ - if(t_2==453){ - return String(L"Inherited_method",16); - }else{ - if(t_2==455){ - return String(L"Inherited_property",18); - }else{ - if(t_2==456){ - return String(L"Inherited_method",16); - }else{ - if(t_2==460){ - return String(L"Inherited_function",18); - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - return String(L"Unspecified",11); -} -String c_DocDecl::p_GetScopeIdent(){ - return p_GetTextOfChild(201); -} -String c_DocDecl::p_GetDocType(bool t_pPutInLink){ - String t_str=p_GetType(t_pPutInLink,false); - if((t_str).Length()!=0){ - t_str=String(L" : ",3)+t_str; - } - c_DocDecl* t_decl=p_GetChild(502); - if((t_decl)!=0){ - if(!((t_str).Length()!=0) && m_kind!=601){ - t_str=String(L" := ",4)+t_decl->m_ident; - }else{ - t_str=t_str+(String(L" = ",3)+t_decl->m_ident); - } - } - c_DocDeclStack* t_decls=p_GetChilds2(600,false); - if((t_decls)!=0){ - t_str=t_str+String(L" ( ",3); - bool t_isfirst=true; - c_Enumerator2* t_=t_decls->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_d=t_->p_NextObject(); - if(!t_isfirst){ - t_str=t_str+String(L", ",2); - } - t_str=t_str+(t_d->m_ident+String(L":",1)); - t_str=t_str+t_d->p_GetType(t_pPutInLink,false); - c_DocDecl* t_decl2=t_d->p_GetChild(502); - if((t_decl2)!=0){ - t_str=t_str+(String(L"=",1)+t_decl2->m_ident); - } - t_isfirst=false; - } - t_str=t_str+String(L" )",2); - }else{ - int t_3=m_kind; - if(t_3==310 || t_3==403 || t_3==405 || t_3==406 || t_3==410 || t_3==453 || t_3==455 || t_3==456 || t_3==460){ - t_str=t_str+String(L" ()",3); - } - } - return t_str; -} -c_DocDecl* c_DocDecl::p__FindChild(String t_pIdent,String t_pParams,int t_pKind){ - if((m_childs)!=0){ - c_Enumerator2* t_=m_childs->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_c=t_->p_NextObject(); - if(t_c->m_canbefound){ - if(t_c->m_ident==t_pIdent && (t_pKind==0 || t_c->m_kind==t_pKind)){ - if((t_pParams).Length()!=0){ - c_DocDecl* t_p=t_c->p_GetChild(202); - if(((t_p)!=0) && t_p->m_ident==t_pParams){ - return t_c; - } - }else{ - return t_c; - } - } - if((t_c->m_childs)!=0){ - c_DocDecl* t_decl=t_c->p__FindChild(t_pIdent,t_pParams,t_pKind); - if((t_decl)!=0){ - return t_decl; - } - } - }else{ - if(t_c->m_kind==102 || t_c->m_kind==101){ - return t_c->p__FindChild(t_pIdent,t_pParams,t_pKind); - } - } - } - } - return 0; -} -c_DocDecl* c_DocDecl::p_FindChild(String t_pIdent,int t_pKind){ - String t__ident=String(); - String t_params=String(); - if(t_pIdent.Contains(String(L"(",1))){ - int t_p0=t_pIdent.Find(String(L"(",1),0); - t_params=t_pIdent.Slice(t_p0); - t__ident=t_pIdent.Slice(0,t_p0); - }else{ - t__ident=t_pIdent; - } - return p__FindChild(t__ident,t_params,t_pKind); -} -String c_DocDecl::p_GetGenType(){ - c_DocDeclStack* t_types=p_GetChilds2(400,false); - if((t_types)!=0){ - String t_str=String(); - c_Enumerator2* t_=t_types->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_t=t_->p_NextObject(); - if((t_str).Length()!=0){ - t_str=t_str+String(L",",1); - } - t_str=t_str+t_t->m_ident; - } - return String(L"<",1)+t_str+String(L">",1); - } - return String(); -} -String c_DocDecl::p_GetDocXType(){ - return p_GetDocType(true); -} -String c_DocDecl::p_GetTargetIdent(){ - if((m_target)!=0){ - return m_target->m_ident; - } - return m_ident; -} -String c_DocDecl::p_ToString(int t_pIndent){ - String t_indstr=String(); - for(int t_i=0;t_im_uid)).Slice(-6); - t_indstr=t_indstr+(String(L" (Targeting ",12)+String(m_target->m_kind)+String(L".",1)+t_uidstr2+String(L")",1)); - } - t_indstr=t_indstr+String(L"\n",1); - if((m_childs)!=0){ - c_Enumerator2* t_=m_childs->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_d=t_->p_NextObject(); - t_indstr=t_indstr+t_d->p_ToString(t_pIndent+1); - } - } - return t_indstr; -} -void c_DocDecl::mark(){ - Object::mark(); -} -c_Stack2::c_Stack2(){ - m_data=Array(); - m_length=0; -} -c_Stack2* c_Stack2::m_new(){ - return this; -} -c_Stack2* c_Stack2::m_new2(Array t_data){ - this->m_data=t_data.Slice(0); - this->m_length=t_data.Length(); - return this; -} -void c_Stack2::p_Push4(c_DocDecl* t_value){ - if(m_length==m_data.Length()){ - m_data=m_data.Resize(m_length*2+10); - } - m_data[m_length]=t_value; - m_length+=1; -} -void c_Stack2::p_Push5(Array t_values,int t_offset,int t_count){ - for(int t_i=0;t_i t_values,int t_offset){ - p_Push5(t_values,t_offset,t_values.Length()-t_offset); -} -c_Enumerator2* c_Stack2::p_ObjectEnumerator(){ - return (new c_Enumerator2)->m_new(this); -} -c_DocDecl* c_Stack2::m_NIL; -void c_Stack2::p_Length(int t_newlength){ - if(t_newlengthm_data.Length()){ - m_data=m_data.Resize(bb_math_Max(m_length*2+10,t_newlength)); - } - } - m_length=t_newlength; -} -int c_Stack2::p_Length2(){ - return m_length; -} -Array c_Stack2::p_ToArray(){ - Array t_t=Array(m_length); - for(int t_i=0;t_it_y){ - break; - } - if(t_xt_y)); - p__Sort(t_lo,t_y,t_ascending); - p__Sort(t_x,t_hi,t_ascending); -} -void c_Stack2::p_Sort2(bool t_ascending){ - if(!((m_length)!=0)){ - return; - } - int t_t=1; - if(!t_ascending){ - t_t=-1; - } - p__Sort(0,m_length-1,t_t); -} -void c_Stack2::mark(){ - Object::mark(); -} -c_DocDeclStack::c_DocDeclStack(){ -} -c_DocDeclStack* c_DocDeclStack::m_new(){ - c_Stack2::m_new(); - return this; -} -void c_DocDeclStack::p_Sort2(bool t_pAsc){ - c_Stack2::p_Sort2(t_pAsc); - c_Enumerator2* t_=this->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_d=t_->p_NextObject(); - t_d->p_Sort(); - } -} -int c_DocDeclStack::p_Compare(c_DocDecl* t_pLhs,c_DocDecl* t_pRhs){ - if(t_pLhs->m_kind<900 || t_pRhs->m_kind<900){ - if(t_pLhs->m_kindm_kind){ - return -1; - } - if(t_pLhs->m_kind>t_pRhs->m_kind){ - return 1; - } - } - int t_5=t_pLhs->m_kind; - if(t_5==400 || t_5==551 || t_5==600 || t_5==800 || t_5==801 || t_5==803 || t_5==804 || t_5==322 || t_5==422 || t_5==601){ - return t_pLhs->m_uid-t_pRhs->m_uid; - } - c_DocDecl* t_lhs=t_pLhs; - c_DocDecl* t_rhs=t_pRhs; - if((t_lhs->m_target)!=0){ - t_lhs=t_lhs->m_target; - } - if((t_rhs->m_target)!=0){ - t_rhs=t_rhs->m_target; - } - int t_c=t_lhs->m_ident.ToLower().Compare(t_rhs->m_ident.ToLower()); - if(t_c!=0){ - return t_c; - } - String t_lident=t_lhs->p_GetIdentWithParams(); - String t_rident=t_rhs->p_GetIdentWithParams(); - return t_lident.Compare(t_rident); -} -void c_DocDeclStack::mark(){ - c_Stack2::mark(); -} -c_Enumerator2::c_Enumerator2(){ - m_stack=0; - m_index=0; -} -c_Enumerator2* c_Enumerator2::m_new(c_Stack2* t_stack){ - this->m_stack=t_stack; - return this; -} -c_Enumerator2* c_Enumerator2::m_new2(){ - return this; -} -bool c_Enumerator2::p_HasNext(){ - return m_indexp_Length2(); -} -c_DocDecl* c_Enumerator2::p_NextObject(){ - m_index+=1; - return m_stack->m_data[m_index-1]; -} -void c_Enumerator2::mark(){ - Object::mark(); -} -int bb_math_Max(int t_x,int t_y){ - if(t_x>t_y){ - return t_x; - } - return t_y; -} -Float bb_math_Max2(Float t_x,Float t_y){ - if(t_x>t_y){ - return t_x; - } - return t_y; -} -c_ApiDoccer::c_ApiDoccer(){ - m_maker=0; - m_cursect=0; - m_curparagraph=0; - m_parser=0; -} -c_ApiDoccer* c_ApiDoccer::m_new(c_Makedocs* t_pMakedocs){ - m_maker=t_pMakedocs; - return this; -} -c_ApiDoccer* c_ApiDoccer::m_new2(){ - return this; -} -void c_ApiDoccer::p_LoadExamples(String t_pDirectory,c_DocDecl* t_pScope){ - Array t_=LoadDir(t_pDirectory); - int t_2=0; - while(t_2m_new(220,t_name.Slice(0,-8)); - t_decl->p_Add((new c_DocDecl)->m_new(221,t_source)); - t_pScope->p_Add(t_decl); - } - } -} -void c_ApiDoccer::p_AppendDocContents(c_DocDecl* t_pDecl,String t_pString){ - if(t_pString.StartsWith(String(L"Example:",8))){ - m_cursect=801; - m_curparagraph=0; - t_pString=t_pString.Slice(8); - }else{ - if(t_pString.StartsWith(String(L"Links:",6))){ - m_cursect=802; - m_curparagraph=0; - t_pString=t_pString.Slice(6); - }else{ - if(t_pString.StartsWith(String(L"Parameters:",11))){ - m_cursect=803; - m_curparagraph=0; - t_pString=t_pString.Slice(11); - }else{ - if(t_pString.StartsWith(String(L"Returns:",8))){ - m_cursect=804; - m_curparagraph=0; - t_pString=t_pString.Slice(8); - } - } - } - } - if(((t_pString.Trim()).Length()!=0) && !((m_curparagraph)!=0)){ - m_curparagraph=(new c_DocDecl)->m_new(m_cursect,String()); - t_pDecl->p_Add(m_curparagraph); - } - if((m_curparagraph)!=0){ - m_curparagraph->m_ident=m_curparagraph->m_ident+bb_stringutil_UnifyLineEndings(t_pString); - } -} -void c_ApiDoccer::p_Error(String t_pMessage){ - m_maker->p_SetErrInfoLine(m_parser->p_GetCarretLine()); - m_maker->p_SetErrInfoChar(m_parser->p_GetCarretChar()); - m_maker->p_Error(t_pMessage); - m_maker->p_ClearErrInfo(); -} -void c_ApiDoccer::p_ParseDocFile(String t_pPath,c_DocDecl* t_pScope,String t_pModulePath){ - m_maker->p_SetErrInfoFile(t_pPath); - int t_p0=t_pModulePath.FindLast(String(L".",1)); - String t_path=String(); - String t_ident=String(); - if((t_p0)!=0){ - t_path=t_pModulePath.Slice(0,t_p0+1); - t_ident=t_pModulePath.Slice(t_p0+1); - }else{ - t_ident=t_pModulePath; - } - c_DocDecl* t_mdecl=(new c_DocDecl)->m_new(901,t_pModulePath); - c_DocDecl* t_curdecl=t_mdecl; - m_cursect=800; - m_curparagraph=0; - try{ - String t_source=LoadString(t_pPath); - m_parser=(new c_Parser)->m_new(t_source); - m_parser->m__tokePos=0; - while(!(m_parser->m__tokeType==0)){ - c_Toker* t_state=m_parser->p_Store(); - m_parser->p_NextSpace(); - if((m_parser->p_NextCdata(String(L"# ",2))).Length()!=0){ - m_parser->p_NextToke(); - t_curdecl=m_parser->p_ParseDecl(t_curdecl); - m_parser->p_NextRestOfLine(); - m_cursect=800; - m_curparagraph=0; - }else{ - if((m_parser->p_NextCdata(String(L"'# ",3))).Length()!=0){ - m_parser->p_NextRestOfLine(); - }else{ - m_parser->p_Restore(t_state); - String t_str=m_parser->p_NextRestOfLine(); - p_AppendDocContents(t_curdecl,t_str); - } - } - } - if((t_mdecl->p_GetChild(200))!=0){ - t_mdecl->m_canbefound=true; - t_pScope->p_Add(t_mdecl); - }else{ - m_maker->p_SetErrInfoLine(0); - m_maker->p_SetErrInfoChar(0); - m_maker->p_Error(String(L"Module header not found",23)); - } - }catch(c_ThrowableString* t_message){ - p_Error(t_message->p_ToString2()); - } -} -void c_ApiDoccer::p_CopyDocsData(String t_pPath,String t_pModulePath){ - String t_path=bb_os_StripExt(t_pPath)+String(L".data",5); - if(FileType(t_path)==2){ - String t_dst=String(L"docs/html/data/",15)+t_pModulePath.Replace(String(L".",1),String(L"/",1)); - m_maker->p_CopyDir(t_path,t_dst,true); - } -} -void c_ApiDoccer::p_ParseSourceFile(String t_pPath,c_DocDecl* t_pScope,String t_pModulePath){ - m_maker->p_SetErrInfoFile(t_pPath); - int t_p0=t_pModulePath.FindLast(String(L".",1)); - String t_path=String(); - String t_ident=String(); - if((t_p0)!=0){ - t_path=t_pModulePath.Slice(0,t_p0+1); - t_ident=t_pModulePath.Slice(t_p0+1); - }else{ - t_ident=t_pModulePath; - } - c_DocDecl* t_mdecl=0; - c_DocDecl* t_doccdecl=0; - c_DocDecl* t_curdecl=0; - m_cursect=800; - m_curparagraph=0; - try{ - int t_docswitch=0; - c_IntStack* t_docblocks=(new c_IntStack)->m_new2(); - bool t_inrem=false; - bool t_indoc=false; - String t_source=LoadString(t_pPath); - m_parser=(new c_Parser)->m_new(t_source); - m_parser->m__tokePos=0; - while(!(m_parser->m__tokeType==0)){ - t_inrem=false; - t_indoc=false; - c_BackwardsEnumerator* t_=t_docblocks->p_Backwards()->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - int t_b=t_->p_NextObject(); - if(t_b==0){ - t_indoc=true; - break; - }else{ - if(t_b==1){ - t_inrem=true; - break; - } - } - } - c_Toker* t_state=m_parser->p_Store(); - m_parser->p_NextSpace(); - if((m_parser->p_NextCdata(String(L"#Rem",4))).Length()!=0){ - m_parser->p_NextToke(); - bool t_doanalyse=!(t_indoc || t_inrem); - if(t_doanalyse && m_parser->p_PopToken(String(L"cerberusdoc",11),false)){ - t_docblocks->p_Push7(0); - m_cursect=800; - m_curparagraph=0; - if(m_parser->p_PopUntilKeyword(String(L"module",6),false)){ - t_mdecl=(new c_DocDecl)->m_new(901,t_pModulePath); - if((t_path).Length()!=0){ - } - m_parser->p_ParseDecl(t_mdecl); - t_docswitch=1; - t_doccdecl=t_mdecl; - t_curdecl=t_mdecl; - }else{ - if(m_parser->p_PopToken(String(L"off",3),false)){ - t_docswitch=0; - t_docblocks->p_Pop(); - t_docblocks->p_Push7(1); - }else{ - if(m_parser->p_PopToken(String(L"on",2),false)){ - t_docswitch=1; - t_doccdecl=(new c_DocDecl)->m_new(901,String()); - m_curparagraph=0; - }else{ - t_doccdecl=(new c_DocDecl)->m_new(901,String()); - m_curparagraph=0; - } - } - } - m_parser->p_NextRestOfLine(); - }else{ - if(t_indoc){ - m_parser->p_Restore(t_state); - String t_str=m_parser->p_NextRestOfLine(); - p_AppendDocContents(t_doccdecl,t_str); - t_docblocks->p_Push7(0); - }else{ - m_parser->p_NextRestOfLine(); - t_docblocks->p_Push7(1); - } - } - }else{ - if((m_parser->p_NextCdata(String(L"#If",3))).Length()!=0){ - if(t_indoc){ - m_parser->p_Restore(t_state); - String t_str2=m_parser->p_NextRestOfLine(); - p_AppendDocContents(t_doccdecl,t_str2); - t_docblocks->p_Push7(0); - }else{ - m_parser->p_NextRestOfLine(); - t_docblocks->p_Push7(2); - } - }else{ - if((m_parser->p_NextCdata(String(L"#End",4))).Length()!=0){ - t_docblocks->p_Pop(); - if(t_docblocks->p_Length2()>0 && t_docblocks->p_Get(0)==0){ - m_parser->p_Restore(t_state); - String t_str3=m_parser->p_NextRestOfLine(); - p_AppendDocContents(t_doccdecl,t_str3); - } - }else{ - if((t_docswitch)!=0){ - if(t_indoc){ - m_parser->p_Restore(t_state); - String t_str4=m_parser->p_NextRestOfLine(); - p_AppendDocContents(t_doccdecl,t_str4); - }else{ - if(!(t_indoc || t_inrem)){ - m_parser->p_NextToke(); - m_parser->p_PopSpace(false); - c_DocDecl* t_decl=m_parser->p_ParseDecl(t_curdecl); - m_parser->p_NextRestOfLine(); - if((t_decl)!=0){ - t_curdecl=t_decl; - if(((t_curdecl)!=0) && ((t_doccdecl)!=0) && t_doccdecl!=t_mdecl && ((t_doccdecl->m_childs)!=0)){ - c_Enumerator2* t_2=t_doccdecl->m_childs->p_ObjectEnumerator(); - while(t_2->p_HasNext()){ - c_DocDecl* t_d=t_2->p_NextObject(); - t_curdecl->p_Add(t_d); - } - t_doccdecl=0; - } - } - }else{ - m_parser->p_NextRestOfLine(); - } - } - }else{ - m_parser->p_NextRestOfLine(); - if(!((t_mdecl)!=0) && m_parser->p_GetCarretLine()>5){ - return; - } - } - } - } - } - } - if((t_mdecl)!=0){ - t_pScope->p_Add(t_mdecl); - } - }catch(c_ThrowableString* t_message){ - p_Error(t_message->p_ToString2()); - } -} -void c_ApiDoccer::p_ParseIn(String t_pDirectory,c_DocDecl* t_pScope,String t_pModulePath){ - Array t_=bb_os_LoadDir(t_pDirectory,false,false); - int t_2=0; - while(t_2m_new(210,t_path); - m_maker->m_branch3rdparty->p_Add(t_decl); - }else{ - if(t_file==String(L"examples",8)){ - p_LoadExamples(t_path,t_pScope); - }else{ - if(t_file==String(L"cerberusdoc",11)){ - String t_expath=t_path+String(L"/examples",9); - if(FileType(t_expath)==2){ - p_LoadExamples(t_expath,t_pScope); - } - }else{ - if(!t_file.Contains(String(L".",1))){ - if((t_modpath).Length()!=0){ - t_modpath=t_modpath+String(L".",1)+t_file; - }else{ - t_modpath=t_file; - } - if(!m_maker->m_ignoremods->p_Contains(t_modpath)){ - c_DocDecl* t_decl2=t_pScope->p_GetChild2(t_file); - bool t_newscope=false; - if(!((t_decl2)!=0)){ - t_decl2=(new c_DocDecl)->m_new(900,t_modpath); - t_newscope=true; - t_decl2->m_parent=t_pScope; - } - p_ParseIn(t_path,t_decl2,t_modpath); - if(t_newscope && (((t_decl2->p_GetChilds2(901,true))!=0) || ((t_decl2->p_GetChild(200))!=0))){ - t_pScope->p_Add(t_decl2); - } - } - } - } - } - } - }else{ - if(t_1==1){ - String t_name=bb_os_StripExt(t_file); - String t_ext=bb_os_ExtractExt(t_file); - String t_docdir=String(); - String t_docext=String(); - if(t_ext==String(L"cxs",3)){ - t_docdir=String(L"cerberusdoc/",12); - t_docext=String(L".cerberusdoc",12); - }else{ - if(t_ext==String(L"monkey",6)){ - t_docdir=String(L"monkeydoc/",10); - t_docext=String(L".monkeydoc",10); - } - } - if((t_docext).Length()!=0){ - c_DocDecl* t_tmpscope=0; - c_DocDeclStack* t_scopechilds=0; - if(t_name==bb_os_StripDir(t_pDirectory)){ - t_tmpscope=(new c_DocDecl)->m_new(901,String()); - }else{ - t_tmpscope=t_pScope; - t_modpath=t_modpath+String(L".",1)+t_name; - c_DocDecl* t_decl3=t_pScope->p_GetChild3(t_modpath,900); - if((t_decl3)!=0){ - t_pScope->m_childs->p_RemoveEach(t_decl3); - t_scopechilds=t_decl3->m_childs; - } - } - if(!m_maker->m_ignoremods->p_Contains(t_modpath)){ - String t_dir=t_pDirectory+String(L"/",1); - String t_p1=t_dir+t_name+t_docext; - String t_p2=t_dir+t_docdir+t_name+t_docext; - if(FileType(t_p1)==1){ - p_ParseDocFile(t_p1,t_tmpscope,t_modpath); - }else{ - if((FileType(t_p2))!=0){ - p_ParseDocFile(t_p2,t_tmpscope,t_modpath); - p_CopyDocsData(t_p2,t_modpath); - }else{ - p_ParseSourceFile(t_path,t_tmpscope,t_modpath); - } - } - if((t_scopechilds)!=0){ - c_DocDecl* t_mdecl=t_tmpscope->p_GetChild3(t_name,901); - if((t_mdecl)!=0){ - c_Enumerator2* t_3=t_scopechilds->p_ObjectEnumerator(); - while(t_3->p_HasNext()){ - c_DocDecl* t_c=t_3->p_NextObject(); - t_mdecl->p_Add(t_c); - } - } - } - if(t_name==bb_os_StripDir(t_pDirectory)){ - c_DocDecl* t_mdecl2=t_tmpscope->p_GetChild(901); - if(((t_mdecl2)!=0) && ((t_mdecl2->m_childs)!=0)){ - c_Enumerator2* t_4=t_mdecl2->m_childs->p_ObjectEnumerator(); - while(t_4->p_HasNext()){ - c_DocDecl* t_c2=t_4->p_NextObject(); - t_pScope->p_Add(t_c2); - } - t_pScope->m_kind=901; - t_pScope->m_canbefound=true; - } - } - } - } - } - } - } -} -void c_ApiDoccer::p_Parse(){ - Array t_=m_maker->m_modpaths.Split(String(L";",1)); - int t_2=0; - while(t_2m_rootmodules,String()); - } - } -} -String c_ApiDoccer::p_StripParagraph(String t_pText){ - if(t_pText.StartsWith(String(L"

",3)) && t_pText.EndsWith(String(L"

",4))){ - t_pText=t_pText.Slice(3,-4); - } - while(((t_pText).Length()!=0) && ((int)t_pText[0]==10 || (int)t_pText[0]==13)){ - t_pText=t_pText.Slice(1); - } - while(((t_pText).Length()!=0) && ((int)t_pText[t_pText.Length()-1]==10 || (int)t_pText[t_pText.Length()-1]==13)){ - t_pText=t_pText.Slice(0,-1); - } - return t_pText; -} -void c_ApiDoccer::p_SetPagerStrings(c_PageMaker* t_pPager,c_DocDecl* t_pDecl,bool t_pOnlyForIndex){ - c_DocDecl* t_tdecl=0; - if((t_pDecl->m_target)!=0){ - t_tdecl=t_pDecl->m_target; - }else{ - t_tdecl=t_pDecl; - } - String t_txt=String(); - t_pPager->p_SetString(String(L"IDENT",5),t_tdecl->p_GetIdent()); - t_pPager->p_SetString(String(L"URL",3),m_maker->p_BuildDocLink(t_tdecl,0)); - t_pPager->p_SetString(String(L"SCOPE",5),t_tdecl->p_GetScopeIdent()); - t_txt=t_tdecl->p_GetTextOfChild(850); - t_txt=p_StripParagraph(m_maker->m_marker->p_ToHtml(t_txt)); - t_pPager->p_SetString(String(L"SUMMARY",7),t_txt); - if(t_pOnlyForIndex){ - return; - } - t_txt=t_pDecl->p_GetKindName(); - t_pPager->p_SetString(String(L"KIND",4),t_txt); - t_pPager->p_SetString(String(L"UIDENT",6),t_tdecl->p_GetIdentWithParams()); - t_txt=t_tdecl->p_GetTextOfChild(202); - t_pPager->p_SetString(String(L"PARAMTYPES",10),t_txt); - if(t_pDecl->m_kind==401){ - t_txt=bb_stringutil_HtmlEscape(t_pDecl->p_GetDocType(false)); - t_pPager->p_SetString(String(L"DECL",4),t_txt); - t_pPager->p_SetString(String(L"XDECL",5),t_txt); - t_pPager->p_SetString(String(L"TYPE",4),t_txt); - t_pPager->p_SetString(String(L"XTYPE",5),t_txt); - }else{ - if(t_tdecl->m_kind==301){ - t_txt=bb_stringutil_HtmlEscape(t_tdecl->p_GetGenType()); - t_pPager->p_SetString(String(L"DECL",4),t_txt); - t_pPager->p_SetString(String(L"XDECL",5),t_txt); - t_pPager->p_SetString(String(L"TYPE",4),t_txt); - t_pPager->p_SetString(String(L"XTYPE",5),t_txt); - }else{ - String t_xtxt=String(); - t_txt=bb_stringutil_HtmlEscape(t_tdecl->p_GetDocType(false)); - t_xtxt=p_StripParagraph(m_maker->m_marker->p_ToHtml(t_tdecl->p_GetDocXType())); - t_pPager->p_SetString(String(L"DECL",4),t_txt); - t_pPager->p_SetString(String(L"XDECL",5),t_xtxt); - t_txt=t_txt.Trim(); - if(t_txt.StartsWith(String(L":",1))){ - t_txt=t_txt.Slice(1).Trim(); - } - t_xtxt=t_xtxt.Trim(); - if(t_xtxt.StartsWith(String(L":",1))){ - t_xtxt=t_xtxt.Slice(1).Trim(); - } - t_pPager->p_SetString(String(L"TYPE",4),t_txt); - t_pPager->p_SetString(String(L"XTYPE",5),t_txt); - } - } - if(t_tdecl->m_kind==601){ - t_tdecl=t_tdecl->m_parent; - } - t_txt=t_tdecl->p_GetTextOfChild(800); - t_pPager->p_SetString(String(L"DESCRIPTION",11),m_maker->m_marker->p_ToHtml(t_txt)); - t_txt=t_tdecl->p_GetTextOfChild(802); - t_pPager->p_SetString(String(L"LINKS",5),m_maker->m_marker->p_ToHtml(t_txt)); - t_txt=t_tdecl->p_GetTextOfChild(801); - t_pPager->p_SetString(String(L"EXAMPLE",7),m_maker->m_marker->p_ToHtml(t_txt)); - t_txt=t_tdecl->p_GetTextOfChild(803); - t_pPager->p_SetString(String(L"PARAMETERS",10),m_maker->m_marker->p_ToHtml(t_txt)); - t_txt=t_tdecl->p_GetTextOfChild(804); - t_pPager->p_SetString(String(L"RETURNS",7),m_maker->m_marker->p_ToHtml(t_txt)); - c_DocDecl* t_ex=t_tdecl->p_GetChild(801); - if((t_ex)!=0){ - t_txt=String(L"examples/",9)+t_ex->p_GetTextOfChild(222); - }else{ - t_txt=String(); - } - t_pPager->p_SetString(String(L"EXAMPLE_URL",11),t_txt); - c_DocDeclStack* t_decls=0; - t_decls=t_pDecl->p_GetChilds2(401,false); - t_txt=String(); - if((t_decls)!=0){ - c_Enumerator2* t_=t_decls->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_d=t_->p_NextObject(); - if((t_txt).Length()!=0){ - t_txt=t_txt+String(L", ",2); - } - t_txt=t_txt+(String(L"[[",2)+t_d->p_GetTargetIdent()+String(L"]]",2)+bb_stringutil_HtmlEscape(t_d->p_GetType(false,true))); - } - } - t_pPager->p_SetString(String(L"XEXTENDS",8),m_maker->m_marker->p_ToHtml(t_txt)); - t_decls=t_pDecl->p_GetChilds2(402,false); - t_txt=String(); - if((t_decls)!=0){ - c_Enumerator2* t_2=t_decls->p_ObjectEnumerator(); - while(t_2->p_HasNext()){ - c_DocDecl* t_d2=t_2->p_NextObject(); - if((t_txt).Length()!=0){ - t_txt=t_txt+String(L", ",2); - } - t_txt=t_txt+(String(L"[[",2)+t_d2->p_GetTargetIdent()+String(L"]]",2)); - } - } - t_pPager->p_SetString(String(L"XIMPLEMENTS",11),m_maker->m_marker->p_ToHtml(t_txt)); - t_decls=t_pDecl->p_GetChilds2(701,false); - t_txt=String(); - if((t_decls)!=0){ - c_Enumerator2* t_3=t_decls->p_ObjectEnumerator(); - while(t_3->p_HasNext()){ - c_DocDecl* t_d3=t_3->p_NextObject(); - if((t_txt).Length()!=0){ - t_txt=t_txt+String(L", ",2); - } - t_txt=t_txt+(String(L"[[",2)+t_d3->m_target->m_ident+String(L"]]",2)+bb_stringutil_HtmlEscape(t_d3->p_GetType(false,true))); - } - } - t_pPager->p_SetString(String(L"XEXTENDED_BY",12),m_maker->m_marker->p_ToHtml(t_txt)); -} -void c_ApiDoccer::p_SetPagerList(c_PageMaker* t_pPager,c_DocDecl* t_pDecl,int t_pKind,String t_pList){ - c_DocDeclStack* t_decls=t_pDecl->p_GetChilds2(t_pKind,false); - if((t_decls)!=0){ - t_pPager->p_BeginList(t_pList); - c_Enumerator2* t_=t_decls->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_d=t_->p_NextObject(); - t_pPager->p_AddItem(); - p_SetPagerStrings(t_pPager,t_d,false); - int t_2=t_pKind; - if(t_2==322 || t_2==422 || t_2==472){ - int t_kind=601; - String t_listname=String(L"ENUM_ELEMENTS",13); - c_DocDecl* t_tdecl=t_d; - if((t_tdecl->m_target)!=0){ - t_tdecl=t_tdecl->m_target; - } - p_SetPagerList(t_pPager,t_tdecl,t_kind,t_listname); - } - } - t_pPager->p_EndList(); - } -} -void c_ApiDoccer::p_SetPagerLists(c_PageMaker* t_pPager,c_DocDecl* t_pDecl,Array t_pKinds,Array t_pLists){ - for(int t_li=0;t_lip_Clear(); - p_SetPagerStrings(t_pPager,t_pDecl,false); - int t_[]={300,700,301,302,310,320,321,322}; - Array t_kinds=Array(t_,8); - String t_2[]={String(L"IMPORTS",7),String(L"IMPORTED_BY",11),String(L"CLASSES",7),String(L"INTERFACES",10),String(L"FUNCTIONS",9),String(L"CONSTS",6),String(L"GLOBALS",7),String(L"ENUMS",5)}; - Array t_lists=Array(t_2,8); - p_SetPagerLists(t_pPager,t_pDecl,t_kinds,t_lists); - return t_pPager->p_MakePage(); -} -String c_ApiDoccer::p_ApplyClassTemplate(c_DocDecl* t_pDecl,c_PageMaker* t_pPager){ - t_pPager->p_Clear(); - p_SetPagerStrings(t_pPager,t_pDecl,false); - int t_[]={401,402,701,702,403,405,406,410,420,421,422,423,453,455,456,460,470,471,472,473}; - Array t_kinds=Array(t_,20); - String t_2[]={String(L"EXTENDS",7),String(L"IMPLEMENTS",10),String(L"EXTENDED_BY",11),String(L"IMPLEMENTED_BY",14),String(L"METHODS",7),String(L"PROPERTIES",10),String(L"CTORS",5),String(L"FUNCTIONS",9),String(L"CONSTS",6),String(L"GLOBALS",7),String(L"ENUMS",5),String(L"FIELDS",6),String(L"INHERITED_METHODS",17),String(L"INHERITED_PROPERTIES",20),String(L"INHERITED_CTORS",15),String(L"INHERITED_FUNCTIONS",19),String(L"INHERITED_CONSTS",16),String(L"INHERITED_GLOBALS",17),String(L"INHERITED_ENUMS",15),String(L"INHERITED_FIELDS",16)}; - Array t_lists=Array(t_2,20); - p_SetPagerLists(t_pPager,t_pDecl,t_kinds,t_lists); - return t_pPager->p_MakePage(); -} -void c_ApiDoccer::mark(){ - Object::mark(); -} -String bb_os_ExtractExt(String t_path){ - int t_i=t_path.FindLast(String(L".",1)); - if(t_i!=-1 && t_path.Find(String(L"/",1),t_i+1)==-1 && t_path.Find(String(L"\\",1),t_i+1)==-1){ - return t_path.Slice(t_i+1); - } - return String(); -} -String bb_os_StripExt(String t_path){ - int t_i=t_path.FindLast(String(L".",1)); - if(t_i!=-1 && t_path.Find(String(L"/",1),t_i+1)==-1 && t_path.Find(String(L"\\",1),t_i+1)==-1){ - return t_path.Slice(0,t_i); - } - return t_path; -} -String bb_os_StripDir(String t_path){ - int t_i=t_path.FindLast(String(L"/",1)); - if(t_i==-1){ - t_i=t_path.FindLast(String(L"\\",1)); - } - if(t_i!=-1){ - return t_path.Slice(t_i+1); - } - return t_path; -} -c_Toker::c_Toker(){ - m__path=String(); - m__line=0; - m__source=String(); - m__length=0; - m__toke=String(); - m__tokeType=0; - m__tokePos=0; -} -c_StringSet* c_Toker::m__keywords; -c_StringSet* c_Toker::m__symbols; -int c_Toker::p__init(){ - if((m__keywords)!=0){ - return 0; - } - m__keywords=(new c_StringSet)->m_new(); - Array t_=String(L"void strict public private protected friend property bool int float string array object mod continue exit include import module extern new self super eachin true false null not extends abstract final select case default const local global field method function class and or shl shr end if then else elseif endif while wend repeat until forever for to step next return interface implements inline alias try catch throw throwable enumerate",437).Split(String(L" ",1)); - int t_2=0; - while(t_2p_Insert(t_t); - } - m__symbols=(new c_StringSet)->m_new(); - m__symbols->p_Insert(String(L"..",2)); - m__symbols->p_Insert(String(L":=",2)); - m__symbols->p_Insert(String(L"*=",2)); - m__symbols->p_Insert(String(L"/=",2)); - m__symbols->p_Insert(String(L"+=",2)); - m__symbols->p_Insert(String(L"-=",2)); - m__symbols->p_Insert(String(L"|=",2)); - m__symbols->p_Insert(String(L"&=",2)); - m__symbols->p_Insert(String(L"~=",2)); - return 0; -} -c_Toker* c_Toker::m_new(String t_path,String t_source){ - p__init(); - m__path=t_path; - m__line=1; - m__source=t_source; - m__length=m__source.Length(); - m__toke=String(); - m__tokeType=0; - m__tokePos=0; - return this; -} -c_Toker* c_Toker::m_new2(c_Toker* t_toker){ - p__init(); - m__path=t_toker->m__path; - m__line=t_toker->m__line; - m__source=t_toker->m__source; - m__length=m__source.Length(); - m__toke=t_toker->m__toke; - m__tokeType=t_toker->m__tokeType; - m__tokePos=t_toker->m__tokePos; - return this; -} -c_Toker* c_Toker::m_new3(){ - return this; -} -int c_Toker::p_TCHR(int t_i){ - t_i+=m__tokePos; - if(t_ip_Contains(m__toke.ToLower())){ - m__tokeType=3; - } - }else{ - if(bb_stringutil_IsDigit(t_chr) || t_str==String(L".",1) && bb_stringutil_IsDigit(p_TCHR(0))){ - m__tokeType=4; - if(t_str==String(L".",1)){ - m__tokeType=5; - } - while(bb_stringutil_IsDigit(p_TCHR(0))){ - m__tokePos+=1; - } - if(m__tokeType==4 && p_TSTR(0)==String(L".",1) && bb_stringutil_IsDigit(p_TCHR(1))){ - m__tokeType=5; - m__tokePos+=2; - while(bb_stringutil_IsDigit(p_TCHR(0))){ - m__tokePos+=1; - } - } - if(p_TSTR(0).ToLower()==String(L"e",1)){ - m__tokeType=5; - m__tokePos+=1; - if(p_TSTR(0)==String(L"+",1) || p_TSTR(0)==String(L"-",1)){ - m__tokePos+=1; - } - while(bb_stringutil_IsDigit(p_TCHR(0))){ - m__tokePos+=1; - } - } - }else{ - if(t_str==String(L"%",1) && bb_stringutil_IsBinDigit(p_TCHR(0))){ - m__tokeType=4; - m__tokePos+=1; - while(bb_stringutil_IsBinDigit(p_TCHR(0))){ - m__tokePos+=1; - } - }else{ - if(t_str==String(L"$",1) && bb_stringutil_IsHexDigit(p_TCHR(0))){ - m__tokeType=4; - m__tokePos+=1; - while(bb_stringutil_IsHexDigit(p_TCHR(0))){ - m__tokePos+=1; - } - }else{ - if(t_str==String(L"\"",1)){ - m__tokeType=6; - while(m__tokePosp_Contains(m__source.Slice(m__tokePos-1,m__tokePos+1))){ - m__tokePos+=1; - } - } - } - } - } - } - } - } - } - } - } - if(!((m__toke).Length()!=0)){ - m__toke=m__source.Slice(t_start,m__tokePos); - } - return m__toke; -} -void c_Toker::mark(){ - Object::mark(); -} -c_Parser::c_Parser(){ -} -c_Parser* c_Parser::m_new(String t_pText){ - c_Toker::m_new(String(),t_pText); - p_NextToke(); - return this; -} -c_Parser* c_Parser::m_new2(){ - c_Toker::m_new3(); - return this; -} -c_Toker* c_Parser::p_Store(){ - c_Toker* t_t=(new c_Toker)->m_new3(); - t_t->m__line=m__line; - t_t->m__toke=m__toke; - t_t->m__tokeType=m__tokeType; - t_t->m__tokePos=m__tokePos; - return t_t; -} -String c_Parser::p_NextSpace(){ - m__toke=String(); - if(m__tokePos==m__length){ - m__tokeType=0; - return m__toke; - } - int t_start=m__tokePos; - do{ - int t_c=p_TCHR(0); - if(t_c!=32 && t_c!=9){ - break; - } - m__tokePos+=1; - }while(!(false)); - m__toke=m__source.Slice(t_start,m__tokePos); - m__tokeType=1; - return m__toke; -} -String c_Parser::p_NextCdata(String t_pString){ - m__toke=String(); - if(m__tokePos==m__length){ - m__tokeType=0; - return m__toke; - } - int t_ln=t_pString.Length(); - if(m__tokePos+t_lnm_new(t_pMessage); -} -void c_Parser::p_PopSpace(bool t_pAlsoLineBreak){ - do{ - if(m__tokeType==0){ - break; - }else{ - if(m__tokeType==9 || m__tokeType==11){ - if(!t_pAlsoLineBreak){ - break; - } - }else{ - if(m__tokeType!=1){ - break; - } - } - } - p_NextToke(); - }while(!(false)); -} -void c_Parser::p_Restore(c_Toker* t_toker){ - m__line=t_toker->m__line; - m__toke=t_toker->m__toke; - m__tokeType=t_toker->m__tokeType; - m__tokePos=t_toker->m__tokePos; -} -bool c_Parser::p__PopToken(String t_pString,int t_pType,bool t_pNewline,bool t_pPop,bool t_pCaseSensitive){ - c_Toker* t_state=p_Store(); - p_PopSpace(t_pNewline); - String t_ltoke=m__toke; - String t_lstr=t_pString; - if(!t_pCaseSensitive){ - t_ltoke=t_ltoke.ToLower(); - t_lstr=t_lstr.ToLower(); - } - if((t_lstr==String() || t_ltoke==t_lstr) && (t_pType==-1 || m__tokeType==t_pType)){ - if(t_pPop){ - p_Pop(); - } - return true; - } - p_Restore(t_state); - return false; -} -bool c_Parser::p_PopUntilToken(String t_pString,bool t_pNewline){ - return p__PopToken(t_pString,-1,t_pNewline,false,true); -} -bool c_Parser::p_PopUntilToken2(int t_pType,bool t_pNewline){ - return p__PopToken(String(),t_pType,t_pNewline,false,true); -} -bool c_Parser::p_PopToken(String t_pString,bool t_pNewline){ - return p__PopToken(t_pString,-1,t_pNewline,true,true); -} -bool c_Parser::p_PopToken2(int t_pType,bool t_pNewline){ - return p__PopToken(String(),t_pType,t_pNewline,true,true); -} -String c_Parser::p_SParseModpath(bool t_pMayEndInKeyword){ - c_Toker* t_state=p_Store(); - String t_str=String(); - do{ - if(p_PopUntilToken2(2,false)){ - t_str=t_str+m__toke; - p_Pop(); - }else{ - if(t_pMayEndInKeyword && p_PopUntilToken2(3,false)){ - t_str=t_str+m__toke; - p_Pop(); - return t_str; - }else{ - p_Restore(t_state); - return String(); - } - } - if(p_PopToken(String(L".",1),false)){ - t_str=t_str+String(L".",1); - }else{ - return t_str; - } - }while(!(false)); -} -c_DocDecl* c_Parser::p_ParseModuleHeader(c_DocDecl* t_pScope){ - if(t_pScope->m_kind!=901){ - p_Error(String(L"Module header must be at module scope",37)); - } - c_DocDecl* t_decl=0; - String t_str=p_SParseModpath(false); - if(t_str==t_pScope->m_ident || t_pScope->m_ident.EndsWith(String(L".",1)+t_str)){ - t_decl=(new c_DocDecl)->m_new(200,String()); - }else{ - if(!((t_str).Length()!=0)){ - p_Error(String(L"Expecting modpath",17)); - }else{ - p_Error(String(L"Module header does not match modpath",36)); - } - } - t_pScope->p_Add(t_decl); - return t_decl; -} -c_DocDecl* c_Parser::p_ParseImportDecl(c_DocDecl* t_pScope){ - if(t_pScope->m_kind!=901){ - p_Error(String(L"Import declaration must be at module scope",42)); - } - c_DocDecl* t_decl=0; - String t_str=p_SParseModpath(false); - if((t_str).Length()!=0){ - t_decl=(new c_DocDecl)->m_new(300,t_str); - }else{ - p_Error(String(L"Expecting modpath",17)); - } - t_pScope->p_Add(t_decl); - return t_decl; -} -c_DocDecl* c_Parser::p_GetModuleScope(c_DocDecl* t_pDecl){ - return t_pDecl->p_GetScope(901); -} -String c_Parser::p_SParseClasspath(){ - return p_SParseModpath(true); -} -void c_Parser::p_PopLineBreak(){ - p_PopSpace(true); -} -c_Stack2* c_Parser::p_ParseTypeParameters(c_DocDecl* t_pScope){ - if(p_PopToken(String(L"<",1),false)){ - c_DocDecl* t_decl=0; - c_Stack2* t_decls=(new c_Stack2)->m_new(); - do{ - if(p_PopUntilToken2(2,false)){ - t_decl=(new c_DocDecl)->m_new(400,m__toke); - t_decls->p_Push4(t_decl); - p_Pop(); - }else{ - p_Error(String(L"Expecting type parameter identifier",35)); - } - if(p_PopToken(String(L">",1),false)){ - t_pScope->p_Add2(t_decls); - return t_decls; - }else{ - if(p_PopToken(String(L",",1),false)){ - p_PopLineBreak(); - } - } - }while(!(false)); - } - return 0; -} -bool c_Parser::p_PopKeyword(String t_pString,bool t_pNewline){ - return p__PopToken(t_pString,3,t_pNewline,true,false); -} -String c_Parser::p_SParseExpression(){ - c_Toker* t_state=p_Store(); - String t_str=String(); - c_StringStack* t_brackets=(new c_StringStack)->m_new2(); - bool t_instr=false; - bool t_linebreakallowed=false; - m__tokePos-=m__toke.Length(); - while(m__tokePosp_Push(t_s); - t_linebreakallowed=true; - t_str=t_str+t_s; - }else{ - if(t_c==93 || t_c==41 || t_c==62){ - if(t_brackets->p_IsEmpty()){ - p_NextToke(); - return t_str; - } - String t_obrack=t_brackets->p_Get(0); - if(t_c==93 && t_obrack==String(L"[",1) || t_c==41 && t_obrack==String(L"(",1) || t_c==62 && t_obrack==String(L"<",1)){ - t_brackets->p_Pop(); - }else{ - p_Error(String(L"Unexpected '",12)+t_s+String(L"'",1)); - } - t_linebreakallowed=false; - t_str=t_str+t_s; - }else{ - if(t_c==39){ - p_NextToke(); - if(!t_linebreakallowed){ - return t_str; - } - if(((t_str).Length()!=0) && (int)t_str.Slice(-1)[0]>32){ - t_str=t_str+String(L" ",1); - } - }else{ - if(t_c==10 || t_c==13){ - p_NextToke(); - if(!t_linebreakallowed){ - return t_str; - } - if(((t_str).Length()!=0) && (int)t_str.Slice(-1)[0]>32){ - t_str=t_str+String(L" ",1); - } - }else{ - if(t_c==44){ - if(t_brackets->p_IsEmpty()){ - p_NextToke(); - return t_str; - } - t_linebreakallowed=true; - }else{ - if(t_c==59){ - p_NextToke(); - return t_str; - }else{ - if(t_c<=32){ - if(((t_str).Length()!=0) && (int)t_str.Slice(-1)[0]>32){ - t_str=t_str+String(L" ",1); - } - }else{ - t_str=t_str+t_s; - } - t_linebreakallowed=false; - } - } - } - } - } - } - String t_e1=m__source.Slice(-1); - String t_e2=m__source.Slice(-2).ToLower(); - String t_e3=m__source.Slice(-3).ToLower(); - if(t_e1==String(L".",1) || t_e1==String(L"+",1) || t_e1==String(L"-",1) || t_e1==String(L"~",1) || t_e3==String(L"not",3) || t_e1==String(L"*",1) || t_e1==String(L"/",1) || t_e3==String(L"mod",3) || t_e3==String(L"shl",3) || t_e3==String(L"shr",3) || t_e1==String(L"&",1) || t_e1==String(L"|",1) || t_e1==String(L"=",1) || t_e1==String(L"<",1) || t_e1==String(L">",1) || t_e3==String(L"and",3) || t_e2==String(L"or",2)){ - t_linebreakallowed=true; - } - } - m__tokePos+=1; - } - return String(); -} -c_DocDecl* c_Parser::p_ParseTypeArray(c_DocDecl* t_pScope){ - if(p_PopToken(String(L"[",1),false)){ - p_SParseExpression(); - if(p_PopToken(String(L"]",1),false)){ - c_DocDecl* t_decl=(new c_DocDecl)->m_new(550,String()); - t_pScope->p_Add(t_decl); - return t_decl; - }else{ - p_Error(String(L"Expecting `]`",13)); - } - } - return 0; -} -c_DocDecl* c_Parser::p_ParseType(c_DocDecl* t_pScope){ - if(p_PopUntilToken2(2,false) || p_PopUntilToken2(3,false)){ - c_DocDecl* t_decl=(new c_DocDecl)->m_new(500,m__toke); - p_Pop(); - do{ - if(p_PopUntilToken(String(L"[",1),false)){ - p_ParseTypeArray(t_decl); - }else{ - if(p_PopUntilToken(String(L"<",1),false)){ - p_ParseTypeArguments(t_decl); - }else{ - break; - } - } - }while(!(false)); - t_pScope->p_Add(t_decl); - return t_decl; - } - return 0; -} -c_Stack2* c_Parser::p_ParseTypeArguments(c_DocDecl* t_pScope){ - if(p_PopToken(String(L"<",1),false)){ - c_DocDecl* t_decl=0; - c_DocDecl* t_arg=0; - c_Stack2* t_args=(new c_Stack2)->m_new(); - do{ - t_arg=(new c_DocDecl)->m_new(551,String()); - if((p_ParseType(t_arg))!=0){ - t_arg->m_ident=t_arg->m_childs->p_Get(0)->m_ident; - t_arg->m_childs=0; - t_args->p_Push4(t_arg); - }else{ - p_Error(String(L"Expecting type argument",23)); - } - if(p_PopToken(String(L">",1),false)){ - t_pScope->p_Add2(t_args); - return t_args; - }else{ - if(p_PopToken(String(L",",1),false)){ - p_PopLineBreak(); - } - } - }while(!(false)); - } - return 0; -} -c_DocDecl* c_Parser::p_ParseClassExtends(c_DocDecl* t_pScope){ - if(p_PopKeyword(String(L"extends",7),false)){ - c_DocDecl* t_decl=0; - String t_str=p_SParseClasspath(); - if((t_str).Length()!=0){ - t_decl=(new c_DocDecl)->m_new(401,t_str); - }else{ - p_Error(String(L"Expecting base class",20)); - } - p_ParseTypeArguments(t_decl); - t_pScope->p_Add(t_decl); - return t_decl; - } - return 0; -} -c_Stack2* c_Parser::p_ParseClassImplements(c_DocDecl* t_pScope,String t_pKeyword){ - if(p_PopKeyword(t_pKeyword,false)){ - String t_str=String(); - c_DocDecl* t_decl=0; - c_Stack2* t_decls=(new c_Stack2)->m_new(); - do{ - t_str=p_SParseModpath(false); - if((t_str).Length()!=0){ - t_decl=(new c_DocDecl)->m_new(401,t_str); - t_decls->p_Push4(t_decl); - }else{ - p_Error(String(L"Expecting base interface",24)); - } - if(p_PopToken(String(L",",1),false)){ - p_PopLineBreak(); - }else{ - t_pScope->p_Add2(t_decls); - return t_decls; - } - }while(!(false)); - } - return 0; -} -c_Stack2* c_Parser::p_ParseInterfaceExtends(c_DocDecl* t_pScope){ - return p_ParseClassImplements(t_pScope,String(L"extends",7)); -} -c_DocDecl* c_Parser::p_ParseClassDecl(c_DocDecl* t_pScope,int t_pKind){ - c_Toker* t_state=p_Store(); - String t_ident=p_SParseClasspath(); - if(!((t_ident).Length()!=0)){ - p_Error(String(L"Expecting class identifier",26)); - } - if(t_ident.Contains(String(L".",1))){ - int t_i=t_ident.FindLast(String(L".",1)); - t_ident=t_ident.Slice(t_i+1); - } - c_DocDecl* t_decl=(new c_DocDecl)->m_new(t_pKind,t_ident); - if(t_pKind==301){ - p_ParseTypeParameters(t_decl); - p_ParseClassExtends(t_decl); - p_ParseClassImplements(t_decl,String(L"implements",10)); - }else{ - if(t_pKind==302){ - p_ParseInterfaceExtends(t_decl); - } - } - t_pScope->p_Add(t_decl); - return t_decl; -} -c_DocDecl* c_Parser::p_GetClassScope(c_DocDecl* t_pDecl){ - c_DocDecl* t_scope=0; - t_scope=t_pDecl->p_GetScope(301); - if(!((t_scope)!=0)){ - t_scope=t_pDecl->p_GetScope(302); - } - return t_scope; -} -c_DocDecl* c_Parser::p_ParseTypeDecl(c_DocDecl* t_pScope,int t_pAllowImplicitTyping){ - c_DocDecl* t_decl=0; - if(p_PopToken(String(L"?",1),false)){ - t_decl=(new c_DocDecl)->m_new(500,String(L"Bool",4)); - p_ParseTypeArray(t_decl); - }else{ - if(p_PopToken(String(L"%",1),false)){ - t_decl=(new c_DocDecl)->m_new(500,String(L"Int",3)); - p_ParseTypeArray(t_decl); - }else{ - if(p_PopToken(String(L"#",1),false)){ - t_decl=(new c_DocDecl)->m_new(500,String(L"Float",5)); - p_ParseTypeArray(t_decl); - }else{ - if(p_PopToken(String(L"$",1),false)){ - t_decl=(new c_DocDecl)->m_new(500,String(L"String",6)); - p_ParseTypeArray(t_decl); - }else{ - if(p_PopUntilToken(String(L"[",1),false) || p_PopUntilToken(String(L"(",1),false) || p_PopUntilToken(String(L"=",1),false) || p_PopUntilToken(String(L",",1),false)){ - t_decl=(new c_DocDecl)->m_new(500,String(L"Int",3)); - p_ParseTypeArray(t_decl); - }else{ - if(p_PopUntilToken(String(L":=",2),false) && ((t_pAllowImplicitTyping)!=0)){ - t_decl=(new c_DocDecl)->m_new(501,String()); - m__tokePos-=1; - p_NextToke(); - }else{ - if(p_PopToken(String(L":",1),false)){ - t_decl=p_ParseType(t_pScope); - return t_decl; - }else{ - p_Error(String(L"Expecting type declaration",26)); - } - } - } - } - } - } - } - t_pScope->p_Add(t_decl); - return t_decl; -} -c_DocDecl* c_Parser::p_ParseInitialValue(c_DocDecl* t_pScope){ - if(p_PopToken(String(L"=",1),false)){ - String t_str=p_SParseExpression().Trim(); - if((t_str).Length()!=0){ - c_DocDecl* t_decl=(new c_DocDecl)->m_new(502,t_str); - t_pScope->p_Add(t_decl); - return t_decl; - }else{ - p_Error(String(L"Expecting expression",20)); - } - } - return 0; -} -c_DocDecl* c_Parser::p_ParseVariable(c_DocDecl* t_pScope,int t_pKind){ - if(p_PopUntilToken2(2,false)){ - c_DocDecl* t_decl=(new c_DocDecl)->m_new(t_pKind,m__toke); - p_Pop(); - c_DocDecl* t_tdecl=p_ParseTypeDecl(t_decl,1); - if(t_tdecl->m_kind==501){ - if(!((p_ParseInitialValue(t_decl))!=0)){ - p_Error(String(L"Expecting initial expression",28)); - } - }else{ - p_ParseInitialValue(t_decl); - } - t_pScope->p_Add(t_decl); - return t_decl; - } - return 0; -} -c_Stack2* c_Parser::p_ParseVariableSet(c_DocDecl* t_pScope,int t_pKind){ - c_Stack2* t_decls=(new c_Stack2)->m_new(); - do{ - c_DocDecl* t_decl=p_ParseVariable(t_pScope,t_pKind); - if((t_decl)!=0){ - t_decls->p_Push4(t_decl); - }else{ - p_Error(String(L"Expecting variable identifier",29)); - } - if(p_PopToken(String(L",",1),false)){ - p_PopLineBreak(); - }else{ - return t_decls; - } - }while(!(false)); -} -c_Stack2* c_Parser::p_ParseFunctionParameters(c_DocDecl* t_pScope){ - if(p_PopToken(String(L"(",1),false)){ - if(p_PopToken(String(L")",1),false)){ - return 0; - } - c_Stack2* t_decls=p_ParseVariableSet(t_pScope,600); - p_PopToken(String(L")",1),false); - return t_decls; - } - return 0; -} -c_DocDecl* c_Parser::p_ParseFunctionDecl(c_DocDecl* t_pScope,int t_pKind){ - if(p_PopUntilToken2(2,false) || p_PopUntilToken2(3,false)){ - c_DocDecl* t_decl=0; - if(m__toke==String(L"New",3)){ - t_decl=(new c_DocDecl)->m_new(406,m__toke); - p_Pop(); - }else{ - t_decl=(new c_DocDecl)->m_new(t_pKind,m__toke); - p_Pop(); - p_ParseTypeDecl(t_decl,0); - } - p_ParseFunctionParameters(t_decl); - if(t_decl->m_kind==403){ - c_Toker* t_state=p_Store(); - if(p_PopKeyword(String(L"property",8),false)){ - t_decl->m_kind=405; - }else{ - p_Restore(t_state); - } - } - t_pScope->p_Add(t_decl); - return t_decl; - }else{ - p_Error(String(L"Expecting function identifier",29)); - } - return 0; -} -c_DocDecl* c_Parser::p_ParseEnumDecl(c_DocDecl* t_pScope,int t_pKind){ - c_DocDecl* t_decl=(new c_DocDecl)->m_new(t_pKind,String()); - do{ - if(p_PopUntilToken2(2,false)){ - c_DocDecl* t_edecl=(new c_DocDecl)->m_new(601,m__toke); - p_Pop(); - t_decl->p_Add(t_edecl); - p_ParseInitialValue(t_edecl); - }else{ - p_Error(String(L"Expecting identifier",20)); - } - if(p_PopToken(String(L",",1),false)){ - p_PopLineBreak(); - }else{ - t_pScope->p_Add(t_decl); - return t_decl; - } - }while(!(false)); -} -c_DocDecl* c_Parser::p_ParseDecl(c_DocDecl* t_pScope){ - String t_1=m__toke.ToLower(); - if(t_1==String(L"module",6)){ - p_Pop(); - p_ParseModuleHeader(t_pScope); - return t_pScope; - }else{ - if(t_1==String(L"import",6)){ - p_Pop(); - p_ParseImportDecl(t_pScope); - return t_pScope; - }else{ - if(t_1==String(L"class",5)){ - p_Pop(); - return p_ParseClassDecl(p_GetModuleScope(t_pScope),301); - }else{ - if(t_1==String(L"interface",9)){ - p_Pop(); - return p_ParseClassDecl(p_GetModuleScope(t_pScope),302); - }else{ - if(t_1==String(L"function",8)){ - p_Pop(); - c_DocDecl* t_scope=p_GetClassScope(t_pScope); - if((t_scope)!=0){ - return p_ParseFunctionDecl(t_scope,410); - }else{ - t_scope=p_GetModuleScope(t_pScope); - return p_ParseFunctionDecl(t_scope,310); - } - }else{ - if(t_1==String(L"method",6)){ - p_Pop(); - c_DocDecl* t_scope2=p_GetClassScope(t_pScope); - if((t_scope2)!=0){ - return p_ParseFunctionDecl(t_scope2,403); - }else{ - p_Error(String(L"Method declaration must be at class scope",41)); - } - }else{ - if(t_1==String(L"const",5) || t_1==String(L"global",6)){ - String t_ltoke=m__toke.ToLower(); - p_Pop(); - c_DocDecl* t_scope3=p_GetClassScope(t_pScope); - if((t_scope3)!=0){ - int t_kind=0; - if(t_ltoke==String(L"const",5)){ - t_kind=420; - } - if(t_ltoke==String(L"global",6)){ - t_kind=421; - } - c_Stack2* t_decls=p_ParseVariableSet(t_scope3,t_kind); - return t_decls->p_Get(0); - }else{ - t_scope3=p_GetModuleScope(t_pScope); - int t_kind2=0; - if(t_ltoke==String(L"const",5)){ - t_kind2=320; - } - if(t_ltoke==String(L"global",6)){ - t_kind2=321; - } - c_Stack2* t_decls2=p_ParseVariableSet(t_scope3,t_kind2); - return t_decls2->p_Get(0); - } - }else{ - if(t_1==String(L"enumerate",9)){ - p_Pop(); - if(t_pScope->m_kind==403 || t_pScope->m_kind==410 || t_pScope->m_kind==310){ - return 0; - } - c_DocDecl* t_scope4=p_GetClassScope(t_pScope); - if((t_scope4)!=0){ - return p_ParseEnumDecl(t_scope4,422); - }else{ - t_scope4=p_GetModuleScope(t_pScope); - return p_ParseEnumDecl(t_scope4,322); - } - }else{ - if(t_1==String(L"field",5)){ - p_Pop(); - c_DocDecl* t_scope5=p_GetClassScope(t_pScope); - if((t_scope5)!=0){ - c_Stack2* t_decls3=p_ParseVariableSet(t_scope5,423); - return t_decls3->p_Get(0); - }else{ - p_Error(String(L"Field declaration must be at class scope",40)); - } - } - } - } - } - } - } - } - } - } - return 0; -} -String c_Parser::p_NextRestOfLine(){ - if(m__tokeType==11 || m__tokeType==9){ - m__tokeType=12; - return m__toke; - } - m__toke=String(); - if(m__tokePos==m__length){ - m__tokeType=0; - return m__toke; - } - int t_start=m__tokePos; - do{ - int t_c=p_TCHR(0); - m__tokePos+=1; - if(t_c==10){ - m__line+=1; - break; - }else{ - if(t_c==13){ - if(p_TCHR(0)==10){ - m__tokePos+=1; - } - m__line+=1; - break; - }else{ - if(t_c==0){ - m__tokePos-=1; - break; - } - } - } - }while(!(false)); - m__toke=m__source.Slice(t_start,m__tokePos); - m__tokeType=12; - return m__toke; -} -int c_Parser::p_GetCarretLine(){ - return m__line; -} -int c_Parser::p_GetCarretChar(){ - int t_i=m__tokePos; - do{ - int t_c=(int)m__source[t_i]; - if(t_c==10 || t_c==13){ - break; - } - t_i-=1; - }while(!(t_i<0)); - return m__tokePos-t_i; -} -bool c_Parser::p_PopUntilKeyword(String t_pString,bool t_pNewline){ - return p__PopToken(t_pString,3,t_pNewline,false,false); -} -void c_Parser::mark(){ - c_Toker::mark(); -} -c_Set::c_Set(){ - m_map=0; -} -c_Set* c_Set::m_new(c_Map* t_map){ - this->m_map=t_map; - return this; -} -c_Set* c_Set::m_new2(){ - return this; -} -int c_Set::p_Insert(String t_value){ - m_map->p_Insert2(t_value,0); - return 0; -} -bool c_Set::p_Contains(String t_value){ - return m_map->p_Contains(t_value); -} -void c_Set::mark(){ - Object::mark(); -} -c_StringSet::c_StringSet(){ -} -c_StringSet* c_StringSet::m_new(){ - c_Set::m_new((new c_StringMap)->m_new()); - return this; -} -void c_StringSet::mark(){ - c_Set::mark(); -} -c_Map::c_Map(){ - m_root=0; -} -c_Map* c_Map::m_new(){ - return this; -} -int c_Map::p_RotateLeft(c_Node2* t_node){ - c_Node2* t_child=t_node->m_right; - t_node->m_right=t_child->m_left; - if((t_child->m_left)!=0){ - t_child->m_left->m_parent=t_node; - } - t_child->m_parent=t_node->m_parent; - if((t_node->m_parent)!=0){ - if(t_node==t_node->m_parent->m_left){ - t_node->m_parent->m_left=t_child; - }else{ - t_node->m_parent->m_right=t_child; - } - }else{ - m_root=t_child; - } - t_child->m_left=t_node; - t_node->m_parent=t_child; - return 0; -} -int c_Map::p_RotateRight(c_Node2* t_node){ - c_Node2* t_child=t_node->m_left; - t_node->m_left=t_child->m_right; - if((t_child->m_right)!=0){ - t_child->m_right->m_parent=t_node; - } - t_child->m_parent=t_node->m_parent; - if((t_node->m_parent)!=0){ - if(t_node==t_node->m_parent->m_right){ - t_node->m_parent->m_right=t_child; - }else{ - t_node->m_parent->m_left=t_child; - } - }else{ - m_root=t_child; - } - t_child->m_right=t_node; - t_node->m_parent=t_child; - return 0; -} -int c_Map::p_InsertFixup(c_Node2* t_node){ - while(((t_node->m_parent)!=0) && t_node->m_parent->m_color==-1 && ((t_node->m_parent->m_parent)!=0)){ - if(t_node->m_parent==t_node->m_parent->m_parent->m_left){ - c_Node2* t_uncle=t_node->m_parent->m_parent->m_right; - if(((t_uncle)!=0) && t_uncle->m_color==-1){ - t_node->m_parent->m_color=1; - t_uncle->m_color=1; - t_uncle->m_parent->m_color=-1; - t_node=t_uncle->m_parent; - }else{ - if(t_node==t_node->m_parent->m_right){ - t_node=t_node->m_parent; - p_RotateLeft(t_node); - } - t_node->m_parent->m_color=1; - t_node->m_parent->m_parent->m_color=-1; - p_RotateRight(t_node->m_parent->m_parent); - } - }else{ - c_Node2* t_uncle2=t_node->m_parent->m_parent->m_left; - if(((t_uncle2)!=0) && t_uncle2->m_color==-1){ - t_node->m_parent->m_color=1; - t_uncle2->m_color=1; - t_uncle2->m_parent->m_color=-1; - t_node=t_uncle2->m_parent; - }else{ - if(t_node==t_node->m_parent->m_left){ - t_node=t_node->m_parent; - p_RotateRight(t_node); - } - t_node->m_parent->m_color=1; - t_node->m_parent->m_parent->m_color=-1; - p_RotateLeft(t_node->m_parent->m_parent); - } - } - } - m_root->m_color=1; - return 0; -} -bool c_Map::p_Set(String t_key,Object* t_value){ - c_Node2* t_node=m_root; - c_Node2* t_parent=0; - int t_cmp=0; - while((t_node)!=0){ - t_parent=t_node; - t_cmp=p_Compare2(t_key,t_node->m_key); - if(t_cmp>0){ - t_node=t_node->m_right; - }else{ - if(t_cmp<0){ - t_node=t_node->m_left; - }else{ - t_node->m_value=t_value; - return false; - } - } - } - t_node=(new c_Node2)->m_new(t_key,t_value,-1,t_parent); - if((t_parent)!=0){ - if(t_cmp>0){ - t_parent->m_right=t_node; - }else{ - t_parent->m_left=t_node; - } - p_InsertFixup(t_node); - }else{ - m_root=t_node; - } - return true; -} -bool c_Map::p_Insert2(String t_key,Object* t_value){ - return p_Set(t_key,t_value); -} -c_Node2* c_Map::p_FindNode(String t_key){ - c_Node2* t_node=m_root; - while((t_node)!=0){ - int t_cmp=p_Compare2(t_key,t_node->m_key); - if(t_cmp>0){ - t_node=t_node->m_right; - }else{ - if(t_cmp<0){ - t_node=t_node->m_left; - }else{ - return t_node; - } - } - } - return t_node; -} -bool c_Map::p_Contains(String t_key){ - return p_FindNode(t_key)!=0; -} -int c_Map::p_Clear(){ - m_root=0; - return 0; -} -Object* c_Map::p_Get2(String t_key){ - c_Node2* t_node=p_FindNode(t_key); - if((t_node)!=0){ - return t_node->m_value; - } - return 0; -} -void c_Map::mark(){ - Object::mark(); -} -c_StringMap::c_StringMap(){ -} -c_StringMap* c_StringMap::m_new(){ - c_Map::m_new(); - return this; -} -int c_StringMap::p_Compare2(String t_lhs,String t_rhs){ - return t_lhs.Compare(t_rhs); -} -void c_StringMap::mark(){ - c_Map::mark(); -} -c_Node2::c_Node2(){ - m_key=String(); - m_right=0; - m_left=0; - m_value=0; - m_color=0; - m_parent=0; -} -c_Node2* c_Node2::m_new(String t_key,Object* t_value,int t_color,c_Node2* t_parent){ - this->m_key=t_key; - this->m_value=t_value; - this->m_color=t_color; - this->m_parent=t_parent; - return this; -} -c_Node2* c_Node2::m_new2(){ - return this; -} -void c_Node2::mark(){ - Object::mark(); -} -bool bb_stringutil_IsSpace(int t_ch){ - return t_ch<=32; -} -bool bb_stringutil_IsAlpha(int t_ch){ - return t_ch>=65 && t_ch<=90 || t_ch>=97 && t_ch<=122; -} -bool bb_stringutil_IsDigit(int t_ch){ - return t_ch>=48 && t_ch<=57; -} -bool bb_stringutil_IsBinDigit(int t_ch){ - return t_ch==48 || t_ch==49; -} -bool bb_stringutil_IsHexDigit(int t_ch){ - return t_ch>=48 && t_ch<=57 || t_ch>=65 && t_ch<=70 || t_ch>=97 && t_ch<=102; -} -c_ThrowableString::c_ThrowableString(){ - m_str=String(); -} -c_ThrowableString* c_ThrowableString::m_new(String t_pString){ - m_str=t_pString; - return this; -} -c_ThrowableString* c_ThrowableString::m_new2(){ - return this; -} -String c_ThrowableString::p_ToString2(){ - return m_str; -} -void c_ThrowableString::mark(){ - ThrowableObject::mark(); -} -String bb_stringutil_UnifyLineEndings(String t_str){ - return t_str.Replace(String(L"\r\n",2),String(L"\n",1)).Replace(String(L"\r",1),String(L"\n",1)); -} -c_Stack3::c_Stack3(){ - m_data=Array(); - m_length=0; -} -c_Stack3* c_Stack3::m_new(){ - return this; -} -c_Stack3* c_Stack3::m_new2(Array t_data){ - this->m_data=t_data.Slice(0); - this->m_length=t_data.Length(); - return this; -} -c_BackwardsStack* c_Stack3::p_Backwards(){ - return (new c_BackwardsStack)->m_new(this); -} -void c_Stack3::p_Push7(int t_value){ - if(m_length==m_data.Length()){ - m_data=m_data.Resize(m_length*2+10); - } - m_data[m_length]=t_value; - m_length+=1; -} -void c_Stack3::p_Push8(Array t_values,int t_offset,int t_count){ - for(int t_i=0;t_i t_values,int t_offset){ - p_Push8(t_values,t_offset,t_values.Length()-t_offset); -} -int c_Stack3::m_NIL; -int c_Stack3::p_Pop(){ - m_length-=1; - int t_v=m_data[m_length]; - m_data[m_length]=m_NIL; - return t_v; -} -void c_Stack3::p_Length(int t_newlength){ - if(t_newlengthm_data.Length()){ - m_data=m_data.Resize(bb_math_Max(m_length*2+10,t_newlength)); - } - } - m_length=t_newlength; -} -int c_Stack3::p_Length2(){ - return m_length; -} -int c_Stack3::p_Get(int t_index){ - return m_data[t_index]; -} -void c_Stack3::p_Clear(){ - for(int t_i=0;t_i t_data){ - c_Stack3::m_new2(t_data); - return this; -} -c_IntStack* c_IntStack::m_new2(){ - c_Stack3::m_new(); - return this; -} -void c_IntStack::mark(){ - c_Stack3::mark(); -} -c_BackwardsStack::c_BackwardsStack(){ - m_stack=0; -} -c_BackwardsStack* c_BackwardsStack::m_new(c_Stack3* t_stack){ - this->m_stack=t_stack; - return this; -} -c_BackwardsStack* c_BackwardsStack::m_new2(){ - return this; -} -c_BackwardsEnumerator* c_BackwardsStack::p_ObjectEnumerator(){ - return (new c_BackwardsEnumerator)->m_new(m_stack); -} -void c_BackwardsStack::mark(){ - Object::mark(); -} -c_BackwardsEnumerator::c_BackwardsEnumerator(){ - m_stack=0; - m_index=0; -} -c_BackwardsEnumerator* c_BackwardsEnumerator::m_new(c_Stack3* t_stack){ - this->m_stack=t_stack; - m_index=t_stack->m_length; - return this; -} -c_BackwardsEnumerator* c_BackwardsEnumerator::m_new2(){ - return this; -} -bool c_BackwardsEnumerator::p_HasNext(){ - return m_index>0; -} -int c_BackwardsEnumerator::p_NextObject(){ - m_index-=1; - return m_stack->m_data[m_index]; -} -void c_BackwardsEnumerator::mark(){ - Object::mark(); -} -c_DocDoccer::c_DocDoccer(){ - m_maker=0; -} -c_DocDoccer* c_DocDoccer::m_new(c_Makedocs* t_pMakedocs){ - m_maker=t_pMakedocs; - return this; -} -c_DocDoccer* c_DocDoccer::m_new2(){ - return this; -} -void c_DocDoccer::p_DocIn(String t_pDirectory,c_DocDecl* t_pScope,String t_pDocPath,bool t_p3rdParty){ - String t_docpath=t_pDocPath; - if((t_docpath).Length()!=0){ - t_docpath=t_docpath+String(L"/",1); - } - Array t_=bb_os_LoadDir(t_pDirectory,false,false); - int t_2=0; - while(t_2p_CopyDir(t_path,String(L"docs/html/data/",15)+t_dst,true); - }else{ - c_DocDecl* t_decl=t_pScope->p_GetChild2(t_file); - if(!((t_decl)!=0)){ - t_decl=(new c_DocDecl)->m_new(903,t_file); - t_decl->p_Add((new c_DocDecl)->m_new(201,t_docpath)); - t_pScope->p_Add(t_decl); - } - p_DocIn(t_path,t_decl,t_docpath+t_file,t_p3rdParty); - } - }else{ - if(t_1==1){ - String t_22=bb_os_ExtractExt(t_file); - if(t_22==String(L"cerberusdoc",11) || t_22==String(L"monkeydoc",9)){ - String t_name2=bb_os_StripExt(t_file); - c_DocDecl* t_decl2=t_pScope->p_GetChild2(t_name2); - bool t_newdoc=false; - if((t_decl2)!=0){ - t_decl2->m_kind=902; - }else{ - t_decl2=(new c_DocDecl)->m_new(902,t_name2); - t_newdoc=true; - t_decl2->p_Add((new c_DocDecl)->m_new(201,t_docpath)); - } - String t_txt=LoadString(t_path); - t_txt=bb_stringutil_UnifyLineEndings(t_txt); - t_decl2->p_Add((new c_DocDecl)->m_new(805,t_txt)); - if(t_newdoc){ - t_pScope->p_Add(t_decl2); - } - if(t_p3rdParty){ - t_path=t_pDirectory+String(L"/",1)+t_name2+String(L".png",4); - if(FileType(t_path)==1){ - String t_filename=String(L"3rd Party Docs_",15)+t_name2+String(L".png",4); - t_decl2->p_Add((new c_DocDecl)->m_new(211,t_filename)); - m_maker->p_CopyFile(t_path,String(L"docs/html/",10)+t_filename); - } - } - } - } - } - } -} -void c_DocDoccer::p_Doc(){ - p_DocIn(m_maker->m_docpath,m_maker->m_rootdocs,String(),false); -} -void c_DocDoccer::p_Doc3rdParty(){ - c_DocDeclStack* t_decls=m_maker->m_branch3rdparty->p_GetChilds2(210,false); - if((t_decls)!=0){ - c_Enumerator2* t_=t_decls->p_ObjectEnumerator(); - while(t_->p_HasNext()){ - c_DocDecl* t_d=t_->p_NextObject(); - p_DocIn(t_d->m_ident,m_maker->m_branch3rdparty,String(L"3rd Party Docs",14),true); - } - } -} -void c_DocDoccer::mark(){ - Object::mark(); -} -c_Map2::c_Map2(){ - m_root=0; -} -c_Map2* c_Map2::m_new(){ - return this; -} -c_Node3* c_Map2::p_FindNode(String t_key){ - c_Node3* t_node=m_root; - while((t_node)!=0){ - int t_cmp=p_Compare2(t_key,t_node->m_key); - if(t_cmp>0){ - t_node=t_node->m_right; - }else{ - if(t_cmp<0){ - t_node=t_node->m_left; - }else{ - return t_node; - } - } - } - return t_node; -} -c_DocDecl* c_Map2::p_Get2(String t_key){ - c_Node3* t_node=p_FindNode(t_key); - if((t_node)!=0){ - return t_node->m_value; - } - return 0; -} -int c_Map2::p_RotateLeft2(c_Node3* t_node){ - c_Node3* t_child=t_node->m_right; - t_node->m_right=t_child->m_left; - if((t_child->m_left)!=0){ - t_child->m_left->m_parent=t_node; - } - t_child->m_parent=t_node->m_parent; - if((t_node->m_parent)!=0){ - if(t_node==t_node->m_parent->m_left){ - t_node->m_parent->m_left=t_child; - }else{ - t_node->m_parent->m_right=t_child; - } - }else{ - m_root=t_child; - } - t_child->m_left=t_node; - t_node->m_parent=t_child; - return 0; -} -int c_Map2::p_RotateRight2(c_Node3* t_node){ - c_Node3* t_child=t_node->m_left; - t_node->m_left=t_child->m_right; - if((t_child->m_right)!=0){ - t_child->m_right->m_parent=t_node; - } - t_child->m_parent=t_node->m_parent; - if((t_node->m_parent)!=0){ - if(t_node==t_node->m_parent->m_right){ - t_node->m_parent->m_right=t_child; - }else{ - t_node->m_parent->m_left=t_child; - } - }else{ - m_root=t_child; - } - t_child->m_right=t_node; - t_node->m_parent=t_child; - return 0; -} -int c_Map2::p_InsertFixup2(c_Node3* t_node){ - while(((t_node->m_parent)!=0) && t_node->m_parent->m_color==-1 && ((t_node->m_parent->m_parent)!=0)){ - if(t_node->m_parent==t_node->m_parent->m_parent->m_left){ - c_Node3* t_uncle=t_node->m_parent->m_parent->m_right; - if(((t_uncle)!=0) && t_uncle->m_color==-1){ - t_node->m_parent->m_color=1; - t_uncle->m_color=1; - t_uncle->m_parent->m_color=-1; - t_node=t_uncle->m_parent; - }else{ - if(t_node==t_node->m_parent->m_right){ - t_node=t_node->m_parent; - p_RotateLeft2(t_node); - } - t_node->m_parent->m_color=1; - t_node->m_parent->m_parent->m_color=-1; - p_RotateRight2(t_node->m_parent->m_parent); - } - }else{ - c_Node3* t_uncle2=t_node->m_parent->m_parent->m_left; - if(((t_uncle2)!=0) && t_uncle2->m_color==-1){ - t_node->m_parent->m_color=1; - t_uncle2->m_color=1; - t_uncle2->m_parent->m_color=-1; - t_node=t_uncle2->m_parent; - }else{ - if(t_node==t_node->m_parent->m_left){ - t_node=t_node->m_parent; - p_RotateRight2(t_node); - } - t_node->m_parent->m_color=1; - t_node->m_parent->m_parent->m_color=-1; - p_RotateLeft2(t_node->m_parent->m_parent); - } - } - } - m_root->m_color=1; - return 0; -} -bool c_Map2::p_Add3(String t_key,c_DocDecl* t_value){ - c_Node3* t_node=m_root; - c_Node3* t_parent=0; - int t_cmp=0; - while((t_node)!=0){ - t_parent=t_node; - t_cmp=p_Compare2(t_key,t_node->m_key); - if(t_cmp>0){ - t_node=t_node->m_right; - }else{ - if(t_cmp<0){ - t_node=t_node->m_left; - }else{ - return false; - } - } - } - t_node=(new c_Node3)->m_new(t_key,t_value,-1,t_parent); - if((t_parent)!=0){ - if(t_cmp>0){ - t_parent->m_right=t_node; - }else{ - t_parent->m_left=t_node; - } - p_InsertFixup2(t_node); - }else{ - m_root=t_node; - } - return true; -} -c_Node3* c_Map2::p_FirstNode(){ - if(!((m_root)!=0)){ - return 0; - } - c_Node3* t_node=m_root; - while((t_node->m_left)!=0){ - t_node=t_node->m_left; - } - return t_node; -} -c_NodeEnumerator3* c_Map2::p_ObjectEnumerator(){ - return (new c_NodeEnumerator3)->m_new(p_FirstNode()); -} -void c_Map2::mark(){ - Object::mark(); -} -c_StringMap2::c_StringMap2(){ -} -c_StringMap2* c_StringMap2::m_new(){ - c_Map2::m_new(); - return this; -} -int c_StringMap2::p_Compare2(String t_lhs,String t_rhs){ - return t_lhs.Compare(t_rhs); -} -void c_StringMap2::mark(){ - c_Map2::mark(); -} -c_Node3::c_Node3(){ - m_key=String(); - m_right=0; - m_left=0; - m_value=0; - m_color=0; - m_parent=0; -} -c_Node3* c_Node3::m_new(String t_key,c_DocDecl* t_value,int t_color,c_Node3* t_parent){ - this->m_key=t_key; - this->m_value=t_value; - this->m_color=t_color; - this->m_parent=t_parent; - return this; -} -c_Node3* c_Node3::m_new2(){ - return this; -} -c_Node3* c_Node3::p_NextNode(){ - c_Node3* t_node=0; - if((m_right)!=0){ - t_node=m_right; - while((t_node->m_left)!=0){ - t_node=t_node->m_left; - } - return t_node; - } - t_node=this; - c_Node3* t_parent=this->m_parent; - while(((t_parent)!=0) && t_node==t_parent->m_right){ - t_node=t_parent; - t_parent=t_parent->m_parent; - } - return t_parent; -} -c_DocDecl* c_Node3::p_Value(){ - return m_value; -} -void c_Node3::mark(){ - Object::mark(); -} -c_Map3::c_Map3(){ - m_root=0; -} -c_Map3* c_Map3::m_new(){ - return this; -} -int c_Map3::p_RotateLeft3(c_Node4* t_node){ - c_Node4* t_child=t_node->m_right; - t_node->m_right=t_child->m_left; - if((t_child->m_left)!=0){ - t_child->m_left->m_parent=t_node; - } - t_child->m_parent=t_node->m_parent; - if((t_node->m_parent)!=0){ - if(t_node==t_node->m_parent->m_left){ - t_node->m_parent->m_left=t_child; - }else{ - t_node->m_parent->m_right=t_child; - } - }else{ - m_root=t_child; - } - t_child->m_left=t_node; - t_node->m_parent=t_child; - return 0; -} -int c_Map3::p_RotateRight3(c_Node4* t_node){ - c_Node4* t_child=t_node->m_left; - t_node->m_left=t_child->m_right; - if((t_child->m_right)!=0){ - t_child->m_right->m_parent=t_node; - } - t_child->m_parent=t_node->m_parent; - if((t_node->m_parent)!=0){ - if(t_node==t_node->m_parent->m_right){ - t_node->m_parent->m_right=t_child; - }else{ - t_node->m_parent->m_left=t_child; - } - }else{ - m_root=t_child; - } - t_child->m_right=t_node; - t_node->m_parent=t_child; - return 0; -} -int c_Map3::p_InsertFixup3(c_Node4* t_node){ - while(((t_node->m_parent)!=0) && t_node->m_parent->m_color==-1 && ((t_node->m_parent->m_parent)!=0)){ - if(t_node->m_parent==t_node->m_parent->m_parent->m_left){ - c_Node4* t_uncle=t_node->m_parent->m_parent->m_right; - if(((t_uncle)!=0) && t_uncle->m_color==-1){ - t_node->m_parent->m_color=1; - t_uncle->m_color=1; - t_uncle->m_parent->m_color=-1; - t_node=t_uncle->m_parent; - }else{ - if(t_node==t_node->m_parent->m_right){ - t_node=t_node->m_parent; - p_RotateLeft3(t_node); - } - t_node->m_parent->m_color=1; - t_node->m_parent->m_parent->m_color=-1; - p_RotateRight3(t_node->m_parent->m_parent); - } - }else{ - c_Node4* t_uncle2=t_node->m_parent->m_parent->m_left; - if(((t_uncle2)!=0) && t_uncle2->m_color==-1){ - t_node->m_parent->m_color=1; - t_uncle2->m_color=1; - t_uncle2->m_parent->m_color=-1; - t_node=t_uncle2->m_parent; - }else{ - if(t_node==t_node->m_parent->m_left){ - t_node=t_node->m_parent; - p_RotateRight3(t_node); - } - t_node->m_parent->m_color=1; - t_node->m_parent->m_parent->m_color=-1; - p_RotateLeft3(t_node->m_parent->m_parent); - } - } - } - m_root->m_color=1; - return 0; -} -bool c_Map3::p_Add4(String t_key,c_StringMap2* t_value){ - c_Node4* t_node=m_root; - c_Node4* t_parent=0; - int t_cmp=0; - while((t_node)!=0){ - t_parent=t_node; - t_cmp=p_Compare2(t_key,t_node->m_key); - if(t_cmp>0){ - t_node=t_node->m_right; - }else{ - if(t_cmp<0){ - t_node=t_node->m_left; - }else{ - return false; - } - } - } - t_node=(new c_Node4)->m_new(t_key,t_value,-1,t_parent); - if((t_parent)!=0){ - if(t_cmp>0){ - t_parent->m_right=t_node; - }else{ - t_parent->m_left=t_node; - } - p_InsertFixup3(t_node); - }else{ - m_root=t_node; - } - return true; -} -c_Node4* c_Map3::p_FirstNode(){ - if(!((m_root)!=0)){ - return 0; - } - c_Node4* t_node=m_root; - while((t_node->m_left)!=0){ - t_node=t_node->m_left; - } - return t_node; -} -c_NodeEnumerator2* c_Map3::p_ObjectEnumerator(){ - return (new c_NodeEnumerator2)->m_new(p_FirstNode()); -} -void c_Map3::mark(){ - Object::mark(); -} -c_StringMap3::c_StringMap3(){ -} -c_StringMap3* c_StringMap3::m_new(){ - c_Map3::m_new(); - return this; -} -int c_StringMap3::p_Compare2(String t_lhs,String t_rhs){ - return t_lhs.Compare(t_rhs); -} -void c_StringMap3::mark(){ - c_Map3::mark(); -} -c_Node4::c_Node4(){ - m_key=String(); - m_right=0; - m_left=0; - m_value=0; - m_color=0; - m_parent=0; -} -c_Node4* c_Node4::m_new(String t_key,c_StringMap2* t_value,int t_color,c_Node4* t_parent){ - this->m_key=t_key; - this->m_value=t_value; - this->m_color=t_color; - this->m_parent=t_parent; - return this; -} -c_Node4* c_Node4::m_new2(){ - return this; -} -c_Node4* c_Node4::p_NextNode(){ - c_Node4* t_node=0; - if((m_right)!=0){ - t_node=m_right; - while((t_node->m_left)!=0){ - t_node=t_node->m_left; - } - return t_node; - } - t_node=this; - c_Node4* t_parent=this->m_parent; - while(((t_parent)!=0) && t_node==t_parent->m_right){ - t_node=t_parent; - t_parent=t_parent->m_parent; - } - return t_parent; -} -String c_Node4::p_Key(){ - return m_key; -} -c_StringMap2* c_Node4::p_Value(){ - return m_value; -} -void c_Node4::mark(){ - Object::mark(); -} -c_Map4::c_Map4(){ - m_root=0; -} -c_Map4* c_Map4::m_new(){ - return this; -} -c_Node5* c_Map4::p_FindNode(String t_key){ - c_Node5* t_node=m_root; - while((t_node)!=0){ - int t_cmp=p_Compare2(t_key,t_node->m_key); - if(t_cmp>0){ - t_node=t_node->m_right; - }else{ - if(t_cmp<0){ - t_node=t_node->m_left; - }else{ - return t_node; - } - } - } - return t_node; -} -bool c_Map4::p_Contains(String t_key){ - return p_FindNode(t_key)!=0; -} -int c_Map4::p_RotateLeft4(c_Node5* t_node){ - c_Node5* t_child=t_node->m_right; - t_node->m_right=t_child->m_left; - if((t_child->m_left)!=0){ - t_child->m_left->m_parent=t_node; - } - t_child->m_parent=t_node->m_parent; - if((t_node->m_parent)!=0){ - if(t_node==t_node->m_parent->m_left){ - t_node->m_parent->m_left=t_child; - }else{ - t_node->m_parent->m_right=t_child; - } - }else{ - m_root=t_child; - } - t_child->m_left=t_node; - t_node->m_parent=t_child; - return 0; -} -int c_Map4::p_RotateRight4(c_Node5* t_node){ - c_Node5* t_child=t_node->m_left; - t_node->m_left=t_child->m_right; - if((t_child->m_right)!=0){ - t_child->m_right->m_parent=t_node; - } - t_child->m_parent=t_node->m_parent; - if((t_node->m_parent)!=0){ - if(t_node==t_node->m_parent->m_right){ - t_node->m_parent->m_right=t_child; - }else{ - t_node->m_parent->m_left=t_child; - } - }else{ - m_root=t_child; - } - t_child->m_right=t_node; - t_node->m_parent=t_child; - return 0; -} -int c_Map4::p_InsertFixup4(c_Node5* t_node){ - while(((t_node->m_parent)!=0) && t_node->m_parent->m_color==-1 && ((t_node->m_parent->m_parent)!=0)){ - if(t_node->m_parent==t_node->m_parent->m_parent->m_left){ - c_Node5* t_uncle=t_node->m_parent->m_parent->m_right; - if(((t_uncle)!=0) && t_uncle->m_color==-1){ - t_node->m_parent->m_color=1; - t_uncle->m_color=1; - t_uncle->m_parent->m_color=-1; - t_node=t_uncle->m_parent; - }else{ - if(t_node==t_node->m_parent->m_right){ - t_node=t_node->m_parent; - p_RotateLeft4(t_node); - } - t_node->m_parent->m_color=1; - t_node->m_parent->m_parent->m_color=-1; - p_RotateRight4(t_node->m_parent->m_parent); - } - }else{ - c_Node5* t_uncle2=t_node->m_parent->m_parent->m_left; - if(((t_uncle2)!=0) && t_uncle2->m_color==-1){ - t_node->m_parent->m_color=1; - t_uncle2->m_color=1; - t_uncle2->m_parent->m_color=-1; - t_node=t_uncle2->m_parent; - }else{ - if(t_node==t_node->m_parent->m_left){ - t_node=t_node->m_parent; - p_RotateRight4(t_node); - } - t_node->m_parent->m_color=1; - t_node->m_parent->m_parent->m_color=-1; - p_RotateLeft4(t_node->m_parent->m_parent); - } - } - } - m_root->m_color=1; - return 0; -} -bool c_Map4::p_Add5(String t_key,String t_value){ - c_Node5* t_node=m_root; - c_Node5* t_parent=0; - int t_cmp=0; - while((t_node)!=0){ - t_parent=t_node; - t_cmp=p_Compare2(t_key,t_node->m_key); - if(t_cmp>0){ - t_node=t_node->m_right; - }else{ - if(t_cmp<0){ - t_node=t_node->m_left; - }else{ - return false; - } - } - } - t_node=(new c_Node5)->m_new(t_key,t_value,-1,t_parent); - if((t_parent)!=0){ - if(t_cmp>0){ - t_parent->m_right=t_node; - }else{ - t_parent->m_left=t_node; - } - p_InsertFixup4(t_node); - }else{ - m_root=t_node; - } - return true; -} -bool c_Map4::p_Set2(String t_key,String t_value){ - c_Node5* t_node=m_root; - c_Node5* t_parent=0; - int t_cmp=0; - while((t_node)!=0){ - t_parent=t_node; - t_cmp=p_Compare2(t_key,t_node->m_key); - if(t_cmp>0){ - t_node=t_node->m_right; - }else{ - if(t_cmp<0){ - t_node=t_node->m_left; - }else{ - t_node->m_value=t_value; - return false; - } - } - } - t_node=(new c_Node5)->m_new(t_key,t_value,-1,t_parent); - if((t_parent)!=0){ - if(t_cmp>0){ - t_parent->m_right=t_node; - }else{ - t_parent->m_left=t_node; - } - p_InsertFixup4(t_node); - }else{ - m_root=t_node; - } - return true; -} -c_Node5* c_Map4::p_FirstNode(){ - if(!((m_root)!=0)){ - return 0; - } - c_Node5* t_node=m_root; - while((t_node->m_left)!=0){ - t_node=t_node->m_left; - } - return t_node; -} -c_NodeEnumerator* c_Map4::p_ObjectEnumerator(){ - return (new c_NodeEnumerator)->m_new(p_FirstNode()); -} -void c_Map4::mark(){ - Object::mark(); -} -c_StringMap4::c_StringMap4(){ -} -c_StringMap4* c_StringMap4::m_new(){ - c_Map4::m_new(); - return this; -} -int c_StringMap4::p_Compare2(String t_lhs,String t_rhs){ - return t_lhs.Compare(t_rhs); -} -void c_StringMap4::mark(){ - c_Map4::mark(); -} -c_Node5::c_Node5(){ - m_key=String(); - m_right=0; - m_left=0; - m_value=String(); - m_color=0; - m_parent=0; -} -c_Node5* c_Node5::m_new(String t_key,String t_value,int t_color,c_Node5* t_parent){ - this->m_key=t_key; - this->m_value=t_value; - this->m_color=t_color; - this->m_parent=t_parent; - return this; -} -c_Node5* c_Node5::m_new2(){ - return this; -} -c_Node5* c_Node5::p_NextNode(){ - c_Node5* t_node=0; - if((m_right)!=0){ - t_node=m_right; - while((t_node->m_left)!=0){ - t_node=t_node->m_left; - } - return t_node; - } - t_node=this; - c_Node5* t_parent=this->m_parent; - while(((t_parent)!=0) && t_node==t_parent->m_right){ - t_node=t_parent; - t_parent=t_parent->m_parent; - } - return t_parent; -} -String c_Node5::p_Key(){ - return m_key; -} -String c_Node5::p_Value(){ - return m_value; -} -void c_Node5::mark(){ - Object::mark(); -} -c_NodeEnumerator::c_NodeEnumerator(){ - m_node=0; -} -c_NodeEnumerator* c_NodeEnumerator::m_new(c_Node5* t_node){ - this->m_node=t_node; - return this; -} -c_NodeEnumerator* c_NodeEnumerator::m_new2(){ - return this; -} -bool c_NodeEnumerator::p_HasNext(){ - return m_node!=0; -} -c_Node5* c_NodeEnumerator::p_NextObject(){ - c_Node5* t_t=m_node; - m_node=m_node->p_NextNode(); - return t_t; -} -void c_NodeEnumerator::mark(){ - Object::mark(); -} -c_PageMaker::c_PageMaker(){ - m__template=String(); - m__decls=(new c_StringMap)->m_new(); - m__scopes=(new c_Stack4)->m_new(); - m__lists=(new c_Stack5)->m_new(); - m__iters=(new c_IntStack)->m_new2(); -} -c_PageMaker* c_PageMaker::m_new(String t_template){ - m__template=t_template; - m__scopes->p_Push10(m__decls); - return this; -} -c_PageMaker* c_PageMaker::m_new2(){ - return this; -} -void c_PageMaker::p_Clear(){ - m__decls->p_Clear(); - m__scopes->p_Clear(); - m__scopes->p_Push10(m__decls); - m__lists->p_Clear(); -} -void c_PageMaker::p_SetString(String t_name,String t_value){ - m__scopes->p_Top()->p_Set(t_name,((new c_StringObject)->m_new3(t_value))); -} -void c_PageMaker::p_BeginList(String t_name){ - c_Stack4* t_list=(new c_Stack4)->m_new(); - m__scopes->p_Top()->p_Set(t_name,(t_list)); - m__scopes->p_Push10(0); - m__lists->p_Push13(t_list); -} -void c_PageMaker::p_AddItem(){ - c_StringMap* t_scope=(new c_StringMap)->m_new(); - m__scopes->p_Pop(); - m__scopes->p_Push10(t_scope); - m__lists->p_Top()->p_Push10(t_scope); -} -void c_PageMaker::p_EndList(){ - m__scopes->p_Pop(); - m__lists->p_Pop(); -} -Object* c_PageMaker::p_GetValue(String t_name){ - for(int t_i=m__scopes->p_Length2()-1;t_i>=0;t_i=t_i+-1){ - c_StringMap* t_sc=m__scopes->p_Get(t_i); - if(t_sc->p_Contains(t_name)){ - return t_sc->p_Get2(t_name); - } - } - return 0; -} -String c_PageMaker::p_GetString(String t_name){ - Object* t_val=p_GetValue(t_name); - c_StringObject* t_str=dynamic_cast(t_val); - if((t_str)!=0){ - return t_str->m_value; - } - c_Stack4* t_list=dynamic_cast(t_val); - if(((t_list)!=0) && ((t_list->p_Length2())!=0)){ - return String(t_list->p_Length2()); - } - return String(); -} -c_Stack4* c_PageMaker::p_GetList(String t_name){ - Object* t_val=p_GetValue(t_name); - c_Stack4* t_list=dynamic_cast(t_val); - if(((t_list)!=0) && ((t_list->p_Length2())!=0)){ - return t_list; - } - return 0; -} -String c_PageMaker::p_MakePage(){ - m__iters->p_Clear(); - m__lists->p_Clear(); - m__scopes->p_Clear(); - m__scopes->p_Push10(m__decls); - c_StringStack* t_output=(new c_StringStack)->m_new2(); - int t_i=0; - int t_ifnest=0; - int t_iftrue=0; - do{ - int t_i0=m__template.Find(String(L"${",2),t_i); - if(t_i0==-1){ - break; - } - int t_i1=m__template.Find(String(L"}",1),t_i0+2); - if(t_i1==-1){ - break; - } - bool t_cc=t_ifnest==t_iftrue; - if(t_cc && t_ip_Push(m__template.Slice(t_i,t_i0)); - } - t_i=t_i1+1; - Array t_bits=m__template.Slice(t_i0+2,t_i1).Split(String(L" ",1)).Resize(5); - String t_1=t_bits[0]; - if(t_1==String(L"IF",2)){ - t_ifnest+=1; - if(t_cc){ - int t_i2=1; - bool t_inv=false; - if(t_bits[t_i2]==String(L"NOT",3)){ - t_inv=true; - t_i2+=1; - } - if(t_bits[t_i2]==String(L"FIRST",5)){ - t_cc=m__iters->p_Get(m__iters->p_Length2()-2)==0; - }else{ - if(t_bits[t_i2]==String(L"LAST",4)){ - t_cc=m__iters->p_Get(m__iters->p_Length2()-2)==m__lists->p_Top()->p_Length2()-1; - }else{ - if(t_bits[t_i2+1]==String(L"EQ",2)){ - t_cc=p_GetString(t_bits[t_i2])==t_bits[t_i2+2]; - }else{ - if(t_bits[t_i2+1]==String(L"NE",2)){ - t_cc=p_GetString(t_bits[t_i2])!=t_bits[t_i2+2]; - }else{ - t_cc=p_GetString(t_bits[t_i2])!=String(); - } - } - } - } - if(t_inv){ - t_cc=!t_cc; - } - if(t_cc){ - t_iftrue=t_ifnest; - } - } - }else{ - if(t_1==String(L"ENDIF",5)){ - t_ifnest-=1; - t_iftrue=bb_math_Min(t_iftrue,t_ifnest); - }else{ - if(t_1==String(L"FOR",3)){ - t_ifnest+=1; - if(t_cc){ - c_Stack4* t_list=p_GetList(t_bits[1]); - if((t_list)!=0){ - t_iftrue=t_ifnest; - m__iters->p_Push7(0); - m__iters->p_Push7(t_i); - m__lists->p_Push13(t_list); - m__scopes->p_Push10(t_list->p_Get(0)); - } - } - }else{ - if(t_1==String(L"NEXT",4)){ - if(t_cc){ - m__scopes->p_Pop(); - c_Stack4* t_list2=m__lists->p_Top(); - int t_p=m__iters->p_Pop(); - int t_j=m__iters->p_Pop()+1; - if(t_jp_Length2()){ - m__iters->p_Push7(t_j); - m__iters->p_Push7(t_p); - m__scopes->p_Push10(t_list2->p_Get(t_j)); - t_i=t_p; - }else{ - m__lists->p_Pop(); - } - } - t_ifnest-=1; - t_iftrue=bb_math_Min(t_iftrue,t_ifnest); - }else{ - if(t_cc){ - String t_str=p_GetString(t_bits[0]); - if((t_str).Length()!=0){ - t_output->p_Push(t_str); - } - } - } - } - } - } - }while(!(false)); - if(t_ip_Push(m__template.Slice(t_i)); - } - return t_output->p_Join(String()); -} -void c_PageMaker::mark(){ - Object::mark(); -} -c_Stack4::c_Stack4(){ - m_data=Array(); - m_length=0; -} -c_Stack4* c_Stack4::m_new(){ - return this; -} -c_Stack4* c_Stack4::m_new2(Array t_data){ - this->m_data=t_data.Slice(0); - this->m_length=t_data.Length(); - return this; -} -void c_Stack4::p_Push10(c_StringMap* t_value){ - if(m_length==m_data.Length()){ - m_data=m_data.Resize(m_length*2+10); - } - m_data[m_length]=t_value; - m_length+=1; -} -void c_Stack4::p_Push11(Array t_values,int t_offset,int t_count){ - for(int t_i=0;t_i t_values,int t_offset){ - p_Push11(t_values,t_offset,t_values.Length()-t_offset); -} -c_StringMap* c_Stack4::m_NIL; -void c_Stack4::p_Clear(){ - for(int t_i=0;t_im_data.Length()){ - m_data=m_data.Resize(bb_math_Max(m_length*2+10,t_newlength)); - } - } - m_length=t_newlength; -} -int c_Stack4::p_Length2(){ - return m_length; -} -c_StringMap* c_Stack4::p_Get(int t_index){ - return m_data[t_index]; -} -void c_Stack4::mark(){ - Object::mark(); -} -c_Markdown::c_Markdown(){ - m__resolver=0; - m__prettifier=0; - m__blk=String(); -} -c_Markdown* c_Markdown::m_new(c_ILinkResolver* t_resolver,c_IPrettifier* t_prettifier){ - m__resolver=t_resolver; - m__prettifier=t_prettifier; - return this; -} -c_Markdown* c_Markdown::m_new2(){ - return this; -} -String c_Markdown::p_Prettify(String t_text){ - if((m__prettifier)!=0){ - return m__prettifier->p_PrettifyLine(t_text); - } - return t_text; -} -String c_Markdown::p_SetBlock(String t_blk){ - String t_t=String(); - if(m__blk!=t_blk){ - if(m__blk==String(L"pre",3) && ((m__prettifier)!=0)){ - t_t=m__prettifier->p_EndPrettyBlock(); - }else{ - if((m__blk).Length()!=0){ - t_t=String(L"",1); - if((t_blk).Length()!=0){ - t_t=t_t+String(L"\n",1); - } - } - } - m__blk=t_blk; - if(m__blk==String(L"pre",3) && ((m__prettifier)!=0)){ - t_t=t_t+m__prettifier->p_BeginPrettyBlock(); - }else{ - if((m__blk).Length()!=0){ - t_t=t_t+(String(L"<",1)+m__blk+String(L">",1)); - t_t=t_t+String(L"\n",1); - } - } - } - return t_t; -} -int c_Markdown::p_Find3(String t_src,String t_text,int t_start){ - do{ - int t_i=t_src.Find(t_text,t_start); - if(t_i==-1){ - return -1; - } - int t_j=t_i; - while(t_j>0 && (int)t_src[t_j-1]==92){ - t_j-=1; - } - if(t_j!=t_i && (t_i-t_j&1)==1){ - t_start=t_i+t_text.Length(); - }else{ - return t_i; - } - }while(!(false)); -} -String c_Markdown::p_ReplaceSpanTags(String t_src,String t_tag,String t_html){ - int t_i=0; - int t_l=t_tag.Length(); - do{ - int t_i0=p_Find3(t_src,t_tag,t_i); - if(t_i0==-1){ - break; - } - int t_i1=p_Find3(t_src,t_tag,t_i0+t_l); - if(t_i1==-1 || t_i1==t_i0+t_l){ - break; - } - String t_r=String(L"<",1)+t_html+String(L">",1)+t_src.Slice(t_i0+t_l,t_i1)+String(L"",1); - t_src=t_src.Slice(0,t_i0)+t_r+t_src.Slice(t_i1+t_l); - t_i=t_i0+t_r.Length(); - }while(!(false)); - return t_src; -} -String c_Markdown::p_ReplacePrefixTags(String t_src,String t_tag,String t_html){ - int t_i=0; - int t_l=t_tag.Length(); - do{ - int t_i0=p_Find3(t_src,t_tag,t_i); - if(t_i0==-1){ - break; - } - int t_i1=t_i0+t_l; - while(t_i1=65 && t_c<=90 || t_c>=97 && t_c<=122 || t_i1>t_i0+t_l && t_c>=48 && t_c<=57){ - t_i1+=1; - continue; - } - break; - } - if(t_i1==t_i0+t_l){ - t_i+=t_l; - continue; - } - String t_r=String(L"<",1)+t_html+String(L">",1)+t_src.Slice(t_i0+t_l,t_i1)+String(L"",1); - t_src=t_src.Slice(0,t_i0)+t_r+t_src.Slice(t_i1); - t_i=t_i0+t_r.Length(); - }while(!(false)); - return t_src; -} -String c_Markdown::p_ReplaceLinks(String t_src){ - int t_i=0; - do{ - int t_i0=p_Find3(t_src,String(L"[[",2),t_i); - if(t_i0==-1){ - break; - } - int t_i1=p_Find3(t_src,String(L"]]",2),t_i0+2); - if(t_i1==-1){ - break; - } - String t_p=t_src.Slice(t_i0+2,t_i1); - String t_t=String(); - int t_j=t_p.Find(String(L"|",1),0); - if(t_j!=-1){ - t_t=t_p.Slice(t_j+1); - t_p=t_p.Slice(0,t_j); - } - String t_r=m__resolver->p_ResolveLink(t_p,t_t); - t_src=t_src.Slice(0,t_i0)+t_r+t_src.Slice(t_i1+2); - t_i=t_i0+t_r.Length(); - }while(!(false)); - t_i=0; - do{ - int t_i02=p_Find3(t_src,String(L"![",2),t_i); - if(t_i02==-1){ - break; - } - int t_i12=p_Find3(t_src,String(L"](",2),t_i02+1); - if(t_i12==-1 || t_i12==t_i02+1){ - break; - } - int t_i2=p_Find3(t_src,String(L")",1),t_i12+2); - if(t_i2==-1 || t_i2==t_i12+2){ - break; - } - String t_t2=t_src.Slice(t_i02+2,t_i12); - String t_p2=t_src.Slice(t_i12+2,t_i2); - String t_r2=m__resolver->p_ResolveLink(String(L"",5)+t_p2,t_t2); - t_src=t_src.Slice(0,t_i02)+t_r2+t_src.Slice(t_i2+1); - t_i=t_i02+t_r2.Length(); - }while(!(false)); - t_i=0; - do{ - int t_i03=p_Find3(t_src,String(L"[",1),t_i); - if(t_i03==-1){ - break; - } - int t_i13=p_Find3(t_src,String(L"](",2),t_i03+1); - if(t_i13==-1 || t_i13==t_i03+1){ - break; - } - int t_i22=p_Find3(t_src,String(L")",1),t_i13+2); - if(t_i22==-1 || t_i22==t_i13+2){ - break; - } - String t_t3=t_src.Slice(t_i03+1,t_i13); - String t_p3=t_src.Slice(t_i13+2,t_i22); - String t_r3=m__resolver->p_ResolveLink(t_p3,t_t3); - t_src=t_src.Slice(0,t_i03)+t_r3+t_src.Slice(t_i22+1); - t_i=t_i03+t_r3.Length(); - }while(!(false)); - return t_src; -} -String c_Markdown::p_ReplaceEscs(String t_src){ - int t_i=0; - do{ - int t_i0=t_src.Find(String(L"\\",1),t_i); - if(t_i0==-1){ - break; - } - String t_r=t_src.Slice(t_i0+1,t_i0+2); - String t_1=t_r; - if(t_1==String(L"<",1)){ - t_r=String(L"<",4); - }else{ - if(t_1==String(L">",1)){ - t_r=String(L">",4); - }else{ - if(t_1==String(L"&",1)){ - t_r=String(L"&",5); - } - } - } - t_src=t_src.Slice(0,t_i0)+t_r+t_src.Slice(t_i0+2); - t_i=t_i0+t_r.Length(); - }while(!(false)); - return t_src; -} -String c_Markdown::p_SpanToHtml(String t_src){ - t_src=p_ReplaceSpanTags(t_src,String(L"`",1),String(L"code",4)); - t_src=p_ReplaceSpanTags(t_src,String(L"*",1),String(L"b",1)); - t_src=p_ReplaceSpanTags(t_src,String(L"%",1),String(L"i",1)); - t_src=p_ReplacePrefixTags(t_src,String(L"@",1),String(L"b",1)); - t_src=p_ReplaceLinks(t_src); - t_src=p_ReplaceEscs(t_src); - return t_src; -} -String c_Markdown::p_LineToHtml(String t_src){ - if(m__blk==String(L"pre",3)){ - int t_i=t_src.Find(String(L"
",6),0); - if(t_i==-1){ - return p_Prettify(t_src); - } - if((t_src.Slice(0,t_i).Trim()).Length()!=0){ - return p_Prettify(t_src.Slice(0,t_i))+p_SetBlock(String()); - } - return p_SetBlock(String()); - } - if(!((t_src).Length()!=0)){ - if(m__blk==String(L"ol",2) || m__blk==String(L"ul",2)){ - return String(L"",9); - }else{ - if(m__blk==String()){ - return String(); - }else{ - return p_SetBlock(String()); - } - } - } - if(t_src==String(L"-",1) || t_src==String(L"--",2) || t_src==String(L"---",3)){ - return p_SetBlock(String())+String(L"
",4); - } - if(t_src.StartsWith(String(L"
",5))){
-		String t_t=p_SetBlock(String(L"pre",3));
-		String t_source=t_src.Slice(5).Trim();
-		if(t_source.EndsWith(String(L"
",6))){ - t_source=t_source.Slice(0,-6); - } - if((t_source).Length()!=0){ - return t_t+p_Prettify(t_source); - } - return t_t; - } - if(t_src.StartsWith(String(L"| ",2))){ - t_src=p_SpanToHtml(t_src); - c_StringStack* t_bits=(new c_StringStack)->m_new2(); - int t_i2=1; - do{ - int t_i0=p_Find3(t_src,String(L"|",1),t_i2); - if(t_i0==-1){ - break; - } - t_bits->p_Push(t_src.Slice(t_i2,t_i0).Trim()); - t_i2=t_i0+1; - }while(!(false)); - t_bits->p_Push(t_src.Slice(t_i2).Trim()); - String t_tag=String(L"td",2); - if(m__blk!=String(L"table",5)){ - t_tag=String(L"th",2); - } - return p_SetBlock(String(L"table",5))+String(L"<",5)+t_tag+String(L">",1)+t_bits->p_Join(String(L"<",2)+t_tag+String(L">",1))+String(L"",6); - } - if(t_src.StartsWith(String(L">",1))){ - int t_i3=1; - while(t_i3",1)+t_src+String(L"",1); - } - } - if(t_src.StartsWith(String(L"* ",2))){ - String t_t3=p_SetBlock(String(L"ul",2)); - return t_t3+String(L"
  • ",4)+p_SpanToHtml(t_src.Slice(2))+String(L"
  • ",5); - } - if(t_src.StartsWith(String(L"+ ",2))){ - String t_t4=p_SetBlock(String(L"ol",2)); - return t_t4+String(L"
  • ",4)+p_SpanToHtml(t_src.Slice(2))+String(L"
  • ",5); - } - String t_t5=p_SetBlock(String(L"p",1)); - int t_i4=p_Find3(t_src,String(L"~n",2),t_src.Length()-2); - if(t_i4!=-1){ - t_src=t_src.Slice(0,-2)+String(L"
    ",4); - } - t_src=p_SpanToHtml(t_src); - return t_t5+t_src; -} -String c_Markdown::p_ToHtml(String t_src){ - String t_html=String(); - if(t_src.Contains(String(L"\n",1))){ - c_StringStack* t_buf=(new c_StringStack)->m_new2(); - Array t_=t_src.Split(String(L"\n",1)); - int t_2=0; - while(t_2p_Push(t_html); - } - } - t_html=t_buf->p_Join(String(L"\n",1)); - }else{ - t_html=p_LineToHtml(t_src); - } - if((m__blk).Length()!=0){ - return t_html+String(L"\n",1)+p_SetBlock(String()); - } - return t_html; -} -void c_Markdown::mark(){ - Object::mark(); -} -c_Stack5::c_Stack5(){ - m_data=Array(); - m_length=0; -} -c_Stack5* c_Stack5::m_new(){ - return this; -} -c_Stack5* c_Stack5::m_new2(Array t_data){ - this->m_data=t_data.Slice(0); - this->m_length=t_data.Length(); - return this; -} -c_Stack4* c_Stack5::m_NIL; -void c_Stack5::p_Clear(){ - for(int t_i=0;t_i t_values,int t_offset,int t_count){ - for(int t_i=0;t_i t_values,int t_offset){ - p_Push14(t_values,t_offset,t_values.Length()-t_offset); -} -c_Stack4* c_Stack5::p_Top(){ - return m_data[m_length-1]; -} -c_Stack4* c_Stack5::p_Pop(){ - m_length-=1; - c_Stack4* t_v=m_data[m_length]; - m_data[m_length]=m_NIL; - return t_v; -} -void c_Stack5::mark(){ - Object::mark(); -} -c_StringObject::c_StringObject(){ - m_value=String(); -} -c_StringObject* c_StringObject::m_new(int t_value){ - this->m_value=String(t_value); - return this; -} -c_StringObject* c_StringObject::m_new2(Float t_value){ - this->m_value=String(t_value); - return this; -} -c_StringObject* c_StringObject::m_new3(String t_value){ - this->m_value=t_value; - return this; -} -c_StringObject* c_StringObject::m_new4(){ - return this; -} -void c_StringObject::mark(){ - Object::mark(); -} -String bb_stringutil_HtmlEscape(String t_str){ - return t_str.Replace(String(L"&",1),String(L"&",5)).Replace(String(L"<",1),String(L"<",4)).Replace(String(L">",1),String(L">",4)); -} -int bb_math_Min(int t_x,int t_y){ - if(t_xm_node=t_node; - return this; -} -c_NodeEnumerator2* c_NodeEnumerator2::m_new2(){ - return this; -} -bool c_NodeEnumerator2::p_HasNext(){ - return m_node!=0; -} -c_Node4* c_NodeEnumerator2::p_NextObject(){ - c_Node4* t_t=m_node; - m_node=m_node->p_NextNode(); - return t_t; -} -void c_NodeEnumerator2::mark(){ - Object::mark(); -} -c_NodeEnumerator3::c_NodeEnumerator3(){ - m_node=0; -} -c_NodeEnumerator3* c_NodeEnumerator3::m_new(c_Node3* t_node){ - this->m_node=t_node; - return this; -} -c_NodeEnumerator3* c_NodeEnumerator3::m_new2(){ - return this; -} -bool c_NodeEnumerator3::p_HasNext(){ - return m_node!=0; -} -c_Node3* c_NodeEnumerator3::p_NextObject(){ - c_Node3* t_t=m_node; - m_node=m_node->p_NextNode(); - return t_t; -} -void c_NodeEnumerator3::mark(){ - Object::mark(); -} -int bbMain(){ - (new c_Makedocs)->m_new(); - return 0; -} -int bbInit(){ - GC_CTOR - c_DocDecl::m__uid=0; - c_Stack2::m_NIL=0; - c_Toker::m__keywords=0; - c_Toker::m__symbols=0; - c_Stack::m_NIL=String(); - c_Stack3::m_NIL=0; - c_DocDecl::m__root=0; - c_DocDecl::m__modroot=0; - c_DocDecl::m__modules=0; - c_DocDecl::m__docroot=0; - c_DocDecl::m__documents=0; - c_DocDecl::m__primnames=(new c_StringStack)->m_new2(); - c_DocDecl::m__primlinks=(new c_StringMap2)->m_new(); - c_DocDecl::m__searchid=0; - c_Makedocs::m_resolvecode=0; - c_Stack4::m_NIL=0; - c_Stack5::m_NIL=0; - return 0; -} -void gc_mark(){ -} -//${TRANSCODE_END} - -String BBPathToFilePath( String path ){ - return path; -} - -int main( int argc,const char **argv ){ - - new BBGame(); - - try{ - - bb_std_main( argc,argv ); - - }catch( ThrowableObject *ex ){ - - bbPrint( "Cerberus Runtime Error : Uncaught Cerberus Exception" ); - - }catch( const char *err ){ - - } -} diff --git a/src/makedocs/makedocs.build/cpptool/main.h b/src/makedocs/makedocs.build/cpptool/main.h deleted file mode 100644 index 9b0538b3..00000000 --- a/src/makedocs/makedocs.build/cpptool/main.h +++ /dev/null @@ -1,35 +0,0 @@ - -//Lang/OS... -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if _WIN32 -#include -#include -#include -#undef LoadString - -#elif __APPLE__ -#include -#include -#include -#include -#include -#include - -#elif __linux -#include -#include -#include -#include -#endif - -#define _QUOTE(X) #X -#define _STRINGIZE( X ) _QUOTE(X) diff --git a/src/makedocs/makedocs.cxs b/src/makedocs/makedocs.cxs index 64f7ad66..bae1154f 100644 --- a/src/makedocs/makedocs.cxs +++ b/src/makedocs/makedocs.cxs @@ -100,7 +100,7 @@ Import apidoccer Import docdoccer '=============================================================================== -Const VERSION:String = "2019-01-20" +Const VERSION:String = "2020-04-26" '=============================================================================== ' path settings diff --git a/src/rebuildall.bmx b/src/rebuildall.bmx index b5dd20b9..64e2f3cd 100644 --- a/src/rebuildall.bmx +++ b/src/rebuildall.bmx @@ -1,8 +1,8 @@ -'RebuildTranscc +RebuildTranscc 'RebuildMakedocs 'RebuildMServer -RebuildLauncher 'Note: On Windows, kill process Cerberus.exe before rebuilding launcher! +'RebuildLauncher 'Note: On Windows, kill process Cerberus.exe before rebuilding launcher! End diff --git a/src/rebuildall.ps1 b/src/rebuildall.ps1 index c68043fb..703ce928 100644 --- a/src/rebuildall.ps1 +++ b/src/rebuildall.ps1 @@ -1,10 +1,12 @@ -# Windows Powershell build script -# TO DO: The cserver needs to be rewritten so it doesn't need BlitzMax +# Windows Powershell build script + +# NOTES: VISUAL STUDIO 2017/2019 +# See: https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=vs-2019 + param( - [string]$mingw = "D:\Applications\Compilers\TDM-GCC-64", #"C:\Mingw", - [string]$qtsdk = "D:\dev\sdk\qt\windows\Qt5\5.5\msvc2013_64", #"C:\Qt\5.5\msvc2013_64", - [string]$visualstudio = "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC", - [string]$qtspec = "win32-msvc2013", + [string]$mingw = "C:\TDM-GCC-64", #"C:\Mingw", + [string]$qtsdk = "C:\Qt\5.9.2\msvc2017_64", + [string]$visualstudio = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build", [bool]$qtdbg = 0, [bool]$buildtrans = 1, [bool]$buildLauncher = 1, @@ -123,11 +125,13 @@ if(Test-Path ..\bin\transcc_winnt.exe){ #Make cserver if(Test-Path ..\bin\cserver_winnt.exe) { remove-item ..\bin\cserver_winnt.exe -force + } write-host "building cserver" - ../bin/transcc_winnt -target="Desktop_Game_(Glfw3)" -builddir="cserver.build" -clean -config="release" +CPP_GC_MODE=1 "cserver\cserver.cxs" + ../bin/transcc_winnt -target="Desktop_Game" -builddir="cserver.build" -clean -config="release" +CPP_GC_MODE=1 "cserver\cserver.cxs" Move-Item cserver\cserver.build\glfw3\gcc_winnt\Release"$arch"\CerberusGame.exe ..\bin\cserver_winnt.exe + Move-Item cserver\cserver.build\glfw3\gcc_winnt\Release"$arch"\data ..\bin\data # Move the openal dll and licence text if(-Not (Test-Path ..\bin\openal.dll)) { @@ -147,7 +151,7 @@ if(Test-Path ..\bin\transcc_winnt.exe){ Remove-Item cserver\cserver.build\glfw3\gcc_winnt\Release"$arch"\Openal32_COPYING ..\bin\OPENAL32_COPYING } } - ErrorMsg "ERROR: Failed to build cserver!" + #ErrorMsg "ERROR: Failed to build cserver!" } } @@ -172,7 +176,7 @@ if($buildted) { New-Item build-ted-Desktop-Release -type directory cd build-ted-Desktop-Release - qmake -spec $qtspec ../ted/ted.pro + qmake ../ted/ted.pro if($qtdbg) { cmd /c nmake -f Makefile.Debug @@ -189,7 +193,7 @@ if($buildted) { windeployqt $deplpoy --no-svg --no-angle --no-compiler-runtime --no-system-d3d-compiler --no-quick-import --no-translations --core ..\bin\Ted.exe $folders = "audio","bearer","imageformats","mediaservice","playlistformats","position","printsupport","sensors","sensorgestures","sqldrivers","opengl32sw.dll" foreach($folder in $folders){ - Remove-Item ..\bin\$folder -Force -Recurse + Remove-Item ..\bin\$folder -Force -Recurse -ErrorAction Ignore } } diff --git a/src/rebuildall.sh b/src/rebuildall.sh index 74f0bea7..0caa421b 100644 --- a/src/rebuildall.sh +++ b/src/rebuildall.sh @@ -5,29 +5,72 @@ echo "building transcc" g++ -O3 -DNDEBUG -o ../bin/transcc_linux transcc/transcc.build/cpptool/main.cpp -lpthread #Make makedocs +echo echo "building makedocs" ../bin/transcc_linux -target=C++_Tool -builddir=makedocs.build -clean -config=release +CPP_GC_MODE=0 makedocs/makedocs.cxs mv makedocs/makedocs.build/cpptool/main_linux ../bin/makedocs_linux rm -rf makedocs/makedocs.build #Make cserver +echo echo "building cserver" -../bin/transcc_linux "-target=Desktop_Game_(Glfw3)" -builddir=cserver.build -clean -config=release +CPP_GC_MODE=1 cserver/cserver.cxs +../bin/transcc_linux "-target=Desktop_Game" -builddir=cserver.build -clean -config=release +CPP_GC_MODE=1 cserver/cserver.cxs mv cserver/cserver.build/glfw3/gcc_linux/Release/CerberusGame ../bin/cserver_linux + +# Make sure that there is a copy of the CX standard font in the bin directory +mv cserver/cserver.build/glfw3/gcc_linux/Release/data ../bin/data rm -rf cserver/cserver.build #Make launcher +echo echo "building launcher" ../bin/transcc_linux -target=C++_Tool -builddir=launcher.build -clean -config=release +CPP_GC_MODE=0 launcher/launcher.cxs mv launcher/launcher.build/cpptool/main_linux ../Cerberus rm -rf launcher/launcher.build #Make ted +echo echo "building ted" rm -rf build-ted-Desktop-Release mkdir build-ted-Desktop-Release cd build-ted-Desktop-Release -qmake ../ted/ted.pro -make + +# Check to see if there is a Qt SDK directory in the users home folder. +if [ -d "$HOME/Qt" ]; then + + if [ -z $1 ]; then + QTVER="5.9.2" + else + QTVER=$1 + fi + + echo "Qt SDK Located....." + echo "Testing for qmake in $HOME/Qt/$QTVER/gcc_64" + + export PATH="$HOME/Qt:$HOME/Qt/$QTVER/gcc_64/bin:$PATH" + if hash qmake 2>/dev/null; then + qmake CONFIG+=release ../ted/ted.pro + else + echo "Cannot locate qmake. Check your Qt SDK installation and the version passed." + exit 1 + fi + + make + make install +else + # The Qt SDK isn't installed in the home directory, so + # check for one of the known qmake variants. + if hash qmake-qt5 2>/dev/null; then + qmake-qt5 CONFIG+=release ../ted/ted.pro + elif hash qt5-qmake 2>/dev/null; then + qmake-qt5 CONFIG+=release ../ted/ted.pro + else + echo "Unknown Qt SDK. Going with the default qmake." + echo "Expect errors......" + qmake CONFIG+=release ../ted/ted.pro + fi + make +fi + cd .. -rm -rf build-ted-Desktop-Release +rm -rf build-ted-Desktop-Release \ No newline at end of file diff --git a/src/rebuildall_macos.sh b/src/rebuildall_macos.sh new file mode 100755 index 00000000..62be3b89 --- /dev/null +++ b/src/rebuildall_macos.sh @@ -0,0 +1,63 @@ +#Quick and nasty linux shell rebuild all +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +#Make transcc +echo "building transcc" +clang++ -O3 -DNDEBUG -o ../bin/transcc_macos transcc/transcc.build/cpptool/main.cpp -Wno-bitwise-op-parentheses -Wno-logical-op-parentheses + +#Make makedocs +echo +echo "building makedocs" +../bin/transcc_macos -target=C++_Tool -builddir=makedocs.build -clean -config=release +CPP_GC_MODE=0 makedocs/makedocs.cxs +mv makedocs/makedocs.build/cpptool/main_macos ../bin/makedocs_macos +rm -rf makedocs/makedocs.build + +#Make cserver +echo +echo "building cserver" +../bin/transcc_macos "-target=Desktop_Game" -builddir=cserver.build -clean -config=release +CPP_GC_MODE=1 cserver/cserver.cxs + +mv cserver/cserver.build/glfw3/xcode/build/Release/CerberusGame.app ../bin/cserver_macos.app +rm -rf cserver/cserver.build + +#Make launcher +echo +echo "building launcher" +defaults write $DIR/launcher/xcode/cerberus-launcher/info.plist CFBundleIdentifier -string "com.whiteskygames.cserver_macos" +xcodebuild -scheme Cerberus -configuration release -project $DIR/launcher/xcode/Cerberus.xcodeproj -derivedDataPath $DIR/launcher/launcher.build +mv launcher/launcher.build/Build/Products/Release/Cerberus.app ../Cerberus.app +rm -rf launcher/launcher.build + +#Make ted +echo +echo "building ted" +rm -rf build-ted-Desktop-Release +mkdir build-ted-Desktop-Release +cd build-ted-Desktop-Release + +# Check to see if there is a Qt SDK directory in the users home folder. +if [ -d "$HOME/Qt" ]; then + + if [ -z $1 ]; then + QTVER="5.9.2" + else + QTVER=$1 + fi + + echo "Qt SDK Located....." + echo "Testing for qmake in $HOME/Qt/$QTVER/clang_64" + + export PATH="$HOME/Qt:$HOME/Qt/$QTVER/clang_64/bin:$PATH" + if hash qmake 2>/dev/null; then + qmake CONFIG+=release ../ted/ted.pro + else + echo "Cannot locate qmake. Check your Qt SDK installation and the version passed." + exit 1 + fi + + make + make install +fi + +cd .. +rm -rf build-ted-Desktop-Release diff --git a/src/ted/mainwindow.cpp b/src/ted/mainwindow.cpp index 82f37181..780d24bf 100644 --- a/src/ted/mainwindow.cpp +++ b/src/ted/mainwindow.cpp @@ -39,7 +39,7 @@ Change Log #include -#define TED_VERSION "2019-10-13" +#define TED_VERSION "2020-05-05" #define SETTINGS_VERSION 2 diff --git a/src/transcc/builder.cxs b/src/transcc/builder.cxs index a9d1dd4e..a00da2aa 100644 --- a/src/transcc/builder.cxs +++ b/src/transcc/builder.cxs @@ -2,6 +2,12 @@ Import transcc Import reflection.reflector +Import "native/stb_image.cpp" +Import "native/stb_image.h" +Import "native/stb_image_write.h" +Import "native/stb_image_resize.h" +Import "native/image.cpp" + Class Builder Method New( tcc:TransCC ) @@ -165,20 +171,46 @@ Class Builder CopyFile src,dst Endif End + + Method MakeIcons:Void(srcFilename:String,icons:String[],round:Int=False) + Local iconPath:=ExtractDir(StripExt( tcc.opt_srcpath )) + Local iconFile:String = RealPath(iconPath+"\"+srcFilename) + + If Not FileType( iconFile )=FILETYPE_FILE Then iconFile = RealPath(srcFilename) + + If FileType( iconFile )=FILETYPE_FILE +' If FileSize(iconFile) = FileSize(CurrentDir()+"\icon.cache") Then Return + + For Local i:Int = 0 Until icons.Length() Step 3 +' Print "building "+CurrentDir()+"/"+icons[i] + _CreateIcon(iconFile,CurrentDir()+"/"+icons[i],Int(icons[i+1]),Int(icons[i+2]),round) + Next + + ' cache icon file +' CopyFile (iconFile,CurrentDir()+"\icon.cache") + Endif + End - Method CopyIcon:Void() + Method CopyIcon:Void(iFile:String,targetIcon:String) If HostOS() = "winnt" - Local targetIcon:= CurrentDir()+"\cerberus.ico" Local iconPath:=ExtractDir(StripExt( tcc.opt_srcpath )) - Local iconFile:String = RealPath(iconPath+"\"+GetConfigVar( "GLFW_APP_ICON")) + local iconFile:String = RealPath(iconPath+"\"+iFile) If FileType( iconFile )=FILETYPE_FILE 'Print "Icon1== "+iconFile - CopyFile (iconFile,targetIcon) + If ExtractExt( iconFile).ToLower() = "ico" + CopyFile (iconFile,targetIcon) + Else + _ConvertToIco (iconFile,targetIcon) + End Else - iconFile = RealPath(GetConfigVar( "GLFW_APP_ICON")) + iconFile = iFile If FileType( iconFile )=FILETYPE_FILE 'Print "Icon2== "+iconFile - CopyFile (iconFile,targetIcon) + If ExtractExt( iconFile).ToLower() = "ico" + CopyFile (iconFile,targetIcon) + Else + _ConvertToIco (iconFile,targetIcon) + End Endif Endif Endif @@ -218,7 +250,7 @@ Class Builder Select FileType( p ) Case FILETYPE_FILE - If MatchPath( r,DATA_FILES ) + If MatchPath( r.ToLower(),DATA_FILES.ToLower() ) CCopyFile p,t udata.Insert t dataFiles.Set p,r @@ -237,7 +269,7 @@ Class Builder For Local p:=Eachin app.fileImports Local r:=StripDir( p ) Local t:=dir+"/"+r - If MatchPath( r,DATA_FILES ) + If MatchPath( r.ToLower(),DATA_FILES.ToLower() ) CCopyFile p,t udata.Insert t dataFiles.Set p,r @@ -280,4 +312,73 @@ Class Builder End + Method CopySourceFiles:Void( dir:String ) + dir=RealPath( dir ) + 'Local srcDir:= ExtractDir(tcc.opt_srcpath) + + For Local p:=Eachin app.fileIncludes + Local oSub:Bool = False + Local oExt:String = "*" + Local oOut:String = "" + Local src:String = "" + + Local p2:= p.Split(" ") + + For Local p3 := Eachin p2 + Select p3[..4] + Case "-sub" + oSub=True + Case "-ext" + oExt = p3[5..] + Case "-out" + oOut = p3[5..] + If (oOut[..1]="\" Or oOut[..1]="/") oOut = oOut[1..] + Local ol:= oOut.Length() + If (oOut[ol-1..]="\" Or oOut[ol-1..]="/") oOut = oOut[..ol-1] + Default + src = p3 + End + Next + + Local targetDir:= dir + If oOut.Length() > 0 + ' Create sub directories + targetDir += "/"+oOut + Local outs:= oOut.Split("/") + oOut = "" + For Local out := Eachin outs + oOut += "/"+out + If (FileType(dir+oOut) <> FILETYPE_DIR) CreateDir(dir+oOut) + Next + Endif + + Local exts := oExt.Split(";") + + If FileType(src)=FILETYPE_FILE + Local filename:=StripDir( src ) + CCopyFile src,targetDir+"/"+filename + Else + Local exts:=oExt.Split(";") + Local files:= LoadDir(src, oSub, False) + For Local file:= Eachin files + Local subDir:= ExtractDir(file) + + If (FileType(targetDir+"/"+subDir) <> FILETYPE_DIR) CreateDir(targetDir+"/"+subDir) + If FileType(src+"/"+file)=FILETYPE_FILE + For Local ext := Eachin exts + If ext = ExtractExt(file) Or ext = "*" + CCopyFile src+"/"+file,targetDir+"/"+file + Endif + Next + Endif + Next + Endif + Next + End + End + + +Extern +Function _CreateIcon:Void(srcFile:String,destFile:String,w:Int,h:Int,round:Int) +Function _ConvertToIco:Void(srcFile:String,destFile:String) diff --git a/src/transcc/builders/android.cxs b/src/transcc/builders/android.cxs index d9351741..ffdc409c 100644 --- a/src/transcc/builders/android.cxs +++ b/src/transcc/builders/android.cxs @@ -149,13 +149,48 @@ Class AndroidBuilder Extends Builder Local i:=src.FindLast( "/src/" ) If i<>-1 Local dst:=src[i+1..] - If CreateDirRecursive( ExtractDir( dst ) ) - CopyFile src,dst + If CreateDirRecursive( ExtractDir( "app/"+dst ) ) + CopyFile src,"app/"+dst + Endif + Endif + Case "xml" + Local i:=src.FindLast( "/src/" ) + If i<>-1 + Local dst:=src[i+1..] + If CreateDirRecursive( ExtractDir( "app/"+dst ) ) + Local str:=LoadString( src ) + str=ReplaceEnv( str ) + SaveString str,"app/"+dst Endif Endif End Next + ' make icons + If GetConfigVar( "ANDROID_APP_ICON") <> "" + Local iconfiles:String[] + + ' normal icons + iconfiles = ["app/src/main/res/mipmap-hdpi/ic_launcher.png","72","72", + "app/src/main/res/mipmap-mdpi/ic_launcher.png","48","48", + "app/src/main/res/mipmap-xhdpi/ic_launcher.png","96","96", + "app/src/main/res/mipmap-xxhdpi/ic_launcher.png","144","144", + "app/src/main/res/mipmap-xxxhdpi/ic_launcher.png","192","192"] + MakeIcons(GetConfigVar( "ANDROID_APP_ICON"),iconfiles) + + ' round icons + iconfiles = ["app/src/main/res/mipmap-hdpi/ic_launcher_round.png","72","72", + "app/src/main/res/mipmap-mdpi/ic_launcher_round.png","48","48", + "app/src/main/res/mipmap-xhdpi/ic_launcher_round.png","96","96", + "app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png","144","144", + "app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png","192","192"] + If GetConfigVar( "ANDROID_APP_ROUND_ICON")="" + MakeIcons(GetConfigVar( "ANDROID_APP_ICON"),iconfiles,True) + Else + MakeIcons(GetConfigVar( "ANDROID_APP_ROUND_ICON"),iconfiles) + End + End + If GetConfigVar( "ANDROID_NATIVE_GL_ENABLED" )="1" CopyDir "nativegl/libs","libs",True CreateDir "src/com" @@ -185,7 +220,7 @@ Class AndroidBuilder Extends Builder Local adb:="adb" If tcc.ANDROID_PATH adb="~q"+tcc.ANDROID_PATH+"/platform-tools/adb~q" Local _file:String = CurrentDir() - _file += "\app\build\outputs\apk\release\app-release.apk" + _file += "/app/build/outputs/apk/release/app-release.apk" Print ("installing "+_file+" ...") 'Execute adb+" logcat -c",False Execute adb+" install -r "+_file,False diff --git a/src/transcc/builders/flash.cxs b/src/transcc/builders/flash.cxs index df026528..7b8f8cd1 100644 --- a/src/transcc/builders/flash.cxs +++ b/src/transcc/builders/flash.cxs @@ -74,6 +74,8 @@ Class FlashBuilder Extends Builder DeleteFile "main.swf" + CopyIcon(GetConfigVar("FLASH_APP_ICON"),CurrentDir()+"\favicon.ico") + Execute "mxmlc"+cc_opts+" CerberusGame.as" If tcc.opt_run diff --git a/src/transcc/builders/glfw.cxs b/src/transcc/builders/glfw.cxs index 0360f696..cdfa954a 100644 --- a/src/transcc/builders/glfw.cxs +++ b/src/transcc/builders/glfw.cxs @@ -30,7 +30,10 @@ Class GlfwBuilder Extends Builder CreateDataDir dst+"/"+tconfig+"/data" - CopyIcon() + CopySourceFiles(".") + + ' need to rewrite resources.rc so that icon is rebuilt + CopyIcon(GetConfigVar( "GLFW_APP_ICON"),CurrentDir()+"/cerberus.ico") Local main:=LoadString( "main.cpp" ) @@ -129,7 +132,8 @@ Class GlfwBuilder Extends Builder CreateDataDir "msvc/"+casedConfig+"/data" - CopyIcon() + ' need to rewrite resources.rc so that icon is rebuilt + CopyIcon(GetConfigVar( "GLFW_APP_ICON"),CurrentDir()+"\cerberus.ico") Local main:=LoadString( "main.cpp" ) @@ -158,6 +162,8 @@ Class GlfwBuilder Extends Builder Method MakeXcode:Void() CreateDataDir "xcode/data" + + CopySourceFiles("xcode") Local main:=LoadString( "main.cpp" ) diff --git a/src/transcc/builders/html5.cxs b/src/transcc/builders/html5.cxs index 1d06002a..6fe263e1 100644 --- a/src/transcc/builders/html5.cxs +++ b/src/transcc/builders/html5.cxs @@ -140,15 +140,26 @@ Class Html5Builder Extends Builder Local meta:="var META_DATA=~q"+MetaData()+"~q;~n" Local main:=LoadString( "main.js" ) - main=ReplaceBlock( main,"TRANSCODE",transCode ) main=ReplaceBlock( main,"METADATA",meta ) main=ReplaceBlock( main,"CONFIG",Config() ) SaveString main,"main.js" - + + CopyIcon(GetConfigVar("HTML5_APP_ICON"),CurrentDir()+"\favicon.ico") + + + Local game:=LoadString( "CerberusGame.html" ) + game = game.Replace("%%HTML5_CONSOLE_SHOW%%", GetConfigVar("HTML5_CONSOLE_SHOW") ) + game = game.Replace("%%HTML5_APP_TITLE%%", GetConfigVar("HTML5_APP_TITLE") ) + game = game.Replace("%%HTML5_CANVAS_WIDTH%%", GetConfigVar("HTML5_CANVAS_WIDTH") ) + game = game.Replace("%%HTML5_CANVAS_HEIGHT%%", GetConfigVar("HTML5_CANVAS_HEIGHT") ) + game = game.Replace("%%HTML5_CANVAS_RESIZE_MODE%%", GetConfigVar("HTML5_CANVAS_RESIZE_MODE") ) + SaveString game, GetConfigVar("HTML5_APP_FILENAME") + + If tcc.opt_run - Local p:=RealPath( "CerberusGame.html" ) + Local p:=RealPath( GetConfigVar("HTML5_APP_FILENAME") ) Local t:=tcc.HTML_PLAYER+" ~q"+p+"~q" Execute t,False Endif diff --git a/src/transcc/builders/ios.cxs b/src/transcc/builders/ios.cxs index bb1d3e19..df83dbd2 100644 --- a/src/transcc/builders/ios.cxs +++ b/src/transcc/builders/ios.cxs @@ -227,9 +227,26 @@ Class IosBuilder Extends Builder Print ("Starting iOS simulator...") Execute "open ~q"+sim_path+"~q" Endif - CreateDataDir "data" + CreateDir "icons" + ' https://docs.microsoft.com/en-us/xamarin/ios/app-fundamentals/images-icons/app-icons?tabs=windows + Local iconfiles:String[] = ["icons/iphone-app-1x-60px.png","60","60", + "icons/iphone-app-2x-120px.png","120","120", + "icons/iphone-app-3x-180px.png","180","180", + "icons/iphone-spotlight-1x-40px.png","40","40", + "icons/iphone-spotlight-2x-80px.png","80","80", + "icons/iphone-spotlight-3x-120px.png","120","120", + "icons/iphone-settings-3x-87px.png","87","87", + "icons/ipad-app-1x-76px.png","76","76", + "icons/ipad-app-2x-152px.png","152","152", + "icons/ipad-app-3x-167px.png","167","167", + "icons/ipad-spotlight-1x-40px.png","40","40", + "icons/ipad-spotlight-2x-80px.png","80","80", + "icons/ipad-spotlight-3x-120px.png","120","120", + "icons/ipad-settings-3x-58px.png","58","58"] + MakeIcons(GetConfigVar( "IOS_APP_ICON"),iconfiles) + Local main:=LoadString( "main.mm" ) main=ReplaceBlock( main,"TRANSCODE",transCode ) diff --git a/src/transcc/builders/stdcpp.cxs b/src/transcc/builders/stdcpp.cxs index cc57bc8e..cffc9001 100644 --- a/src/transcc/builders/stdcpp.cxs +++ b/src/transcc/builders/stdcpp.cxs @@ -38,6 +38,8 @@ Class StdcppBuilder Extends Builder Case "profile" SetConfigVar "PROFILE","1" End + CopySourceFiles(".") + Local main:=LoadString( "main.cpp" ) main=ReplaceBlock( main,"TRANSCODE",transCode ) diff --git a/src/transcc/native/image.cpp b/src/transcc/native/image.cpp new file mode 100644 index 00000000..f7b3c19f --- /dev/null +++ b/src/transcc/native/image.cpp @@ -0,0 +1,156 @@ +#include +#include +#include + +std::string get_file_contents(const char *filename) +{ + std::ifstream in(filename, std::ios::in | std::ios::binary); + if (in) + { + std::string contents; + in.seekg(0, std::ios::end); + contents.resize(in.tellg()); + in.seekg(0, std::ios::beg); + in.read(&contents[0], contents.size()); + in.close(); + return(contents); + } +} + +std::ifstream::pos_type getFileSize(const char* filename) +{ + std::ifstream in(filename, std::ifstream::ate | std::ifstream::binary); + return in.tellg(); +} + +void _CreateIcon(String srcFilename, String dstFilename, int w, int h,int round) { + int width,height,n; + + stbi_uc *input_pixels = stbi_load(C_STR(srcFilename), &width, &height, &n, 4); + stbi_uc output_pixels[4*w*h]; + + stbir_resize_uint8(input_pixels,width,height,0, output_pixels, w,h,0,4); + + if (round) { + int i,r; + for (int x = 0; x < w; x++) { + for (int y = 0; y < h; y++) { + i = x + y*w; + r = sqrt(((w/2-x)*(w/2-x)) + ((h/2-y)*(h/2-y))); + if (r>w/2-1) { + output_pixels[i*4+3] = 0; + } + } + } + } + + stbi_write_png(C_STR(dstFilename), w, h, 4, &output_pixels, 0); +} + +// crudely build the icon file... file format on wiki +// https://en.wikipedia.org/wiki/ICO_(file_format) +void _ConvertToIco(String srcFilename,String destFilename) { + // widths for icons + int widths[] = {16,32,48,64,128,256}; + + // build indiviual icon files for icon file + int num_of_images=sizeof(widths) / sizeof(widths[0]);; + int size_of_files[num_of_images]; + int width; + int size_of_data=0; + int i=0; + while (i> 8) & 255; + + // image headers + int offset=6; + int data_pointer = 6+num_of_images*16; + + i=0; + while (i> 0) & 255; + new_data[offset+9] = (size_of_files[i] >> 8) & 255; + new_data[offset+10] = (size_of_files[i] >> 16) & 255; + new_data[offset+11] = (size_of_files[i] >> 24) & 255; + // offset to image data (little endian) + new_data[offset+12] = (data_pointer >> 0) & 255; + new_data[offset+13] = (data_pointer >> 8) & 255; + new_data[offset+14] = (data_pointer >> 16) & 255; + new_data[offset+15] = (data_pointer >> 24) & 255; + + offset = offset+16; + data_pointer = data_pointer + size_of_files[i]; + i++; + } + + // add data + data_pointer = 6+num_of_images*16; // end of header + + i=0; + while (i +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +#include +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STBIDEF +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// on most compilers (and ALL modern mainstream compilers) this is threadsafe +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define STBI_THREAD_LOCAL _Thread_local + #elif defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) +#endif +#endif + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#endif + +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif + +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +// assume GCC or Clang on ARM targets +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + fseek((FILE*) user, n, SEEK_CUR); +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +#ifndef STBI_NO_FAILURE_STRINGS +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} +#endif + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} +#endif + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} +#endif + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load_global = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +#ifndef STBI_NO_GIF +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} +#endif + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 8) { + STBI_ASSERT(ri.bits_per_channel == 16); + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 16) { + STBI_ASSERT(ri.bits_per_channel == 8); + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + return 0; + +#if _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else +static void stbi__skip(stbi__context *s, int n) +{ + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} +#endif + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + return z + (stbi__get16le(s) << 16); +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (stbi_uc) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + k = stbi_lrot(j->code_buffer, n); + STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & ~sgn); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc << j->succ_low); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[288]; + stbi__uint16 value[288]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + if (z->zbuffer >= z->zbuffer_end) return 0; + return *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + STBI_ASSERT(z->size[b] == s); + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) stbi__fill_bits(a); + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (int) (z->zout - z->zout_start); + limit = old_limit = (int) (z->zout_end - z->zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) + c = stbi__zreceive(a,3)+3; + else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a,7)+11; + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + STBI_ASSERT(a->num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[288] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior; + int filter = *raw++; + + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + STBI_ASSERT(img_width_bytes <= x); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes+1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*filter_bytes; + #define STBI__CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + } + #undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define STBI__CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ + for (k=0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; + } + #undef STBI__CASE + + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride*j; // start at the beginning of the row again + for (i=0; i < x; ++i,cur+=output_bytes) { + cur[filter_bytes+1] = 255; + } + } + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16*)cur; + + for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load = 0; +static int stbi__de_iphone_flag = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]={0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth < 8) + ri->bits_per_channel = 8; + else + ri->bits_per_channel = p->depth; + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(unsigned int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; + int extra_read; +} stbi__bmp_data; + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - info.extra_read - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + STBI_ASSERT(info.offset == (s->img_buffer - s->buffer_start)); + } + + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i]; p1[i] = p2[i]; p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispoase of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + void *tmp = (stbi_uc*) STBI_REALLOC( out, layers * stride ); + if (NULL == tmp) { + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + return stbi__errpuc("outofmem", "Out of memory"); + } + else + out = (stbi_uc*) tmp; + if (delays) { + *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + stbi__rewind( s ); + if (p == NULL) + return 0; + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + (void) stbi__get32be(s); + (void) stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) +// Does not support 16-bit-per-channel + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +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. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/src/transcc/native/stb_image_resize.h b/src/transcc/native/stb_image_resize.h new file mode 100644 index 00000000..42a8efb1 --- /dev/null +++ b/src/transcc/native/stb_image_resize.h @@ -0,0 +1,2631 @@ +/* stb_image_resize - v0.96 - public domain image resizing + by Jorge L Rodriguez (@VinoBS) - 2014 + http://github.com/nothings/stb + + Written with emphasis on usability, portability, and efficiency. (No + SIMD or threads, so it be easily outperformed by libs that use those.) + Only scaling and translation is supported, no rotations or shears. + Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation. + + COMPILING & LINKING + In one C/C++ file that #includes this file, do this: + #define STB_IMAGE_RESIZE_IMPLEMENTATION + before the #include. That will create the implementation in that file. + + QUICKSTART + stbir_resize_uint8( input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, num_channels) + stbir_resize_float(...) + stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, + num_channels , alpha_chan , 0) + stbir_resize_uint8_srgb_edgemode( + input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, + num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP) + // WRAP/REFLECT/ZERO + + FULL API + See the "header file" section of the source for API documentation. + + ADDITIONAL DOCUMENTATION + + SRGB & FLOATING POINT REPRESENTATION + The sRGB functions presume IEEE floating point. If you do not have + IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use + a slower implementation. + + MEMORY ALLOCATION + The resize functions here perform a single memory allocation using + malloc. To control the memory allocation, before the #include that + triggers the implementation, do: + + #define STBIR_MALLOC(size,context) ... + #define STBIR_FREE(ptr,context) ... + + Each resize function makes exactly one call to malloc/free, so to use + temp memory, store the temp memory in the context and return that. + + ASSERT + Define STBIR_ASSERT(boolval) to override assert() and not use assert.h + + OPTIMIZATION + Define STBIR_SATURATE_INT to compute clamp values in-range using + integer operations instead of float operations. This may be faster + on some platforms. + + DEFAULT FILTERS + For functions which don't provide explicit control over what filters + to use, you can change the compile-time defaults with + + #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something + #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something + + See stbir_filter in the header-file section for the list of filters. + + NEW FILTERS + A number of 1D filter kernels are used. For a list of + supported filters see the stbir_filter enum. To add a new filter, + write a filter function and add it to stbir__filter_info_table. + + PROGRESS + For interactive use with slow resize operations, you can install + a progress-report callback: + + #define STBIR_PROGRESS_REPORT(val) some_func(val) + + The parameter val is a float which goes from 0 to 1 as progress is made. + + For example: + + static void my_progress_report(float progress); + #define STBIR_PROGRESS_REPORT(val) my_progress_report(val) + + #define STB_IMAGE_RESIZE_IMPLEMENTATION + #include "stb_image_resize.h" + + static void my_progress_report(float progress) + { + printf("Progress: %f%%\n", progress*100); + } + + MAX CHANNELS + If your image has more than 64 channels, define STBIR_MAX_CHANNELS + to the max you'll have. + + ALPHA CHANNEL + Most of the resizing functions provide the ability to control how + the alpha channel of an image is processed. The important things + to know about this: + + 1. The best mathematically-behaved version of alpha to use is + called "premultiplied alpha", in which the other color channels + have had the alpha value multiplied in. If you use premultiplied + alpha, linear filtering (such as image resampling done by this + library, or performed in texture units on GPUs) does the "right + thing". While premultiplied alpha is standard in the movie CGI + industry, it is still uncommon in the videogame/real-time world. + + If you linearly filter non-premultiplied alpha, strange effects + occur. (For example, the 50/50 average of 99% transparent bright green + and 1% transparent black produces 50% transparent dark green when + non-premultiplied, whereas premultiplied it produces 50% + transparent near-black. The former introduces green energy + that doesn't exist in the source image.) + + 2. Artists should not edit premultiplied-alpha images; artists + want non-premultiplied alpha images. Thus, art tools generally output + non-premultiplied alpha images. + + 3. You will get best results in most cases by converting images + to premultiplied alpha before processing them mathematically. + + 4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the + resizer does not do anything special for the alpha channel; + it is resampled identically to other channels. This produces + the correct results for premultiplied-alpha images, but produces + less-than-ideal results for non-premultiplied-alpha images. + + 5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, + then the resizer weights the contribution of input pixels + based on their alpha values, or, equivalently, it multiplies + the alpha value into the color channels, resamples, then divides + by the resultant alpha value. Input pixels which have alpha=0 do + not contribute at all to output pixels unless _all_ of the input + pixels affecting that output pixel have alpha=0, in which case + the result for that pixel is the same as it would be without + STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for + input images in integer formats. For input images in float format, + input pixels with alpha=0 have no effect, and output pixels + which have alpha=0 will be 0 in all channels. (For float images, + you can manually achieve the same result by adding a tiny epsilon + value to the alpha channel of every image, and then subtracting + or clamping it at the end.) + + 6. You can suppress the behavior described in #5 and make + all-0-alpha pixels have 0 in all channels by #defining + STBIR_NO_ALPHA_EPSILON. + + 7. You can separately control whether the alpha channel is + interpreted as linear or affected by the colorspace. By default + it is linear; you almost never want to apply the colorspace. + (For example, graphics hardware does not apply sRGB conversion + to the alpha channel.) + + CONTRIBUTORS + Jorge L Rodriguez: Implementation + Sean Barrett: API design, optimizations + Aras Pranckevicius: bugfix + Nathan Reed: warning fixes + + REVISIONS + 0.97 (2020-02-02) fixed warning + 0.96 (2019-03-04) fixed warnings + 0.95 (2017-07-23) fixed warnings + 0.94 (2017-03-18) fixed warnings + 0.93 (2017-03-03) fixed bug with certain combinations of heights + 0.92 (2017-01-02) fix integer overflow on large (>2GB) images + 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions + 0.90 (2014-09-17) first released version + + LICENSE + See end of file for license information. + + TODO + Don't decode all of the image data when only processing a partial tile + Don't use full-width decode buffers when only processing a partial tile + When processing wide images, break processing into tiles so data fits in L1 cache + Installable filters? + Resize that respects alpha test coverage + (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage: + https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp ) +*/ + +#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H +#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H + +#ifdef _MSC_VER +typedef unsigned char stbir_uint8; +typedef unsigned short stbir_uint16; +typedef unsigned int stbir_uint32; +#else +#include +typedef uint8_t stbir_uint8; +typedef uint16_t stbir_uint16; +typedef uint32_t stbir_uint32; +#endif + +#ifndef STBIRDEF +#ifdef STB_IMAGE_RESIZE_STATIC +#define STBIRDEF static +#else +#ifdef __cplusplus +#define STBIRDEF extern "C" +#else +#define STBIRDEF extern +#endif +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// Easy-to-use API: +// +// * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4) +// * input_w is input image width (x-axis), input_h is input image height (y-axis) +// * stride is the offset between successive rows of image data in memory, in bytes. you can +// specify 0 to mean packed continuously in memory +// * alpha channel is treated identically to other channels. +// * colorspace is linear or sRGB as specified by function name +// * returned result is 1 for success or 0 in case of an error. +// #define STBIR_ASSERT() to trigger an assert on parameter validation errors. +// * Memory required grows approximately linearly with input and output size, but with +// discontinuities at input_w == output_w and input_h == output_h. +// * These functions use a "default" resampling filter defined at compile time. To change the filter, +// you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE +// and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API. + +STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels); + +STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels); + + +// The following functions interpret image data as gamma-corrected sRGB. +// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel, +// or otherwise provide the index of the alpha channel. Flags value +// of 0 will probably do the right thing if you're not sure what +// the flags mean. + +#define STBIR_ALPHA_CHANNEL_NONE -1 + +// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will +// use alpha-weighted resampling (effectively premultiplying, resampling, +// then unpremultiplying). +#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0) +// The specified alpha channel should be handled as gamma-corrected value even +// when doing sRGB operations. +#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1) + +STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags); + + +typedef enum +{ + STBIR_EDGE_CLAMP = 1, + STBIR_EDGE_REFLECT = 2, + STBIR_EDGE_WRAP = 3, + STBIR_EDGE_ZERO = 4, +} stbir_edge; + +// This function adds the ability to specify how requests to sample off the edge of the image are handled. +STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode); + +////////////////////////////////////////////////////////////////////////////// +// +// Medium-complexity API +// +// This extends the easy-to-use API as follows: +// +// * Alpha-channel can be processed separately +// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE +// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT) +// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED) +// * Filter can be selected explicitly +// * uint16 image type +// * sRGB colorspace available for all types +// * context parameter for passing to STBIR_MALLOC + +typedef enum +{ + STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses + STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios + STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering + STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque + STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline + STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3 +} stbir_filter; + +typedef enum +{ + STBIR_COLORSPACE_LINEAR, + STBIR_COLORSPACE_SRGB, + + STBIR_MAX_COLORSPACES, +} stbir_colorspace; + +// The following functions are all identical except for the type of the image data + +STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + +STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + +STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + + + +////////////////////////////////////////////////////////////////////////////// +// +// Full-complexity API +// +// This extends the medium API as follows: +// +// * uint32 image type +// * not typesafe +// * separate filter types for each axis +// * separate edge modes for each axis +// * can specify scale explicitly for subpixel correctness +// * can specify image source tile using texture coordinates + +typedef enum +{ + STBIR_TYPE_UINT8 , + STBIR_TYPE_UINT16, + STBIR_TYPE_UINT32, + STBIR_TYPE_FLOAT , + + STBIR_MAX_TYPES +} stbir_datatype; + +STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context); + +STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float x_scale, float y_scale, + float x_offset, float y_offset); + +STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float s0, float t0, float s1, float t1); +// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use. + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H + + + + + +#ifdef STB_IMAGE_RESIZE_IMPLEMENTATION + +#ifndef STBIR_ASSERT +#include +#define STBIR_ASSERT(x) assert(x) +#endif + +// For memset +#include + +#include + +#ifndef STBIR_MALLOC +#include +// use comma operator to evaluate c, to avoid "unused parameter" warnings +#define STBIR_MALLOC(size,c) ((void)(c), malloc(size)) +#define STBIR_FREE(ptr,c) ((void)(c), free(ptr)) +#endif + +#ifndef _MSC_VER +#ifdef __cplusplus +#define stbir__inline inline +#else +#define stbir__inline +#endif +#else +#define stbir__inline __forceinline +#endif + + +// should produce compiler error if size is wrong +typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBIR__NOTUSED(v) (void)(v) +#else +#define STBIR__NOTUSED(v) (void)sizeof(v) +#endif + +#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0])) + +#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE +#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM +#endif + +#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE +#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL +#endif + +#ifndef STBIR_PROGRESS_REPORT +#define STBIR_PROGRESS_REPORT(float_0_to_1) +#endif + +#ifndef STBIR_MAX_CHANNELS +#define STBIR_MAX_CHANNELS 64 +#endif + +#if STBIR_MAX_CHANNELS > 65536 +#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536." +// because we store the indices in 16-bit variables +#endif + +// This value is added to alpha just before premultiplication to avoid +// zeroing out color values. It is equivalent to 2^-80. If you don't want +// that behavior (it may interfere if you have floating point images with +// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to +// disable it. +#ifndef STBIR_ALPHA_EPSILON +#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20)) +#endif + + + +#ifdef _MSC_VER +#define STBIR__UNUSED_PARAM(v) (void)(v) +#else +#define STBIR__UNUSED_PARAM(v) (void)sizeof(v) +#endif + +// must match stbir_datatype +static unsigned char stbir__type_size[] = { + 1, // STBIR_TYPE_UINT8 + 2, // STBIR_TYPE_UINT16 + 4, // STBIR_TYPE_UINT32 + 4, // STBIR_TYPE_FLOAT +}; + +// Kernel function centered at 0 +typedef float (stbir__kernel_fn)(float x, float scale); +typedef float (stbir__support_fn)(float scale); + +typedef struct +{ + stbir__kernel_fn* kernel; + stbir__support_fn* support; +} stbir__filter_info; + +// When upsampling, the contributors are which source pixels contribute. +// When downsampling, the contributors are which destination pixels are contributed to. +typedef struct +{ + int n0; // First contributing pixel + int n1; // Last contributing pixel +} stbir__contributors; + +typedef struct +{ + const void* input_data; + int input_w; + int input_h; + int input_stride_bytes; + + void* output_data; + int output_w; + int output_h; + int output_stride_bytes; + + float s0, t0, s1, t1; + + float horizontal_shift; // Units: output pixels + float vertical_shift; // Units: output pixels + float horizontal_scale; + float vertical_scale; + + int channels; + int alpha_channel; + stbir_uint32 flags; + stbir_datatype type; + stbir_filter horizontal_filter; + stbir_filter vertical_filter; + stbir_edge edge_horizontal; + stbir_edge edge_vertical; + stbir_colorspace colorspace; + + stbir__contributors* horizontal_contributors; + float* horizontal_coefficients; + + stbir__contributors* vertical_contributors; + float* vertical_coefficients; + + int decode_buffer_pixels; + float* decode_buffer; + + float* horizontal_buffer; + + // cache these because ceil/floor are inexplicably showing up in profile + int horizontal_coefficient_width; + int vertical_coefficient_width; + int horizontal_filter_pixel_width; + int vertical_filter_pixel_width; + int horizontal_filter_pixel_margin; + int vertical_filter_pixel_margin; + int horizontal_num_contributors; + int vertical_num_contributors; + + int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter) + int ring_buffer_num_entries; // Total number of entries in the ring buffer. + int ring_buffer_first_scanline; + int ring_buffer_last_scanline; + int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer + float* ring_buffer; + + float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds. + + int horizontal_contributors_size; + int horizontal_coefficients_size; + int vertical_contributors_size; + int vertical_coefficients_size; + int decode_buffer_size; + int horizontal_buffer_size; + int ring_buffer_size; + int encode_buffer_size; +} stbir__info; + + +static const float stbir__max_uint8_as_float = 255.0f; +static const float stbir__max_uint16_as_float = 65535.0f; +static const double stbir__max_uint32_as_float = 4294967295.0; + + +static stbir__inline int stbir__min(int a, int b) +{ + return a < b ? a : b; +} + +static stbir__inline float stbir__saturate(float x) +{ + if (x < 0) + return 0; + + if (x > 1) + return 1; + + return x; +} + +#ifdef STBIR_SATURATE_INT +static stbir__inline stbir_uint8 stbir__saturate8(int x) +{ + if ((unsigned int) x <= 255) + return x; + + if (x < 0) + return 0; + + return 255; +} + +static stbir__inline stbir_uint16 stbir__saturate16(int x) +{ + if ((unsigned int) x <= 65535) + return x; + + if (x < 0) + return 0; + + return 65535; +} +#endif + +static float stbir__srgb_uchar_to_linear_float[256] = { + 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f, + 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f, + 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f, + 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f, + 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f, + 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f, + 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f, + 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f, + 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f, + 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f, + 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f, + 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f, + 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f, + 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f, + 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f, + 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f, + 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f, + 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f, + 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f, + 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f, + 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f, + 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f, + 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f, + 0.982251f, 0.991102f, 1.0f +}; + +static float stbir__srgb_to_linear(float f) +{ + if (f <= 0.04045f) + return f / 12.92f; + else + return (float)pow((f + 0.055f) / 1.055f, 2.4f); +} + +static float stbir__linear_to_srgb(float f) +{ + if (f <= 0.0031308f) + return f * 12.92f; + else + return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f; +} + +#ifndef STBIR_NON_IEEE_FLOAT +// From https://gist.github.com/rygorous/2203834 + +typedef union +{ + stbir_uint32 u; + float f; +} stbir__FP32; + +static const stbir_uint32 fp32_to_srgb8_tab4[104] = { + 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d, + 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a, + 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033, + 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067, + 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5, + 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2, + 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143, + 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af, + 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240, + 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300, + 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401, + 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559, + 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723, +}; + +static stbir_uint8 stbir__linear_to_srgb_uchar(float in) +{ + static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps + static const stbir__FP32 minval = { (127-13) << 23 }; + stbir_uint32 tab,bias,scale,t; + stbir__FP32 f; + + // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively. + // The tests are carefully written so that NaNs map to 0, same as in the reference + // implementation. + if (!(in > minval.f)) // written this way to catch NaNs + in = minval.f; + if (in > almostone.f) + in = almostone.f; + + // Do the table lookup and unpack bias, scale + f.f = in; + tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20]; + bias = (tab >> 16) << 9; + scale = tab & 0xffff; + + // Grab next-highest mantissa bits and perform linear interpolation + t = (f.u >> 12) & 0xff; + return (unsigned char) ((bias + scale*t) >> 16); +} + +#else +// sRGB transition values, scaled by 1<<28 +static int stbir__srgb_offset_to_linear_scaled[256] = +{ + 0, 40738, 122216, 203693, 285170, 366648, 448125, 529603, + 611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926, + 1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148, + 2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856, + 3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731, + 5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369, + 7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021, + 10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073, + 13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389, + 17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552, + 21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066, + 25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490, + 31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568, + 36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316, + 43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096, + 49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700, + 57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376, + 65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912, + 74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648, + 83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512, + 93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072, + 104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544, + 115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832, + 127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528, + 140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968, + 154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184, + 168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992, + 183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968, + 199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480, + 215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656, + 232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464, + 250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664, +}; + +static stbir_uint8 stbir__linear_to_srgb_uchar(float f) +{ + int x = (int) (f * (1 << 28)); // has headroom so you don't need to clamp + int v = 0; + int i; + + // Refine the guess with a short binary search. + i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + + return (stbir_uint8) v; +} +#endif + +static float stbir__filter_trapezoid(float x, float scale) +{ + float halfscale = scale / 2; + float t = 0.5f + halfscale; + STBIR_ASSERT(scale <= 1); + + x = (float)fabs(x); + + if (x >= t) + return 0; + else + { + float r = 0.5f - halfscale; + if (x <= r) + return 1; + else + return (t - x) / scale; + } +} + +static float stbir__support_trapezoid(float scale) +{ + STBIR_ASSERT(scale <= 1); + return 0.5f + scale / 2; +} + +static float stbir__filter_triangle(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x <= 1.0f) + return 1 - x; + else + return 0; +} + +static float stbir__filter_cubic(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return (4 + x*x*(3*x - 6))/6; + else if (x < 2.0f) + return (8 + x*(-12 + x*(6 - x)))/6; + + return (0.0f); +} + +static float stbir__filter_catmullrom(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return 1 - x*x*(2.5f - 1.5f*x); + else if (x < 2.0f) + return 2 - x*(4 + x*(0.5f*x - 2.5f)); + + return (0.0f); +} + +static float stbir__filter_mitchell(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return (16 + x*x*(21 * x - 36))/18; + else if (x < 2.0f) + return (32 + x*(-60 + x*(36 - 7*x)))/18; + + return (0.0f); +} + +static float stbir__support_zero(float s) +{ + STBIR__UNUSED_PARAM(s); + return 0; +} + +static float stbir__support_one(float s) +{ + STBIR__UNUSED_PARAM(s); + return 1; +} + +static float stbir__support_two(float s) +{ + STBIR__UNUSED_PARAM(s); + return 2; +} + +static stbir__filter_info stbir__filter_info_table[] = { + { NULL, stbir__support_zero }, + { stbir__filter_trapezoid, stbir__support_trapezoid }, + { stbir__filter_triangle, stbir__support_one }, + { stbir__filter_cubic, stbir__support_two }, + { stbir__filter_catmullrom, stbir__support_two }, + { stbir__filter_mitchell, stbir__support_two }, +}; + +stbir__inline static int stbir__use_upsampling(float ratio) +{ + return ratio > 1; +} + +stbir__inline static int stbir__use_width_upsampling(stbir__info* stbir_info) +{ + return stbir__use_upsampling(stbir_info->horizontal_scale); +} + +stbir__inline static int stbir__use_height_upsampling(stbir__info* stbir_info) +{ + return stbir__use_upsampling(stbir_info->vertical_scale); +} + +// This is the maximum number of input samples that can affect an output sample +// with the given filter +static int stbir__get_filter_pixel_width(stbir_filter filter, float scale) +{ + STBIR_ASSERT(filter != 0); + STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + + if (stbir__use_upsampling(scale)) + return (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2); + else + return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale); +} + +// This is how much to expand buffers to account for filters seeking outside +// the image boundaries. +static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale) +{ + return stbir__get_filter_pixel_width(filter, scale) / 2; +} + +static int stbir__get_coefficient_width(stbir_filter filter, float scale) +{ + if (stbir__use_upsampling(scale)) + return (int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2); + else + return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2); +} + +static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size) +{ + if (stbir__use_upsampling(scale)) + return output_size; + else + return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2); +} + +static int stbir__get_total_horizontal_coefficients(stbir__info* info) +{ + return info->horizontal_num_contributors + * stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale); +} + +static int stbir__get_total_vertical_coefficients(stbir__info* info) +{ + return info->vertical_num_contributors + * stbir__get_coefficient_width (info->vertical_filter, info->vertical_scale); +} + +static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n) +{ + return &contributors[n]; +} + +// For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample, +// if you change it here change it there too. +static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c) +{ + int width = stbir__get_coefficient_width(filter, scale); + return &coefficients[width*n + c]; +} + +static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max) +{ + switch (edge) + { + case STBIR_EDGE_ZERO: + return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later + + case STBIR_EDGE_CLAMP: + if (n < 0) + return 0; + + if (n >= max) + return max - 1; + + return n; // NOTREACHED + + case STBIR_EDGE_REFLECT: + { + if (n < 0) + { + if (n < max) + return -n; + else + return max - 1; + } + + if (n >= max) + { + int max2 = max * 2; + if (n >= max2) + return 0; + else + return max2 - n - 1; + } + + return n; // NOTREACHED + } + + case STBIR_EDGE_WRAP: + if (n >= 0) + return (n % max); + else + { + int m = (-n) % max; + + if (m != 0) + m = max - m; + + return (m); + } + // NOTREACHED + + default: + STBIR_ASSERT(!"Unimplemented edge type"); + return 0; + } +} + +stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max) +{ + // avoid per-pixel switch + if (n >= 0 && n < max) + return n; + return stbir__edge_wrap_slow(edge, n, max); +} + +// What input pixels contribute to this output pixel? +static void stbir__calculate_sample_range_upsample(int n, float out_filter_radius, float scale_ratio, float out_shift, int* in_first_pixel, int* in_last_pixel, float* in_center_of_out) +{ + float out_pixel_center = (float)n + 0.5f; + float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius; + float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius; + + float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio; + float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio; + + *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio; + *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5)); + *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5)); +} + +// What output pixels does this input pixel contribute to? +static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radius, float scale_ratio, float out_shift, int* out_first_pixel, int* out_last_pixel, float* out_center_of_in) +{ + float in_pixel_center = (float)n + 0.5f; + float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius; + float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius; + + float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift; + float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift; + + *out_center_of_in = in_pixel_center * scale_ratio - out_shift; + *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5)); + *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5)); +} + +static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group) +{ + int i; + float total_filter = 0; + float filter_scale; + + STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. + + contributor->n0 = in_first_pixel; + contributor->n1 = in_last_pixel; + + STBIR_ASSERT(contributor->n1 >= contributor->n0); + + for (i = 0; i <= in_last_pixel - in_first_pixel; i++) + { + float in_pixel_center = (float)(i + in_first_pixel) + 0.5f; + coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale); + + // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.) + if (i == 0 && !coefficient_group[i]) + { + contributor->n0 = ++in_first_pixel; + i--; + continue; + } + + total_filter += coefficient_group[i]; + } + + STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0); + + STBIR_ASSERT(total_filter > 0.9); + STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off. + + // Make sure the sum of all coefficients is 1. + filter_scale = 1 / total_filter; + + for (i = 0; i <= in_last_pixel - in_first_pixel; i++) + coefficient_group[i] *= filter_scale; + + for (i = in_last_pixel - in_first_pixel; i >= 0; i--) + { + if (coefficient_group[i]) + break; + + // This line has no weight. We can skip it. + contributor->n1 = contributor->n0 + i - 1; + } +} + +static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group) +{ + int i; + + STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. + + contributor->n0 = out_first_pixel; + contributor->n1 = out_last_pixel; + + STBIR_ASSERT(contributor->n1 >= contributor->n0); + + for (i = 0; i <= out_last_pixel - out_first_pixel; i++) + { + float out_pixel_center = (float)(i + out_first_pixel) + 0.5f; + float x = out_pixel_center - out_center_of_in; + coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio; + } + + STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0); + + for (i = out_last_pixel - out_first_pixel; i >= 0; i--) + { + if (coefficient_group[i]) + break; + + // This line has no weight. We can skip it. + contributor->n1 = contributor->n0 + i - 1; + } +} + +static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size) +{ + int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); + int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio); + int i, j; + int skip; + + for (i = 0; i < output_size; i++) + { + float scale; + float total = 0; + + for (j = 0; j < num_contributors; j++) + { + if (i >= contributors[j].n0 && i <= contributors[j].n1) + { + float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0); + total += coefficient; + } + else if (i < contributors[j].n0) + break; + } + + STBIR_ASSERT(total > 0.9f); + STBIR_ASSERT(total < 1.1f); + + scale = 1 / total; + + for (j = 0; j < num_contributors; j++) + { + if (i >= contributors[j].n0 && i <= contributors[j].n1) + *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale; + else if (i < contributors[j].n0) + break; + } + } + + // Optimize: Skip zero coefficients and contributions outside of image bounds. + // Do this after normalizing because normalization depends on the n0/n1 values. + for (j = 0; j < num_contributors; j++) + { + int range, max, width; + + skip = 0; + while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0) + skip++; + + contributors[j].n0 += skip; + + while (contributors[j].n0 < 0) + { + contributors[j].n0++; + skip++; + } + + range = contributors[j].n1 - contributors[j].n0 + 1; + max = stbir__min(num_coefficients, range); + + width = stbir__get_coefficient_width(filter, scale_ratio); + for (i = 0; i < max; i++) + { + if (i + skip >= width) + break; + + *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip); + } + + continue; + } + + // Using min to avoid writing into invalid pixels. + for (i = 0; i < num_contributors; i++) + contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1); +} + +// Each scan line uses the same kernel values so we should calculate the kernel +// values once and then we can use them for every scan line. +static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size) +{ + int n; + int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); + + if (stbir__use_upsampling(scale_ratio)) + { + float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio; + + // Looping through out pixels + for (n = 0; n < total_contributors; n++) + { + float in_center_of_out; // Center of the current out pixel in the in pixel space + int in_first_pixel, in_last_pixel; + + stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out); + + stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); + } + } + else + { + float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio; + + // Looping through in pixels + for (n = 0; n < total_contributors; n++) + { + float out_center_of_in; // Center of the current out pixel in the in pixel space + int out_first_pixel, out_last_pixel; + int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio); + + stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in); + + stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); + } + + stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size); + } +} + +static float* stbir__get_decode_buffer(stbir__info* stbir_info) +{ + // The 0 index of the decode buffer starts after the margin. This makes + // it okay to use negative indexes on the decode buffer. + return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels]; +} + +#define STBIR__DECODE(type, colorspace) ((int)(type) * (STBIR_MAX_COLORSPACES) + (int)(colorspace)) + +static void stbir__decode_scanline(stbir__info* stbir_info, int n) +{ + int c; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int input_w = stbir_info->input_w; + size_t input_stride_bytes = stbir_info->input_stride_bytes; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir_edge edge_horizontal = stbir_info->edge_horizontal; + stbir_edge edge_vertical = stbir_info->edge_vertical; + size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes; + const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset; + int max_x = input_w + stbir_info->horizontal_filter_pixel_margin; + int decode = STBIR__DECODE(type, colorspace); + + int x = -stbir_info->horizontal_filter_pixel_margin; + + // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input, + // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO + if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h)) + { + for (; x < max_x; x++) + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + return; + } + + switch (decode) + { + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]]; + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float)); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c]; + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel]; + } + + break; + + default: + STBIR_ASSERT(!"Unknown type/colorspace/channels combination."); + break; + } + + if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED)) + { + for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++) + { + int decode_pixel_index = x * channels; + + // If the alpha value is 0 it will clobber the color values. Make sure it's not. + float alpha = decode_buffer[decode_pixel_index + alpha_channel]; +#ifndef STBIR_NO_ALPHA_EPSILON + if (stbir_info->type != STBIR_TYPE_FLOAT) { + alpha += STBIR_ALPHA_EPSILON; + decode_buffer[decode_pixel_index + alpha_channel] = alpha; + } +#endif + for (c = 0; c < channels; c++) + { + if (c == alpha_channel) + continue; + + decode_buffer[decode_pixel_index + c] *= alpha; + } + } + } + + if (edge_horizontal == STBIR_EDGE_ZERO) + { + for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++) + { + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + } + for (x = input_w; x < max_x; x++) + { + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + } + } +} + +static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length) +{ + return &ring_buffer[index * ring_buffer_length]; +} + +static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n) +{ + int ring_buffer_index; + float* ring_buffer; + + stbir_info->ring_buffer_last_scanline = n; + + if (stbir_info->ring_buffer_begin_index < 0) + { + ring_buffer_index = stbir_info->ring_buffer_begin_index = 0; + stbir_info->ring_buffer_first_scanline = n; + } + else + { + ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries; + STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index); + } + + ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float)); + memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes); + + return ring_buffer; +} + + +static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer) +{ + int x, k; + int output_w = stbir_info->output_w; + int channels = stbir_info->channels; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; + float* horizontal_coefficients = stbir_info->horizontal_coefficients; + int coefficient_width = stbir_info->horizontal_coefficient_width; + + for (x = 0; x < output_w; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int out_pixel_index = x * channels; + int coefficient_group = coefficient_width * x; + int coefficient_counter = 0; + + STBIR_ASSERT(n1 >= n0); + STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); + + switch (channels) { + case 1: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 1; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + } + break; + case 2: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 2; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + } + break; + case 3: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 3; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + } + break; + case 4: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 4; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient; + } + break; + default: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * channels; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + int c; + STBIR_ASSERT(coefficient != 0); + for (c = 0; c < channels; c++) + output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; + } + break; + } + } +} + +static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer) +{ + int x, k; + int input_w = stbir_info->input_w; + int channels = stbir_info->channels; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; + float* horizontal_coefficients = stbir_info->horizontal_coefficients; + int coefficient_width = stbir_info->horizontal_coefficient_width; + int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin; + int max_x = input_w + filter_pixel_margin * 2; + + STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info)); + + switch (channels) { + case 1: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 1; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 1; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + } + } + break; + + case 2: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 2; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 2; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + } + } + break; + + case 3: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 3; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 3; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + } + } + break; + + case 4: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 4; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 4; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient; + } + } + break; + + default: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * channels; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int c; + int out_pixel_index = k * channels; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + for (c = 0; c < channels; c++) + output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; + } + } + break; + } +} + +static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n) +{ + // Decode the nth scanline from the source image into the decode buffer. + stbir__decode_scanline(stbir_info, n); + + // Now resample it into the ring buffer. + if (stbir__use_width_upsampling(stbir_info)) + stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n)); + else + stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n)); + + // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling. +} + +static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n) +{ + // Decode the nth scanline from the source image into the decode buffer. + stbir__decode_scanline(stbir_info, n); + + memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float)); + + // Now resample it into the horizontal buffer. + if (stbir__use_width_upsampling(stbir_info)) + stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer); + else + stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer); + + // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers. +} + +// Get the specified scan line from the ring buffer. +static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length) +{ + int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries; + return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length); +} + + +static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode) +{ + int x; + int n; + int num_nonalpha; + stbir_uint16 nonalpha[STBIR_MAX_CHANNELS]; + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) + { + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + float alpha = encode_buffer[pixel_index + alpha_channel]; + float reciprocal_alpha = alpha ? 1.0f / alpha : 0; + + // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb + for (n = 0; n < channels; n++) + if (n != alpha_channel) + encode_buffer[pixel_index + n] *= reciprocal_alpha; + + // We added in a small epsilon to prevent the color channel from being deleted with zero alpha. + // Because we only add it for integer types, it will automatically be discarded on integer + // conversion, so we don't need to subtract it back out (which would be problematic for + // numeric precision reasons). + } + } + + // build a table of all channels that need colorspace correction, so + // we don't perform colorspace correction on channels that don't need it. + for (x = 0, num_nonalpha = 0; x < channels; ++x) + { + if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) + { + nonalpha[num_nonalpha++] = (stbir_uint16)x; + } + } + + #define STBIR__ROUND_INT(f) ((int) ((f)+0.5)) + #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5)) + + #ifdef STBIR__SATURATE_INT + #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float )) + #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float)) + #else + #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float ) + #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float) + #endif + + switch (decode) + { + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]); + } + + if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]); + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]); + } + + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((float*)output_buffer)[index] = encode_buffer[index]; + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel]; + } + break; + + default: + STBIR_ASSERT(!"Unknown type/colorspace/channels combination."); + break; + } +} + +static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n) +{ + int x, k; + int output_w = stbir_info->output_w; + stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; + float* vertical_coefficients = stbir_info->vertical_coefficients; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int ring_buffer_entries = stbir_info->ring_buffer_num_entries; + void* output_data = stbir_info->output_data; + float* encode_buffer = stbir_info->encode_buffer; + int decode = STBIR__DECODE(type, colorspace); + int coefficient_width = stbir_info->vertical_coefficient_width; + int coefficient_counter; + int contributor = n; + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; + int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + + int n0,n1, output_row_start; + int coefficient_group = coefficient_width * contributor; + + n0 = vertical_contributors[contributor].n0; + n1 = vertical_contributors[contributor].n1; + + output_row_start = n * stbir_info->output_stride_bytes; + + STBIR_ASSERT(stbir__use_height_upsampling(stbir_info)); + + memset(encode_buffer, 0, output_w * sizeof(float) * channels); + + // I tried reblocking this for better cache usage of encode_buffer + // (using x_outer, k, x_inner), but it lost speed. -- stb + + coefficient_counter = 0; + switch (channels) { + case 1: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 1; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + } + } + break; + case 2: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 2; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + } + } + break; + case 3: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 3; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient; + } + } + break; + case 4: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 4; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient; + encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient; + } + } + break; + default: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * channels; + int c; + for (c = 0; c < channels; c++) + encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient; + } + } + break; + } + stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode); +} + +static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n) +{ + int x, k; + int output_w = stbir_info->output_w; + stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; + float* vertical_coefficients = stbir_info->vertical_coefficients; + int channels = stbir_info->channels; + int ring_buffer_entries = stbir_info->ring_buffer_num_entries; + float* horizontal_buffer = stbir_info->horizontal_buffer; + int coefficient_width = stbir_info->vertical_coefficient_width; + int contributor = n + stbir_info->vertical_filter_pixel_margin; + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; + int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + int n0,n1; + + n0 = vertical_contributors[contributor].n0; + n1 = vertical_contributors[contributor].n1; + + STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info)); + + for (k = n0; k <= n1; k++) + { + int coefficient_index = k - n0; + int coefficient_group = coefficient_width * contributor; + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + + switch (channels) { + case 1: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 1; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + } + break; + case 2: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 2; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + } + break; + case 3: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 3; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient; + } + break; + case 4: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 4; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient; + ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient; + } + break; + default: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * channels; + + int c; + for (c = 0; c < channels; c++) + ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient; + } + break; + } + } +} + +static void stbir__buffer_loop_upsample(stbir__info* stbir_info) +{ + int y; + float scale_ratio = stbir_info->vertical_scale; + float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio; + + STBIR_ASSERT(stbir__use_height_upsampling(stbir_info)); + + for (y = 0; y < stbir_info->output_h; y++) + { + float in_center_of_out = 0; // Center of the current out scanline in the in scanline space + int in_first_scanline = 0, in_last_scanline = 0; + + stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out); + + STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); + + if (stbir_info->ring_buffer_begin_index >= 0) + { + // Get rid of whatever we don't need anymore. + while (in_first_scanline > stbir_info->ring_buffer_first_scanline) + { + if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline) + { + // We just popped the last scanline off the ring buffer. + // Reset it to the empty state. + stbir_info->ring_buffer_begin_index = -1; + stbir_info->ring_buffer_first_scanline = 0; + stbir_info->ring_buffer_last_scanline = 0; + break; + } + else + { + stbir_info->ring_buffer_first_scanline++; + stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries; + } + } + } + + // Load in new ones. + if (stbir_info->ring_buffer_begin_index < 0) + stbir__decode_and_resample_upsample(stbir_info, in_first_scanline); + + while (in_last_scanline > stbir_info->ring_buffer_last_scanline) + stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1); + + // Now all buffers should be ready to write a row of vertical sampling. + stbir__resample_vertical_upsample(stbir_info, y); + + STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h); + } +} + +static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline) +{ + int output_stride_bytes = stbir_info->output_stride_bytes; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int output_w = stbir_info->output_w; + void* output_data = stbir_info->output_data; + int decode = STBIR__DECODE(type, colorspace); + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + + if (stbir_info->ring_buffer_begin_index >= 0) + { + // Get rid of whatever we don't need anymore. + while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline) + { + if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h) + { + int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes; + float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length); + stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode); + STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h); + } + + if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline) + { + // We just popped the last scanline off the ring buffer. + // Reset it to the empty state. + stbir_info->ring_buffer_begin_index = -1; + stbir_info->ring_buffer_first_scanline = 0; + stbir_info->ring_buffer_last_scanline = 0; + break; + } + else + { + stbir_info->ring_buffer_first_scanline++; + stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries; + } + } + } +} + +static void stbir__buffer_loop_downsample(stbir__info* stbir_info) +{ + int y; + float scale_ratio = stbir_info->vertical_scale; + int output_h = stbir_info->output_h; + float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio; + int pixel_margin = stbir_info->vertical_filter_pixel_margin; + int max_y = stbir_info->input_h + pixel_margin; + + STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info)); + + for (y = -pixel_margin; y < max_y; y++) + { + float out_center_of_in; // Center of the current out scanline in the in scanline space + int out_first_scanline, out_last_scanline; + + stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in); + + STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); + + if (out_last_scanline < 0 || out_first_scanline >= output_h) + continue; + + stbir__empty_ring_buffer(stbir_info, out_first_scanline); + + stbir__decode_and_resample_downsample(stbir_info, y); + + // Load in new ones. + if (stbir_info->ring_buffer_begin_index < 0) + stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline); + + while (out_last_scanline > stbir_info->ring_buffer_last_scanline) + stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1); + + // Now the horizontal buffer is ready to write to all ring buffer rows. + stbir__resample_vertical_downsample(stbir_info, y); + } + + stbir__empty_ring_buffer(stbir_info, stbir_info->output_h); +} + +static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels) +{ + info->input_w = input_w; + info->input_h = input_h; + info->output_w = output_w; + info->output_h = output_h; + info->channels = channels; +} + +static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform) +{ + info->s0 = s0; + info->t0 = t0; + info->s1 = s1; + info->t1 = t1; + + if (transform) + { + info->horizontal_scale = transform[0]; + info->vertical_scale = transform[1]; + info->horizontal_shift = transform[2]; + info->vertical_shift = transform[3]; + } + else + { + info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0); + info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0); + + info->horizontal_shift = s0 * info->output_w / (s1 - s0); + info->vertical_shift = t0 * info->output_h / (t1 - t0); + } +} + +static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter) +{ + if (h_filter == 0) + h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE; + if (v_filter == 0) + v_filter = stbir__use_upsampling(info->vertical_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE; + info->horizontal_filter = h_filter; + info->vertical_filter = v_filter; +} + +static stbir_uint32 stbir__calculate_memory(stbir__info *info) +{ + int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale); + int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale); + + info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w); + info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h); + + // One extra entry because floating point precision problems sometimes cause an extra to be necessary. + info->ring_buffer_num_entries = filter_height + 1; + + info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors); + info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float); + info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors); + info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float); + info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float); + info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float); + info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float); + info->encode_buffer_size = info->output_w * info->channels * sizeof(float); + + STBIR_ASSERT(info->horizontal_filter != 0); + STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late + STBIR_ASSERT(info->vertical_filter != 0); + STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late + + if (stbir__use_height_upsampling(info)) + // The horizontal buffer is for when we're downsampling the height and we + // can't output the result of sampling the decode buffer directly into the + // ring buffers. + info->horizontal_buffer_size = 0; + else + // The encode buffer is to retain precision in the height upsampling method + // and isn't used when height downsampling. + info->encode_buffer_size = 0; + + return info->horizontal_contributors_size + info->horizontal_coefficients_size + + info->vertical_contributors_size + info->vertical_coefficients_size + + info->decode_buffer_size + info->horizontal_buffer_size + + info->ring_buffer_size + info->encode_buffer_size; +} + +static int stbir__resize_allocated(stbir__info *info, + const void* input_data, int input_stride_in_bytes, + void* output_data, int output_stride_in_bytes, + int alpha_channel, stbir_uint32 flags, stbir_datatype type, + stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace, + void* tempmem, size_t tempmem_size_in_bytes) +{ + size_t memory_required = stbir__calculate_memory(info); + + int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type]; + int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type]; + +#ifdef STBIR_DEBUG_OVERWRITE_TEST +#define OVERWRITE_ARRAY_SIZE 8 + unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE]; + + size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type]; + memcpy(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE); +#endif + + STBIR_ASSERT(info->channels >= 0); + STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS); + + if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS) + return 0; + + STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + + if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table)) + return 0; + if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table)) + return 0; + + if (alpha_channel < 0) + flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED; + + if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) { + STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels); + } + + if (alpha_channel >= info->channels) + return 0; + + STBIR_ASSERT(tempmem); + + if (!tempmem) + return 0; + + STBIR_ASSERT(tempmem_size_in_bytes >= memory_required); + + if (tempmem_size_in_bytes < memory_required) + return 0; + + memset(tempmem, 0, tempmem_size_in_bytes); + + info->input_data = input_data; + info->input_stride_bytes = width_stride_input; + + info->output_data = output_data; + info->output_stride_bytes = width_stride_output; + + info->alpha_channel = alpha_channel; + info->flags = flags; + info->type = type; + info->edge_horizontal = edge_horizontal; + info->edge_vertical = edge_vertical; + info->colorspace = colorspace; + + info->horizontal_coefficient_width = stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale); + info->vertical_coefficient_width = stbir__get_coefficient_width (info->vertical_filter , info->vertical_scale ); + info->horizontal_filter_pixel_width = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale); + info->vertical_filter_pixel_width = stbir__get_filter_pixel_width (info->vertical_filter , info->vertical_scale ); + info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale); + info->vertical_filter_pixel_margin = stbir__get_filter_pixel_margin(info->vertical_filter , info->vertical_scale ); + + info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float); + info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2; + +#define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size) + + info->horizontal_contributors = (stbir__contributors *) tempmem; + info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float); + info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors); + info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float); + info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float); + + if (stbir__use_height_upsampling(info)) + { + info->horizontal_buffer = NULL; + info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float); + info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float); + + STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes); + } + else + { + info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float); + info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float); + info->encode_buffer = NULL; + + STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes); + } + +#undef STBIR__NEXT_MEMPTR + + // This signals that the ring buffer is empty + info->ring_buffer_begin_index = -1; + + stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w); + stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h); + + STBIR_PROGRESS_REPORT(0); + + if (stbir__use_height_upsampling(info)) + stbir__buffer_loop_upsample(info); + else + stbir__buffer_loop_downsample(info); + + STBIR_PROGRESS_REPORT(1); + +#ifdef STBIR_DEBUG_OVERWRITE_TEST + STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0); +#endif + + return 1; +} + + +static int stbir__resize_arbitrary( + void *alloc_context, + const void* input_data, int input_w, int input_h, int input_stride_in_bytes, + void* output_data, int output_w, int output_h, int output_stride_in_bytes, + float s0, float t0, float s1, float t1, float *transform, + int channels, int alpha_channel, stbir_uint32 flags, stbir_datatype type, + stbir_filter h_filter, stbir_filter v_filter, + stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace) +{ + stbir__info info; + int result; + size_t memory_required; + void* extra_memory; + + stbir__setup(&info, input_w, input_h, output_w, output_h, channels); + stbir__calculate_transform(&info, s0,t0,s1,t1,transform); + stbir__choose_filter(&info, h_filter, v_filter); + memory_required = stbir__calculate_memory(&info); + extra_memory = STBIR_MALLOC(memory_required, alloc_context); + + if (!extra_memory) + return 0; + + result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes, + output_data, output_stride_in_bytes, + alpha_channel, flags, type, + edge_horizontal, edge_vertical, + colorspace, extra_memory, memory_required); + + STBIR_FREE(extra_memory, alloc_context); + + return result; +} + +STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); +} + +STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); +} + +STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB); +} + +STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB); +} + +STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + +STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + + +STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + + +STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + + +STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float x_scale, float y_scale, + float x_offset, float y_offset) +{ + float transform[4]; + transform[0] = x_scale; + transform[1] = y_scale; + transform[2] = x_offset; + transform[3] = y_offset; + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + +STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float s0, float t0, float s1, float t1) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + +#endif // STB_IMAGE_RESIZE_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +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. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/src/transcc/native/stb_image_write.h b/src/transcc/native/stb_image_write.h new file mode 100644 index 00000000..cffd473c --- /dev/null +++ b/src/transcc/native/stb_image_write.h @@ -0,0 +1,1666 @@ +/* stb_image_write - v1.14 - public domain - http://nothings.org/stb + writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 + no warranty implied; use at your own risk + + Before #including, + + #define STB_IMAGE_WRITE_IMPLEMENTATION + + in the file that you want to have the implementation. + + Will probably not work correctly with strict-aliasing optimizations. + +ABOUT: + + This header file is a library for writing images to C stdio or a callback. + + The PNG output is not optimal; it is 20-50% larger than the file + written by a decent optimizing implementation; though providing a custom + zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. + This library is designed for source code compactness and simplicity, + not optimal image file size or run-time performance. + +BUILDING: + + You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. + You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace + malloc,realloc,free. + You can #define STBIW_MEMMOVE() to replace memmove() + You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function + for PNG compression (instead of the builtin one), it must have the following signature: + unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); + The returned data will be freed with STBIW_FREE() (free() by default), + so it must be heap allocated with STBIW_MALLOC() (malloc() by default), + +UNICODE: + + If compiling for Windows and you wish to use Unicode filenames, compile + with + #define STBIW_WINDOWS_UTF8 + and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert + Windows wchar_t filenames to utf8. + +USAGE: + + There are five functions, one for each image file format: + + int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); + int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); + + void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically + + There are also five equivalent functions that use an arbitrary write function. You are + expected to open/close your file-equivalent before and after calling these: + + int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); + int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + + where the callback is: + void stbi_write_func(void *context, void *data, int size); + + You can configure it with these global variables: + int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE + int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression + int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode + + + You can define STBI_WRITE_NO_STDIO to disable the file variant of these + functions, so the library will not use stdio.h at all. However, this will + also disable HDR writing, because it requires stdio for formatted output. + + Each function returns 0 on failure and non-0 on success. + + The functions create an image file defined by the parameters. The image + is a rectangle of pixels stored from left-to-right, top-to-bottom. + Each pixel contains 'comp' channels of data stored interleaved with 8-bits + per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is + monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. + The *data pointer points to the first byte of the top-left-most pixel. + For PNG, "stride_in_bytes" is the distance in bytes from the first byte of + a row of pixels to the first byte of the next row of pixels. + + PNG creates output files with the same number of components as the input. + The BMP format expands Y to RGB in the file format and does not + output alpha. + + PNG supports writing rectangles of data even when the bytes storing rows of + data are not consecutive in memory (e.g. sub-rectangles of a larger image), + by supplying the stride between the beginning of adjacent rows. The other + formats do not. (Thus you cannot write a native-format BMP through the BMP + writer, both because it is in BGR order and because it may have padding + at the end of the line.) + + PNG allows you to set the deflate compression level by setting the global + variable 'stbi_write_png_compression_level' (it defaults to 8). + + HDR expects linear float data. Since the format is always 32-bit rgb(e) + data, alpha (if provided) is discarded, and for monochrome data it is + replicated across all three channels. + + TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed + data, set the global variable 'stbi_write_tga_with_rle' to 0. + + JPEG does ignore alpha channels in input data; quality is between 1 and 100. + Higher quality looks better but results in a bigger image. + JPEG baseline (no JPEG progressive). + +CREDITS: + + + Sean Barrett - PNG/BMP/TGA + Baldur Karlsson - HDR + Jean-Sebastien Guay - TGA monochrome + Tim Kelsey - misc enhancements + Alan Hickman - TGA RLE + Emmanuel Julien - initial file IO callback implementation + Jon Olick - original jo_jpeg.cpp code + Daniel Gibson - integrate JPEG, allow external zlib + Aarni Koskela - allow choosing PNG filter + + bugfixes: + github:Chribba + Guillaume Chereau + github:jry2 + github:romigrou + Sergio Gonzalez + Jonas Karlsson + Filip Wasil + Thatcher Ulrich + github:poppolopoppo + Patrick Boettcher + github:xeekworx + Cap Petschulat + Simon Rodriguez + Ivan Tikhonov + github:ignotion + Adam Schackart + +LICENSE + + See end of file for license information. + +*/ + +#ifndef INCLUDE_STB_IMAGE_WRITE_H +#define INCLUDE_STB_IMAGE_WRITE_H + +#include + +// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' +#ifndef STBIWDEF +#ifdef STB_IMAGE_WRITE_STATIC +#define STBIWDEF static +#else +#ifdef __cplusplus +#define STBIWDEF extern "C" +#else +#define STBIWDEF extern +#endif +#endif +#endif + +#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations +extern int stbi_write_tga_with_rle; +extern int stbi_write_png_compression_level; +extern int stbi_write_force_png_filter; +#endif + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); + +#ifdef STBI_WINDOWS_UTF8 +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif +#endif + +typedef void stbi_write_func(void *context, void *data, int size); + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + +STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); + +#endif//INCLUDE_STB_IMAGE_WRITE_H + +#ifdef STB_IMAGE_WRITE_IMPLEMENTATION + +#ifdef _WIN32 + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif + #ifndef _CRT_NONSTDC_NO_DEPRECATE + #define _CRT_NONSTDC_NO_DEPRECATE + #endif +#endif + +#ifndef STBI_WRITE_NO_STDIO +#include +#endif // STBI_WRITE_NO_STDIO + +#include +#include +#include +#include + +#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) +// ok +#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." +#endif + +#ifndef STBIW_MALLOC +#define STBIW_MALLOC(sz) malloc(sz) +#define STBIW_REALLOC(p,newsz) realloc(p,newsz) +#define STBIW_FREE(p) free(p) +#endif + +#ifndef STBIW_REALLOC_SIZED +#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) +#endif + + +#ifndef STBIW_MEMMOVE +#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) +#endif + + +#ifndef STBIW_ASSERT +#include +#define STBIW_ASSERT(x) assert(x) +#endif + +#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) + +#ifdef STB_IMAGE_WRITE_STATIC +static int stbi_write_png_compression_level = 8; +static int stbi_write_tga_with_rle = 1; +static int stbi_write_force_png_filter = -1; +#else +int stbi_write_png_compression_level = 8; +int stbi_write_tga_with_rle = 1; +int stbi_write_force_png_filter = -1; +#endif + +static int stbi__flip_vertically_on_write = 0; + +STBIWDEF void stbi_flip_vertically_on_write(int flag) +{ + stbi__flip_vertically_on_write = flag; +} + +typedef struct +{ + stbi_write_func *func; + void *context; +} stbi__write_context; + +// initialize a callback-based context +static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) +{ + s->func = c; + s->context = context; +} + +#ifndef STBI_WRITE_NO_STDIO + +static void stbi__stdio_write(void *context, void *data, int size) +{ + fwrite(data,1,size,(FILE*) context); +} + +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#ifdef __cplusplus +#define STBIW_EXTERN extern "C" +#else +#define STBIW_EXTERN extern +#endif +STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); + +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbiw__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + return 0; + +#if _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + +static int stbi__start_write_file(stbi__write_context *s, const char *filename) +{ + FILE *f = stbiw__fopen(filename, "wb"); + stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); + return f != NULL; +} + +static void stbi__end_write_file(stbi__write_context *s) +{ + fclose((FILE *)s->context); +} + +#endif // !STBI_WRITE_NO_STDIO + +typedef unsigned int stbiw_uint32; +typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; + +static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) +{ + while (*fmt) { + switch (*fmt++) { + case ' ': break; + case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); + s->func(s->context,&x,1); + break; } + case '2': { int x = va_arg(v,int); + unsigned char b[2]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x>>8); + s->func(s->context,b,2); + break; } + case '4': { stbiw_uint32 x = va_arg(v,int); + unsigned char b[4]; + b[0]=STBIW_UCHAR(x); + b[1]=STBIW_UCHAR(x>>8); + b[2]=STBIW_UCHAR(x>>16); + b[3]=STBIW_UCHAR(x>>24); + s->func(s->context,b,4); + break; } + default: + STBIW_ASSERT(0); + return; + } + } +} + +static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); +} + +static void stbiw__putc(stbi__write_context *s, unsigned char c) +{ + s->func(s->context, &c, 1); +} + +static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) +{ + unsigned char arr[3]; + arr[0] = a; arr[1] = b; arr[2] = c; + s->func(s->context, arr, 3); +} + +static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) +{ + unsigned char bg[3] = { 255, 0, 255}, px[3]; + int k; + + if (write_alpha < 0) + s->func(s->context, &d[comp - 1], 1); + + switch (comp) { + case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case + case 1: + if (expand_mono) + stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp + else + s->func(s->context, d, 1); // monochrome TGA + break; + case 4: + if (!write_alpha) { + // composite against pink background + for (k = 0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + s->func(s->context, &d[comp - 1], 1); +} + +static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) +{ + stbiw_uint32 zero = 0; + int i,j, j_end; + + if (y <= 0) + return; + + if (stbi__flip_vertically_on_write) + vdir *= -1; + + if (vdir < 0) { + j_end = -1; j = y-1; + } else { + j_end = y; j = 0; + } + + for (; j != j_end; j += vdir) { + for (i=0; i < x; ++i) { + unsigned char *d = (unsigned char *) data + (j*x+i)*comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } + s->func(s->context, &zero, scanline_pad); + } +} + +static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) +{ + if (y < 0 || x < 0) { + return 0; + } else { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); + stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); + return 1; + } +} + +static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) +{ + int pad = (-x*3) & 3; + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header +} + +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif //!STBI_WRITE_NO_STDIO + +static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) +{ + int has_alpha = (comp == 2 || comp == 4); + int colorbytes = has_alpha ? comp-1 : comp; + int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 + + if (y < 0 || x < 0) + return 0; + + if (!stbi_write_tga_with_rle) { + return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, + "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); + } else { + int i,j,k; + int jend, jdir; + + stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); + + if (stbi__flip_vertically_on_write) { + j = 0; + jend = y; + jdir = 1; + } else { + j = y-1; + jend = -1; + jdir = -1; + } + for (; j != jend; j += jdir) { + unsigned char *row = (unsigned char *) data + j * x * comp; + int len; + + for (i = 0; i < x; i += len) { + unsigned char *begin = row + i * comp; + int diff = 1; + len = 1; + + if (i < x - 1) { + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); + if (diff) { + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; + } else { + --len; + break; + } + } + } else { + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; + } else { + break; + } + } + } + } + + if (diff) { + unsigned char header = STBIW_UCHAR(len - 1); + s->func(s->context, &header, 1); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = STBIW_UCHAR(len - 129); + s->func(s->context, &header, 1); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } + } + } + } + return 1; +} + +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR writer +// by Baldur Karlsson + +#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) + +static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) +{ + int exponent; + float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); + + if (maxcomp < 1e-32f) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } else { + float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; + + rgbe[0] = (unsigned char)(linear[0] * normalize); + rgbe[1] = (unsigned char)(linear[1] * normalize); + rgbe[2] = (unsigned char)(linear[2] * normalize); + rgbe[3] = (unsigned char)(exponent + 128); + } +} + +static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) +{ + unsigned char lengthbyte = STBIW_UCHAR(length+128); + STBIW_ASSERT(length+128 <= 255); + s->func(s->context, &lengthbyte, 1); + s->func(s->context, &databyte, 1); +} + +static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) +{ + unsigned char lengthbyte = STBIW_UCHAR(length); + STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code + s->func(s->context, &lengthbyte, 1); + s->func(s->context, data, length); +} + +static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) +{ + unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; + unsigned char rgbe[4]; + float linear[3]; + int x; + + scanlineheader[2] = (width&0xff00)>>8; + scanlineheader[3] = (width&0x00ff); + + /* skip RLE for images too small or large */ + if (width < 8 || width >= 32768) { + for (x=0; x < width; x++) { + switch (ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + s->func(s->context, rgbe, 4); + } + } else { + int c,r; + /* encode into scratch buffer */ + for (x=0; x < width; x++) { + switch(ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + scratch[x + width*0] = rgbe[0]; + scratch[x + width*1] = rgbe[1]; + scratch[x + width*2] = rgbe[2]; + scratch[x + width*3] = rgbe[3]; + } + + s->func(s->context, scanlineheader, 4); + + /* RLE each component separately */ + for (c=0; c < 4; c++) { + unsigned char *comp = &scratch[width*c]; + + x = 0; + while (x < width) { + // find first run + r = x; + while (r+2 < width) { + if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) + break; + ++r; + } + if (r+2 >= width) + r = width; + // dump up to first run + while (x < r) { + int len = r-x; + if (len > 128) len = 128; + stbiw__write_dump_data(s, len, &comp[x]); + x += len; + } + // if there's a run, output it + if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd + // find next byte after run + while (r < width && comp[r] == comp[x]) + ++r; + // output run up to r + while (x < r) { + int len = r-x; + if (len > 127) len = 127; + stbiw__write_run_data(s, len, comp[x]); + x += len; + } + } + } + } + } +} + +static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) +{ + if (y <= 0 || x <= 0 || data == NULL) + return 0; + else { + // Each component is stored separately. Allocate scratch space for full output scanline. + unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); + int i, len; + char buffer[128]; + char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header)-1); + +#ifdef __STDC_WANT_SECURE_LIB__ + len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#else + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#endif + s->func(s->context, buffer, len); + + for(i=0; i < y; i++) + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); + STBIW_FREE(scratch); + return 1; + } +} + +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif // STBI_WRITE_NO_STDIO + + +////////////////////////////////////////////////////////////////////////////// +// +// PNG writer +// + +#ifndef STBIW_ZLIB_COMPRESS +// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() +#define stbiw__sbraw(a) ((int *) (void *) (a) - 2) +#define stbiw__sbm(a) stbiw__sbraw(a)[0] +#define stbiw__sbn(a) stbiw__sbraw(a)[1] + +#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) +#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) +#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) + +#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) +#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) +#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) + +static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) +{ + int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; + void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); + STBIW_ASSERT(p); + if (p) { + if (!*arr) ((int *) p)[1] = 0; + *arr = (void *) ((int *) p + 2); + stbiw__sbm(*arr) = m; + } + return *arr; +} + +static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) +{ + while (*bitcount >= 8) { + stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; +} + +static int stbiw__zlib_bitrev(int code, int codebits) +{ + int res=0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; +} + +static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) +{ + int i; + for (i=0; i < limit && i < 258; ++i) + if (a[i] != b[i]) break; + return i; +} + +static unsigned int stbiw__zhash(unsigned char *data) +{ + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; +} + +#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) +#define stbiw__zlib_add(code,codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) +#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) +// default huffman tables +#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) +#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) +#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) +#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) +#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) +#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) + +#define stbiw__ZHASH 16384 + +#endif // STBIW_ZLIB_COMPRESS + +STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +{ +#ifdef STBIW_ZLIB_COMPRESS + // user provided a zlib compress implementation, use that + return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); +#else // use builtin + static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; + static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; + static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; + static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; + unsigned int bitbuf=0; + int i,j, bitcount=0; + unsigned char *out = NULL; + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); + if (hash_table == NULL) + return NULL; + if (quality < 5) quality = 5; + + stbiw__sbpush(out, 0x78); // DEFLATE 32K window + stbiw__sbpush(out, 0x5e); // FLEVEL = 1 + stbiw__zlib_add(1,1); // BFINAL = 1 + stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman + + for (i=0; i < stbiw__ZHASH; ++i) + hash_table[i] = NULL; + + i=0; + while (i < data_len-3) { + // hash next 3 bytes of data to be compressed + int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32768) { // if entry lies within window + int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); + if (d >= best) { best=d; bestloc=hlist[j]; } + } + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { + STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); + stbiw__sbn(hash_table[h]) = quality; + } + stbiw__sbpush(hash_table[h],data+i); + + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal + h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); + hlist = hash_table[h]; + n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32767) { + int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } + } + } + + if (bestloc) { + int d = (int) (data+i - bestloc); // distance back + STBIW_ASSERT(d <= 32767 && best <= 258); + for (j=0; best > lengthc[j+1]-1; ++j); + stbiw__zlib_huff(j+257); + if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + for (j=0; d > distc[j+1]-1; ++j); + stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); + if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { + stbiw__zlib_huffb(data[i]); + ++i; + } + } + // write out final bytes + for (;i < data_len; ++i) + stbiw__zlib_huffb(data[i]); + stbiw__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbiw__zlib_add(0,1); + + for (i=0; i < stbiw__ZHASH; ++i) + (void) stbiw__sbfree(hash_table[i]); + STBIW_FREE(hash_table); + + { + // compute adler32 on input + unsigned int s1=1, s2=0; + int blocklen = (int) (data_len % 5552); + j=0; + while (j < data_len) { + for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } + s1 %= 65521; s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s2)); + stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s1)); + } + *out_len = stbiw__sbn(out); + // make returned pointer freeable + STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); + return (unsigned char *) stbiw__sbraw(out); +#endif // STBIW_ZLIB_COMPRESS +} + +static unsigned int stbiw__crc32(unsigned char *buffer, int len) +{ +#ifdef STBIW_CRC32 + return STBIW_CRC32(buffer, len); +#else + static unsigned int crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + unsigned int crc = ~0u; + int i; + for (i=0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; +#endif +} + +#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) +#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); +#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) + +static void stbiw__wpcrc(unsigned char **data, int len) +{ + unsigned int crc = stbiw__crc32(*data - len - 4, len+4); + stbiw__wp32(*data, crc); +} + +static unsigned char stbiw__paeth(int a, int b, int c) +{ + int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); + if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); + if (pb <= pc) return STBIW_UCHAR(b); + return STBIW_UCHAR(c); +} + +// @OPTIMIZE: provide an option that always forces left-predict or paeth predict +static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) +{ + static int mapping[] = { 0,1,2,3,4 }; + static int firstmap[] = { 0,1,0,5,6 }; + int *mymap = (y != 0) ? mapping : firstmap; + int i; + int type = mymap[filter_type]; + unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); + int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; + + if (type==0) { + memcpy(line_buffer, z, width*n); + return; + } + + // first loop isn't optimized since it's just one pixel + for (i = 0; i < n; ++i) { + switch (type) { + case 1: line_buffer[i] = z[i]; break; + case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; + case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; + case 5: line_buffer[i] = z[i]; break; + case 6: line_buffer[i] = z[i]; break; + } + } + switch (type) { + case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; + case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; + case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; + case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; + } +} + +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +{ + int force_filter = stbi_write_force_png_filter; + int ctype[5] = { -1, 0, 4, 2, 6 }; + unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; + unsigned char *out,*o, *filt, *zlib; + signed char *line_buffer; + int j,zlen; + + if (stride_bytes == 0) + stride_bytes = x * n; + + if (force_filter >= 5) { + force_filter = -1; + } + + filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; + line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } + for (j=0; j < y; ++j) { + int filter_type; + if (force_filter > -1) { + filter_type = force_filter; + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); + } else { // Estimate the best filter by running through all of them: + int best_filter = 0, best_filter_val = 0x7fffffff, est, i; + for (filter_type = 0; filter_type < 5; filter_type++) { + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); + + // Estimate the entropy of the line using this filter; the less, the better. + est = 0; + for (i = 0; i < x*n; ++i) { + est += abs((signed char) line_buffer[i]); + } + if (est < best_filter_val) { + best_filter_val = est; + best_filter = filter_type; + } + } + if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); + filter_type = best_filter; + } + } + // when we get here, filter_type contains the filter type, and line_buffer contains the data + filt[j*(x*n+1)] = (unsigned char) filter_type; + STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); + STBIW_FREE(filt); + if (!zlib) return 0; + + // each tag requires 12 bytes of overhead + out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); + if (!out) return 0; + *out_len = 8 + 12+13 + 12+zlen + 12; + + o=out; + STBIW_MEMMOVE(o,sig,8); o+= 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = STBIW_UCHAR(ctype[n]); + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o,13); + + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); + + stbiw__wp32(o,0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o,0); + + STBIW_ASSERT(o == out + *out_len); + + return out; +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) +{ + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + + f = stbiw__fopen(filename, "wb"); + if (!f) { STBIW_FREE(png); return 0; } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; +} +#endif + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) +{ + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; +} + + +/* *************************************************************************** + * + * JPEG writer + * + * This is based on Jon Olick's jo_jpeg.cpp: + * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html + */ + +static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, + 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; + +static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { + int bitBuf = *bitBufP, bitCnt = *bitCntP; + bitCnt += bs[1]; + bitBuf |= bs[0] << (24 - bitCnt); + while(bitCnt >= 8) { + unsigned char c = (bitBuf >> 16) & 255; + stbiw__putc(s, c); + if(c == 255) { + stbiw__putc(s, 0); + } + bitBuf <<= 8; + bitCnt -= 8; + } + *bitBufP = bitBuf; + *bitCntP = bitCnt; +} + +static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { + float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; + float z1, z2, z3, z4, z5, z11, z13; + + float tmp0 = d0 + d7; + float tmp7 = d0 - d7; + float tmp1 = d1 + d6; + float tmp6 = d1 - d6; + float tmp2 = d2 + d5; + float tmp5 = d2 - d5; + float tmp3 = d3 + d4; + float tmp4 = d3 - d4; + + // Even part + float tmp10 = tmp0 + tmp3; // phase 2 + float tmp13 = tmp0 - tmp3; + float tmp11 = tmp1 + tmp2; + float tmp12 = tmp1 - tmp2; + + d0 = tmp10 + tmp11; // phase 3 + d4 = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * 0.707106781f; // c4 + d2 = tmp13 + z1; // phase 5 + d6 = tmp13 - z1; + + // Odd part + tmp10 = tmp4 + tmp5; // phase 2 + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = (tmp10 - tmp12) * 0.382683433f; // c6 + z2 = tmp10 * 0.541196100f + z5; // c2-c6 + z4 = tmp12 * 1.306562965f + z5; // c2+c6 + z3 = tmp11 * 0.707106781f; // c4 + + z11 = tmp7 + z3; // phase 5 + z13 = tmp7 - z3; + + *d5p = z13 + z2; // phase 6 + *d3p = z13 - z2; + *d1p = z11 + z4; + *d7p = z11 - z4; + + *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; +} + +static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { + int tmp1 = val < 0 ? -val : val; + val = val < 0 ? val-1 : val; + bits[1] = 1; + while(tmp1 >>= 1) { + ++bits[1]; + } + bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { + } + // end0pos = first element in reverse order !=0 + if(end0pos == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + return DU[0]; + } + for(i = 1; i <= end0pos; ++i) { + int startpos = i; + int nrzeroes; + unsigned short bits[2]; + for (; DU[i]==0 && i<=end0pos; ++i) { + } + nrzeroes = i-startpos; + if ( nrzeroes >= 16 ) { + int lng = nrzeroes>>4; + int nrmarker; + for (nrmarker=1; nrmarker <= lng; ++nrmarker) + stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); + nrzeroes &= 15; + } + stbiw__jpg_calcBits(DU[i], bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + if(end0pos != 63) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + } + return DU[0]; +} + +static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { + // Constants that don't pollute global namespace + static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; + static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; + static const unsigned char std_ac_luminance_values[] = { + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, + 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, + 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, + 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, + 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; + static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; + static const unsigned char std_ac_chrominance_values[] = { + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, + 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, + 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, + 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, + 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, + 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + // Huffman tables + static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; + static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; + static const unsigned short YAC_HT[256][2] = { + {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const unsigned short UVAC_HT[256][2] = { + {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, + 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; + static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; + static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, + 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; + + int row, col, i, k, subsample; + float fdtbl_Y[64], fdtbl_UV[64]; + unsigned char YTable[64], UVTable[64]; + + if(!data || !width || !height || comp > 4 || comp < 1) { + return 0; + } + + quality = quality ? quality : 90; + subsample = quality <= 90 ? 1 : 0; + quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + + for(i = 0; i < 64; ++i) { + int uvti, yti = (YQT[i]*quality+50)/100; + YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); + uvti = (UVQT[i]*quality+50)/100; + UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); + } + + for(row = 0, k = 0; row < 8; ++row) { + for(col = 0; col < 8; ++col, ++k) { + fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + } + } + + // Write Headers + { + static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; + static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; + const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), + 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; + s->func(s->context, (void*)head0, sizeof(head0)); + s->func(s->context, (void*)YTable, sizeof(YTable)); + stbiw__putc(s, 1); + s->func(s->context, UVTable, sizeof(UVTable)); + s->func(s->context, (void*)head1, sizeof(head1)); + s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); + s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); + stbiw__putc(s, 0x10); // HTYACinfo + s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); + s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); + stbiw__putc(s, 1); // HTUDCinfo + s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); + stbiw__putc(s, 0x11); // HTUACinfo + s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); + s->func(s->context, (void*)head2, sizeof(head2)); + } + + // Encode 8x8 macroblocks + { + static const unsigned short fillBits[] = {0x7F, 7}; + int DCY=0, DCU=0, DCV=0; + int bitBuf=0, bitCnt=0; + // comp == 2 is grey+alpha (alpha is ignored) + int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + const unsigned char *dataR = (const unsigned char *)data; + const unsigned char *dataG = dataR + ofsG; + const unsigned char *dataB = dataR + ofsB; + int x, y, pos; + if(subsample) { + for(y = 0; y < height; y += 16) { + for(x = 0; x < width; x += 16) { + float Y[256], U[256], V[256]; + for(row = y, pos = 0; row < y+16; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+16; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + + // subsample U,V + { + float subU[64], subV[64]; + int yy, xx; + for(yy = 0, pos = 0; yy < 8; ++yy) { + for(xx = 0; xx < 8; ++xx, ++pos) { + int j = yy*32+xx*2; + subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; + subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; + } + } + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + } else { + for(y = 0; y < height; y += 8) { + for(x = 0; x < width; x += 8) { + float Y[64], U[64], V[64]; + for(row = y, pos = 0; row < y+8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+8; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + + // Do the bit alignment of the EOI marker + stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); + } + + // EOI + stbiw__putc(s, 0xFF); + stbiw__putc(s, 0xD9); + + return 1; +} + +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); +} + + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +#endif // STB_IMAGE_WRITE_IMPLEMENTATION + +/* Revision history + 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels + 1.13 + 1.12 + 1.11 (2019-08-11) + + 1.10 (2019-02-07) + support utf8 filenames in Windows; fix warnings and platform ifdefs + 1.09 (2018-02-11) + fix typo in zlib quality API, improve STB_I_W_STATIC in C++ + 1.08 (2018-01-29) + add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter + 1.07 (2017-07-24) + doc fix + 1.06 (2017-07-23) + writing JPEG (using Jon Olick's code) + 1.05 ??? + 1.04 (2017-03-03) + monochrome BMP expansion + 1.03 ??? + 1.02 (2016-04-02) + avoid allocating large structures on the stack + 1.01 (2016-01-16) + STBIW_REALLOC_SIZED: support allocators with no realloc support + avoid race-condition in crc initialization + minor compile issues + 1.00 (2015-09-14) + installable file IO function + 0.99 (2015-09-13) + warning fixes; TGA rle support + 0.98 (2015-04-08) + added STBIW_MALLOC, STBIW_ASSERT etc + 0.97 (2015-01-18) + fixed HDR asserts, rewrote HDR rle logic + 0.96 (2015-01-17) + add HDR output + fix monochrome BMP + 0.95 (2014-08-17) + add monochrome TGA output + 0.94 (2014-05-31) + rename private functions to avoid conflicts with stb_image.h + 0.93 (2014-05-27) + warning fixes + 0.92 (2010-08-01) + casts to unsigned char to fix warnings + 0.91 (2010-07-17) + first public release + 0.90 first internal release +*/ + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +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. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/src/transcc/transcc.build/cpptool/main.cpp b/src/transcc/transcc.build/cpptool/main.cpp index 3495c348..e30d814e 100755 --- a/src/transcc/transcc.build/cpptool/main.cpp +++ b/src/transcc/transcc.build/cpptool/main.cpp @@ -11,7 +11,7 @@ #define CFG_CONFIG release #define CFG_CPP_DOUBLE_PRECISION_FLOATS 1 #define CFG_CPP_GC_MODE 0 -#define CFG_HOST winnt +#define CFG_HOST macos #define CFG_LANG cpp #define CFG_MODPATH #define CFG_RELEASE 1 @@ -2525,429 +2525,12547 @@ int ExitApp( int retcode ){ return 0; } +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_WRITE_IMPLEMENTATION +#define STB_IMAGE_RESIZE_IMPLEMENTATION +// undefining __STDC_WANT_SECURE_LIB__ makes an error disappear +#undef __STDC_WANT_SECURE_LIB__ +/* stb_image - v2.25 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine + John-Mark Allen + Carmelo J Fdez-Aguera + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan + Dave Moore Roy Eltham Hayaki Saito Nathan Reed + Won Chun Luke Graham Johan Duparc Nick Verigakis + the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar + Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex + Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 + Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw + Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus + Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo + Christian Floisand Kevin Schmidt JR Smith github:darealshinji + Brad Weinberger Matvey Cherevko github:Michaelangel007 + Blazej Dariusz Roszkowski Alexander Veselov +*/ -// ***** thread.h ***** +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H -#if __cplusplus_winrt +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// =========================================================================== +// +// UNICODE: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy-to-use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// provide more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. You can still load any file through the existing +// interface; if you attempt to load an HDR file, it will be automatically remapped +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// By default we convert iphone-formatted PNGs back to RGB, even though +// they are internally encoded differently. You can disable this conversion +// by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through (which +// is BGR stored in RGB). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// -using namespace Windows::System::Threading; -#endif +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO -class BBThread : public Object{ -public: - Object *result; - - BBThread(); - - virtual void Start(); - virtual bool IsRunning(); - - virtual Object *Result(); - virtual void SetResult( Object *result ); - - static String Strdup( const String &str ); - - virtual void Run__UNSAFE__(); - - -private: +#define STBI_VERSION 1 - enum{ - INIT=0, - RUNNING=1, - FINISHED=2 - }; +enum +{ + STBI_default = 0, // only used for desired_channels - - int _state; - Object *_result; - -#if __cplusplus_winrt + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; - friend class Launcher; +#include +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; - class Launcher{ - - friend class BBThread; - BBThread *_thread; - - Launcher( BBThread *thread ):_thread(thread){ - } - - public: - - void operator()( IAsyncAction ^operation ){ - _thread->Run__UNSAFE__(); - _thread->_state=FINISHED; - } - }; - -#elif _WIN32 +#ifdef __cplusplus +extern "C" { +#endif - static DWORD WINAPI run( void *p ); - +#ifndef STBIDEF +#ifdef STB_IMAGE_STATIC +#define STBIDEF static #else - - static void *run( void *p ); - +#define STBIDEF extern +#endif #endif -}; +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// -// ***** thread.cpp ***** +// +// load image by filename, open file, or memory buffer +// -BBThread::BBThread():_state( INIT ),_result( 0 ){ -} +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; -bool BBThread::IsRunning(){ - return _state==RUNNING; -} +//////////////////////////////////// +// +// 8-bits-per-channel interface +// -Object *BBThread::Result(){ - return _result; -} +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); -void BBThread::SetResult( Object *result ){ - _result=result; -} +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif -String BBThread::Strdup( const String &str ){ - return str.Copy(); -} +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif -void BBThread::Run__UNSAFE__(){ -} +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif -#if __cplusplus_winrt +//////////////////////////////////// +// +// 16-bits-per-channel interface +// -void BBThread::Start(){ - if( _state==RUNNING ) return; - - _result=0; - _state=RUNNING; - - Launcher launcher( this ); - - auto handler=ref new WorkItemHandler( launcher ); - - ThreadPool::RunAsync( handler ); -} +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); -#elif _WIN32 +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif -void BBThread::Start(){ - if( _state==RUNNING ) return; - - _result=0; - _state=RUNNING; - - DWORD _id; - HANDLE _handle; +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif - if( _handle=CreateThread( 0,0,run,this,0,&_id ) ){ - CloseHandle( _handle ); - return; - } - - puts( "CreateThread failed!" ); - exit( -1 ); -} +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// on most compilers (and ALL modern mainstream compilers) this is threadsafe +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif -DWORD WINAPI BBThread::run( void *p ){ - BBThread *thread=(BBThread*)p; - thread->Run__UNSAFE__(); - - thread->_state=FINISHED; - return 0; -} -#else +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); -void BBThread::Start(){ - if( _state==RUNNING ) return; - - _result=0; - _state=RUNNING; - - pthread_t _handle; - - if( !pthread_create( &_handle,0,run,this ) ){ - pthread_detach( _handle ); - return; - } - - puts( "pthread_create failed!" ); - exit( -1 ); -} +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); -void *BBThread::run( void *p ){ - BBThread *thread=(BBThread*)p; +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); - thread->Run__UNSAFE__(); +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); - thread->_state=FINISHED; - return 0; +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus } +#endif +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif #endif +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif -// ***** databuffer.h ***** -class BBDataBuffer : public Object{ -public: - - BBDataBuffer(); - - ~BBDataBuffer(); - - bool _New( int length,void *data=0 ); - - bool _Load( String path ); - - void _LoadAsync( const String &path,BBThread *thread ); +#include +#include // ptrdiff_t on osx +#include +#include +#include - void Discard(); - - const void *ReadPointer( int offset=0 ){ - return _data+offset; - } - - void *WritePointer( int offset=0 ){ - return _data+offset; - } - - int Length(){ - return _length; - } - - void PokeByte( int addr,int value ){ - *(_data+addr)=value; - } +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif - void PokeShort( int addr,int value ){ - *(short*)(_data+addr)=value; - } - - void PokeInt( int addr,int value ){ - *(int*)(_data+addr)=value; - } - - void PokeFloat( int addr,float value ){ - *(float*)(_data+addr)=value; - } +#ifndef STBI_NO_STDIO +#include +#endif - int PeekByte( int addr ){ - return *(_data+addr); - } - - int PeekShort( int addr ){ - return *(short*)(_data+addr); - } - - int PeekInt( int addr ){ - return *(int*)(_data+addr); - } - - float PeekFloat( int addr ){ - return *(float*)(_data+addr); - } - -private: - signed char *_data; - int _length; -}; +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif -// ***** databuffer.cpp ***** +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif -BBDataBuffer::BBDataBuffer():_data(0),_length(0){ + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define STBI_THREAD_LOCAL _Thread_local + #elif defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) +#endif +#endif + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; } +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif -BBDataBuffer::~BBDataBuffer(){ - if( _data ) free( _data ); +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; } +#endif -bool BBDataBuffer::_New( int length,void *data ){ - if( _data ) return false; - if( !data ) data=malloc( length ); - _data=(signed char*)data; - _length=length; - return true; +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; } +#endif -bool BBDataBuffer::_Load( String path ){ - if( _data ) return false; - - _data=(signed char*)BBGame::Game()->LoadData( path,&_length ); - if( !_data ) return false; - - return true; +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +// assume GCC or Clang on ARM targets +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; } -void BBDataBuffer::_LoadAsync( const String &cpath,BBThread *thread ){ +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} - String path=cpath.Copy(); - - if( _Load( path ) ) thread->SetResult( this ); +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); } -void BBDataBuffer::Discard(){ - if( !_data ) return; - free( _data ); - _data=0; - _length=0; +static void stbi__stdio_skip(void *user, int n) +{ + fseek((FILE*) user, n, SEEK_CUR); } +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user); +} -// ***** stream.h ***** +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; -class BBStream : public Object{ -public: +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} - virtual int Eof(){ - return 0; - } +//static void stop_file(stbi__context *s) { } - virtual void Close(){ - } +#endif // !STBI_NO_STDIO - virtual int Length(){ - return 0; - } - - virtual int Position(){ - return 0; - } - - virtual int Seek( int position ){ - return 0; - } - - virtual int Read( BBDataBuffer *buffer,int offset,int count ){ - return 0; - } +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} - virtual int Write( BBDataBuffer *buffer,int offset,int count ){ - return 0; - } +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR }; -// ***** stream.cpp ***** +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif -// ***** filestream.h ***** +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif -class BBFileStream : public BBStream{ -public: +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif - BBFileStream(); - ~BBFileStream(); +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif - void Close(); - int Eof(); - int Length(); - int Position(); - int Seek( int position ); - int Read( BBDataBuffer *buffer,int offset,int count ); - int Write( BBDataBuffer *buffer,int offset,int count ); +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif - bool Open( String path,String mode ); - -private: - FILE *_file; - int _position; - int _length; -}; +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif -// ***** filestream.cpp ***** +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif -BBFileStream::BBFileStream():_file(0),_position(0),_length(0){ +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; } -BBFileStream::~BBFileStream(){ - if( _file ) fclose( _file ); +#ifndef STBI_NO_FAILURE_STRINGS +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; } +#endif -bool BBFileStream::Open( String path,String mode ){ - if( _file ) return false; +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} - String fmode; - if( mode=="r" ){ - fmode="rb"; - }else if( mode=="w" ){ - fmode="wb"; - }else if( mode=="u" ){ - fmode="rb+"; - }else{ - return false; - } +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} +#endif - _file=BBGame::Game()->OpenFile( path,fmode ); - if( !_file && mode=="u" ) _file=BBGame::Game()->OpenFile( path,"wb+" ); - if( !_file ) return false; - - fseek( _file,0,SEEK_END ); - _length=ftell( _file ); - fseek( _file,0,SEEK_SET ); - _position=0; - - return true; +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); } -void BBFileStream::Close(){ - if( !_file ) return; - - fclose( _file ); - _file=0; - _position=0; - _length=0; +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); } +#endif -int BBFileStream::Eof(){ - if( !_file ) return -1; - - return _position==_length; +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); } +#endif -int BBFileStream::Length(){ - return _length; +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); } -int BBFileStream::Position(){ - return _position; +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); } +#endif -int BBFileStream::Seek( int position ){ - if( !_file ) return 0; - - fseek( _file,position,SEEK_SET ); - _position=ftell( _file ); - return _position; +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); } -int BBFileStream::Read( BBDataBuffer *buffer,int offset,int count ){ - if( !_file ) return 0; - - int n=fread( buffer->WritePointer(offset),1,count,_file ); - _position+=n; - return n; +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load_global = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; } -int BBFileStream::Write( BBDataBuffer *buffer,int offset,int count ){ - if( !_file ) return 0; - - int n=fwrite( buffer->ReadPointer(offset),1,count,_file ); - _position+=n; - if( _position>_length ) _length=_position; - return n; +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +#ifndef STBI_NO_GIF +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } } +#endif -class c_TransCC; -class c_Type; -class c_StringType; -class c_Decl; +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 8) { + STBI_ASSERT(ri.bits_per_channel == 16); + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 16) { + STBI_ASSERT(ri.bits_per_channel == 8); + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + return 0; + +#if _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else +static void stbi__skip(stbi__context *s, int n) +{ + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} +#endif + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + return z + (stbi__get16le(s) << 16); +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (stbi_uc) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + k = stbi_lrot(j->code_buffer, n); + STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & ~sgn); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc << j->succ_low); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[288]; + stbi__uint16 value[288]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + if (z->zbuffer >= z->zbuffer_end) return 0; + return *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + STBI_ASSERT(z->size[b] == s); + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) stbi__fill_bits(a); + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (int) (z->zout - z->zout_start); + limit = old_limit = (int) (z->zout_end - z->zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) + c = stbi__zreceive(a,3)+3; + else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a,7)+11; + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + STBI_ASSERT(a->num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[288] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior; + int filter = *raw++; + + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + STBI_ASSERT(img_width_bytes <= x); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes+1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*filter_bytes; + #define STBI__CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + } + #undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define STBI__CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ + for (k=0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; + } + #undef STBI__CASE + + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride*j; // start at the beginning of the row again + for (i=0; i < x; ++i,cur+=output_bytes) { + cur[filter_bytes+1] = 255; + } + } + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16*)cur; + + for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load = 0; +static int stbi__de_iphone_flag = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]={0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth < 8) + ri->bits_per_channel = 8; + else + ri->bits_per_channel = p->depth; + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(unsigned int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; + int extra_read; +} stbi__bmp_data; + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - info.extra_read - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + STBI_ASSERT(info.offset == (s->img_buffer - s->buffer_start)); + } + + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i]; p1[i] = p2[i]; p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispoase of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + void *tmp = (stbi_uc*) STBI_REALLOC( out, layers * stride ); + if (NULL == tmp) { + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + return stbi__errpuc("outofmem", "Out of memory"); + } + else + out = (stbi_uc*) tmp; + if (delays) { + *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + stbi__rewind( s ); + if (p == NULL) + return 0; + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + (void) stbi__get32be(s); + (void) stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) +// Does not support 16-bit-per-channel + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +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. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ + +/* stb_image_write - v1.14 - public domain - http://nothings.org/stb + writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 + no warranty implied; use at your own risk + + Before #including, + + #define STB_IMAGE_WRITE_IMPLEMENTATION + + in the file that you want to have the implementation. + + Will probably not work correctly with strict-aliasing optimizations. + +ABOUT: + + This header file is a library for writing images to C stdio or a callback. + + The PNG output is not optimal; it is 20-50% larger than the file + written by a decent optimizing implementation; though providing a custom + zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. + This library is designed for source code compactness and simplicity, + not optimal image file size or run-time performance. + +BUILDING: + + You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. + You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace + malloc,realloc,free. + You can #define STBIW_MEMMOVE() to replace memmove() + You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function + for PNG compression (instead of the builtin one), it must have the following signature: + unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); + The returned data will be freed with STBIW_FREE() (free() by default), + so it must be heap allocated with STBIW_MALLOC() (malloc() by default), + +UNICODE: + + If compiling for Windows and you wish to use Unicode filenames, compile + with + #define STBIW_WINDOWS_UTF8 + and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert + Windows wchar_t filenames to utf8. + +USAGE: + + There are five functions, one for each image file format: + + int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); + int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); + + void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically + + There are also five equivalent functions that use an arbitrary write function. You are + expected to open/close your file-equivalent before and after calling these: + + int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); + int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + + where the callback is: + void stbi_write_func(void *context, void *data, int size); + + You can configure it with these global variables: + int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE + int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression + int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode + + + You can define STBI_WRITE_NO_STDIO to disable the file variant of these + functions, so the library will not use stdio.h at all. However, this will + also disable HDR writing, because it requires stdio for formatted output. + + Each function returns 0 on failure and non-0 on success. + + The functions create an image file defined by the parameters. The image + is a rectangle of pixels stored from left-to-right, top-to-bottom. + Each pixel contains 'comp' channels of data stored interleaved with 8-bits + per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is + monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. + The *data pointer points to the first byte of the top-left-most pixel. + For PNG, "stride_in_bytes" is the distance in bytes from the first byte of + a row of pixels to the first byte of the next row of pixels. + + PNG creates output files with the same number of components as the input. + The BMP format expands Y to RGB in the file format and does not + output alpha. + + PNG supports writing rectangles of data even when the bytes storing rows of + data are not consecutive in memory (e.g. sub-rectangles of a larger image), + by supplying the stride between the beginning of adjacent rows. The other + formats do not. (Thus you cannot write a native-format BMP through the BMP + writer, both because it is in BGR order and because it may have padding + at the end of the line.) + + PNG allows you to set the deflate compression level by setting the global + variable 'stbi_write_png_compression_level' (it defaults to 8). + + HDR expects linear float data. Since the format is always 32-bit rgb(e) + data, alpha (if provided) is discarded, and for monochrome data it is + replicated across all three channels. + + TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed + data, set the global variable 'stbi_write_tga_with_rle' to 0. + + JPEG does ignore alpha channels in input data; quality is between 1 and 100. + Higher quality looks better but results in a bigger image. + JPEG baseline (no JPEG progressive). + +CREDITS: + + + Sean Barrett - PNG/BMP/TGA + Baldur Karlsson - HDR + Jean-Sebastien Guay - TGA monochrome + Tim Kelsey - misc enhancements + Alan Hickman - TGA RLE + Emmanuel Julien - initial file IO callback implementation + Jon Olick - original jo_jpeg.cpp code + Daniel Gibson - integrate JPEG, allow external zlib + Aarni Koskela - allow choosing PNG filter + + bugfixes: + github:Chribba + Guillaume Chereau + github:jry2 + github:romigrou + Sergio Gonzalez + Jonas Karlsson + Filip Wasil + Thatcher Ulrich + github:poppolopoppo + Patrick Boettcher + github:xeekworx + Cap Petschulat + Simon Rodriguez + Ivan Tikhonov + github:ignotion + Adam Schackart + +LICENSE + + See end of file for license information. + +*/ + +#ifndef INCLUDE_STB_IMAGE_WRITE_H +#define INCLUDE_STB_IMAGE_WRITE_H + +#include + +// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' +#ifndef STBIWDEF +#ifdef STB_IMAGE_WRITE_STATIC +#define STBIWDEF static +#else +#ifdef __cplusplus +#define STBIWDEF extern "C" +#else +#define STBIWDEF extern +#endif +#endif +#endif + +#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations +extern int stbi_write_tga_with_rle; +extern int stbi_write_png_compression_level; +extern int stbi_write_force_png_filter; +#endif + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); + +#ifdef STBI_WINDOWS_UTF8 +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif +#endif + +typedef void stbi_write_func(void *context, void *data, int size); + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + +STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); + +#endif//INCLUDE_STB_IMAGE_WRITE_H + +#ifdef STB_IMAGE_WRITE_IMPLEMENTATION + +#ifdef _WIN32 + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif + #ifndef _CRT_NONSTDC_NO_DEPRECATE + #define _CRT_NONSTDC_NO_DEPRECATE + #endif +#endif + +#ifndef STBI_WRITE_NO_STDIO +#include +#endif // STBI_WRITE_NO_STDIO + +#include +#include +#include +#include + +#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) +// ok +#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." +#endif + +#ifndef STBIW_MALLOC +#define STBIW_MALLOC(sz) malloc(sz) +#define STBIW_REALLOC(p,newsz) realloc(p,newsz) +#define STBIW_FREE(p) free(p) +#endif + +#ifndef STBIW_REALLOC_SIZED +#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) +#endif + + +#ifndef STBIW_MEMMOVE +#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) +#endif + + +#ifndef STBIW_ASSERT +#include +#define STBIW_ASSERT(x) assert(x) +#endif + +#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) + +#ifdef STB_IMAGE_WRITE_STATIC +static int stbi_write_png_compression_level = 8; +static int stbi_write_tga_with_rle = 1; +static int stbi_write_force_png_filter = -1; +#else +int stbi_write_png_compression_level = 8; +int stbi_write_tga_with_rle = 1; +int stbi_write_force_png_filter = -1; +#endif + +static int stbi__flip_vertically_on_write = 0; + +STBIWDEF void stbi_flip_vertically_on_write(int flag) +{ + stbi__flip_vertically_on_write = flag; +} + +typedef struct +{ + stbi_write_func *func; + void *context; +} stbi__write_context; + +// initialize a callback-based context +static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) +{ + s->func = c; + s->context = context; +} + +#ifndef STBI_WRITE_NO_STDIO + +static void stbi__stdio_write(void *context, void *data, int size) +{ + fwrite(data,1,size,(FILE*) context); +} + +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#ifdef __cplusplus +#define STBIW_EXTERN extern "C" +#else +#define STBIW_EXTERN extern +#endif +STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); + +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbiw__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + return 0; + +#if _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + +static int stbi__start_write_file(stbi__write_context *s, const char *filename) +{ + FILE *f = stbiw__fopen(filename, "wb"); + stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); + return f != NULL; +} + +static void stbi__end_write_file(stbi__write_context *s) +{ + fclose((FILE *)s->context); +} + +#endif // !STBI_WRITE_NO_STDIO + +typedef unsigned int stbiw_uint32; +typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; + +static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) +{ + while (*fmt) { + switch (*fmt++) { + case ' ': break; + case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); + s->func(s->context,&x,1); + break; } + case '2': { int x = va_arg(v,int); + unsigned char b[2]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x>>8); + s->func(s->context,b,2); + break; } + case '4': { stbiw_uint32 x = va_arg(v,int); + unsigned char b[4]; + b[0]=STBIW_UCHAR(x); + b[1]=STBIW_UCHAR(x>>8); + b[2]=STBIW_UCHAR(x>>16); + b[3]=STBIW_UCHAR(x>>24); + s->func(s->context,b,4); + break; } + default: + STBIW_ASSERT(0); + return; + } + } +} + +static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); +} + +static void stbiw__putc(stbi__write_context *s, unsigned char c) +{ + s->func(s->context, &c, 1); +} + +static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) +{ + unsigned char arr[3]; + arr[0] = a; arr[1] = b; arr[2] = c; + s->func(s->context, arr, 3); +} + +static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) +{ + unsigned char bg[3] = { 255, 0, 255}, px[3]; + int k; + + if (write_alpha < 0) + s->func(s->context, &d[comp - 1], 1); + + switch (comp) { + case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case + case 1: + if (expand_mono) + stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp + else + s->func(s->context, d, 1); // monochrome TGA + break; + case 4: + if (!write_alpha) { + // composite against pink background + for (k = 0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + s->func(s->context, &d[comp - 1], 1); +} + +static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) +{ + stbiw_uint32 zero = 0; + int i,j, j_end; + + if (y <= 0) + return; + + if (stbi__flip_vertically_on_write) + vdir *= -1; + + if (vdir < 0) { + j_end = -1; j = y-1; + } else { + j_end = y; j = 0; + } + + for (; j != j_end; j += vdir) { + for (i=0; i < x; ++i) { + unsigned char *d = (unsigned char *) data + (j*x+i)*comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } + s->func(s->context, &zero, scanline_pad); + } +} + +static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) +{ + if (y < 0 || x < 0) { + return 0; + } else { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); + stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); + return 1; + } +} + +static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) +{ + int pad = (-x*3) & 3; + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header +} + +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif //!STBI_WRITE_NO_STDIO + +static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) +{ + int has_alpha = (comp == 2 || comp == 4); + int colorbytes = has_alpha ? comp-1 : comp; + int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 + + if (y < 0 || x < 0) + return 0; + + if (!stbi_write_tga_with_rle) { + return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, + "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); + } else { + int i,j,k; + int jend, jdir; + + stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); + + if (stbi__flip_vertically_on_write) { + j = 0; + jend = y; + jdir = 1; + } else { + j = y-1; + jend = -1; + jdir = -1; + } + for (; j != jend; j += jdir) { + unsigned char *row = (unsigned char *) data + j * x * comp; + int len; + + for (i = 0; i < x; i += len) { + unsigned char *begin = row + i * comp; + int diff = 1; + len = 1; + + if (i < x - 1) { + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); + if (diff) { + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; + } else { + --len; + break; + } + } + } else { + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; + } else { + break; + } + } + } + } + + if (diff) { + unsigned char header = STBIW_UCHAR(len - 1); + s->func(s->context, &header, 1); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = STBIW_UCHAR(len - 129); + s->func(s->context, &header, 1); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } + } + } + } + return 1; +} + +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR writer +// by Baldur Karlsson + +#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) + +static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) +{ + int exponent; + float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); + + if (maxcomp < 1e-32f) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } else { + float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; + + rgbe[0] = (unsigned char)(linear[0] * normalize); + rgbe[1] = (unsigned char)(linear[1] * normalize); + rgbe[2] = (unsigned char)(linear[2] * normalize); + rgbe[3] = (unsigned char)(exponent + 128); + } +} + +static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) +{ + unsigned char lengthbyte = STBIW_UCHAR(length+128); + STBIW_ASSERT(length+128 <= 255); + s->func(s->context, &lengthbyte, 1); + s->func(s->context, &databyte, 1); +} + +static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) +{ + unsigned char lengthbyte = STBIW_UCHAR(length); + STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code + s->func(s->context, &lengthbyte, 1); + s->func(s->context, data, length); +} + +static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) +{ + unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; + unsigned char rgbe[4]; + float linear[3]; + int x; + + scanlineheader[2] = (width&0xff00)>>8; + scanlineheader[3] = (width&0x00ff); + + /* skip RLE for images too small or large */ + if (width < 8 || width >= 32768) { + for (x=0; x < width; x++) { + switch (ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + s->func(s->context, rgbe, 4); + } + } else { + int c,r; + /* encode into scratch buffer */ + for (x=0; x < width; x++) { + switch(ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + scratch[x + width*0] = rgbe[0]; + scratch[x + width*1] = rgbe[1]; + scratch[x + width*2] = rgbe[2]; + scratch[x + width*3] = rgbe[3]; + } + + s->func(s->context, scanlineheader, 4); + + /* RLE each component separately */ + for (c=0; c < 4; c++) { + unsigned char *comp = &scratch[width*c]; + + x = 0; + while (x < width) { + // find first run + r = x; + while (r+2 < width) { + if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) + break; + ++r; + } + if (r+2 >= width) + r = width; + // dump up to first run + while (x < r) { + int len = r-x; + if (len > 128) len = 128; + stbiw__write_dump_data(s, len, &comp[x]); + x += len; + } + // if there's a run, output it + if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd + // find next byte after run + while (r < width && comp[r] == comp[x]) + ++r; + // output run up to r + while (x < r) { + int len = r-x; + if (len > 127) len = 127; + stbiw__write_run_data(s, len, comp[x]); + x += len; + } + } + } + } + } +} + +static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) +{ + if (y <= 0 || x <= 0 || data == NULL) + return 0; + else { + // Each component is stored separately. Allocate scratch space for full output scanline. + unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); + int i, len; + char buffer[128]; + char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header)-1); + +#ifdef __STDC_WANT_SECURE_LIB__ + len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#else + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#endif + s->func(s->context, buffer, len); + + for(i=0; i < y; i++) + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); + STBIW_FREE(scratch); + return 1; + } +} + +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif // STBI_WRITE_NO_STDIO + + +////////////////////////////////////////////////////////////////////////////// +// +// PNG writer +// + +#ifndef STBIW_ZLIB_COMPRESS +// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() +#define stbiw__sbraw(a) ((int *) (void *) (a) - 2) +#define stbiw__sbm(a) stbiw__sbraw(a)[0] +#define stbiw__sbn(a) stbiw__sbraw(a)[1] + +#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) +#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) +#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) + +#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) +#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) +#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) + +static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) +{ + int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; + void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); + STBIW_ASSERT(p); + if (p) { + if (!*arr) ((int *) p)[1] = 0; + *arr = (void *) ((int *) p + 2); + stbiw__sbm(*arr) = m; + } + return *arr; +} + +static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) +{ + while (*bitcount >= 8) { + stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; +} + +static int stbiw__zlib_bitrev(int code, int codebits) +{ + int res=0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; +} + +static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) +{ + int i; + for (i=0; i < limit && i < 258; ++i) + if (a[i] != b[i]) break; + return i; +} + +static unsigned int stbiw__zhash(unsigned char *data) +{ + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; +} + +#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) +#define stbiw__zlib_add(code,codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) +#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) +// default huffman tables +#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) +#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) +#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) +#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) +#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) +#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) + +#define stbiw__ZHASH 16384 + +#endif // STBIW_ZLIB_COMPRESS + +STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +{ +#ifdef STBIW_ZLIB_COMPRESS + // user provided a zlib compress implementation, use that + return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); +#else // use builtin + static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; + static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; + static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; + static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; + unsigned int bitbuf=0; + int i,j, bitcount=0; + unsigned char *out = NULL; + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); + if (hash_table == NULL) + return NULL; + if (quality < 5) quality = 5; + + stbiw__sbpush(out, 0x78); // DEFLATE 32K window + stbiw__sbpush(out, 0x5e); // FLEVEL = 1 + stbiw__zlib_add(1,1); // BFINAL = 1 + stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman + + for (i=0; i < stbiw__ZHASH; ++i) + hash_table[i] = NULL; + + i=0; + while (i < data_len-3) { + // hash next 3 bytes of data to be compressed + int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32768) { // if entry lies within window + int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); + if (d >= best) { best=d; bestloc=hlist[j]; } + } + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { + STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); + stbiw__sbn(hash_table[h]) = quality; + } + stbiw__sbpush(hash_table[h],data+i); + + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal + h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); + hlist = hash_table[h]; + n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32767) { + int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } + } + } + + if (bestloc) { + int d = (int) (data+i - bestloc); // distance back + STBIW_ASSERT(d <= 32767 && best <= 258); + for (j=0; best > lengthc[j+1]-1; ++j); + stbiw__zlib_huff(j+257); + if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + for (j=0; d > distc[j+1]-1; ++j); + stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); + if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { + stbiw__zlib_huffb(data[i]); + ++i; + } + } + // write out final bytes + for (;i < data_len; ++i) + stbiw__zlib_huffb(data[i]); + stbiw__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbiw__zlib_add(0,1); + + for (i=0; i < stbiw__ZHASH; ++i) + (void) stbiw__sbfree(hash_table[i]); + STBIW_FREE(hash_table); + + { + // compute adler32 on input + unsigned int s1=1, s2=0; + int blocklen = (int) (data_len % 5552); + j=0; + while (j < data_len) { + for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } + s1 %= 65521; s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s2)); + stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s1)); + } + *out_len = stbiw__sbn(out); + // make returned pointer freeable + STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); + return (unsigned char *) stbiw__sbraw(out); +#endif // STBIW_ZLIB_COMPRESS +} + +static unsigned int stbiw__crc32(unsigned char *buffer, int len) +{ +#ifdef STBIW_CRC32 + return STBIW_CRC32(buffer, len); +#else + static unsigned int crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + unsigned int crc = ~0u; + int i; + for (i=0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; +#endif +} + +#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) +#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); +#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) + +static void stbiw__wpcrc(unsigned char **data, int len) +{ + unsigned int crc = stbiw__crc32(*data - len - 4, len+4); + stbiw__wp32(*data, crc); +} + +static unsigned char stbiw__paeth(int a, int b, int c) +{ + int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); + if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); + if (pb <= pc) return STBIW_UCHAR(b); + return STBIW_UCHAR(c); +} + +// @OPTIMIZE: provide an option that always forces left-predict or paeth predict +static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) +{ + static int mapping[] = { 0,1,2,3,4 }; + static int firstmap[] = { 0,1,0,5,6 }; + int *mymap = (y != 0) ? mapping : firstmap; + int i; + int type = mymap[filter_type]; + unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); + int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; + + if (type==0) { + memcpy(line_buffer, z, width*n); + return; + } + + // first loop isn't optimized since it's just one pixel + for (i = 0; i < n; ++i) { + switch (type) { + case 1: line_buffer[i] = z[i]; break; + case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; + case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; + case 5: line_buffer[i] = z[i]; break; + case 6: line_buffer[i] = z[i]; break; + } + } + switch (type) { + case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; + case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; + case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; + case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; + } +} + +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +{ + int force_filter = stbi_write_force_png_filter; + int ctype[5] = { -1, 0, 4, 2, 6 }; + unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; + unsigned char *out,*o, *filt, *zlib; + signed char *line_buffer; + int j,zlen; + + if (stride_bytes == 0) + stride_bytes = x * n; + + if (force_filter >= 5) { + force_filter = -1; + } + + filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; + line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } + for (j=0; j < y; ++j) { + int filter_type; + if (force_filter > -1) { + filter_type = force_filter; + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); + } else { // Estimate the best filter by running through all of them: + int best_filter = 0, best_filter_val = 0x7fffffff, est, i; + for (filter_type = 0; filter_type < 5; filter_type++) { + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); + + // Estimate the entropy of the line using this filter; the less, the better. + est = 0; + for (i = 0; i < x*n; ++i) { + est += abs((signed char) line_buffer[i]); + } + if (est < best_filter_val) { + best_filter_val = est; + best_filter = filter_type; + } + } + if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); + filter_type = best_filter; + } + } + // when we get here, filter_type contains the filter type, and line_buffer contains the data + filt[j*(x*n+1)] = (unsigned char) filter_type; + STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); + STBIW_FREE(filt); + if (!zlib) return 0; + + // each tag requires 12 bytes of overhead + out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); + if (!out) return 0; + *out_len = 8 + 12+13 + 12+zlen + 12; + + o=out; + STBIW_MEMMOVE(o,sig,8); o+= 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = STBIW_UCHAR(ctype[n]); + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o,13); + + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); + + stbiw__wp32(o,0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o,0); + + STBIW_ASSERT(o == out + *out_len); + + return out; +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) +{ + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + + f = stbiw__fopen(filename, "wb"); + if (!f) { STBIW_FREE(png); return 0; } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; +} +#endif + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) +{ + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; +} + + +/* *************************************************************************** + * + * JPEG writer + * + * This is based on Jon Olick's jo_jpeg.cpp: + * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html + */ + +static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, + 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; + +static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { + int bitBuf = *bitBufP, bitCnt = *bitCntP; + bitCnt += bs[1]; + bitBuf |= bs[0] << (24 - bitCnt); + while(bitCnt >= 8) { + unsigned char c = (bitBuf >> 16) & 255; + stbiw__putc(s, c); + if(c == 255) { + stbiw__putc(s, 0); + } + bitBuf <<= 8; + bitCnt -= 8; + } + *bitBufP = bitBuf; + *bitCntP = bitCnt; +} + +static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { + float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; + float z1, z2, z3, z4, z5, z11, z13; + + float tmp0 = d0 + d7; + float tmp7 = d0 - d7; + float tmp1 = d1 + d6; + float tmp6 = d1 - d6; + float tmp2 = d2 + d5; + float tmp5 = d2 - d5; + float tmp3 = d3 + d4; + float tmp4 = d3 - d4; + + // Even part + float tmp10 = tmp0 + tmp3; // phase 2 + float tmp13 = tmp0 - tmp3; + float tmp11 = tmp1 + tmp2; + float tmp12 = tmp1 - tmp2; + + d0 = tmp10 + tmp11; // phase 3 + d4 = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * 0.707106781f; // c4 + d2 = tmp13 + z1; // phase 5 + d6 = tmp13 - z1; + + // Odd part + tmp10 = tmp4 + tmp5; // phase 2 + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = (tmp10 - tmp12) * 0.382683433f; // c6 + z2 = tmp10 * 0.541196100f + z5; // c2-c6 + z4 = tmp12 * 1.306562965f + z5; // c2+c6 + z3 = tmp11 * 0.707106781f; // c4 + + z11 = tmp7 + z3; // phase 5 + z13 = tmp7 - z3; + + *d5p = z13 + z2; // phase 6 + *d3p = z13 - z2; + *d1p = z11 + z4; + *d7p = z11 - z4; + + *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; +} + +static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { + int tmp1 = val < 0 ? -val : val; + val = val < 0 ? val-1 : val; + bits[1] = 1; + while(tmp1 >>= 1) { + ++bits[1]; + } + bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { + } + // end0pos = first element in reverse order !=0 + if(end0pos == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + return DU[0]; + } + for(i = 1; i <= end0pos; ++i) { + int startpos = i; + int nrzeroes; + unsigned short bits[2]; + for (; DU[i]==0 && i<=end0pos; ++i) { + } + nrzeroes = i-startpos; + if ( nrzeroes >= 16 ) { + int lng = nrzeroes>>4; + int nrmarker; + for (nrmarker=1; nrmarker <= lng; ++nrmarker) + stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); + nrzeroes &= 15; + } + stbiw__jpg_calcBits(DU[i], bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + if(end0pos != 63) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + } + return DU[0]; +} + +static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { + // Constants that don't pollute global namespace + static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; + static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; + static const unsigned char std_ac_luminance_values[] = { + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, + 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, + 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, + 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, + 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; + static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; + static const unsigned char std_ac_chrominance_values[] = { + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, + 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, + 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, + 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, + 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, + 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + // Huffman tables + static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; + static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; + static const unsigned short YAC_HT[256][2] = { + {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const unsigned short UVAC_HT[256][2] = { + {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, + 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; + static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; + static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, + 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; + + int row, col, i, k, subsample; + float fdtbl_Y[64], fdtbl_UV[64]; + unsigned char YTable[64], UVTable[64]; + + if(!data || !width || !height || comp > 4 || comp < 1) { + return 0; + } + + quality = quality ? quality : 90; + subsample = quality <= 90 ? 1 : 0; + quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + + for(i = 0; i < 64; ++i) { + int uvti, yti = (YQT[i]*quality+50)/100; + YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); + uvti = (UVQT[i]*quality+50)/100; + UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); + } + + for(row = 0, k = 0; row < 8; ++row) { + for(col = 0; col < 8; ++col, ++k) { + fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + } + } + + // Write Headers + { + static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; + static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; + const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), + 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; + s->func(s->context, (void*)head0, sizeof(head0)); + s->func(s->context, (void*)YTable, sizeof(YTable)); + stbiw__putc(s, 1); + s->func(s->context, UVTable, sizeof(UVTable)); + s->func(s->context, (void*)head1, sizeof(head1)); + s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); + s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); + stbiw__putc(s, 0x10); // HTYACinfo + s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); + s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); + stbiw__putc(s, 1); // HTUDCinfo + s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); + stbiw__putc(s, 0x11); // HTUACinfo + s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); + s->func(s->context, (void*)head2, sizeof(head2)); + } + + // Encode 8x8 macroblocks + { + static const unsigned short fillBits[] = {0x7F, 7}; + int DCY=0, DCU=0, DCV=0; + int bitBuf=0, bitCnt=0; + // comp == 2 is grey+alpha (alpha is ignored) + int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + const unsigned char *dataR = (const unsigned char *)data; + const unsigned char *dataG = dataR + ofsG; + const unsigned char *dataB = dataR + ofsB; + int x, y, pos; + if(subsample) { + for(y = 0; y < height; y += 16) { + for(x = 0; x < width; x += 16) { + float Y[256], U[256], V[256]; + for(row = y, pos = 0; row < y+16; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+16; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + + // subsample U,V + { + float subU[64], subV[64]; + int yy, xx; + for(yy = 0, pos = 0; yy < 8; ++yy) { + for(xx = 0; xx < 8; ++xx, ++pos) { + int j = yy*32+xx*2; + subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; + subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; + } + } + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + } else { + for(y = 0; y < height; y += 8) { + for(x = 0; x < width; x += 8) { + float Y[64], U[64], V[64]; + for(row = y, pos = 0; row < y+8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+8; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + + // Do the bit alignment of the EOI marker + stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); + } + + // EOI + stbiw__putc(s, 0xFF); + stbiw__putc(s, 0xD9); + + return 1; +} + +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); +} + + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +#endif // STB_IMAGE_WRITE_IMPLEMENTATION + +/* Revision history + 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels + 1.13 + 1.12 + 1.11 (2019-08-11) + + 1.10 (2019-02-07) + support utf8 filenames in Windows; fix warnings and platform ifdefs + 1.09 (2018-02-11) + fix typo in zlib quality API, improve STB_I_W_STATIC in C++ + 1.08 (2018-01-29) + add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter + 1.07 (2017-07-24) + doc fix + 1.06 (2017-07-23) + writing JPEG (using Jon Olick's code) + 1.05 ??? + 1.04 (2017-03-03) + monochrome BMP expansion + 1.03 ??? + 1.02 (2016-04-02) + avoid allocating large structures on the stack + 1.01 (2016-01-16) + STBIW_REALLOC_SIZED: support allocators with no realloc support + avoid race-condition in crc initialization + minor compile issues + 1.00 (2015-09-14) + installable file IO function + 0.99 (2015-09-13) + warning fixes; TGA rle support + 0.98 (2015-04-08) + added STBIW_MALLOC, STBIW_ASSERT etc + 0.97 (2015-01-18) + fixed HDR asserts, rewrote HDR rle logic + 0.96 (2015-01-17) + add HDR output + fix monochrome BMP + 0.95 (2014-08-17) + add monochrome TGA output + 0.94 (2014-05-31) + rename private functions to avoid conflicts with stb_image.h + 0.93 (2014-05-27) + warning fixes + 0.92 (2010-08-01) + casts to unsigned char to fix warnings + 0.91 (2010-07-17) + first public release + 0.90 first internal release +*/ + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +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. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ + +/* stb_image_resize - v0.96 - public domain image resizing + by Jorge L Rodriguez (@VinoBS) - 2014 + http://github.com/nothings/stb + + Written with emphasis on usability, portability, and efficiency. (No + SIMD or threads, so it be easily outperformed by libs that use those.) + Only scaling and translation is supported, no rotations or shears. + Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation. + + COMPILING & LINKING + In one C/C++ file that #includes this file, do this: + #define STB_IMAGE_RESIZE_IMPLEMENTATION + before the #include. That will create the implementation in that file. + + QUICKSTART + stbir_resize_uint8( input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, num_channels) + stbir_resize_float(...) + stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, + num_channels , alpha_chan , 0) + stbir_resize_uint8_srgb_edgemode( + input_pixels , in_w , in_h , 0, + output_pixels, out_w, out_h, 0, + num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP) + // WRAP/REFLECT/ZERO + + FULL API + See the "header file" section of the source for API documentation. + + ADDITIONAL DOCUMENTATION + + SRGB & FLOATING POINT REPRESENTATION + The sRGB functions presume IEEE floating point. If you do not have + IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use + a slower implementation. + + MEMORY ALLOCATION + The resize functions here perform a single memory allocation using + malloc. To control the memory allocation, before the #include that + triggers the implementation, do: + + #define STBIR_MALLOC(size,context) ... + #define STBIR_FREE(ptr,context) ... + + Each resize function makes exactly one call to malloc/free, so to use + temp memory, store the temp memory in the context and return that. + + ASSERT + Define STBIR_ASSERT(boolval) to override assert() and not use assert.h + + OPTIMIZATION + Define STBIR_SATURATE_INT to compute clamp values in-range using + integer operations instead of float operations. This may be faster + on some platforms. + + DEFAULT FILTERS + For functions which don't provide explicit control over what filters + to use, you can change the compile-time defaults with + + #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something + #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something + + See stbir_filter in the header-file section for the list of filters. + + NEW FILTERS + A number of 1D filter kernels are used. For a list of + supported filters see the stbir_filter enum. To add a new filter, + write a filter function and add it to stbir__filter_info_table. + + PROGRESS + For interactive use with slow resize operations, you can install + a progress-report callback: + + #define STBIR_PROGRESS_REPORT(val) some_func(val) + + The parameter val is a float which goes from 0 to 1 as progress is made. + + For example: + + static void my_progress_report(float progress); + #define STBIR_PROGRESS_REPORT(val) my_progress_report(val) + + #define STB_IMAGE_RESIZE_IMPLEMENTATION + #include "stb_image_resize.h" + + static void my_progress_report(float progress) + { + printf("Progress: %f%%\n", progress*100); + } + + MAX CHANNELS + If your image has more than 64 channels, define STBIR_MAX_CHANNELS + to the max you'll have. + + ALPHA CHANNEL + Most of the resizing functions provide the ability to control how + the alpha channel of an image is processed. The important things + to know about this: + + 1. The best mathematically-behaved version of alpha to use is + called "premultiplied alpha", in which the other color channels + have had the alpha value multiplied in. If you use premultiplied + alpha, linear filtering (such as image resampling done by this + library, or performed in texture units on GPUs) does the "right + thing". While premultiplied alpha is standard in the movie CGI + industry, it is still uncommon in the videogame/real-time world. + + If you linearly filter non-premultiplied alpha, strange effects + occur. (For example, the 50/50 average of 99% transparent bright green + and 1% transparent black produces 50% transparent dark green when + non-premultiplied, whereas premultiplied it produces 50% + transparent near-black. The former introduces green energy + that doesn't exist in the source image.) + + 2. Artists should not edit premultiplied-alpha images; artists + want non-premultiplied alpha images. Thus, art tools generally output + non-premultiplied alpha images. + + 3. You will get best results in most cases by converting images + to premultiplied alpha before processing them mathematically. + + 4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the + resizer does not do anything special for the alpha channel; + it is resampled identically to other channels. This produces + the correct results for premultiplied-alpha images, but produces + less-than-ideal results for non-premultiplied-alpha images. + + 5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, + then the resizer weights the contribution of input pixels + based on their alpha values, or, equivalently, it multiplies + the alpha value into the color channels, resamples, then divides + by the resultant alpha value. Input pixels which have alpha=0 do + not contribute at all to output pixels unless _all_ of the input + pixels affecting that output pixel have alpha=0, in which case + the result for that pixel is the same as it would be without + STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for + input images in integer formats. For input images in float format, + input pixels with alpha=0 have no effect, and output pixels + which have alpha=0 will be 0 in all channels. (For float images, + you can manually achieve the same result by adding a tiny epsilon + value to the alpha channel of every image, and then subtracting + or clamping it at the end.) + + 6. You can suppress the behavior described in #5 and make + all-0-alpha pixels have 0 in all channels by #defining + STBIR_NO_ALPHA_EPSILON. + + 7. You can separately control whether the alpha channel is + interpreted as linear or affected by the colorspace. By default + it is linear; you almost never want to apply the colorspace. + (For example, graphics hardware does not apply sRGB conversion + to the alpha channel.) + + CONTRIBUTORS + Jorge L Rodriguez: Implementation + Sean Barrett: API design, optimizations + Aras Pranckevicius: bugfix + Nathan Reed: warning fixes + + REVISIONS + 0.97 (2020-02-02) fixed warning + 0.96 (2019-03-04) fixed warnings + 0.95 (2017-07-23) fixed warnings + 0.94 (2017-03-18) fixed warnings + 0.93 (2017-03-03) fixed bug with certain combinations of heights + 0.92 (2017-01-02) fix integer overflow on large (>2GB) images + 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions + 0.90 (2014-09-17) first released version + + LICENSE + See end of file for license information. + + TODO + Don't decode all of the image data when only processing a partial tile + Don't use full-width decode buffers when only processing a partial tile + When processing wide images, break processing into tiles so data fits in L1 cache + Installable filters? + Resize that respects alpha test coverage + (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage: + https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp ) +*/ + +#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H +#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H + +#ifdef _MSC_VER +typedef unsigned char stbir_uint8; +typedef unsigned short stbir_uint16; +typedef unsigned int stbir_uint32; +#else +#include +typedef uint8_t stbir_uint8; +typedef uint16_t stbir_uint16; +typedef uint32_t stbir_uint32; +#endif + +#ifndef STBIRDEF +#ifdef STB_IMAGE_RESIZE_STATIC +#define STBIRDEF static +#else +#ifdef __cplusplus +#define STBIRDEF extern "C" +#else +#define STBIRDEF extern +#endif +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// Easy-to-use API: +// +// * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4) +// * input_w is input image width (x-axis), input_h is input image height (y-axis) +// * stride is the offset between successive rows of image data in memory, in bytes. you can +// specify 0 to mean packed continuously in memory +// * alpha channel is treated identically to other channels. +// * colorspace is linear or sRGB as specified by function name +// * returned result is 1 for success or 0 in case of an error. +// #define STBIR_ASSERT() to trigger an assert on parameter validation errors. +// * Memory required grows approximately linearly with input and output size, but with +// discontinuities at input_w == output_w and input_h == output_h. +// * These functions use a "default" resampling filter defined at compile time. To change the filter, +// you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE +// and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API. + +STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels); + +STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels); + + +// The following functions interpret image data as gamma-corrected sRGB. +// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel, +// or otherwise provide the index of the alpha channel. Flags value +// of 0 will probably do the right thing if you're not sure what +// the flags mean. + +#define STBIR_ALPHA_CHANNEL_NONE -1 + +// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will +// use alpha-weighted resampling (effectively premultiplying, resampling, +// then unpremultiplying). +#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0) +// The specified alpha channel should be handled as gamma-corrected value even +// when doing sRGB operations. +#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1) + +STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags); + + +typedef enum +{ + STBIR_EDGE_CLAMP = 1, + STBIR_EDGE_REFLECT = 2, + STBIR_EDGE_WRAP = 3, + STBIR_EDGE_ZERO = 4, +} stbir_edge; + +// This function adds the ability to specify how requests to sample off the edge of the image are handled. +STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode); + +////////////////////////////////////////////////////////////////////////////// +// +// Medium-complexity API +// +// This extends the easy-to-use API as follows: +// +// * Alpha-channel can be processed separately +// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE +// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT) +// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED) +// * Filter can be selected explicitly +// * uint16 image type +// * sRGB colorspace available for all types +// * context parameter for passing to STBIR_MALLOC + +typedef enum +{ + STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses + STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios + STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering + STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque + STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline + STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3 +} stbir_filter; + +typedef enum +{ + STBIR_COLORSPACE_LINEAR, + STBIR_COLORSPACE_SRGB, + + STBIR_MAX_COLORSPACES, +} stbir_colorspace; + +// The following functions are all identical except for the type of the image data + +STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + +STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + +STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context); + + + +////////////////////////////////////////////////////////////////////////////// +// +// Full-complexity API +// +// This extends the medium API as follows: +// +// * uint32 image type +// * not typesafe +// * separate filter types for each axis +// * separate edge modes for each axis +// * can specify scale explicitly for subpixel correctness +// * can specify image source tile using texture coordinates + +typedef enum +{ + STBIR_TYPE_UINT8 , + STBIR_TYPE_UINT16, + STBIR_TYPE_UINT32, + STBIR_TYPE_FLOAT , + + STBIR_MAX_TYPES +} stbir_datatype; + +STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context); + +STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float x_scale, float y_scale, + float x_offset, float y_offset); + +STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float s0, float t0, float s1, float t1); +// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use. + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H + + + + + +#ifdef STB_IMAGE_RESIZE_IMPLEMENTATION + +#ifndef STBIR_ASSERT +#include +#define STBIR_ASSERT(x) assert(x) +#endif + +// For memset +#include + +#include + +#ifndef STBIR_MALLOC +#include +// use comma operator to evaluate c, to avoid "unused parameter" warnings +#define STBIR_MALLOC(size,c) ((void)(c), malloc(size)) +#define STBIR_FREE(ptr,c) ((void)(c), free(ptr)) +#endif + +#ifndef _MSC_VER +#ifdef __cplusplus +#define stbir__inline inline +#else +#define stbir__inline +#endif +#else +#define stbir__inline __forceinline +#endif + + +// should produce compiler error if size is wrong +typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBIR__NOTUSED(v) (void)(v) +#else +#define STBIR__NOTUSED(v) (void)sizeof(v) +#endif + +#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0])) + +#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE +#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM +#endif + +#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE +#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL +#endif + +#ifndef STBIR_PROGRESS_REPORT +#define STBIR_PROGRESS_REPORT(float_0_to_1) +#endif + +#ifndef STBIR_MAX_CHANNELS +#define STBIR_MAX_CHANNELS 64 +#endif + +#if STBIR_MAX_CHANNELS > 65536 +#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536." +// because we store the indices in 16-bit variables +#endif + +// This value is added to alpha just before premultiplication to avoid +// zeroing out color values. It is equivalent to 2^-80. If you don't want +// that behavior (it may interfere if you have floating point images with +// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to +// disable it. +#ifndef STBIR_ALPHA_EPSILON +#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20)) +#endif + + + +#ifdef _MSC_VER +#define STBIR__UNUSED_PARAM(v) (void)(v) +#else +#define STBIR__UNUSED_PARAM(v) (void)sizeof(v) +#endif + +// must match stbir_datatype +static unsigned char stbir__type_size[] = { + 1, // STBIR_TYPE_UINT8 + 2, // STBIR_TYPE_UINT16 + 4, // STBIR_TYPE_UINT32 + 4, // STBIR_TYPE_FLOAT +}; + +// Kernel function centered at 0 +typedef float (stbir__kernel_fn)(float x, float scale); +typedef float (stbir__support_fn)(float scale); + +typedef struct +{ + stbir__kernel_fn* kernel; + stbir__support_fn* support; +} stbir__filter_info; + +// When upsampling, the contributors are which source pixels contribute. +// When downsampling, the contributors are which destination pixels are contributed to. +typedef struct +{ + int n0; // First contributing pixel + int n1; // Last contributing pixel +} stbir__contributors; + +typedef struct +{ + const void* input_data; + int input_w; + int input_h; + int input_stride_bytes; + + void* output_data; + int output_w; + int output_h; + int output_stride_bytes; + + float s0, t0, s1, t1; + + float horizontal_shift; // Units: output pixels + float vertical_shift; // Units: output pixels + float horizontal_scale; + float vertical_scale; + + int channels; + int alpha_channel; + stbir_uint32 flags; + stbir_datatype type; + stbir_filter horizontal_filter; + stbir_filter vertical_filter; + stbir_edge edge_horizontal; + stbir_edge edge_vertical; + stbir_colorspace colorspace; + + stbir__contributors* horizontal_contributors; + float* horizontal_coefficients; + + stbir__contributors* vertical_contributors; + float* vertical_coefficients; + + int decode_buffer_pixels; + float* decode_buffer; + + float* horizontal_buffer; + + // cache these because ceil/floor are inexplicably showing up in profile + int horizontal_coefficient_width; + int vertical_coefficient_width; + int horizontal_filter_pixel_width; + int vertical_filter_pixel_width; + int horizontal_filter_pixel_margin; + int vertical_filter_pixel_margin; + int horizontal_num_contributors; + int vertical_num_contributors; + + int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter) + int ring_buffer_num_entries; // Total number of entries in the ring buffer. + int ring_buffer_first_scanline; + int ring_buffer_last_scanline; + int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer + float* ring_buffer; + + float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds. + + int horizontal_contributors_size; + int horizontal_coefficients_size; + int vertical_contributors_size; + int vertical_coefficients_size; + int decode_buffer_size; + int horizontal_buffer_size; + int ring_buffer_size; + int encode_buffer_size; +} stbir__info; + + +static const float stbir__max_uint8_as_float = 255.0f; +static const float stbir__max_uint16_as_float = 65535.0f; +static const double stbir__max_uint32_as_float = 4294967295.0; + + +static stbir__inline int stbir__min(int a, int b) +{ + return a < b ? a : b; +} + +static stbir__inline float stbir__saturate(float x) +{ + if (x < 0) + return 0; + + if (x > 1) + return 1; + + return x; +} + +#ifdef STBIR_SATURATE_INT +static stbir__inline stbir_uint8 stbir__saturate8(int x) +{ + if ((unsigned int) x <= 255) + return x; + + if (x < 0) + return 0; + + return 255; +} + +static stbir__inline stbir_uint16 stbir__saturate16(int x) +{ + if ((unsigned int) x <= 65535) + return x; + + if (x < 0) + return 0; + + return 65535; +} +#endif + +static float stbir__srgb_uchar_to_linear_float[256] = { + 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f, + 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f, + 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f, + 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f, + 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f, + 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f, + 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f, + 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f, + 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f, + 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f, + 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f, + 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f, + 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f, + 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f, + 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f, + 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f, + 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f, + 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f, + 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f, + 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f, + 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f, + 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f, + 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f, + 0.982251f, 0.991102f, 1.0f +}; + +static float stbir__srgb_to_linear(float f) +{ + if (f <= 0.04045f) + return f / 12.92f; + else + return (float)pow((f + 0.055f) / 1.055f, 2.4f); +} + +static float stbir__linear_to_srgb(float f) +{ + if (f <= 0.0031308f) + return f * 12.92f; + else + return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f; +} + +#ifndef STBIR_NON_IEEE_FLOAT +// From https://gist.github.com/rygorous/2203834 + +typedef union +{ + stbir_uint32 u; + float f; +} stbir__FP32; + +static const stbir_uint32 fp32_to_srgb8_tab4[104] = { + 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d, + 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a, + 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033, + 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067, + 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5, + 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2, + 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143, + 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af, + 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240, + 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300, + 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401, + 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559, + 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723, +}; + +static stbir_uint8 stbir__linear_to_srgb_uchar(float in) +{ + static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps + static const stbir__FP32 minval = { (127-13) << 23 }; + stbir_uint32 tab,bias,scale,t; + stbir__FP32 f; + + // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively. + // The tests are carefully written so that NaNs map to 0, same as in the reference + // implementation. + if (!(in > minval.f)) // written this way to catch NaNs + in = minval.f; + if (in > almostone.f) + in = almostone.f; + + // Do the table lookup and unpack bias, scale + f.f = in; + tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20]; + bias = (tab >> 16) << 9; + scale = tab & 0xffff; + + // Grab next-highest mantissa bits and perform linear interpolation + t = (f.u >> 12) & 0xff; + return (unsigned char) ((bias + scale*t) >> 16); +} + +#else +// sRGB transition values, scaled by 1<<28 +static int stbir__srgb_offset_to_linear_scaled[256] = +{ + 0, 40738, 122216, 203693, 285170, 366648, 448125, 529603, + 611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926, + 1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148, + 2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856, + 3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731, + 5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369, + 7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021, + 10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073, + 13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389, + 17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552, + 21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066, + 25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490, + 31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568, + 36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316, + 43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096, + 49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700, + 57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376, + 65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912, + 74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648, + 83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512, + 93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072, + 104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544, + 115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832, + 127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528, + 140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968, + 154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184, + 168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992, + 183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968, + 199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480, + 215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656, + 232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464, + 250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664, +}; + +static stbir_uint8 stbir__linear_to_srgb_uchar(float f) +{ + int x = (int) (f * (1 << 28)); // has headroom so you don't need to clamp + int v = 0; + int i; + + // Refine the guess with a short binary search. + i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + i = v + 1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i; + + return (stbir_uint8) v; +} +#endif + +static float stbir__filter_trapezoid(float x, float scale) +{ + float halfscale = scale / 2; + float t = 0.5f + halfscale; + STBIR_ASSERT(scale <= 1); + + x = (float)fabs(x); + + if (x >= t) + return 0; + else + { + float r = 0.5f - halfscale; + if (x <= r) + return 1; + else + return (t - x) / scale; + } +} + +static float stbir__support_trapezoid(float scale) +{ + STBIR_ASSERT(scale <= 1); + return 0.5f + scale / 2; +} + +static float stbir__filter_triangle(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x <= 1.0f) + return 1 - x; + else + return 0; +} + +static float stbir__filter_cubic(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return (4 + x*x*(3*x - 6))/6; + else if (x < 2.0f) + return (8 + x*(-12 + x*(6 - x)))/6; + + return (0.0f); +} + +static float stbir__filter_catmullrom(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return 1 - x*x*(2.5f - 1.5f*x); + else if (x < 2.0f) + return 2 - x*(4 + x*(0.5f*x - 2.5f)); + + return (0.0f); +} + +static float stbir__filter_mitchell(float x, float s) +{ + STBIR__UNUSED_PARAM(s); + + x = (float)fabs(x); + + if (x < 1.0f) + return (16 + x*x*(21 * x - 36))/18; + else if (x < 2.0f) + return (32 + x*(-60 + x*(36 - 7*x)))/18; + + return (0.0f); +} + +static float stbir__support_zero(float s) +{ + STBIR__UNUSED_PARAM(s); + return 0; +} + +static float stbir__support_one(float s) +{ + STBIR__UNUSED_PARAM(s); + return 1; +} + +static float stbir__support_two(float s) +{ + STBIR__UNUSED_PARAM(s); + return 2; +} + +static stbir__filter_info stbir__filter_info_table[] = { + { NULL, stbir__support_zero }, + { stbir__filter_trapezoid, stbir__support_trapezoid }, + { stbir__filter_triangle, stbir__support_one }, + { stbir__filter_cubic, stbir__support_two }, + { stbir__filter_catmullrom, stbir__support_two }, + { stbir__filter_mitchell, stbir__support_two }, +}; + +stbir__inline static int stbir__use_upsampling(float ratio) +{ + return ratio > 1; +} + +stbir__inline static int stbir__use_width_upsampling(stbir__info* stbir_info) +{ + return stbir__use_upsampling(stbir_info->horizontal_scale); +} + +stbir__inline static int stbir__use_height_upsampling(stbir__info* stbir_info) +{ + return stbir__use_upsampling(stbir_info->vertical_scale); +} + +// This is the maximum number of input samples that can affect an output sample +// with the given filter +static int stbir__get_filter_pixel_width(stbir_filter filter, float scale) +{ + STBIR_ASSERT(filter != 0); + STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + + if (stbir__use_upsampling(scale)) + return (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2); + else + return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale); +} + +// This is how much to expand buffers to account for filters seeking outside +// the image boundaries. +static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale) +{ + return stbir__get_filter_pixel_width(filter, scale) / 2; +} + +static int stbir__get_coefficient_width(stbir_filter filter, float scale) +{ + if (stbir__use_upsampling(scale)) + return (int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2); + else + return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2); +} + +static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size) +{ + if (stbir__use_upsampling(scale)) + return output_size; + else + return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2); +} + +static int stbir__get_total_horizontal_coefficients(stbir__info* info) +{ + return info->horizontal_num_contributors + * stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale); +} + +static int stbir__get_total_vertical_coefficients(stbir__info* info) +{ + return info->vertical_num_contributors + * stbir__get_coefficient_width (info->vertical_filter, info->vertical_scale); +} + +static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n) +{ + return &contributors[n]; +} + +// For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample, +// if you change it here change it there too. +static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c) +{ + int width = stbir__get_coefficient_width(filter, scale); + return &coefficients[width*n + c]; +} + +static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max) +{ + switch (edge) + { + case STBIR_EDGE_ZERO: + return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later + + case STBIR_EDGE_CLAMP: + if (n < 0) + return 0; + + if (n >= max) + return max - 1; + + return n; // NOTREACHED + + case STBIR_EDGE_REFLECT: + { + if (n < 0) + { + if (n < max) + return -n; + else + return max - 1; + } + + if (n >= max) + { + int max2 = max * 2; + if (n >= max2) + return 0; + else + return max2 - n - 1; + } + + return n; // NOTREACHED + } + + case STBIR_EDGE_WRAP: + if (n >= 0) + return (n % max); + else + { + int m = (-n) % max; + + if (m != 0) + m = max - m; + + return (m); + } + // NOTREACHED + + default: + STBIR_ASSERT(!"Unimplemented edge type"); + return 0; + } +} + +stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max) +{ + // avoid per-pixel switch + if (n >= 0 && n < max) + return n; + return stbir__edge_wrap_slow(edge, n, max); +} + +// What input pixels contribute to this output pixel? +static void stbir__calculate_sample_range_upsample(int n, float out_filter_radius, float scale_ratio, float out_shift, int* in_first_pixel, int* in_last_pixel, float* in_center_of_out) +{ + float out_pixel_center = (float)n + 0.5f; + float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius; + float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius; + + float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio; + float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio; + + *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio; + *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5)); + *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5)); +} + +// What output pixels does this input pixel contribute to? +static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radius, float scale_ratio, float out_shift, int* out_first_pixel, int* out_last_pixel, float* out_center_of_in) +{ + float in_pixel_center = (float)n + 0.5f; + float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius; + float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius; + + float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift; + float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift; + + *out_center_of_in = in_pixel_center * scale_ratio - out_shift; + *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5)); + *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5)); +} + +static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group) +{ + int i; + float total_filter = 0; + float filter_scale; + + STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. + + contributor->n0 = in_first_pixel; + contributor->n1 = in_last_pixel; + + STBIR_ASSERT(contributor->n1 >= contributor->n0); + + for (i = 0; i <= in_last_pixel - in_first_pixel; i++) + { + float in_pixel_center = (float)(i + in_first_pixel) + 0.5f; + coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale); + + // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.) + if (i == 0 && !coefficient_group[i]) + { + contributor->n0 = ++in_first_pixel; + i--; + continue; + } + + total_filter += coefficient_group[i]; + } + + STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0); + + STBIR_ASSERT(total_filter > 0.9); + STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off. + + // Make sure the sum of all coefficients is 1. + filter_scale = 1 / total_filter; + + for (i = 0; i <= in_last_pixel - in_first_pixel; i++) + coefficient_group[i] *= filter_scale; + + for (i = in_last_pixel - in_first_pixel; i >= 0; i--) + { + if (coefficient_group[i]) + break; + + // This line has no weight. We can skip it. + contributor->n1 = contributor->n0 + i - 1; + } +} + +static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group) +{ + int i; + + STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical. + + contributor->n0 = out_first_pixel; + contributor->n1 = out_last_pixel; + + STBIR_ASSERT(contributor->n1 >= contributor->n0); + + for (i = 0; i <= out_last_pixel - out_first_pixel; i++) + { + float out_pixel_center = (float)(i + out_first_pixel) + 0.5f; + float x = out_pixel_center - out_center_of_in; + coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio; + } + + STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0); + + for (i = out_last_pixel - out_first_pixel; i >= 0; i--) + { + if (coefficient_group[i]) + break; + + // This line has no weight. We can skip it. + contributor->n1 = contributor->n0 + i - 1; + } +} + +static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size) +{ + int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); + int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio); + int i, j; + int skip; + + for (i = 0; i < output_size; i++) + { + float scale; + float total = 0; + + for (j = 0; j < num_contributors; j++) + { + if (i >= contributors[j].n0 && i <= contributors[j].n1) + { + float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0); + total += coefficient; + } + else if (i < contributors[j].n0) + break; + } + + STBIR_ASSERT(total > 0.9f); + STBIR_ASSERT(total < 1.1f); + + scale = 1 / total; + + for (j = 0; j < num_contributors; j++) + { + if (i >= contributors[j].n0 && i <= contributors[j].n1) + *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale; + else if (i < contributors[j].n0) + break; + } + } + + // Optimize: Skip zero coefficients and contributions outside of image bounds. + // Do this after normalizing because normalization depends on the n0/n1 values. + for (j = 0; j < num_contributors; j++) + { + int range, max, width; + + skip = 0; + while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0) + skip++; + + contributors[j].n0 += skip; + + while (contributors[j].n0 < 0) + { + contributors[j].n0++; + skip++; + } + + range = contributors[j].n1 - contributors[j].n0 + 1; + max = stbir__min(num_coefficients, range); + + width = stbir__get_coefficient_width(filter, scale_ratio); + for (i = 0; i < max; i++) + { + if (i + skip >= width) + break; + + *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip); + } + + continue; + } + + // Using min to avoid writing into invalid pixels. + for (i = 0; i < num_contributors; i++) + contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1); +} + +// Each scan line uses the same kernel values so we should calculate the kernel +// values once and then we can use them for every scan line. +static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size) +{ + int n; + int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size); + + if (stbir__use_upsampling(scale_ratio)) + { + float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio; + + // Looping through out pixels + for (n = 0; n < total_contributors; n++) + { + float in_center_of_out; // Center of the current out pixel in the in pixel space + int in_first_pixel, in_last_pixel; + + stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out); + + stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); + } + } + else + { + float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio; + + // Looping through in pixels + for (n = 0; n < total_contributors; n++) + { + float out_center_of_in; // Center of the current out pixel in the in pixel space + int out_first_pixel, out_last_pixel; + int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio); + + stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in); + + stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0)); + } + + stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size); + } +} + +static float* stbir__get_decode_buffer(stbir__info* stbir_info) +{ + // The 0 index of the decode buffer starts after the margin. This makes + // it okay to use negative indexes on the decode buffer. + return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels]; +} + +#define STBIR__DECODE(type, colorspace) ((int)(type) * (STBIR_MAX_COLORSPACES) + (int)(colorspace)) + +static void stbir__decode_scanline(stbir__info* stbir_info, int n) +{ + int c; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int input_w = stbir_info->input_w; + size_t input_stride_bytes = stbir_info->input_stride_bytes; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir_edge edge_horizontal = stbir_info->edge_horizontal; + stbir_edge edge_vertical = stbir_info->edge_vertical; + size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes; + const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset; + int max_x = input_w + stbir_info->horizontal_filter_pixel_margin; + int decode = STBIR__DECODE(type, colorspace); + + int x = -stbir_info->horizontal_filter_pixel_margin; + + // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input, + // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO + if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h)) + { + for (; x < max_x; x++) + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + return; + } + + switch (decode) + { + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]]; + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float; + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float)); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c]; + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB): + for (; x < max_x; x++) + { + int decode_pixel_index = x * channels; + int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels; + for (c = 0; c < channels; c++) + decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]); + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel]; + } + + break; + + default: + STBIR_ASSERT(!"Unknown type/colorspace/channels combination."); + break; + } + + if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED)) + { + for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++) + { + int decode_pixel_index = x * channels; + + // If the alpha value is 0 it will clobber the color values. Make sure it's not. + float alpha = decode_buffer[decode_pixel_index + alpha_channel]; +#ifndef STBIR_NO_ALPHA_EPSILON + if (stbir_info->type != STBIR_TYPE_FLOAT) { + alpha += STBIR_ALPHA_EPSILON; + decode_buffer[decode_pixel_index + alpha_channel] = alpha; + } +#endif + for (c = 0; c < channels; c++) + { + if (c == alpha_channel) + continue; + + decode_buffer[decode_pixel_index + c] *= alpha; + } + } + } + + if (edge_horizontal == STBIR_EDGE_ZERO) + { + for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++) + { + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + } + for (x = input_w; x < max_x; x++) + { + for (c = 0; c < channels; c++) + decode_buffer[x*channels + c] = 0; + } + } +} + +static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length) +{ + return &ring_buffer[index * ring_buffer_length]; +} + +static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n) +{ + int ring_buffer_index; + float* ring_buffer; + + stbir_info->ring_buffer_last_scanline = n; + + if (stbir_info->ring_buffer_begin_index < 0) + { + ring_buffer_index = stbir_info->ring_buffer_begin_index = 0; + stbir_info->ring_buffer_first_scanline = n; + } + else + { + ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries; + STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index); + } + + ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float)); + memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes); + + return ring_buffer; +} + + +static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer) +{ + int x, k; + int output_w = stbir_info->output_w; + int channels = stbir_info->channels; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; + float* horizontal_coefficients = stbir_info->horizontal_coefficients; + int coefficient_width = stbir_info->horizontal_coefficient_width; + + for (x = 0; x < output_w; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int out_pixel_index = x * channels; + int coefficient_group = coefficient_width * x; + int coefficient_counter = 0; + + STBIR_ASSERT(n1 >= n0); + STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); + STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin); + + switch (channels) { + case 1: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 1; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + } + break; + case 2: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 2; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + } + break; + case 3: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 3; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + } + break; + case 4: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * 4; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient; + } + break; + default: + for (k = n0; k <= n1; k++) + { + int in_pixel_index = k * channels; + float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++]; + int c; + STBIR_ASSERT(coefficient != 0); + for (c = 0; c < channels; c++) + output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; + } + break; + } + } +} + +static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer) +{ + int x, k; + int input_w = stbir_info->input_w; + int channels = stbir_info->channels; + float* decode_buffer = stbir__get_decode_buffer(stbir_info); + stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors; + float* horizontal_coefficients = stbir_info->horizontal_coefficients; + int coefficient_width = stbir_info->horizontal_coefficient_width; + int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin; + int max_x = input_w + filter_pixel_margin * 2; + + STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info)); + + switch (channels) { + case 1: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 1; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 1; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + } + } + break; + + case 2: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 2; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 2; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + } + } + break; + + case 3: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 3; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 3; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + } + } + break; + + case 4: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * 4; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int out_pixel_index = k * 4; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient; + output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient; + output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient; + output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient; + } + } + break; + + default: + for (x = 0; x < max_x; x++) + { + int n0 = horizontal_contributors[x].n0; + int n1 = horizontal_contributors[x].n1; + + int in_x = x - filter_pixel_margin; + int in_pixel_index = in_x * channels; + int max_n = n1; + int coefficient_group = coefficient_width * x; + + for (k = n0; k <= max_n; k++) + { + int c; + int out_pixel_index = k * channels; + float coefficient = horizontal_coefficients[coefficient_group + k - n0]; + STBIR_ASSERT(coefficient != 0); + for (c = 0; c < channels; c++) + output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient; + } + } + break; + } +} + +static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n) +{ + // Decode the nth scanline from the source image into the decode buffer. + stbir__decode_scanline(stbir_info, n); + + // Now resample it into the ring buffer. + if (stbir__use_width_upsampling(stbir_info)) + stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n)); + else + stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n)); + + // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling. +} + +static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n) +{ + // Decode the nth scanline from the source image into the decode buffer. + stbir__decode_scanline(stbir_info, n); + + memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float)); + + // Now resample it into the horizontal buffer. + if (stbir__use_width_upsampling(stbir_info)) + stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer); + else + stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer); + + // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers. +} + +// Get the specified scan line from the ring buffer. +static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length) +{ + int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries; + return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length); +} + + +static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode) +{ + int x; + int n; + int num_nonalpha; + stbir_uint16 nonalpha[STBIR_MAX_CHANNELS]; + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) + { + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + float alpha = encode_buffer[pixel_index + alpha_channel]; + float reciprocal_alpha = alpha ? 1.0f / alpha : 0; + + // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb + for (n = 0; n < channels; n++) + if (n != alpha_channel) + encode_buffer[pixel_index + n] *= reciprocal_alpha; + + // We added in a small epsilon to prevent the color channel from being deleted with zero alpha. + // Because we only add it for integer types, it will automatically be discarded on integer + // conversion, so we don't need to subtract it back out (which would be problematic for + // numeric precision reasons). + } + } + + // build a table of all channels that need colorspace correction, so + // we don't perform colorspace correction on channels that don't need it. + for (x = 0, num_nonalpha = 0; x < channels; ++x) + { + if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) + { + nonalpha[num_nonalpha++] = (stbir_uint16)x; + } + } + + #define STBIR__ROUND_INT(f) ((int) ((f)+0.5)) + #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5)) + + #ifdef STBIR__SATURATE_INT + #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float )) + #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float)) + #else + #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float ) + #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float) + #endif + + switch (decode) + { + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]); + } + + if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]); + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]); + } + + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float); + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float); + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < channels; n++) + { + int index = pixel_index + n; + ((float*)output_buffer)[index] = encode_buffer[index]; + } + } + break; + + case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB): + for (x=0; x < num_pixels; ++x) + { + int pixel_index = x*channels; + + for (n = 0; n < num_nonalpha; n++) + { + int index = pixel_index + nonalpha[n]; + ((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]); + } + + if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE)) + ((float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel]; + } + break; + + default: + STBIR_ASSERT(!"Unknown type/colorspace/channels combination."); + break; + } +} + +static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n) +{ + int x, k; + int output_w = stbir_info->output_w; + stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; + float* vertical_coefficients = stbir_info->vertical_coefficients; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int ring_buffer_entries = stbir_info->ring_buffer_num_entries; + void* output_data = stbir_info->output_data; + float* encode_buffer = stbir_info->encode_buffer; + int decode = STBIR__DECODE(type, colorspace); + int coefficient_width = stbir_info->vertical_coefficient_width; + int coefficient_counter; + int contributor = n; + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; + int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + + int n0,n1, output_row_start; + int coefficient_group = coefficient_width * contributor; + + n0 = vertical_contributors[contributor].n0; + n1 = vertical_contributors[contributor].n1; + + output_row_start = n * stbir_info->output_stride_bytes; + + STBIR_ASSERT(stbir__use_height_upsampling(stbir_info)); + + memset(encode_buffer, 0, output_w * sizeof(float) * channels); + + // I tried reblocking this for better cache usage of encode_buffer + // (using x_outer, k, x_inner), but it lost speed. -- stb + + coefficient_counter = 0; + switch (channels) { + case 1: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 1; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + } + } + break; + case 2: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 2; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + } + } + break; + case 3: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 3; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient; + } + } + break; + case 4: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * 4; + encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient; + encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient; + encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient; + encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient; + } + } + break; + default: + for (k = n0; k <= n1; k++) + { + int coefficient_index = coefficient_counter++; + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + for (x = 0; x < output_w; ++x) + { + int in_pixel_index = x * channels; + int c; + for (c = 0; c < channels; c++) + encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient; + } + } + break; + } + stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode); +} + +static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n) +{ + int x, k; + int output_w = stbir_info->output_w; + stbir__contributors* vertical_contributors = stbir_info->vertical_contributors; + float* vertical_coefficients = stbir_info->vertical_coefficients; + int channels = stbir_info->channels; + int ring_buffer_entries = stbir_info->ring_buffer_num_entries; + float* horizontal_buffer = stbir_info->horizontal_buffer; + int coefficient_width = stbir_info->vertical_coefficient_width; + int contributor = n + stbir_info->vertical_filter_pixel_margin; + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index; + int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + int n0,n1; + + n0 = vertical_contributors[contributor].n0; + n1 = vertical_contributors[contributor].n1; + + STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info)); + + for (k = n0; k <= n1; k++) + { + int coefficient_index = k - n0; + int coefficient_group = coefficient_width * contributor; + float coefficient = vertical_coefficients[coefficient_group + coefficient_index]; + + float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length); + + switch (channels) { + case 1: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 1; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + } + break; + case 2: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 2; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + } + break; + case 3: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 3; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient; + } + break; + case 4: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * 4; + ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient; + ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient; + ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient; + ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient; + } + break; + default: + for (x = 0; x < output_w; x++) + { + int in_pixel_index = x * channels; + + int c; + for (c = 0; c < channels; c++) + ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient; + } + break; + } + } +} + +static void stbir__buffer_loop_upsample(stbir__info* stbir_info) +{ + int y; + float scale_ratio = stbir_info->vertical_scale; + float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio; + + STBIR_ASSERT(stbir__use_height_upsampling(stbir_info)); + + for (y = 0; y < stbir_info->output_h; y++) + { + float in_center_of_out = 0; // Center of the current out scanline in the in scanline space + int in_first_scanline = 0, in_last_scanline = 0; + + stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out); + + STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); + + if (stbir_info->ring_buffer_begin_index >= 0) + { + // Get rid of whatever we don't need anymore. + while (in_first_scanline > stbir_info->ring_buffer_first_scanline) + { + if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline) + { + // We just popped the last scanline off the ring buffer. + // Reset it to the empty state. + stbir_info->ring_buffer_begin_index = -1; + stbir_info->ring_buffer_first_scanline = 0; + stbir_info->ring_buffer_last_scanline = 0; + break; + } + else + { + stbir_info->ring_buffer_first_scanline++; + stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries; + } + } + } + + // Load in new ones. + if (stbir_info->ring_buffer_begin_index < 0) + stbir__decode_and_resample_upsample(stbir_info, in_first_scanline); + + while (in_last_scanline > stbir_info->ring_buffer_last_scanline) + stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1); + + // Now all buffers should be ready to write a row of vertical sampling. + stbir__resample_vertical_upsample(stbir_info, y); + + STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h); + } +} + +static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline) +{ + int output_stride_bytes = stbir_info->output_stride_bytes; + int channels = stbir_info->channels; + int alpha_channel = stbir_info->alpha_channel; + int type = stbir_info->type; + int colorspace = stbir_info->colorspace; + int output_w = stbir_info->output_w; + void* output_data = stbir_info->output_data; + int decode = STBIR__DECODE(type, colorspace); + + float* ring_buffer = stbir_info->ring_buffer; + int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float); + + if (stbir_info->ring_buffer_begin_index >= 0) + { + // Get rid of whatever we don't need anymore. + while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline) + { + if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h) + { + int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes; + float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length); + stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode); + STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h); + } + + if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline) + { + // We just popped the last scanline off the ring buffer. + // Reset it to the empty state. + stbir_info->ring_buffer_begin_index = -1; + stbir_info->ring_buffer_first_scanline = 0; + stbir_info->ring_buffer_last_scanline = 0; + break; + } + else + { + stbir_info->ring_buffer_first_scanline++; + stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries; + } + } + } +} + +static void stbir__buffer_loop_downsample(stbir__info* stbir_info) +{ + int y; + float scale_ratio = stbir_info->vertical_scale; + int output_h = stbir_info->output_h; + float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio; + int pixel_margin = stbir_info->vertical_filter_pixel_margin; + int max_y = stbir_info->input_h + pixel_margin; + + STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info)); + + for (y = -pixel_margin; y < max_y; y++) + { + float out_center_of_in; // Center of the current out scanline in the in scanline space + int out_first_scanline, out_last_scanline; + + stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in); + + STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries); + + if (out_last_scanline < 0 || out_first_scanline >= output_h) + continue; + + stbir__empty_ring_buffer(stbir_info, out_first_scanline); + + stbir__decode_and_resample_downsample(stbir_info, y); + + // Load in new ones. + if (stbir_info->ring_buffer_begin_index < 0) + stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline); + + while (out_last_scanline > stbir_info->ring_buffer_last_scanline) + stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1); + + // Now the horizontal buffer is ready to write to all ring buffer rows. + stbir__resample_vertical_downsample(stbir_info, y); + } + + stbir__empty_ring_buffer(stbir_info, stbir_info->output_h); +} + +static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels) +{ + info->input_w = input_w; + info->input_h = input_h; + info->output_w = output_w; + info->output_h = output_h; + info->channels = channels; +} + +static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform) +{ + info->s0 = s0; + info->t0 = t0; + info->s1 = s1; + info->t1 = t1; + + if (transform) + { + info->horizontal_scale = transform[0]; + info->vertical_scale = transform[1]; + info->horizontal_shift = transform[2]; + info->vertical_shift = transform[3]; + } + else + { + info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0); + info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0); + + info->horizontal_shift = s0 * info->output_w / (s1 - s0); + info->vertical_shift = t0 * info->output_h / (t1 - t0); + } +} + +static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter) +{ + if (h_filter == 0) + h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE; + if (v_filter == 0) + v_filter = stbir__use_upsampling(info->vertical_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE; + info->horizontal_filter = h_filter; + info->vertical_filter = v_filter; +} + +static stbir_uint32 stbir__calculate_memory(stbir__info *info) +{ + int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale); + int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale); + + info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w); + info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h); + + // One extra entry because floating point precision problems sometimes cause an extra to be necessary. + info->ring_buffer_num_entries = filter_height + 1; + + info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors); + info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float); + info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors); + info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float); + info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float); + info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float); + info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float); + info->encode_buffer_size = info->output_w * info->channels * sizeof(float); + + STBIR_ASSERT(info->horizontal_filter != 0); + STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late + STBIR_ASSERT(info->vertical_filter != 0); + STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late + + if (stbir__use_height_upsampling(info)) + // The horizontal buffer is for when we're downsampling the height and we + // can't output the result of sampling the decode buffer directly into the + // ring buffers. + info->horizontal_buffer_size = 0; + else + // The encode buffer is to retain precision in the height upsampling method + // and isn't used when height downsampling. + info->encode_buffer_size = 0; + + return info->horizontal_contributors_size + info->horizontal_coefficients_size + + info->vertical_contributors_size + info->vertical_coefficients_size + + info->decode_buffer_size + info->horizontal_buffer_size + + info->ring_buffer_size + info->encode_buffer_size; +} + +static int stbir__resize_allocated(stbir__info *info, + const void* input_data, int input_stride_in_bytes, + void* output_data, int output_stride_in_bytes, + int alpha_channel, stbir_uint32 flags, stbir_datatype type, + stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace, + void* tempmem, size_t tempmem_size_in_bytes) +{ + size_t memory_required = stbir__calculate_memory(info); + + int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type]; + int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type]; + +#ifdef STBIR_DEBUG_OVERWRITE_TEST +#define OVERWRITE_ARRAY_SIZE 8 + unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE]; + unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE]; + + size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type]; + memcpy(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE); + memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE); +#endif + + STBIR_ASSERT(info->channels >= 0); + STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS); + + if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS) + return 0; + + STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); + + if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table)) + return 0; + if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table)) + return 0; + + if (alpha_channel < 0) + flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED; + + if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) { + STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels); + } + + if (alpha_channel >= info->channels) + return 0; + + STBIR_ASSERT(tempmem); + + if (!tempmem) + return 0; + + STBIR_ASSERT(tempmem_size_in_bytes >= memory_required); + + if (tempmem_size_in_bytes < memory_required) + return 0; + + memset(tempmem, 0, tempmem_size_in_bytes); + + info->input_data = input_data; + info->input_stride_bytes = width_stride_input; + + info->output_data = output_data; + info->output_stride_bytes = width_stride_output; + + info->alpha_channel = alpha_channel; + info->flags = flags; + info->type = type; + info->edge_horizontal = edge_horizontal; + info->edge_vertical = edge_vertical; + info->colorspace = colorspace; + + info->horizontal_coefficient_width = stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale); + info->vertical_coefficient_width = stbir__get_coefficient_width (info->vertical_filter , info->vertical_scale ); + info->horizontal_filter_pixel_width = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale); + info->vertical_filter_pixel_width = stbir__get_filter_pixel_width (info->vertical_filter , info->vertical_scale ); + info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale); + info->vertical_filter_pixel_margin = stbir__get_filter_pixel_margin(info->vertical_filter , info->vertical_scale ); + + info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float); + info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2; + +#define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size) + + info->horizontal_contributors = (stbir__contributors *) tempmem; + info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float); + info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors); + info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float); + info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float); + + if (stbir__use_height_upsampling(info)) + { + info->horizontal_buffer = NULL; + info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float); + info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float); + + STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes); + } + else + { + info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float); + info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float); + info->encode_buffer = NULL; + + STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes); + } + +#undef STBIR__NEXT_MEMPTR + + // This signals that the ring buffer is empty + info->ring_buffer_begin_index = -1; + + stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w); + stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h); + + STBIR_PROGRESS_REPORT(0); + + if (stbir__use_height_upsampling(info)) + stbir__buffer_loop_upsample(info); + else + stbir__buffer_loop_downsample(info); + + STBIR_PROGRESS_REPORT(1); + +#ifdef STBIR_DEBUG_OVERWRITE_TEST + STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0); + STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0); +#endif + + return 1; +} + + +static int stbir__resize_arbitrary( + void *alloc_context, + const void* input_data, int input_w, int input_h, int input_stride_in_bytes, + void* output_data, int output_w, int output_h, int output_stride_in_bytes, + float s0, float t0, float s1, float t1, float *transform, + int channels, int alpha_channel, stbir_uint32 flags, stbir_datatype type, + stbir_filter h_filter, stbir_filter v_filter, + stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace) +{ + stbir__info info; + int result; + size_t memory_required; + void* extra_memory; + + stbir__setup(&info, input_w, input_h, output_w, output_h, channels); + stbir__calculate_transform(&info, s0,t0,s1,t1,transform); + stbir__choose_filter(&info, h_filter, v_filter); + memory_required = stbir__calculate_memory(&info); + extra_memory = STBIR_MALLOC(memory_required, alloc_context); + + if (!extra_memory) + return 0; + + result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes, + output_data, output_stride_in_bytes, + alpha_channel, flags, type, + edge_horizontal, edge_vertical, + colorspace, extra_memory, memory_required); + + STBIR_FREE(extra_memory, alloc_context); + + return result; +} + +STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); +} + +STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR); +} + +STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB); +} + +STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode) +{ + return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, + edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB); +} + +STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + +STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + + +STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + float *output_pixels , int output_w, int output_h, int output_stride_in_bytes, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, + void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter, + edge_wrap_mode, edge_wrap_mode, space); +} + + +STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + + +STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float x_scale, float y_scale, + float x_offset, float y_offset) +{ + float transform[4]; + transform[0] = x_scale; + transform[1] = y_scale; + transform[2] = x_offset; + transform[3] = y_offset; + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + 0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + +STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes, + void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, + stbir_datatype datatype, + int num_channels, int alpha_channel, int flags, + stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, + stbir_filter filter_horizontal, stbir_filter filter_vertical, + stbir_colorspace space, void *alloc_context, + float s0, float t0, float s1, float t1) +{ + return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes, + output_pixels, output_w, output_h, output_stride_in_bytes, + s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical, + edge_mode_horizontal, edge_mode_vertical, space); +} + +#endif // STB_IMAGE_RESIZE_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +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. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ + +#include +#include +#include + +std::string get_file_contents(const char *filename) +{ + std::ifstream in(filename, std::ios::in | std::ios::binary); + if (in) + { + std::string contents; + in.seekg(0, std::ios::end); + contents.resize(in.tellg()); + in.seekg(0, std::ios::beg); + in.read(&contents[0], contents.size()); + in.close(); + return(contents); + } +} + +std::ifstream::pos_type getFileSize(const char* filename) +{ + std::ifstream in(filename, std::ifstream::ate | std::ifstream::binary); + return in.tellg(); +} + +void _CreateIcon(String srcFilename, String dstFilename, int w, int h,int round) { + int width,height,n; + + stbi_uc *input_pixels = stbi_load(C_STR(srcFilename), &width, &height, &n, 4); + stbi_uc output_pixels[4*w*h]; + + stbir_resize_uint8(input_pixels,width,height,0, output_pixels, w,h,0,4); + + if (round) { + int i,r; + for (int x = 0; x < w; x++) { + for (int y = 0; y < h; y++) { + i = x + y*w; + r = sqrt(((w/2-x)*(w/2-x)) + ((h/2-y)*(h/2-y))); + if (r>w/2-1) { + output_pixels[i*4+3] = 0; + } + } + } + } + + stbi_write_png(C_STR(dstFilename), w, h, 4, &output_pixels, 0); +} + +// crudely build the icon file... file format on wiki +// https://en.wikipedia.org/wiki/ICO_(file_format) +void _ConvertToIco(String srcFilename,String destFilename) { + // widths for icons + int widths[] = {16,32,48,64,128,256}; + + // build indiviual icon files for icon file + int num_of_images=sizeof(widths) / sizeof(widths[0]);; + int size_of_files[num_of_images]; + int width; + int size_of_data=0; + int i=0; + while (i> 8) & 255; + + // image headers + int offset=6; + int data_pointer = 6+num_of_images*16; + + i=0; + while (i> 0) & 255; + new_data[offset+9] = (size_of_files[i] >> 8) & 255; + new_data[offset+10] = (size_of_files[i] >> 16) & 255; + new_data[offset+11] = (size_of_files[i] >> 24) & 255; + // offset to image data (little endian) + new_data[offset+12] = (data_pointer >> 0) & 255; + new_data[offset+13] = (data_pointer >> 8) & 255; + new_data[offset+14] = (data_pointer >> 16) & 255; + new_data[offset+15] = (data_pointer >> 24) & 255; + + offset = offset+16; + data_pointer = data_pointer + size_of_files[i]; + i++; + } + + // add data + data_pointer = 6+num_of_images*16; // end of header + + i=0; + while (iRun__UNSAFE__(); + _thread->_state=FINISHED; + } + }; + +#elif _WIN32 + + static DWORD WINAPI run( void *p ); + +#else + + static void *run( void *p ); + +#endif + +}; + +// ***** thread.cpp ***** + +BBThread::BBThread():_state( INIT ),_result( 0 ){ +} + +bool BBThread::IsRunning(){ + return _state==RUNNING; +} + +Object *BBThread::Result(){ + return _result; +} + +void BBThread::SetResult( Object *result ){ + _result=result; +} + +String BBThread::Strdup( const String &str ){ + return str.Copy(); +} + +void BBThread::Run__UNSAFE__(){ +} + +#if __cplusplus_winrt + +void BBThread::Start(){ + if( _state==RUNNING ) return; + + _result=0; + _state=RUNNING; + + Launcher launcher( this ); + + auto handler=ref new WorkItemHandler( launcher ); + + ThreadPool::RunAsync( handler ); +} + +#elif _WIN32 + +void BBThread::Start(){ + if( _state==RUNNING ) return; + + _result=0; + _state=RUNNING; + + DWORD _id; + HANDLE _handle; + + if( _handle=CreateThread( 0,0,run,this,0,&_id ) ){ + CloseHandle( _handle ); + return; + } + + puts( "CreateThread failed!" ); + exit( -1 ); +} + +DWORD WINAPI BBThread::run( void *p ){ + BBThread *thread=(BBThread*)p; + + thread->Run__UNSAFE__(); + + thread->_state=FINISHED; + return 0; +} + +#else + +void BBThread::Start(){ + if( _state==RUNNING ) return; + + _result=0; + _state=RUNNING; + + pthread_t _handle; + + if( !pthread_create( &_handle,0,run,this ) ){ + pthread_detach( _handle ); + return; + } + + puts( "pthread_create failed!" ); + exit( -1 ); +} + +void *BBThread::run( void *p ){ + BBThread *thread=(BBThread*)p; + + thread->Run__UNSAFE__(); + + thread->_state=FINISHED; + return 0; +} + +#endif + + +// ***** databuffer.h ***** + +class BBDataBuffer : public Object{ +public: + + BBDataBuffer(); + + ~BBDataBuffer(); + + bool _New( int length,void *data=0 ); + + bool _Load( String path ); + + void _LoadAsync( const String &path,BBThread *thread ); + + void Discard(); + + const void *ReadPointer( int offset=0 ){ + return _data+offset; + } + + void *WritePointer( int offset=0 ){ + return _data+offset; + } + + int Length(){ + return _length; + } + + void PokeByte( int addr,int value ){ + *(_data+addr)=value; + } + + void PokeShort( int addr,int value ){ + *(short*)(_data+addr)=value; + } + + void PokeInt( int addr,int value ){ + *(int*)(_data+addr)=value; + } + + void PokeFloat( int addr,float value ){ + *(float*)(_data+addr)=value; + } + + int PeekByte( int addr ){ + return *(_data+addr); + } + + int PeekShort( int addr ){ + return *(short*)(_data+addr); + } + + int PeekInt( int addr ){ + return *(int*)(_data+addr); + } + + float PeekFloat( int addr ){ + return *(float*)(_data+addr); + } + +private: + signed char *_data; + int _length; +}; + +// ***** databuffer.cpp ***** + +BBDataBuffer::BBDataBuffer():_data(0),_length(0){ +} + +BBDataBuffer::~BBDataBuffer(){ + if( _data ) free( _data ); +} + +bool BBDataBuffer::_New( int length,void *data ){ + if( _data ) return false; + if( !data ) data=malloc( length ); + _data=(signed char*)data; + _length=length; + return true; +} + +bool BBDataBuffer::_Load( String path ){ + if( _data ) return false; + + _data=(signed char*)BBGame::Game()->LoadData( path,&_length ); + if( !_data ) return false; + + return true; +} + +void BBDataBuffer::_LoadAsync( const String &cpath,BBThread *thread ){ + + String path=cpath.Copy(); + + if( _Load( path ) ) thread->SetResult( this ); +} + +void BBDataBuffer::Discard(){ + if( !_data ) return; + free( _data ); + _data=0; + _length=0; +} + + +// ***** stream.h ***** + +class BBStream : public Object{ +public: + + virtual int Eof(){ + return 0; + } + + virtual void Close(){ + } + + virtual int Length(){ + return 0; + } + + virtual int Position(){ + return 0; + } + + virtual int Seek( int position ){ + return 0; + } + + virtual int Read( BBDataBuffer *buffer,int offset,int count ){ + return 0; + } + + virtual int Write( BBDataBuffer *buffer,int offset,int count ){ + return 0; + } +}; + +// ***** stream.cpp ***** + + +// ***** filestream.h ***** + +class BBFileStream : public BBStream{ +public: + + BBFileStream(); + ~BBFileStream(); + + void Close(); + int Eof(); + int Length(); + int Position(); + int Seek( int position ); + int Read( BBDataBuffer *buffer,int offset,int count ); + int Write( BBDataBuffer *buffer,int offset,int count ); + + bool Open( String path,String mode ); + +private: + FILE *_file; + int _position; + int _length; +}; + +// ***** filestream.cpp ***** + +BBFileStream::BBFileStream():_file(0),_position(0),_length(0){ +} + +BBFileStream::~BBFileStream(){ + if( _file ) fclose( _file ); +} + +bool BBFileStream::Open( String path,String mode ){ + if( _file ) return false; + + String fmode; + if( mode=="r" ){ + fmode="rb"; + }else if( mode=="w" ){ + fmode="wb"; + }else if( mode=="u" ){ + fmode="rb+"; + }else{ + return false; + } + + _file=BBGame::Game()->OpenFile( path,fmode ); + if( !_file && mode=="u" ) _file=BBGame::Game()->OpenFile( path,"wb+" ); + if( !_file ) return false; + + fseek( _file,0,SEEK_END ); + _length=ftell( _file ); + fseek( _file,0,SEEK_SET ); + _position=0; + + return true; +} + +void BBFileStream::Close(){ + if( !_file ) return; + + fclose( _file ); + _file=0; + _position=0; + _length=0; +} + +int BBFileStream::Eof(){ + if( !_file ) return -1; + + return _position==_length; +} + +int BBFileStream::Length(){ + return _length; +} + +int BBFileStream::Position(){ + return _position; +} + +int BBFileStream::Seek( int position ){ + if( !_file ) return 0; + + fseek( _file,position,SEEK_SET ); + _position=ftell( _file ); + return _position; +} + +int BBFileStream::Read( BBDataBuffer *buffer,int offset,int count ){ + if( !_file ) return 0; + + int n=fread( buffer->WritePointer(offset),1,count,_file ); + _position+=n; + return n; +} + +int BBFileStream::Write( BBDataBuffer *buffer,int offset,int count ){ + if( !_file ) return 0; + + int n=fwrite( buffer->ReadPointer(offset),1,count,_file ); + _position+=n; + if( _position>_length ) _length=_position; + return n; +} + +class c_TransCC; +class c_Type; +class c_StringType; +class c_Decl; class c_ScopeDecl; class c_ConfigScope; class c_ValDecl; @@ -2986,6 +15104,8 @@ class c_HeadNode; class c_Enumerator; class c_Stack2; class c_ModuleDecl; +class c_Stack3; +class c_IntStack; class c_List2; class c_Node5; class c_HeadNode2; @@ -3000,27 +15120,37 @@ class c_Map5; class c_StringMap5; class c_Node7; class c_Parser; +class c_BlockTrace; +class c_List3; +class c_IntList; +class c_Map6; +class c_IntMap; +class c_Node8; +class c_TraceRecord; +class c_List4; +class c_Node9; +class c_HeadNode3; class c_NumericType; class c_IntType; class c_FloatType; class c_AliasDecl; -class c_List3; -class c_Node8; -class c_HeadNode3; +class c_List5; +class c_Node10; +class c_HeadNode4; class c_BlockDecl; class c_FuncDecl; -class c_List4; +class c_List6; class c_FuncDeclList; -class c_Node9; -class c_HeadNode4; +class c_Node11; +class c_HeadNode5; class c_ClassDecl; class c_VoidType; class c_IdentType; -class c_Stack3; +class c_Stack4; class c_ArrayType; class c_UnaryExpr; class c_ArrayExpr; -class c_Stack4; +class c_Stack5; class c_ConstExpr; class c_ScopeExpr; class c_NewArrayExpr; @@ -3029,11 +15159,16 @@ class c_CastExpr; class c_IdentExpr; class c_SelfExpr; class c_Stmt; -class c_List5; -class c_Node10; -class c_HeadNode5; +class c_List7; +class c_Node12; +class c_HeadNode6; class c_InvokeSuperExpr; class c_IdentTypeExpr; +class c_Node13; +class c_HeadNode7; +class c_Enumerator2; +class c_MapKeys; +class c_KeyEnumerator; class c_FuncCallExpr; class c_SliceExpr; class c_IndexExpr; @@ -3045,18 +15180,18 @@ class c_VarDecl; class c_GlobalDecl; class c_FieldDecl; class c_LocalDecl; -class c_Enumerator2; +class c_Enumerator3; class c_DeclStmt; -class c_Stack5; +class c_Stack6; class c_ObjectType; -class c_List6; -class c_Node11; -class c_HeadNode6; +class c_List8; +class c_Node14; +class c_HeadNode8; class c_ArgDecl; -class c_Stack6; -class c_List7; -class c_Node12; -class c_HeadNode7; +class c_Stack7; +class c_List9; +class c_Node15; +class c_HeadNode9; class c_ReturnStmt; class c_BreakStmt; class c_ContinueStmt; @@ -3067,28 +15202,28 @@ class c_ForEachinStmt; class c_AssignStmt; class c_ForStmt; class c_CatchStmt; -class c_Stack7; +class c_Stack8; class c_TryStmt; class c_ThrowStmt; class c_ExprStmt; -class c_Enumerator3; -class c_List8; -class c_Node13; -class c_HeadNode8; +class c_Enumerator4; +class c_List10; +class c_Node16; +class c_HeadNode10; class c_InvokeMemberExpr; class c_Target; -class c_Map6; +class c_Map7; class c_StringMap6; -class c_Node14; +class c_Node17; class c_NodeEnumerator2; class c_Reflector; class c_MapValues; class c_ValueEnumerator; -class c_Map7; +class c_Map8; class c_StringMap7; -class c_Node15; -class c_Enumerator4; -class c_Stack8; +class c_Node18; +class c_Enumerator5; +class c_Stack9; class c_Translator; class c_CTranslator; class c_JavaTranslator; @@ -3100,26 +15235,26 @@ class c_FileStream; class c_DataBuffer; class c_AsTranslator; class c_CsTranslator; -class c_List9; -class c_Node16; -class c_HeadNode9; -class c_Enumerator5; +class c_List11; +class c_Node19; +class c_HeadNode11; +class c_Enumerator6; class c_InvokeExpr; class c_StmtExpr; class c_MemberVarExpr; class c_VarExpr; -class c_Map8; -class c_StringMap8; -class c_Node17; class c_Map9; -class c_StringMap9; -class c_Node18; +class c_StringMap8; +class c_Node20; class c_Map10; +class c_StringMap9; +class c_Node21; +class c_Map11; class c_StringMap10; -class c_Node19; -class c_Enumerator6; -class c_Stack9; +class c_Node22; class c_Enumerator7; +class c_Stack10; +class c_Enumerator8; class c_TransCC : public Object{ public: Array m_args; @@ -3230,27 +15365,27 @@ class c_Decl : public Object{ }; class c_ScopeDecl : public c_Decl{ public: - c_List3* m_decls; + c_List5* m_decls; c_StringMap4* m_declsMap; - c_List3* m_semanted; + c_List5* m_semanted; c_ScopeDecl(); c_ScopeDecl* m_new(); int p_InsertDecl(c_Decl*); virtual Object* p_GetDecl(String); Object* p_FindDecl(String); - int p_InsertDecls(c_List3*); + int p_InsertDecls(c_List5*); virtual c_FuncDecl* p_FindFuncDecl(String,Array,int); - c_List3* p_Decls(); + c_List5* p_Decls(); c_Type* p_FindType(String,Array); - c_List4* p_MethodDecls(String); - c_List3* p_Semanted(); - c_List4* p_SemantedMethods(String); + c_List6* p_MethodDecls(String); + c_List5* p_Semanted(); + c_List6* p_SemantedMethods(String); virtual c_ValDecl* p_FindValDecl(String); c_Decl* p_OnCopy(); int p_OnSemant(); - c_List4* p_SemantedFuncs(String); + c_List6* p_SemantedFuncs(String); c_ModuleDecl* p_FindModuleDecl(String); - c_List4* p_FuncDecls(String); + c_List6* p_FuncDecls(String); c_ScopeDecl* p_FindScopeDecl(String); void mark(); }; @@ -3452,8 +15587,10 @@ class c_Builder : public Object{ void p_Make(); void p_CCopyFile(String,String); void p_CreateDataDir(String); + void p_MakeIcons(String,Array,int); bool p_Execute(String,bool); - void p_CopyIcon(); + void p_CopySourceFiles(String); + void p_CopyIcon(String,String); void mark(); }; class c_Map3 : public Object{ @@ -3763,6 +15900,32 @@ class c_ModuleDecl : public c_ScopeDecl{ int p_OnSemant(); void mark(); }; +class c_Stack3 : public Object{ + public: + Array m_data; + int m_length; + c_Stack3(); + c_Stack3* m_new(); + c_Stack3* m_new2(Array); + void p_Push7(int); + void p_Push8(Array,int,int); + void p_Push9(Array,int); + bool p_IsEmpty(); + static int m_NIL; + int p_Pop(); + void p_Length(int); + int p_Length2(); + int p_Get2(int); + void p_Clear(); + void mark(); +}; +class c_IntStack : public c_Stack3{ + public: + c_IntStack(); + c_IntStack* m_new(Array); + c_IntStack* m_new2(); + void mark(); +}; c_ScopeDecl* bb_config_GetConfigScope(); extern c_ScopeDecl* bb_decl__env; class c_List2 : public Object{ @@ -3817,12 +15980,16 @@ class c_Toker : public Object{ c_Toker* m_new3(); int p_TCHR(int); String p_TSTR(int); + static int m__tokenFlags; + static bool m_Remarks(); String p_NextToke(); String p_Toke(); int p_TokeType(); String p_Path(); int p_Line(); int p_SkipSpace(); + static int m_RemarksOn(); + static int m_RemarksOff(); void mark(); }; class c_Set : public Object{ @@ -3894,9 +16061,10 @@ class c_AppDecl : public c_ScopeDecl{ c_StringMap5* m_imported; c_ModuleDecl* m_mainModule; c_StringList* m_fileImports; - c_List3* m_allSemantedDecls; - c_List8* m_semantedGlobals; - c_List6* m_semantedClasses; + c_StringList* m_fileIncludes; + c_List5* m_allSemantedDecls; + c_List10* m_semantedGlobals; + c_List8* m_semantedClasses; c_FuncDecl* m_mainFunc; c_AppDecl(); int p_InsertModule(c_ModuleDecl*); @@ -3953,11 +16121,11 @@ class c_Parser : public Object{ int m__defattrs; int m__tokeType; c_BlockDecl* m__block; - c_List7* m__blockStack; + c_List9* m__blockStack; c_StringList* m__errStack; int m__selTmpId; c_Parser(); - int p_SetErr(); + int p_SetErr(int); int p_CParse(String); int p_SkipEols(); String p_NextToke(); @@ -3978,6 +16146,7 @@ class c_Parser : public Object{ int p_AtEos(); Array p_ParseArgs2(int); c_IdentType* p_CParseIdentType(bool); + c_TraceRecord* p_BackTrace(int); c_Expr* p_ParsePrimaryExpr(int); c_Expr* p_ParseUnaryExpr(); c_Expr* p_ParseMulDivExpr(); @@ -3989,15 +16158,19 @@ class c_Parser : public Object{ c_Expr* p_ParseOrExpr(); c_Expr* p_ParseExpr(); c_Decl* p_ParseDecl(String,int); - c_List3* p_ParseDecls(String,int); - c_List3* p_ParseEnumStmt(int,bool); - c_List3* p_ParseEnum(String,int); + c_List5* p_ParseDecls(String,int); + c_List5* p_ParseEnumStmt(int,bool); + c_List5* p_ParseEnum(String,int); int p_PushBlock(c_BlockDecl*); int p_ParseDeclStmts(); int p_ParseReturnStmt(); int p_ParseExitStmt(); int p_ParseContinueStmt(); + int p_AtEOF(int,String); + int p_AtEOF2(String,String); int p_PopBlock(); + int p_AtEos2(); + int p_ParseBlockEnd(String,String,int); int p_ParseIfStmt(String); int p_ParseWhileStmt(); int p_PushErr(); @@ -4013,6 +16186,134 @@ class c_Parser : public Object{ int p_ParseMain(); void mark(); }; +class c_BlockTrace : public Object{ + public: + c_IntMap* m__map; + c_List4* m__record; + c_BlockTrace(); + c_BlockTrace* m_new(); + static c_BlockTrace* m__Blocks; + static int m_Clear(); + c_TraceRecord* p_LastBlockItem(); + c_IntList* p_BlockLineList(int); + int p_Unwind(int); + static int m_TraceLog(int); + static int m_Str2Code(String); + static int m_TraceLog2(String); + c_TraceRecord* p_RemoveRecord(); + static c_TraceRecord* m_Pop(); + static String m_Code2Str(int); + int p_AddRecord(c_TraceRecord*); + static int m_Push(int,int); + static int m_Push2(String,int); + void mark(); +}; +class c_List3 : public Object{ + public: + c_Node13* m__head; + c_List3(); + c_List3* m_new(); + c_Node13* p_AddLast3(int); + c_List3* m_new2(Array); + c_Enumerator2* p_ObjectEnumerator(); + virtual int p_Compare2(int,int); + int p_Sort(int); + int p_Count(); + Array p_ToArray(); + void mark(); +}; +class c_IntList : public c_List3{ + public: + c_IntList(); + c_IntList* m_new(Array); + c_IntList* m_new2(); + int p_Compare2(int,int); + void mark(); +}; +class c_Map6 : public Object{ + public: + c_Node8* m_root; + c_Map6(); + c_Map6* m_new(); + int p_Clear(); + virtual int p_Compare2(int,int)=0; + c_Node8* p_FindNode2(int); + c_IntList* p_Get2(int); + c_MapKeys* p_Keys(); + c_Node8* p_FirstNode(); + bool p_Contains2(int); + int p_RotateLeft6(c_Node8*); + int p_RotateRight6(c_Node8*); + int p_InsertFixup6(c_Node8*); + bool p_Add(int,c_IntList*); + void mark(); +}; +class c_IntMap : public c_Map6{ + public: + c_IntMap(); + c_IntMap* m_new(); + int p_Compare2(int,int); + void mark(); +}; +class c_Node8 : public Object{ + public: + int m_key; + c_Node8* m_right; + c_Node8* m_left; + c_IntList* m_value; + c_Node8* m_parent; + int m_color; + c_Node8(); + c_Node8* p_NextNode(); + c_Node8* m_new(int,c_IntList*,int,c_Node8*); + c_Node8* m_new2(); + void mark(); +}; +class c_TraceRecord : public Object{ + public: + int m__line; + int m__toke; + c_TraceRecord(); + int p_Line(); + int p_Toke(); + c_TraceRecord* m_new(int,int); + c_TraceRecord* m_new2(); + void mark(); +}; +class c_List4 : public Object{ + public: + c_Node9* m__head; + c_List4(); + c_List4* m_new(); + c_Node9* p_AddLast4(c_TraceRecord*); + c_List4* m_new2(Array); + int p_Clear(); + bool p_IsEmpty(); + c_TraceRecord* p_Last(); + c_TraceRecord* p_RemoveLast(); + bool p_Equals3(c_TraceRecord*,c_TraceRecord*); + c_Node9* p_FindLast5(c_TraceRecord*,c_Node9*); + c_Node9* p_FindLast6(c_TraceRecord*); + void p_RemoveLast4(c_TraceRecord*); + void mark(); +}; +class c_Node9 : public Object{ + public: + c_Node9* m__succ; + c_Node9* m__pred; + c_TraceRecord* m__data; + c_Node9(); + c_Node9* m_new(c_Node9*,c_Node9*,c_TraceRecord*); + c_Node9* m_new2(); + int p_Remove(); + void mark(); +}; +class c_HeadNode3 : public c_Node9{ + public: + c_HeadNode3(); + c_HeadNode3* m_new(); + void mark(); +}; int bb_config_InternalErr(String); int bb_config_StringToInt(String,int); String bb_config_Dequote(String,String); @@ -4054,36 +16355,36 @@ class c_AliasDecl : public c_Decl{ int p_OnSemant(); void mark(); }; -class c_List3 : public Object{ +class c_List5 : public Object{ public: - c_Node8* m__head; - c_List3(); - c_List3* m_new(); - c_Node8* p_AddLast3(c_Decl*); - c_List3* m_new2(Array); - c_Enumerator2* p_ObjectEnumerator(); + c_Node10* m__head; + c_List5(); + c_List5* m_new(); + c_Node10* p_AddLast5(c_Decl*); + c_List5* m_new2(Array); + c_Enumerator3* p_ObjectEnumerator(); int p_Count(); void mark(); }; -class c_Node8 : public Object{ +class c_Node10 : public Object{ public: - c_Node8* m__succ; - c_Node8* m__pred; + c_Node10* m__succ; + c_Node10* m__pred; c_Decl* m__data; - c_Node8(); - c_Node8* m_new(c_Node8*,c_Node8*,c_Decl*); - c_Node8* m_new2(); + c_Node10(); + c_Node10* m_new(c_Node10*,c_Node10*,c_Decl*); + c_Node10* m_new2(); void mark(); }; -class c_HeadNode3 : public c_Node8{ +class c_HeadNode4 : public c_Node10{ public: - c_HeadNode3(); - c_HeadNode3* m_new(); + c_HeadNode4(); + c_HeadNode4* m_new(); void mark(); }; class c_BlockDecl : public c_ScopeDecl{ public: - c_List5* m_stmts; + c_List7* m_stmts; c_BlockDecl(); int p_AddStmt(c_Stmt*); c_BlockDecl* m_new(c_ScopeDecl*); @@ -4113,36 +16414,36 @@ class c_FuncDecl : public c_BlockDecl{ bool p_IsVirtual(); void mark(); }; -class c_List4 : public Object{ +class c_List6 : public Object{ public: - c_Node9* m__head; - c_List4(); - c_List4* m_new(); - c_Node9* p_AddLast4(c_FuncDecl*); - c_List4* m_new2(Array); - c_Enumerator3* p_ObjectEnumerator(); + c_Node11* m__head; + c_List6(); + c_List6* m_new(); + c_Node11* p_AddLast6(c_FuncDecl*); + c_List6* m_new2(Array); + c_Enumerator4* p_ObjectEnumerator(); void mark(); }; -class c_FuncDeclList : public c_List4{ +class c_FuncDeclList : public c_List6{ public: c_FuncDeclList(); c_FuncDeclList* m_new(); void mark(); }; -class c_Node9 : public Object{ +class c_Node11 : public Object{ public: - c_Node9* m__succ; - c_Node9* m__pred; + c_Node11* m__succ; + c_Node11* m__pred; c_FuncDecl* m__data; - c_Node9(); - c_Node9* m_new(c_Node9*,c_Node9*,c_FuncDecl*); - c_Node9* m_new2(); + c_Node11(); + c_Node11* m_new(c_Node11*,c_Node11*,c_FuncDecl*); + c_Node11* m_new2(); void mark(); }; -class c_HeadNode4 : public c_Node9{ +class c_HeadNode5 : public c_Node11{ public: - c_HeadNode4(); - c_HeadNode4* m_new(); + c_HeadNode5(); + c_HeadNode5* m_new(); void mark(); }; class c_ClassDecl : public c_ScopeDecl{ @@ -4152,7 +16453,7 @@ class c_ClassDecl : public c_ScopeDecl{ c_IdentType* m_superTy; Array m_impltys; c_ObjectType* m_objectType; - c_List6* m_instances; + c_List8* m_instances; c_ClassDecl* m_instanceof; Array m_instArgs; Array m_implmentsAll; @@ -4202,16 +16503,16 @@ class c_IdentType : public c_Type{ String p_ToString(); void mark(); }; -class c_Stack3 : public Object{ +class c_Stack4 : public Object{ public: Array m_data; int m_length; - c_Stack3(); - c_Stack3* m_new(); - c_Stack3* m_new2(Array); - void p_Push7(c_Type*); - void p_Push8(Array,int,int); - void p_Push9(Array,int); + c_Stack4(); + c_Stack4* m_new(); + c_Stack4* m_new2(Array); + void p_Push10(c_Type*); + void p_Push11(Array,int,int); + void p_Push12(Array,int); Array p_ToArray(); void mark(); }; @@ -4252,16 +16553,16 @@ class c_ArrayExpr : public c_Expr{ String p_Trans(); void mark(); }; -class c_Stack4 : public Object{ +class c_Stack5 : public Object{ public: Array m_data; int m_length; - c_Stack4(); - c_Stack4* m_new(); - c_Stack4* m_new2(Array); - void p_Push10(c_Expr*); - void p_Push11(Array,int,int); - void p_Push12(Array,int); + c_Stack5(); + c_Stack5* m_new(); + c_Stack5* m_new2(Array); + void p_Push13(c_Expr*); + void p_Push14(Array,int,int); + void p_Push15(Array,int); Array p_ToArray(); void mark(); }; @@ -4374,32 +16675,32 @@ class c_Stmt : public Object{ virtual String p_Trans()=0; void mark(); }; -class c_List5 : public Object{ +class c_List7 : public Object{ public: - c_Node10* m__head; - c_List5(); - c_List5* m_new(); - c_Node10* p_AddLast5(c_Stmt*); - c_List5* m_new2(Array); + c_Node12* m__head; + c_List7(); + c_List7* m_new(); + c_Node12* p_AddLast7(c_Stmt*); + c_List7* m_new2(Array); bool p_IsEmpty(); - c_Enumerator5* p_ObjectEnumerator(); - c_Node10* p_AddFirst(c_Stmt*); + c_Enumerator6* p_ObjectEnumerator(); + c_Node12* p_AddFirst(c_Stmt*); void mark(); }; -class c_Node10 : public Object{ +class c_Node12 : public Object{ public: - c_Node10* m__succ; - c_Node10* m__pred; + c_Node12* m__succ; + c_Node12* m__pred; c_Stmt* m__data; - c_Node10(); - c_Node10* m_new(c_Node10*,c_Node10*,c_Stmt*); - c_Node10* m_new2(); + c_Node12(); + c_Node12* m_new(c_Node12*,c_Node12*,c_Stmt*); + c_Node12* m_new2(); void mark(); }; -class c_HeadNode5 : public c_Node10{ +class c_HeadNode6 : public c_Node12{ public: - c_HeadNode5(); - c_HeadNode5* m_new(); + c_HeadNode6(); + c_HeadNode6* m_new(); void mark(); }; class c_InvokeSuperExpr : public c_Expr{ @@ -4428,6 +16729,52 @@ class c_IdentTypeExpr : public c_Expr{ c_Expr* p_SemantFunc(Array); void mark(); }; +class c_Node13 : public Object{ + public: + c_Node13* m__succ; + c_Node13* m__pred; + int m__data; + c_Node13(); + c_Node13* m_new(c_Node13*,c_Node13*,int); + c_Node13* m_new2(); + void mark(); +}; +class c_HeadNode7 : public c_Node13{ + public: + c_HeadNode7(); + c_HeadNode7* m_new(); + void mark(); +}; +class c_Enumerator2 : public Object{ + public: + c_List3* m__list; + c_Node13* m__curr; + c_Enumerator2(); + c_Enumerator2* m_new(c_List3*); + c_Enumerator2* m_new2(); + bool p_HasNext(); + int p_NextObject(); + void mark(); +}; +class c_MapKeys : public Object{ + public: + c_Map6* m_map; + c_MapKeys(); + c_MapKeys* m_new(c_Map6*); + c_MapKeys* m_new2(); + c_KeyEnumerator* p_ObjectEnumerator(); + void mark(); +}; +class c_KeyEnumerator : public Object{ + public: + c_Node8* m_node; + c_KeyEnumerator(); + c_KeyEnumerator* m_new(c_Node8*); + c_KeyEnumerator* m_new2(); + bool p_HasNext(); + int p_NextObject(); + void mark(); +}; class c_FuncCallExpr : public c_Expr{ public: c_Expr* m_expr; @@ -4545,13 +16892,13 @@ class c_LocalDecl : public c_VarDecl{ c_Decl* p_OnCopy(); void mark(); }; -class c_Enumerator2 : public Object{ +class c_Enumerator3 : public Object{ public: - c_List3* m__list; - c_Node8* m__curr; - c_Enumerator2(); - c_Enumerator2* m_new(c_List3*); - c_Enumerator2* m_new2(); + c_List5* m__list; + c_Node10* m__curr; + c_Enumerator3(); + c_Enumerator3* m_new(c_List5*); + c_Enumerator3* m_new2(); bool p_HasNext(); c_Decl* p_NextObject(); void mark(); @@ -4568,16 +16915,16 @@ class c_DeclStmt : public c_Stmt{ String p_Trans(); void mark(); }; -class c_Stack5 : public Object{ +class c_Stack6 : public Object{ public: Array m_data; int m_length; - c_Stack5(); - c_Stack5* m_new(); - c_Stack5* m_new2(Array); - void p_Push13(c_IdentType*); - void p_Push14(Array,int,int); - void p_Push15(Array,int); + c_Stack6(); + c_Stack6* m_new(); + c_Stack6* m_new2(Array); + void p_Push16(c_IdentType*); + void p_Push17(Array,int,int); + void p_Push18(Array,int); Array p_ToArray(); void mark(); }; @@ -4593,30 +16940,30 @@ class c_ObjectType : public c_Type{ String p_ToString(); void mark(); }; -class c_List6 : public Object{ +class c_List8 : public Object{ public: - c_Node11* m__head; - c_List6(); - c_List6* m_new(); - c_Node11* p_AddLast6(c_ClassDecl*); - c_List6* m_new2(Array); - c_Enumerator4* p_ObjectEnumerator(); + c_Node14* m__head; + c_List8(); + c_List8* m_new(); + c_Node14* p_AddLast8(c_ClassDecl*); + c_List8* m_new2(Array); + c_Enumerator5* p_ObjectEnumerator(); void mark(); }; -class c_Node11 : public Object{ +class c_Node14 : public Object{ public: - c_Node11* m__succ; - c_Node11* m__pred; + c_Node14* m__succ; + c_Node14* m__pred; c_ClassDecl* m__data; - c_Node11(); - c_Node11* m_new(c_Node11*,c_Node11*,c_ClassDecl*); - c_Node11* m_new2(); + c_Node14(); + c_Node14* m_new(c_Node14*,c_Node14*,c_ClassDecl*); + c_Node14* m_new2(); void mark(); }; -class c_HeadNode6 : public c_Node11{ +class c_HeadNode8 : public c_Node14{ public: - c_HeadNode6(); - c_HeadNode6* m_new(); + c_HeadNode8(); + c_HeadNode8* m_new(); void mark(); }; class c_ArgDecl : public c_LocalDecl{ @@ -4628,48 +16975,48 @@ class c_ArgDecl : public c_LocalDecl{ c_Decl* p_OnCopy(); void mark(); }; -class c_Stack6 : public Object{ +class c_Stack7 : public Object{ public: Array m_data; int m_length; - c_Stack6(); - c_Stack6* m_new(); - c_Stack6* m_new2(Array); - void p_Push16(c_ArgDecl*); - void p_Push17(Array,int,int); - void p_Push18(Array,int); + c_Stack7(); + c_Stack7* m_new(); + c_Stack7* m_new2(Array); + void p_Push19(c_ArgDecl*); + void p_Push20(Array,int,int); + void p_Push21(Array,int); Array p_ToArray(); void mark(); }; -class c_List7 : public Object{ +class c_List9 : public Object{ public: - c_Node12* m__head; - c_List7(); - c_List7* m_new(); - c_Node12* p_AddLast7(c_BlockDecl*); - c_List7* m_new2(Array); + c_Node15* m__head; + c_List9(); + c_List9* m_new(); + c_Node15* p_AddLast9(c_BlockDecl*); + c_List9* m_new2(Array); c_BlockDecl* p_RemoveLast(); - bool p_Equals3(c_BlockDecl*,c_BlockDecl*); - c_Node12* p_FindLast5(c_BlockDecl*,c_Node12*); - c_Node12* p_FindLast6(c_BlockDecl*); - void p_RemoveLast4(c_BlockDecl*); + bool p_Equals4(c_BlockDecl*,c_BlockDecl*); + c_Node15* p_FindLast7(c_BlockDecl*,c_Node15*); + c_Node15* p_FindLast8(c_BlockDecl*); + void p_RemoveLast5(c_BlockDecl*); void mark(); }; -class c_Node12 : public Object{ +class c_Node15 : public Object{ public: - c_Node12* m__succ; - c_Node12* m__pred; + c_Node15* m__succ; + c_Node15* m__pred; c_BlockDecl* m__data; - c_Node12(); - c_Node12* m_new(c_Node12*,c_Node12*,c_BlockDecl*); - c_Node12* m_new2(); + c_Node15(); + c_Node15* m_new(c_Node15*,c_Node15*,c_BlockDecl*); + c_Node15* m_new2(); int p_Remove(); void mark(); }; -class c_HeadNode7 : public c_Node12{ +class c_HeadNode9 : public c_Node15{ public: - c_HeadNode7(); - c_HeadNode7* m_new(); + c_HeadNode9(); + c_HeadNode9* m_new(); void mark(); }; class c_ReturnStmt : public c_Stmt{ @@ -4795,16 +17142,16 @@ class c_CatchStmt : public c_Stmt{ String p_Trans(); void mark(); }; -class c_Stack7 : public Object{ +class c_Stack8 : public Object{ public: Array m_data; int m_length; - c_Stack7(); - c_Stack7* m_new(); - c_Stack7* m_new2(Array); - void p_Push19(c_CatchStmt*); - void p_Push20(Array,int,int); - void p_Push21(Array,int); + c_Stack8(); + c_Stack8* m_new(); + c_Stack8* m_new2(Array); + void p_Push22(c_CatchStmt*); + void p_Push23(Array,int,int); + void p_Push24(Array,int); static c_CatchStmt* m_NIL; void p_Length(int); int p_Length2(); @@ -4848,43 +17195,43 @@ class c_ExprStmt : public c_Stmt{ void mark(); }; c_ModuleDecl* bb_parser_ParseModule(String,String,c_AppDecl*); -class c_Enumerator3 : public Object{ +class c_Enumerator4 : public Object{ public: - c_List4* m__list; - c_Node9* m__curr; - c_Enumerator3(); - c_Enumerator3* m_new(c_List4*); - c_Enumerator3* m_new2(); + c_List6* m__list; + c_Node11* m__curr; + c_Enumerator4(); + c_Enumerator4* m_new(c_List6*); + c_Enumerator4* m_new2(); bool p_HasNext(); c_FuncDecl* p_NextObject(); void mark(); }; extern c_StringList* bb_config__errStack; int bb_config_PushErr(String); -class c_List8 : public Object{ +class c_List10 : public Object{ public: - c_Node13* m__head; - c_List8(); - c_List8* m_new(); - c_Node13* p_AddLast8(c_GlobalDecl*); - c_List8* m_new2(Array); - c_Enumerator6* p_ObjectEnumerator(); + c_Node16* m__head; + c_List10(); + c_List10* m_new(); + c_Node16* p_AddLast10(c_GlobalDecl*); + c_List10* m_new2(Array); + c_Enumerator7* p_ObjectEnumerator(); void mark(); }; -class c_Node13 : public Object{ +class c_Node16 : public Object{ public: - c_Node13* m__succ; - c_Node13* m__pred; + c_Node16* m__succ; + c_Node16* m__pred; c_GlobalDecl* m__data; - c_Node13(); - c_Node13* m_new(c_Node13*,c_Node13*,c_GlobalDecl*); - c_Node13* m_new2(); + c_Node16(); + c_Node16* m_new(c_Node16*,c_Node16*,c_GlobalDecl*); + c_Node16* m_new2(); void mark(); }; -class c_HeadNode8 : public c_Node13{ +class c_HeadNode10 : public c_Node16{ public: - c_HeadNode8(); - c_HeadNode8* m_new(); + c_HeadNode10(); + c_HeadNode10* m_new(); void mark(); }; int bb_config_PopErr(); @@ -4920,53 +17267,53 @@ class c_Target : public Object{ c_Target* m_new2(); void mark(); }; -class c_Map6 : public Object{ +class c_Map7 : public Object{ public: - c_Node14* m_root; - c_Map6(); - c_Map6* m_new(); + c_Node17* m_root; + c_Map7(); + c_Map7* m_new(); virtual int p_Compare(String,String)=0; - int p_RotateLeft6(c_Node14*); - int p_RotateRight6(c_Node14*); - int p_InsertFixup6(c_Node14*); + int p_RotateLeft7(c_Node17*); + int p_RotateRight7(c_Node17*); + int p_InsertFixup7(c_Node17*); bool p_Set6(String,c_Target*); - c_Node14* p_FirstNode(); + c_Node17* p_FirstNode(); c_NodeEnumerator2* p_ObjectEnumerator(); - c_Node14* p_FindNode(String); + c_Node17* p_FindNode(String); c_Target* p_Get(String); void mark(); }; -class c_StringMap6 : public c_Map6{ +class c_StringMap6 : public c_Map7{ public: c_StringMap6(); c_StringMap6* m_new(); int p_Compare(String,String); void mark(); }; -class c_Node14 : public Object{ +class c_Node17 : public Object{ public: String m_key; - c_Node14* m_right; - c_Node14* m_left; + c_Node17* m_right; + c_Node17* m_left; c_Target* m_value; int m_color; - c_Node14* m_parent; - c_Node14(); - c_Node14* m_new(String,c_Target*,int,c_Node14*); - c_Node14* m_new2(); - c_Node14* p_NextNode(); + c_Node17* m_parent; + c_Node17(); + c_Node17* m_new(String,c_Target*,int,c_Node17*); + c_Node17* m_new2(); + c_Node17* p_NextNode(); String p_Key(); void mark(); }; void bb_config_PopConfigScope(); class c_NodeEnumerator2 : public Object{ public: - c_Node14* m_node; + c_Node17* m_node; c_NodeEnumerator2(); - c_NodeEnumerator2* m_new(c_Node14*); + c_NodeEnumerator2* m_new(c_Node17*); c_NodeEnumerator2* m_new2(); bool p_HasNext(); - c_Node14* p_NextObject(); + c_Node17* p_NextObject(); void mark(); }; extern String bb_config_ENV_HOST; @@ -4984,7 +17331,7 @@ class c_Reflector : public Object{ c_StringMap7* m_munged; c_StringMap2* m_modexprs; c_StringSet* m_refmods; - c_Stack8* m_classdecls; + c_Stack9* m_classdecls; c_StringMap7* m_classids; c_StringStack* m_output; c_Reflector(); @@ -5027,65 +17374,65 @@ class c_ValueEnumerator : public Object{ c_ModuleDecl* p_NextObject(); void mark(); }; -class c_Map7 : public Object{ +class c_Map8 : public Object{ public: - c_Node15* m_root; - c_Map7(); - c_Map7* m_new(); + c_Node18* m_root; + c_Map8(); + c_Map8* m_new(); virtual int p_Compare(String,String)=0; - c_Node15* p_FindNode(String); + c_Node18* p_FindNode(String); bool p_Contains(String); int p_Get(String); - int p_RotateLeft7(c_Node15*); - int p_RotateRight7(c_Node15*); - int p_InsertFixup7(c_Node15*); + int p_RotateLeft8(c_Node18*); + int p_RotateRight8(c_Node18*); + int p_InsertFixup8(c_Node18*); bool p_Set7(String,int); void mark(); }; -class c_StringMap7 : public c_Map7{ +class c_StringMap7 : public c_Map8{ public: c_StringMap7(); c_StringMap7* m_new(); int p_Compare(String,String); void mark(); }; -class c_Node15 : public Object{ +class c_Node18 : public Object{ public: String m_key; - c_Node15* m_right; - c_Node15* m_left; + c_Node18* m_right; + c_Node18* m_left; int m_value; int m_color; - c_Node15* m_parent; - c_Node15(); - c_Node15* m_new(String,int,int,c_Node15*); - c_Node15* m_new2(); + c_Node18* m_parent; + c_Node18(); + c_Node18* m_new(String,int,int,c_Node18*); + c_Node18* m_new2(); void mark(); }; -class c_Enumerator4 : public Object{ +class c_Enumerator5 : public Object{ public: - c_List6* m__list; - c_Node11* m__curr; - c_Enumerator4(); - c_Enumerator4* m_new(c_List6*); - c_Enumerator4* m_new2(); + c_List8* m__list; + c_Node14* m__curr; + c_Enumerator5(); + c_Enumerator5* m_new(c_List8*); + c_Enumerator5* m_new2(); bool p_HasNext(); c_ClassDecl* p_NextObject(); void mark(); }; -class c_Stack8 : public Object{ +class c_Stack9 : public Object{ public: Array m_data; int m_length; - c_Stack8(); - c_Stack8* m_new(); - c_Stack8* m_new2(Array); + c_Stack9(); + c_Stack9* m_new(); + c_Stack9* m_new2(Array); static c_ClassDecl* m_NIL; void p_Length(int); int p_Length2(); - void p_Push22(c_ClassDecl*); - void p_Push23(Array,int,int); - void p_Push24(Array,int); + void p_Push25(c_ClassDecl*); + void p_Push26(Array,int,int); + void p_Push27(Array,int); c_ClassDecl* p_Get2(int); void mark(); }; @@ -5248,7 +17595,7 @@ class c_CppTranslator : public c_CTranslator{ public: bool m_unsafe; int m_gc_mode; - c_Stack9* m_dbgLocals; + c_Stack10* m_dbgLocals; String m_lastDbgInfo; int m_pure; c_CppTranslator(); @@ -5438,45 +17785,45 @@ class c_CsTranslator : public c_CTranslator{ String p_TransTryStmt(c_TryStmt*); void mark(); }; -class c_List9 : public Object{ +class c_List11 : public Object{ public: - c_Node16* m__head; - c_List9(); - c_List9* m_new(); - c_Node16* p_AddLast9(c_ModuleDecl*); - c_List9* m_new2(Array); + c_Node19* m__head; + c_List11(); + c_List11* m_new(); + c_Node19* p_AddLast11(c_ModuleDecl*); + c_List11* m_new2(Array); bool p_IsEmpty(); c_ModuleDecl* p_RemoveLast(); - bool p_Equals4(c_ModuleDecl*,c_ModuleDecl*); - c_Node16* p_FindLast7(c_ModuleDecl*,c_Node16*); - c_Node16* p_FindLast8(c_ModuleDecl*); - void p_RemoveLast5(c_ModuleDecl*); + bool p_Equals5(c_ModuleDecl*,c_ModuleDecl*); + c_Node19* p_FindLast9(c_ModuleDecl*,c_Node19*); + c_Node19* p_FindLast10(c_ModuleDecl*); + void p_RemoveLast6(c_ModuleDecl*); void mark(); }; -class c_Node16 : public Object{ +class c_Node19 : public Object{ public: - c_Node16* m__succ; - c_Node16* m__pred; + c_Node19* m__succ; + c_Node19* m__pred; c_ModuleDecl* m__data; - c_Node16(); - c_Node16* m_new(c_Node16*,c_Node16*,c_ModuleDecl*); - c_Node16* m_new2(); + c_Node19(); + c_Node19* m_new(c_Node19*,c_Node19*,c_ModuleDecl*); + c_Node19* m_new2(); int p_Remove(); void mark(); }; -class c_HeadNode9 : public c_Node16{ +class c_HeadNode11 : public c_Node19{ public: - c_HeadNode9(); - c_HeadNode9* m_new(); + c_HeadNode11(); + c_HeadNode11* m_new(); void mark(); }; -class c_Enumerator5 : public Object{ +class c_Enumerator6 : public Object{ public: - c_List5* m__list; - c_Node10* m__curr; - c_Enumerator5(); - c_Enumerator5* m_new(c_List5*); - c_Enumerator5* m_new2(); + c_List7* m__list; + c_Node12* m__curr; + c_Enumerator6(); + c_Enumerator6* m_new(c_List7*); + c_Enumerator6* m_new2(); bool p_HasNext(); c_Stmt* p_NextObject(); void mark(); @@ -5537,143 +17884,143 @@ class c_VarExpr : public c_Expr{ void mark(); }; extern int bb_decl__loopnest; -class c_Map8 : public Object{ +class c_Map9 : public Object{ public: - c_Node17* m_root; - c_Map8(); - c_Map8* m_new(); + c_Node20* m_root; + c_Map9(); + c_Map9* m_new(); virtual int p_Compare(String,String)=0; - c_Node17* p_FindNode(String); + c_Node20* p_FindNode(String); c_FuncDeclList* p_Get(String); - int p_RotateLeft8(c_Node17*); - int p_RotateRight8(c_Node17*); - int p_InsertFixup8(c_Node17*); + int p_RotateLeft9(c_Node20*); + int p_RotateRight9(c_Node20*); + int p_InsertFixup9(c_Node20*); bool p_Set8(String,c_FuncDeclList*); void mark(); }; -class c_StringMap8 : public c_Map8{ +class c_StringMap8 : public c_Map9{ public: c_StringMap8(); c_StringMap8* m_new(); int p_Compare(String,String); void mark(); }; -class c_Node17 : public Object{ +class c_Node20 : public Object{ public: String m_key; - c_Node17* m_right; - c_Node17* m_left; + c_Node20* m_right; + c_Node20* m_left; c_FuncDeclList* m_value; int m_color; - c_Node17* m_parent; - c_Node17(); - c_Node17* m_new(String,c_FuncDeclList*,int,c_Node17*); - c_Node17* m_new2(); + c_Node20* m_parent; + c_Node20(); + c_Node20* m_new(String,c_FuncDeclList*,int,c_Node20*); + c_Node20* m_new2(); void mark(); }; -class c_Map9 : public Object{ +class c_Map10 : public Object{ public: - c_Node18* m_root; - c_Map9(); - c_Map9* m_new(); + c_Node21* m_root; + c_Map10(); + c_Map10* m_new(); virtual int p_Compare(String,String)=0; - c_Node18* p_FindNode(String); + c_Node21* p_FindNode(String); bool p_Contains(String); - int p_RotateLeft9(c_Node18*); - int p_RotateRight9(c_Node18*); - int p_InsertFixup9(c_Node18*); + int p_RotateLeft10(c_Node21*); + int p_RotateRight10(c_Node21*); + int p_InsertFixup10(c_Node21*); bool p_Set9(String,c_FuncDecl*); void mark(); }; -class c_StringMap9 : public c_Map9{ +class c_StringMap9 : public c_Map10{ public: c_StringMap9(); c_StringMap9* m_new(); int p_Compare(String,String); void mark(); }; -class c_Node18 : public Object{ +class c_Node21 : public Object{ public: String m_key; - c_Node18* m_right; - c_Node18* m_left; + c_Node21* m_right; + c_Node21* m_left; c_FuncDecl* m_value; int m_color; - c_Node18* m_parent; - c_Node18(); - c_Node18* m_new(String,c_FuncDecl*,int,c_Node18*); - c_Node18* m_new2(); + c_Node21* m_parent; + c_Node21(); + c_Node21* m_new(String,c_FuncDecl*,int,c_Node21*); + c_Node21* m_new2(); void mark(); }; -class c_Map10 : public Object{ +class c_Map11 : public Object{ public: - c_Node19* m_root; - c_Map10(); - c_Map10* m_new(); + c_Node22* m_root; + c_Map11(); + c_Map11* m_new(); virtual int p_Compare(String,String)=0; - c_Node19* p_FindNode(String); + c_Node22* p_FindNode(String); c_StringSet* p_Get(String); - int p_RotateLeft10(c_Node19*); - int p_RotateRight10(c_Node19*); - int p_InsertFixup10(c_Node19*); + int p_RotateLeft11(c_Node22*); + int p_RotateRight11(c_Node22*); + int p_InsertFixup11(c_Node22*); bool p_Set10(String,c_StringSet*); void mark(); }; -class c_StringMap10 : public c_Map10{ +class c_StringMap10 : public c_Map11{ public: c_StringMap10(); c_StringMap10* m_new(); int p_Compare(String,String); void mark(); }; -class c_Node19 : public Object{ +class c_Node22 : public Object{ public: String m_key; - c_Node19* m_right; - c_Node19* m_left; + c_Node22* m_right; + c_Node22* m_left; c_StringSet* m_value; int m_color; - c_Node19* m_parent; - c_Node19(); - c_Node19* m_new(String,c_StringSet*,int,c_Node19*); - c_Node19* m_new2(); + c_Node22* m_parent; + c_Node22(); + c_Node22* m_new(String,c_StringSet*,int,c_Node22*); + c_Node22* m_new2(); void mark(); }; -class c_Enumerator6 : public Object{ +class c_Enumerator7 : public Object{ public: - c_List8* m__list; - c_Node13* m__curr; - c_Enumerator6(); - c_Enumerator6* m_new(c_List8*); - c_Enumerator6* m_new2(); + c_List10* m__list; + c_Node16* m__curr; + c_Enumerator7(); + c_Enumerator7* m_new(c_List10*); + c_Enumerator7* m_new2(); bool p_HasNext(); c_GlobalDecl* p_NextObject(); void mark(); }; -class c_Stack9 : public Object{ +class c_Stack10 : public Object{ public: Array m_data; int m_length; - c_Stack9(); - c_Stack9* m_new(); - c_Stack9* m_new2(Array); + c_Stack10(); + c_Stack10* m_new(); + c_Stack10* m_new2(Array); static c_LocalDecl* m_NIL; void p_Clear(); - c_Enumerator7* p_ObjectEnumerator(); + c_Enumerator8* p_ObjectEnumerator(); void p_Length(int); int p_Length2(); - void p_Push25(c_LocalDecl*); - void p_Push26(Array,int,int); - void p_Push27(Array,int); + void p_Push28(c_LocalDecl*); + void p_Push29(Array,int,int); + void p_Push30(Array,int); void mark(); }; -class c_Enumerator7 : public Object{ +class c_Enumerator8 : public Object{ public: - c_Stack9* m_stack; + c_Stack10* m_stack; int m_index; - c_Enumerator7(); - c_Enumerator7* m_new(c_Stack9*); - c_Enumerator7* m_new2(); + c_Enumerator8(); + c_Enumerator8* m_new(c_Stack10*); + c_Enumerator8* m_new2(); bool p_HasNext(); c_LocalDecl* p_NextObject(); void mark(); @@ -6015,7 +18362,7 @@ String c_TransCC::p_GetReleaseVersion(){ } void c_TransCC::p_Run(Array t_args){ this->m_args=t_args; - bbPrint(String(L"TRANS cerberus compiler V2019-10-13",35)); + bbPrint(String(L"TRANS cerberus compiler V2020-05-09",35)); m_cerberusdir=RealPath(bb_os_ExtractDir(AppPath())+String(L"/..",3)); SetEnv(String(L"CERBERUSDIR",11),m_cerberusdir); SetEnv(String(L"MONKEYDIR",9),m_cerberusdir); @@ -6028,7 +18375,7 @@ void c_TransCC::p_Run(Array t_args){ String t_valid=String(); c_NodeEnumerator2* t_=m__targets->p_ObjectEnumerator(); while(t_->p_HasNext()){ - c_Node14* t_it=t_->p_NextObject(); + c_Node17* t_it=t_->p_NextObject(); t_valid=t_valid+(String(L" ",1)+t_it->p_Key().Replace(String(L" ",1),String(L"_",1))); } bbPrint(String(L"TRANS Usage: transcc [-update] [-build] [-run] [-clean] [-config=...] [-target=...] [-cfgfile=...] [-modpath=...] ",141)); @@ -6268,16 +18615,16 @@ int c_Decl::p_Semant(){ if((m_scope)!=0){ if((p_IsExtern())!=0){ if((dynamic_cast(m_scope))!=0){ - p_AppScope()->m_allSemantedDecls->p_AddLast3(this); + p_AppScope()->m_allSemantedDecls->p_AddLast5(this); } }else{ - m_scope->m_semanted->p_AddLast3(this); + m_scope->m_semanted->p_AddLast5(this); if((dynamic_cast(this))!=0){ - p_AppScope()->m_semantedGlobals->p_AddLast8(dynamic_cast(this)); + p_AppScope()->m_semantedGlobals->p_AddLast10(dynamic_cast(this)); } if((dynamic_cast(m_scope))!=0){ - p_AppScope()->m_semanted->p_AddLast3(this); - p_AppScope()->m_allSemantedDecls->p_AddLast3(this); + p_AppScope()->m_semanted->p_AddLast5(this); + p_AppScope()->m_allSemantedDecls->p_AddLast5(this); } } bb_decl_PopEnv(); @@ -6314,9 +18661,9 @@ void c_Decl::mark(){ Object::mark(); } c_ScopeDecl::c_ScopeDecl(){ - m_decls=(new c_List3)->m_new(); + m_decls=(new c_List5)->m_new(); m_declsMap=(new c_StringMap4)->m_new(); - m_semanted=(new c_List3)->m_new(); + m_semanted=(new c_List5)->m_new(); } c_ScopeDecl* c_ScopeDecl::m_new(){ c_Decl::m_new(); @@ -6331,7 +18678,7 @@ int c_ScopeDecl::p_InsertDecl(c_Decl* t_decl){ return 0; } t_decl->m_scope=this; - m_decls->p_AddLast3(t_decl); + m_decls->p_AddLast5(t_decl); c_StringMap4* t_decls=0; Object* t_tdecl=m_declsMap->p_Get(t_ident); if((dynamic_cast(t_decl))!=0){ @@ -6341,7 +18688,7 @@ int c_ScopeDecl::p_InsertDecl(c_Decl* t_decl){ t_funcs=(new c_FuncDeclList)->m_new(); m_declsMap->p_Insert2(t_ident,(t_funcs)); } - t_funcs->p_AddLast4(dynamic_cast(t_decl)); + t_funcs->p_AddLast6(dynamic_cast(t_decl)); }else{ bb_config_Err(String(L"Duplicate identifier '",22)+t_ident+String(L"'.",2)); } @@ -6353,7 +18700,7 @@ int c_ScopeDecl::p_InsertDecl(c_Decl* t_decl){ } } if((t_decl->p_IsSemanted())!=0){ - m_semanted->p_AddLast3(t_decl); + m_semanted->p_AddLast5(t_decl); } return 0; } @@ -6385,8 +18732,8 @@ Object* c_ScopeDecl::p_FindDecl(String t_ident){ } return 0; } -int c_ScopeDecl::p_InsertDecls(c_List3* t_decls){ - c_Enumerator2* t_=t_decls->p_ObjectEnumerator(); +int c_ScopeDecl::p_InsertDecls(c_List5* t_decls){ + c_Enumerator3* t_=t_decls->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_Decl* t_decl=t_->p_NextObject(); p_InsertDecl(t_decl); @@ -6398,7 +18745,7 @@ c_FuncDecl* c_ScopeDecl::p_FindFuncDecl(String t_ident,Array t_argExpr if(!((t_funcs)!=0)){ return 0; } - c_Enumerator3* t_=t_funcs->p_ObjectEnumerator(); + c_Enumerator4* t_=t_funcs->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_FuncDecl* t_func=t_->p_NextObject(); t_func->p_Semant(); @@ -6406,7 +18753,7 @@ c_FuncDecl* c_ScopeDecl::p_FindFuncDecl(String t_ident,Array t_argExpr c_FuncDecl* t_match=0; int t_isexact=0; String t_err=String(); - c_Enumerator3* t_2=t_funcs->p_ObjectEnumerator(); + c_Enumerator4* t_2=t_funcs->p_ObjectEnumerator(); while(t_2->p_HasNext()){ c_FuncDecl* t_func2=t_2->p_NextObject(); Array t_argDecls=t_func2->m_argDecls; @@ -6480,7 +18827,7 @@ c_FuncDecl* c_ScopeDecl::p_FindFuncDecl(String t_ident,Array t_argExpr t_match->p_AssertAccess(); return t_match; } -c_List3* c_ScopeDecl::p_Decls(){ +c_List5* c_ScopeDecl::p_Decls(){ return m_decls; } c_Type* c_ScopeDecl::p_FindType(String t_ident,Array t_args){ @@ -6506,9 +18853,9 @@ c_Type* c_ScopeDecl::p_FindType(String t_ident,Array t_args){ } return 0; } -c_List4* c_ScopeDecl::p_MethodDecls(String t_id){ - c_List4* t_fdecls=(new c_List4)->m_new(); - c_Enumerator2* t_=m_decls->p_ObjectEnumerator(); +c_List6* c_ScopeDecl::p_MethodDecls(String t_id){ + c_List6* t_fdecls=(new c_List6)->m_new(); + c_Enumerator3* t_=m_decls->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_Decl* t_decl=t_->p_NextObject(); if(((t_id).Length()!=0) && t_decl->m_ident!=t_id){ @@ -6516,17 +18863,17 @@ c_List4* c_ScopeDecl::p_MethodDecls(String t_id){ } c_FuncDecl* t_fdecl=dynamic_cast(t_decl); if(((t_fdecl)!=0) && t_fdecl->p_IsMethod()){ - t_fdecls->p_AddLast4(t_fdecl); + t_fdecls->p_AddLast6(t_fdecl); } } return t_fdecls; } -c_List3* c_ScopeDecl::p_Semanted(){ +c_List5* c_ScopeDecl::p_Semanted(){ return m_semanted; } -c_List4* c_ScopeDecl::p_SemantedMethods(String t_id){ - c_List4* t_fdecls=(new c_List4)->m_new(); - c_Enumerator2* t_=m_semanted->p_ObjectEnumerator(); +c_List6* c_ScopeDecl::p_SemantedMethods(String t_id){ + c_List6* t_fdecls=(new c_List6)->m_new(); + c_Enumerator3* t_=m_semanted->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_Decl* t_decl=t_->p_NextObject(); if(((t_id).Length()!=0) && t_decl->m_ident!=t_id){ @@ -6534,7 +18881,7 @@ c_List4* c_ScopeDecl::p_SemantedMethods(String t_id){ } c_FuncDecl* t_fdecl=dynamic_cast(t_decl); if(((t_fdecl)!=0) && t_fdecl->p_IsMethod()){ - t_fdecls->p_AddLast4(t_fdecl); + t_fdecls->p_AddLast6(t_fdecl); } } return t_fdecls; @@ -6555,9 +18902,9 @@ c_Decl* c_ScopeDecl::p_OnCopy(){ int c_ScopeDecl::p_OnSemant(){ return 0; } -c_List4* c_ScopeDecl::p_SemantedFuncs(String t_id){ - c_List4* t_fdecls=(new c_List4)->m_new(); - c_Enumerator2* t_=m_semanted->p_ObjectEnumerator(); +c_List6* c_ScopeDecl::p_SemantedFuncs(String t_id){ + c_List6* t_fdecls=(new c_List6)->m_new(); + c_Enumerator3* t_=m_semanted->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_Decl* t_decl=t_->p_NextObject(); if(((t_id).Length()!=0) && t_decl->m_ident!=t_id){ @@ -6565,7 +18912,7 @@ c_List4* c_ScopeDecl::p_SemantedFuncs(String t_id){ } c_FuncDecl* t_fdecl=dynamic_cast(t_decl); if((t_fdecl)!=0){ - t_fdecls->p_AddLast4(t_fdecl); + t_fdecls->p_AddLast6(t_fdecl); } } return t_fdecls; @@ -6582,9 +18929,9 @@ c_ModuleDecl* c_ScopeDecl::p_FindModuleDecl(String t_ident){ } return 0; } -c_List4* c_ScopeDecl::p_FuncDecls(String t_id){ - c_List4* t_fdecls=(new c_List4)->m_new(); - c_Enumerator2* t_=m_decls->p_ObjectEnumerator(); +c_List6* c_ScopeDecl::p_FuncDecls(String t_id){ + c_List6* t_fdecls=(new c_List6)->m_new(); + c_Enumerator3* t_=m_decls->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_Decl* t_decl=t_->p_NextObject(); if(((t_id).Length()!=0) && t_decl->m_ident!=t_id){ @@ -6592,7 +18939,7 @@ c_List4* c_ScopeDecl::p_FuncDecls(String t_id){ } c_FuncDecl* t_fdecl=dynamic_cast(t_decl); if((t_fdecl)!=0){ - t_fdecls->p_AddLast4(t_fdecl); + t_fdecls->p_AddLast6(t_fdecl); } } return t_fdecls; @@ -7582,7 +19929,7 @@ void c_Builder::p_CreateDataDir(String t_dir){ String t_t=t_dir+String(L"/",1)+t_r; int t_22=FileType(t_p); if(t_22==1){ - if(bb_transcc_MatchPath(t_r,m_DATA_FILES)){ + if(bb_transcc_MatchPath(t_r.ToLower(),m_DATA_FILES.ToLower())){ p_CCopyFile(t_p,t_t); t_udata->p_Insert(t_t); m_dataFiles->p_Set2(t_p,t_r); @@ -7601,7 +19948,7 @@ void c_Builder::p_CreateDataDir(String t_dir){ String t_p2=t_3->p_NextObject(); String t_r2=bb_os_StripDir(t_p2); String t_t2=t_dir+String(L"/",1)+t_r2; - if(bb_transcc_MatchPath(t_r2,m_DATA_FILES)){ + if(bb_transcc_MatchPath(t_r2.ToLower(),m_DATA_FILES.ToLower())){ p_CCopyFile(t_p2,t_t2); t_udata->p_Insert(t_t2); m_dataFiles->p_Set2(t_p2,t_r2); @@ -7641,20 +19988,123 @@ void c_Builder::p_CreateDataDir(String t_dir){ } } } +void c_Builder::p_MakeIcons(String t_srcFilename,Array t_icons,int t_round){ + String t_iconPath=bb_os_ExtractDir(bb_os_StripExt(m_tcc->m_opt_srcpath)); + String t_iconFile=RealPath(t_iconPath+String(L"\\",1)+t_srcFilename); + if(((!((FileType(t_iconFile))!=0))?1:0)==1){ + t_iconFile=RealPath(t_srcFilename); + } + if(FileType(t_iconFile)==1){ + for(int t_i=0;t_ip_Execute(t_cmd,t_failHard); } -void c_Builder::p_CopyIcon(){ +void c_Builder::p_CopySourceFiles(String t_dir){ + t_dir=RealPath(t_dir); + c_Enumerator* t_=m_app->m_fileIncludes->p_ObjectEnumerator(); + while(t_->p_HasNext()){ + String t_p=t_->p_NextObject(); + bool t_oSub=false; + String t_oExt=String(L"*",1); + String t_oOut=String(); + String t_src=String(); + Array t_p2=t_p.Split(String(L" ",1)); + Array t_2=t_p2; + int t_3=0; + while(t_30){ + t_targetDir=t_targetDir+(String(L"/",1)+t_oOut); + Array t_outs=t_oOut.Split(String(L"/",1)); + t_oOut=String(); + Array t_5=t_outs; + int t_6=0; + while(t_6 t_exts=t_oExt.Split(String(L";",1)); + if(FileType(t_src)==1){ + String t_filename=bb_os_StripDir(t_src); + p_CCopyFile(t_src,t_targetDir+String(L"/",1)+t_filename); + }else{ + Array t_exts2=t_oExt.Split(String(L";",1)); + Array t_files=bb_os_LoadDir(t_src,t_oSub,false); + Array t_7=t_files; + int t_8=0; + while(t_8 t_9=t_exts2; + int t_10=0; + while(t_10m_opt_srcpath)); - String t_iconFile=RealPath(t_iconPath+String(L"\\",1)+bb_config_GetConfigVar(String(L"GLFW_APP_ICON",13))); + String t_iconFile=RealPath(t_iconPath+String(L"\\",1)+t_iFile); if(FileType(t_iconFile)==1){ - CopyFile(t_iconFile,t_targetIcon); + if(bb_os_ExtractExt(t_iconFile).ToLower()==String(L"ico",3)){ + CopyFile(t_iconFile,t_targetIcon); + }else{ + _ConvertToIco(t_iconFile,t_targetIcon); + } }else{ - t_iconFile=RealPath(bb_config_GetConfigVar(String(L"GLFW_APP_ICON",13))); + t_iconFile=t_iFile; if(FileType(t_iconFile)==1){ - CopyFile(t_iconFile,t_targetIcon); + if(bb_os_ExtractExt(t_iconFile).ToLower()==String(L"ico",3)){ + CopyFile(t_iconFile,t_targetIcon); + }else{ + _ConvertToIco(t_iconFile,t_targetIcon); + } } } } @@ -7985,12 +20435,37 @@ void c_AndroidBuilder::p_MakeTarget(){ int t_i3=t_src.FindLast(String(L"/src/",5)); if(t_i3!=-1){ String t_dst=t_src.Slice(t_i3+1); - if(p_CreateDirRecursive(bb_os_ExtractDir(t_dst))){ - CopyFile(t_src,t_dst); + if(p_CreateDirRecursive(bb_os_ExtractDir(String(L"app/",4)+t_dst))){ + CopyFile(t_src,String(L"app/",4)+t_dst); + } + } + }else{ + if(t_42==String(L"xml",3)){ + int t_i4=t_src.FindLast(String(L"/src/",5)); + if(t_i4!=-1){ + String t_dst2=t_src.Slice(t_i4+1); + if(p_CreateDirRecursive(bb_os_ExtractDir(String(L"app/",4)+t_dst2))){ + String t_str2=LoadString(t_src); + t_str2=bb_transcc_ReplaceEnv(t_str2); + SaveString(t_str2,String(L"app/",4)+t_dst2); + } } } } } + if(bb_config_GetConfigVar(String(L"ANDROID_APP_ICON",16))!=String()){ + Array t_iconfiles=Array(); + String t_11[]={String(L"app/src/main/res/mipmap-hdpi/ic_launcher.png",44),String(L"72",2),String(L"72",2),String(L"app/src/main/res/mipmap-mdpi/ic_launcher.png",44),String(L"48",2),String(L"48",2),String(L"app/src/main/res/mipmap-xhdpi/ic_launcher.png",45),String(L"96",2),String(L"96",2),String(L"app/src/main/res/mipmap-xxhdpi/ic_launcher.png",46),String(L"144",3),String(L"144",3),String(L"app/src/main/res/mipmap-xxxhdpi/ic_launcher.png",47),String(L"192",3),String(L"192",3)}; + t_iconfiles=Array(t_11,15); + p_MakeIcons(bb_config_GetConfigVar(String(L"ANDROID_APP_ICON",16)),t_iconfiles,0); + String t_12[]={String(L"app/src/main/res/mipmap-hdpi/ic_launcher_round.png",50),String(L"72",2),String(L"72",2),String(L"app/src/main/res/mipmap-mdpi/ic_launcher_round.png",50),String(L"48",2),String(L"48",2),String(L"app/src/main/res/mipmap-xhdpi/ic_launcher_round.png",51),String(L"96",2),String(L"96",2),String(L"app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png",52),String(L"144",3),String(L"144",3),String(L"app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png",53),String(L"192",3),String(L"192",3)}; + t_iconfiles=Array(t_12,15); + if(bb_config_GetConfigVar(String(L"ANDROID_APP_ROUND_ICON",22))==String()){ + p_MakeIcons(bb_config_GetConfigVar(String(L"ANDROID_APP_ICON",16)),t_iconfiles,1); + }else{ + p_MakeIcons(bb_config_GetConfigVar(String(L"ANDROID_APP_ROUND_ICON",22)),t_iconfiles,0); + } + } if(bb_config_GetConfigVar(String(L"ANDROID_NATIVE_GL_ENABLED",25))==String(L"1",1)){ bb_os_CopyDir(String(L"nativegl/libs",13),String(L"libs",4),true,false); CreateDir(String(L"src/com",7)); @@ -8017,7 +20492,7 @@ void c_AndroidBuilder::p_MakeTarget(){ t_adb=String(L"\"",1)+m_tcc->m_ANDROID_PATH+String(L"/platform-tools/adb\"",20); } String t__file=CurrentDir(); - t__file=t__file+String(L"\\app\\build\\outputs\\apk\\release\\app-release.apk",46); + t__file=t__file+String(L"/app/build/outputs/apk/release/app-release.apk",46); bbPrint(String(L"installing ",11)+t__file+String(L" ...",4)); p_Execute(t_adb+String(L" install -r ",12)+t__file,false); } @@ -8315,7 +20790,8 @@ void c_GlfwBuilder::p_MakeGcc(){ CreateDir(t_dst+String(L"/",1)+t_tconfig+String(L"/internal",9)); CreateDir(t_dst+String(L"/",1)+t_tconfig+String(L"/external",9)); p_CreateDataDir(t_dst+String(L"/",1)+t_tconfig+String(L"/data",5)); - p_CopyIcon(); + p_CopySourceFiles(String(L".",1)); + p_CopyIcon(bb_config_GetConfigVar(String(L"GLFW_APP_ICON",13)),CurrentDir()+String(L"/cerberus.ico",13)); String t_main=LoadString(String(L"main.cpp",8)); t_main=bb_transcc_ReplaceBlock(t_main,String(L"TRANSCODE",9),m_transCode,String(L"\n//",3)); t_main=bb_transcc_ReplaceBlock(t_main,String(L"CONFIG",6),p_Config(),String(L"\n//",3)); @@ -8386,7 +20862,7 @@ void c_GlfwBuilder::p_MakeMsvc(){ CreateDir(String(L"msvc/",5)+m_casedConfig+String(L"/internal",9)); CreateDir(String(L"msvc/",5)+m_casedConfig+String(L"/external",9)); p_CreateDataDir(String(L"msvc/",5)+m_casedConfig+String(L"/data",5)); - p_CopyIcon(); + p_CopyIcon(bb_config_GetConfigVar(String(L"GLFW_APP_ICON",13)),CurrentDir()+String(L"\\cerberus.ico",13)); String t_main=LoadString(String(L"main.cpp",8)); t_main=bb_transcc_ReplaceBlock(t_main,String(L"TRANSCODE",9),m_transCode,String(L"\n//",3)); t_main=bb_transcc_ReplaceBlock(t_main,String(L"CONFIG",6),p_Config(),String(L"\n//",3)); @@ -8402,6 +20878,7 @@ void c_GlfwBuilder::p_MakeMsvc(){ } void c_GlfwBuilder::p_MakeXcode(){ p_CreateDataDir(String(L"xcode/data",10)); + p_CopySourceFiles(String(L"xcode",5)); String t_main=LoadString(String(L"main.cpp",8)); t_main=bb_transcc_ReplaceBlock(t_main,String(L"TRANSCODE",9),m_transCode,String(L"\n//",3)); t_main=bb_transcc_ReplaceBlock(t_main,String(L"CONFIG",6),p_Config(),String(L"\n//",3)); @@ -8515,8 +20992,16 @@ void c_Html5Builder::p_MakeTarget(){ t_main=bb_transcc_ReplaceBlock(t_main,String(L"METADATA",8),t_meta,String(L"\n//",3)); t_main=bb_transcc_ReplaceBlock(t_main,String(L"CONFIG",6),p_Config(),String(L"\n//",3)); SaveString(t_main,String(L"main.js",7)); + p_CopyIcon(bb_config_GetConfigVar(String(L"HTML5_APP_ICON",14)),CurrentDir()+String(L"\\favicon.ico",12)); + String t_game=LoadString(String(L"CerberusGame.html",17)); + t_game=t_game.Replace(String(L"%%HTML5_CONSOLE_SHOW%%",22),bb_config_GetConfigVar(String(L"HTML5_CONSOLE_SHOW",18))); + t_game=t_game.Replace(String(L"%%HTML5_APP_TITLE%%",19),bb_config_GetConfigVar(String(L"HTML5_APP_TITLE",15))); + t_game=t_game.Replace(String(L"%%HTML5_CANVAS_WIDTH%%",22),bb_config_GetConfigVar(String(L"HTML5_CANVAS_WIDTH",18))); + t_game=t_game.Replace(String(L"%%HTML5_CANVAS_HEIGHT%%",23),bb_config_GetConfigVar(String(L"HTML5_CANVAS_HEIGHT",19))); + t_game=t_game.Replace(String(L"%%HTML5_CANVAS_RESIZE_MODE%%",28),bb_config_GetConfigVar(String(L"HTML5_CANVAS_RESIZE_MODE",24))); + SaveString(t_game,bb_config_GetConfigVar(String(L"HTML5_APP_FILENAME",18))); if(m_tcc->m_opt_run){ - String t_p=RealPath(String(L"CerberusGame.html",17)); + String t_p=RealPath(bb_config_GetConfigVar(String(L"HTML5_APP_FILENAME",18))); String t_t=m_tcc->m_HTML_PLAYER+String(L" \"",2)+t_p+String(L"\"",1); p_Execute(t_t,false); } @@ -8759,17 +21244,21 @@ void c_IosBuilder::p_MakeTarget(){ p_Execute(String(L"open \"",6)+t_sim_path+String(L"\"",1),true); } p_CreateDataDir(String(L"data",4)); + CreateDir(String(L"icons",5)); + String t_[]={String(L"icons/iphone-app-1x-60px.png",28),String(L"60",2),String(L"60",2),String(L"icons/iphone-app-2x-120px.png",29),String(L"120",3),String(L"120",3),String(L"icons/iphone-app-3x-180px.png",29),String(L"180",3),String(L"180",3),String(L"icons/iphone-spotlight-1x-40px.png",34),String(L"40",2),String(L"40",2),String(L"icons/iphone-spotlight-2x-80px.png",34),String(L"80",2),String(L"80",2),String(L"icons/iphone-spotlight-3x-120px.png",35),String(L"120",3),String(L"120",3),String(L"icons/iphone-settings-3x-87px.png",33),String(L"87",2),String(L"87",2),String(L"icons/ipad-app-1x-76px.png",26),String(L"76",2),String(L"76",2),String(L"icons/ipad-app-2x-152px.png",27),String(L"152",3),String(L"152",3),String(L"icons/ipad-app-3x-167px.png",27),String(L"167",3),String(L"167",3),String(L"icons/ipad-spotlight-1x-40px.png",32),String(L"40",2),String(L"40",2),String(L"icons/ipad-spotlight-2x-80px.png",32),String(L"80",2),String(L"80",2),String(L"icons/ipad-spotlight-3x-120px.png",33),String(L"120",3),String(L"120",3),String(L"icons/ipad-settings-3x-58px.png",31),String(L"58",2),String(L"58",2)}; + Array t_iconfiles=Array(t_,42); + p_MakeIcons(bb_config_GetConfigVar(String(L"IOS_APP_ICON",12)),t_iconfiles,0); String t_main=LoadString(String(L"main.mm",7)); t_main=bb_transcc_ReplaceBlock(t_main,String(L"TRANSCODE",9),m_transCode,String(L"\n//",3)); t_main=bb_transcc_ReplaceBlock(t_main,String(L"CONFIG",6),p_Config(),String(L"\n//",3)); SaveString(t_main,String(L"main.mm",7)); String t_libs=bb_config_GetConfigVar(String(L"LIBS",4)); if((t_libs).Length()!=0){ - Array t_=t_libs.Split(String(L";",1)); - int t_2=0; - while(t_2 t_2=t_libs.Split(String(L";",1)); + int t_3=0; + while(t_3m_opt_run){ if((m_tcc->m_FLASH_PLAYER).Length()!=0){ @@ -9051,6 +21541,7 @@ void c_StdcppBuilder::p_MakeTarget(){ } } } + p_CopySourceFiles(String(L".",1)); String t_main=LoadString(String(L"main.cpp",8)); t_main=bb_transcc_ReplaceBlock(t_main,String(L"TRANSCODE",9),m_transCode,String(L"\n//",3)); t_main=bb_transcc_ReplaceBlock(t_main,String(L"CONFIG",6),p_Config(),String(L"\n//",3)); @@ -10057,7 +22548,7 @@ int c_ModuleDecl::p_ImportModule(String t_modpath,int t_attrs){ return 0; } int c_ModuleDecl::p_SemantAll(){ - c_Enumerator2* t_=p_Decls()->p_ObjectEnumerator(); + c_Enumerator3* t_=p_Decls()->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_Decl* t_decl=t_->p_NextObject(); if((dynamic_cast(t_decl))!=0){ @@ -10066,10 +22557,10 @@ int c_ModuleDecl::p_SemantAll(){ c_ClassDecl* t_cdecl=dynamic_cast(t_decl); if((t_cdecl)!=0){ if((t_cdecl->m_args).Length()!=0){ - c_Enumerator4* t_2=t_cdecl->m_instances->p_ObjectEnumerator(); + c_Enumerator5* t_2=t_cdecl->m_instances->p_ObjectEnumerator(); while(t_2->p_HasNext()){ c_ClassDecl* t_inst=t_2->p_NextObject(); - c_Enumerator2* t_3=t_inst->p_Decls()->p_ObjectEnumerator(); + c_Enumerator3* t_3=t_inst->p_Decls()->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_Decl* t_decl2=t_3->p_NextObject(); if((dynamic_cast(t_decl2))!=0){ @@ -10080,7 +22571,7 @@ int c_ModuleDecl::p_SemantAll(){ } }else{ t_decl->p_Semant(); - c_Enumerator2* t_4=t_cdecl->p_Decls()->p_ObjectEnumerator(); + c_Enumerator3* t_4=t_cdecl->p_Decls()->p_ObjectEnumerator(); while(t_4->p_HasNext()){ c_Decl* t_decl3=t_4->p_NextObject(); if((dynamic_cast(t_decl3))!=0){ @@ -10103,9 +22594,9 @@ Object* c_ModuleDecl::p_GetDecl2(String t_ident){ return c_ScopeDecl::p_GetDecl(t_ident); } Object* c_ModuleDecl::p_GetDecl(String t_ident){ - c_List9* t_todo=(new c_List9)->m_new(); + c_List11* t_todo=(new c_List11)->m_new(); c_StringMap5* t_done=(new c_StringMap5)->m_new(); - t_todo->p_AddLast9(this); + t_todo->p_AddLast11(this); t_done->p_Insert3(m_filepath,this); Object* t_decl=0; String t_declmod=String(); @@ -10120,7 +22611,7 @@ Object* c_ModuleDecl::p_GetDecl(String t_ident){ c_FuncDeclList* t_flist=dynamic_cast(t_tdecl); if((t_flist)!=0){ bool t_pub=false; - c_Enumerator3* t_=t_flist->p_ObjectEnumerator(); + c_Enumerator4* t_=t_flist->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_FuncDecl* t_fdecl=t_->p_NextObject(); if(!((t_fdecl->p_CheckAccess())!=0)){ @@ -10155,7 +22646,7 @@ Object* c_ModuleDecl::p_GetDecl(String t_ident){ while(t_2->p_HasNext()){ c_ModuleDecl* t_mdecl2=t_2->p_NextObject(); if(!t_done->p_Contains(t_mdecl2->m_filepath)){ - t_todo->p_AddLast9(t_mdecl2); + t_todo->p_AddLast11(t_mdecl2); t_done->p_Insert3(t_mdecl2->m_filepath,t_mdecl2); } } @@ -10168,6 +22659,83 @@ int c_ModuleDecl::p_OnSemant(){ void c_ModuleDecl::mark(){ c_ScopeDecl::mark(); } +c_Stack3::c_Stack3(){ + m_data=Array(); + m_length=0; +} +c_Stack3* c_Stack3::m_new(){ + return this; +} +c_Stack3* c_Stack3::m_new2(Array t_data){ + this->m_data=t_data.Slice(0); + this->m_length=t_data.Length(); + return this; +} +void c_Stack3::p_Push7(int t_value){ + if(m_length==m_data.Length()){ + m_data=m_data.Resize(m_length*2+10); + } + m_data[m_length]=t_value; + m_length+=1; +} +void c_Stack3::p_Push8(Array t_values,int t_offset,int t_count){ + for(int t_i=0;t_i t_values,int t_offset){ + p_Push8(t_values,t_offset,t_values.Length()-t_offset); +} +bool c_Stack3::p_IsEmpty(){ + return m_length==0; +} +int c_Stack3::m_NIL; +int c_Stack3::p_Pop(){ + m_length-=1; + int t_v=m_data[m_length]; + m_data[m_length]=m_NIL; + return t_v; +} +void c_Stack3::p_Length(int t_newlength){ + if(t_newlengthm_data.Length()){ + m_data=m_data.Resize(bb_math_Max(m_length*2+10,t_newlength)); + } + } + m_length=t_newlength; +} +int c_Stack3::p_Length2(){ + return m_length; +} +int c_Stack3::p_Get2(int t_index){ + return m_data[t_index]; +} +void c_Stack3::p_Clear(){ + for(int t_i=0;t_i t_data){ + c_Stack3::m_new2(t_data); + return this; +} +c_IntStack* c_IntStack::m_new2(){ + c_Stack3::m_new(); + return this; +} +void c_IntStack::mark(){ + c_Stack3::mark(); +} c_ScopeDecl* bb_config_GetConfigScope(){ return (bb_config__cfgScope); } @@ -10338,6 +22906,10 @@ String c_Toker::p_TSTR(int t_i){ } return String(); } +int c_Toker::m__tokenFlags; +bool c_Toker::m_Remarks(){ + return ((m__tokenFlags&1)!=0); +} String c_Toker::p_NextToke(){ m__toke=String(); if(m__tokePos==m__length){ @@ -10358,90 +22930,116 @@ String c_Toker::p_NextToke(){ m__tokePos+=1; } }else{ - if(t_str==String(L"_",1) || ((bb_config_IsAlpha(t_chr))!=0)){ - m__tokeType=2; - while(m__tokePosp_Contains(m__toke.ToLower())){ - m__tokeType=3; + if(m__tokePosp_Contains(m__toke.ToLower())){ + m__tokeType=3; } - if(p_TSTR(0).ToLower()==String(L"e",1)){ - m__tokeType=5; - m__tokePos+=1; - if(p_TSTR(0)==String(L"+",1) || p_TSTR(0)==String(L"-",1)){ - m__tokePos+=1; + }else{ + if(((bb_config_IsDigit(t_chr))!=0) || t_str==String(L".",1) && ((bb_config_IsDigit(p_TCHR(0)))!=0)){ + m__tokeType=4; + if(t_str==String(L".",1)){ + m__tokeType=5; } while((bb_config_IsDigit(p_TCHR(0)))!=0){ m__tokePos+=1; } - } - }else{ - if(t_str==String(L"%",1) && ((bb_config_IsBinDigit(p_TCHR(0)))!=0)){ - m__tokeType=4; - m__tokePos+=1; - while((bb_config_IsBinDigit(p_TCHR(0)))!=0){ + if(m__tokeType==4 && p_TSTR(0)==String(L".",1) && ((bb_config_IsDigit(p_TCHR(1)))!=0)){ + m__tokeType=5; + m__tokePos+=2; + while((bb_config_IsDigit(p_TCHR(0)))!=0){ + m__tokePos+=1; + } + } + if(p_TSTR(0).ToLower()==String(L"e",1)){ + m__tokeType=5; m__tokePos+=1; + if(p_TSTR(0)==String(L"+",1) || p_TSTR(0)==String(L"-",1)){ + m__tokePos+=1; + } + while((bb_config_IsDigit(p_TCHR(0)))!=0){ + m__tokePos+=1; + } } }else{ - if(t_str==String(L"$",1) && ((bb_config_IsHexDigit(p_TCHR(0)))!=0)){ + if(t_str==String(L"%",1) && ((bb_config_IsBinDigit(p_TCHR(0)))!=0)){ m__tokeType=4; m__tokePos+=1; - while((bb_config_IsHexDigit(p_TCHR(0)))!=0){ + while((bb_config_IsBinDigit(p_TCHR(0)))!=0){ m__tokePos+=1; } }else{ - if(t_str==String(L"\"",1)){ - m__tokeType=6; - while(m__tokePosm_new(); m_mainModule=0; m_fileImports=(new c_StringList)->m_new2(); - m_allSemantedDecls=(new c_List3)->m_new(); - m_semantedGlobals=(new c_List8)->m_new(); - m_semantedClasses=(new c_List6)->m_new(); + m_fileIncludes=(new c_StringList)->m_new2(); + m_allSemantedDecls=(new c_List5)->m_new(); + m_semantedGlobals=(new c_List10)->m_new(); + m_semantedClasses=(new c_List8)->m_new(); m_mainFunc=0; } int c_AppDecl::p_InsertModule(c_ModuleDecl* t_mdecl){ @@ -10780,7 +23387,7 @@ int c_AppDecl::p_FinalizeClasses(){ bb_decl__env=0; do{ int t_more=0; - c_Enumerator4* t_=m_semantedClasses->p_ObjectEnumerator(); + c_Enumerator5* t_=m_semantedClasses->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_ClassDecl* t_cdecl=t_->p_NextObject(); t_more+=t_cdecl->p_UpdateLiveMethods(); @@ -10789,7 +23396,7 @@ int c_AppDecl::p_FinalizeClasses(){ break; } }while(!(false)); - c_Enumerator4* t_2=m_semantedClasses->p_ObjectEnumerator(); + c_Enumerator5* t_2=m_semantedClasses->p_ObjectEnumerator(); while(t_2->p_HasNext()){ c_ClassDecl* t_cdecl2=t_2->p_NextObject(); t_cdecl2->p_FinalizeClass(); @@ -11030,13 +23637,16 @@ c_Parser::c_Parser(){ m__defattrs=0; m__tokeType=0; m__block=0; - m__blockStack=(new c_List7)->m_new(); + m__blockStack=(new c_List9)->m_new(); m__errStack=(new c_StringList)->m_new2(); m__selTmpId=0; } -int c_Parser::p_SetErr(){ +int c_Parser::p_SetErr(int t_line){ + if(t_line==-1){ + t_line=m__toker->p_Line(); + } if((m__toker->p_Path()).Length()!=0){ - bb_config__errInfo=m__toker->p_Path()+String(L"<",1)+String(m__toker->p_Line())+String(L">",1); + bb_config__errInfo=m__toker->p_Path()+String(L"<",1)+String(t_line)+String(L">",1); } return 0; } @@ -11050,7 +23660,7 @@ int c_Parser::p_CParse(String t_toke){ int c_Parser::p_SkipEols(){ while((p_CParse(String(L"\n",1)))!=0){ } - p_SetErr(); + p_SetErr(-1); return 0; } String c_Parser::p_NextToke(){ @@ -11080,7 +23690,7 @@ c_Parser* c_Parser::m_new(c_Toker* t_toker,c_AppDecl* t_app,c_ModuleDecl* t_mdec m__app=t_app; m__module=t_mdecl; m__defattrs=t_defattrs; - p_SetErr(); + p_SetErr(-1); p_NextToke(); return this; } @@ -11123,7 +23733,7 @@ String c_Parser::p_ParseIdent(){ if(t_3==String(L"object",6) || t_3==String(L"throwable",9)){ }else{ if(m__tokeType!=2){ - bb_config_Err(String(L"Syntax error - expecting identifier.",36)); + bb_config_Err(String(L"Syntax error - Expecting identifier.",36)); } } } @@ -11143,7 +23753,7 @@ int c_Parser::p_ImportModule(String t_modpath,int t_attrs){ } int c_Parser::p_Parse(String t_toke){ if(!((p_CParse(t_toke))!=0)){ - bb_config_Err(String(L"Syntax error - expecting '",26)+t_toke+String(L"'.",2)); + bb_config_Err(String(L"Syntax error - Expecting '",26)+t_toke+String(L"'.",2)); } return 0; } @@ -11176,14 +23786,14 @@ c_IdentType* c_Parser::p_ParseIdentType(){ if((p_CParse(String(L".",1)))!=0){ t_id=t_id+(String(L".",1)+p_ParseIdent()); } - c_Stack3* t_args=(new c_Stack3)->m_new(); + c_Stack4* t_args=(new c_Stack4)->m_new(); if((p_CParse(String(L"<",1)))!=0){ do{ c_Type* t_arg=p_ParseType(); while((p_CParse(String(L"[]",2)))!=0){ t_arg=(t_arg->p_ArrayOf()); } - t_args->p_Push7(t_arg); + t_args->p_Push10(t_arg); }while(!(!((p_CParse(String(L",",1)))!=0))); p_Parse(String(L">",1)); } @@ -11235,9 +23845,9 @@ c_Type* c_Parser::p_ParseDeclType(){ } c_ArrayExpr* c_Parser::p_ParseArrayExpr(){ p_Parse(String(L"[",1)); - c_Stack4* t_args=(new c_Stack4)->m_new(); + c_Stack5* t_args=(new c_Stack5)->m_new(); do{ - t_args->p_Push10(p_ParseExpr()); + t_args->p_Push13(p_ParseExpr()); }while(!(!((p_CParse(String(L",",1)))!=0))); p_Parse(String(L"]",1)); return (new c_ArrayExpr)->m_new(t_args->p_ToArray()); @@ -11338,7 +23948,7 @@ c_IdentType* c_Parser::p_CParseIdentType(bool t_inner){ } return 0; } - c_Stack3* t_args=(new c_Stack3)->m_new(); + c_Stack4* t_args=(new c_Stack4)->m_new(); do{ c_Type* t_arg=p_CParsePrimitiveType(); if(!((t_arg)!=0)){ @@ -11350,13 +23960,21 @@ c_IdentType* c_Parser::p_CParseIdentType(bool t_inner){ while((p_CParse(String(L"[]",2)))!=0){ t_arg=(t_arg->p_ArrayOf()); } - t_args->p_Push7(t_arg); + t_args->p_Push10(t_arg); }while(!(!((p_CParse(String(L",",1)))!=0))); if(!((p_CParse(String(L">",1)))!=0)){ return 0; } return (new c_IdentType)->m_new(t_id,t_args->p_ToArray()); } +c_TraceRecord* c_Parser::p_BackTrace(int t_tokeID){ + int t_blk=c_BlockTrace::m_TraceLog(t_tokeID); + c_TraceRecord* t_record=c_BlockTrace::m_Pop(); + if(t_record!=0){ + p_SetErr(t_record->p_Line()); + } + return t_record; +} c_Expr* c_Parser::p_ParsePrimaryExpr(int t_stmt){ c_Expr* t_expr=0; String t_7=m__toke; @@ -11458,7 +24076,18 @@ c_Expr* c_Parser::p_ParsePrimaryExpr(int t_stmt){ t_expr=((new c_ConstExpr)->m_new((c_Type::m_stringType),bb_config_Dequote(m__toke,String(L"cerberus",8)))); p_NextToke(); }else{ - bb_config_Err(String(L"Syntax error - unexpected token '",33)+m__toke+String(L"'",1)); + if(t_8==0){ + c_TraceRecord* t_record=p_BackTrace(0); + bb_config_Err(String(L"End-Of-File. ",13)+c_BlockTrace::m_Code2Str(t_record->p_Toke())+String(L" block incorrectly terminated.",30)); + }else{ + c_TraceRecord* t_record2=p_BackTrace(0); + if(t_record2!=0){ + p_SetErr(m__toker->p_Line()); + }else{ + p_SetErr(-1); + } + bb_config_Err(String(L"Syntax error - Unexpected token '",33)+m__toke+String(L"'.",2)); + } } } } @@ -11633,7 +24262,7 @@ c_Expr* c_Parser::p_ParseExpr(){ return p_ParseOrExpr(); } c_Decl* c_Parser::p_ParseDecl(String t_toke,int t_attrs){ - p_SetErr(); + p_SetErr(-1); String t_id=p_ParseIdent(); c_Type* t_ty=0; c_Expr* t_init=0; @@ -11690,26 +24319,26 @@ c_Decl* c_Parser::p_ParseDecl(String t_toke,int t_attrs){ } return (t_decl); } -c_List3* c_Parser::p_ParseDecls(String t_toke,int t_attrs){ +c_List5* c_Parser::p_ParseDecls(String t_toke,int t_attrs){ if((t_toke).Length()!=0){ p_Parse(t_toke); } - c_List3* t_decls=(new c_List3)->m_new(); + c_List5* t_decls=(new c_List5)->m_new(); do{ c_Decl* t_decl=p_ParseDecl(t_toke,t_attrs); - t_decls->p_AddLast3(t_decl); + t_decls->p_AddLast5(t_decl); if(!((p_CParse(String(L",",1)))!=0)){ return t_decls; } }while(!(false)); } -c_List3* c_Parser::p_ParseEnumStmt(int t_attrs,bool t_createDeclList){ +c_List5* c_Parser::p_ParseEnumStmt(int t_attrs,bool t_createDeclList){ if((t_attrs&256)!=0){ bb_config_Err(String(L"Enumerations cannot be extern.",30)); } - c_List3* t_declList=0; + c_List5* t_declList=0; if(t_createDeclList){ - t_declList=(new c_List3)->m_new(); + t_declList=(new c_List5)->m_new(); } String t_toke=m__toke; p_NextToke(); @@ -11737,18 +24366,18 @@ c_List3* c_Parser::p_ParseEnumStmt(int t_attrs,bool t_createDeclList){ } t_i+=1; if(t_createDeclList){ - t_declList->p_AddLast3(t_decl); + t_declList->p_AddLast5(t_decl); }else{ m__block->p_AddStmt((new c_DeclStmt)->m_new(t_decl)); } }while(!(!((p_CParse(String(L",",1)))!=0))); return t_declList; } -c_List3* c_Parser::p_ParseEnum(String t_toke,int t_attrs){ +c_List5* c_Parser::p_ParseEnum(String t_toke,int t_attrs){ return p_ParseEnumStmt(t_attrs,true); } int c_Parser::p_PushBlock(c_BlockDecl* t_block){ - m__blockStack->p_AddLast7(m__block); + m__blockStack->p_AddLast9(m__block); m__errStack->p_AddLast(bb_config__errInfo); m__block=t_block; return 0; @@ -11781,12 +24410,40 @@ int c_Parser::p_ParseContinueStmt(){ m__block->p_AddStmt((new c_ContinueStmt)->m_new()); return 0; } +int c_Parser::p_AtEOF(int t_tokeID,String t_msg){ + p_SetErr(c_BlockTrace::m_TraceLog(t_tokeID)); + bb_config_Err(String(L"End-Of-File Reached. ",21)+t_msg+String(L" block not terminated correctly.",32)); + return 0; +} +int c_Parser::p_AtEOF2(String t_tokeID,String t_msg){ + p_SetErr(c_BlockTrace::m_TraceLog2(t_tokeID)); + bb_config_Err(String(L"End-Of-File Reached. ",21)+t_msg+String(L" block not terminated correctly.",32)); + return 0; +} int c_Parser::p_PopBlock(){ m__block=m__blockStack->p_RemoveLast(); bb_config__errInfo=m__errStack->p_RemoveLast(); return 0; } +int c_Parser::p_AtEos2(){ + return ((m__toke==String() || m__toke==String(L";",1) || m__toke==String(L"\n",1))?1:0); +} +int c_Parser::p_ParseBlockEnd(String t_toke,String t_msg,int t_log){ + p_SetErr(-1); + if(!((p_CParse(t_toke))!=0) && p_AtEos2()==0 && m__tokeType!=9){ + if(t_msg!=String()){ + if((t_log)!=0){ + c_BlockTrace::m_TraceLog2(t_toke); + } + bb_config_Err(t_msg); + } + return 1; + } + return 0; +} int c_Parser::p_ParseIfStmt(String t_term){ + int t_lineStart=m__toker->p_Line(); + int t_tokeID=4; p_CParse(String(L"if",2)); c_Expr* t_expr=p_ParseExpr(); p_CParse(String(L"then",4)); @@ -11801,14 +24458,19 @@ int c_Parser::p_ParseIfStmt(String t_term){ } t_eatTerm=1; } + c_BlockTrace::m_Push(t_tokeID,t_lineStart); p_PushBlock(t_thenBlock); while(m__toke!=t_term){ + if(m__tokeType==0){ + p_AtEOF(t_tokeID,String(L"Conditional",11)); + } String t_16=m__toke; if(t_16==String(L"endif",5)){ if(t_term==String(L"end",3)){ break; } - bb_config_Err(String(L"Syntax error - expecting 'End'.",31)); + p_SetErr(c_BlockTrace::m_TraceLog(t_tokeID)); + bb_config_Err(String(L"Syntax error - Expecting conditional blocks to terminate with 'End', 'End If' or 'Endif'.",89)); }else{ if(t_16==String(L"else",4) || t_16==String(L"elseif",6)){ int t_elif=((m__toke==String(L"elseif",6))?1:0); @@ -11827,10 +24489,11 @@ int c_Parser::p_ParseIfStmt(String t_term){ } } p_PopBlock(); + c_TraceRecord* t_blkTrace=c_BlockTrace::m_Pop(); if((t_eatTerm)!=0){ p_NextToke(); if(t_term==String(L"end",3)){ - p_CParse(String(L"if",2)); + p_ParseBlockEnd(String(L"if",2),String(L"Syntax error - Expecting conditional blocks to terminate with 'End', 'Endif' Or 'End If'.",89),1); } } c_IfStmt* t_stmt=(new c_IfStmt)->m_new(t_expr,t_thenBlock,t_elseBlock); @@ -11838,18 +24501,37 @@ int c_Parser::p_ParseIfStmt(String t_term){ return 0; } int c_Parser::p_ParseWhileStmt(){ + int t_lineStart=m__toker->p_Line(); + int t_tokeID=6; + p_SetErr(-1); + String t_errLine=bb_config__errInfo; p_Parse(String(L"while",5)); c_Expr* t_expr=p_ParseExpr(); c_BlockDecl* t_block=(new c_BlockDecl)->m_new(m__block); + c_BlockTrace::m_Push(t_tokeID,t_lineStart); p_PushBlock(t_block); - while(!((p_CParse(String(L"wend",4)))!=0)){ - if((p_CParse(String(L"end",3)))!=0){ - p_CParse(String(L"while",5)); + while(true){ + if(m__tokeType==0){ + p_AtEOF(t_tokeID,String(L"While/Wend/End While iterator",29)); + } + if(!((p_CParse(String(L"wend",4)))!=0)){ + if((p_CParse(String(L"end",3)))!=0){ + if(!((p_ParseBlockEnd(String(L"while",5),String(L"Syntax error - Expecting 'while' block to terminate with 'End' or 'End While'.",78),0))!=0)){ + break; + } + break; + } + }else{ + if(!((p_AtEos2())!=0)){ + p_SetErr(-1); + bb_config_Err(String(L"Syntax error - Wend does not except a variable or expression.",61)); + } break; } p_ParseStmt(); } p_PopBlock(); + c_TraceRecord* t_blkTrace=c_BlockTrace::m_Pop(); c_WhileStmt* t_stmt=(new c_WhileStmt)->m_new(t_expr,t_block); m__block->p_AddStmt(t_stmt); return 0; @@ -11863,13 +24545,20 @@ int c_Parser::p_PopErr(){ return 0; } int c_Parser::p_ParseRepeatStmt(){ + int t_lineStart=m__toker->p_Line(); + int t_tokeID=5; p_Parse(String(L"repeat",6)); c_BlockDecl* t_block=(new c_BlockDecl)->m_new(m__block); + c_BlockTrace::m_Push(t_tokeID,t_lineStart); p_PushBlock(t_block); - while(m__toke!=String(L"until",5) && m__toke!=String(L"forever",7)){ + while(m__toke!=String(L"until",5) && m__toke!=String(L"forever",7) && m__tokeType!=0){ p_ParseStmt(); } p_PopBlock(); + if(m__tokeType==0){ + p_AtEOF(t_tokeID,String(L"Repeat/Until/Forever",20)); + } + c_TraceRecord* t_blkTrace=c_BlockTrace::m_Pop(); c_Expr* t_expr=0; if((p_CParse(String(L"until",5)))!=0){ p_PushErr(); @@ -11884,6 +24573,8 @@ int c_Parser::p_ParseRepeatStmt(){ return 0; } int c_Parser::p_ParseForStmt(){ + int t_lineStart=m__toker->p_Line(); + int t_tokeID=1; p_Parse(String(L"for",3)); String t_varid=String(); c_Type* t_varty=0; @@ -11903,18 +24594,48 @@ int c_Parser::p_ParseForStmt(){ if((p_CParse(String(L"eachin",6)))!=0){ c_Expr* t_expr=p_ParseExpr(); c_BlockDecl* t_block=(new c_BlockDecl)->m_new(m__block); + c_BlockTrace::m_Push(t_tokeID,t_lineStart); p_PushBlock(t_block); - while(!((p_CParse(String(L"next",4)))!=0)){ - if((p_CParse(String(L"end",3)))!=0){ - p_CParse(String(L"for",3)); + while(true){ + if(m__tokeType==0){ + p_AtEOF(t_tokeID,String(L"For/Next/End For",16)); + } + if((p_CParse(String(L"next",4)))!=0){ + if(m__tokeType==2 && p_ParseIdent()!=t_varid){ + bb_config_Err(String(L"Syntax error - Next variable name does not match For variable name",66)); + } + if(!((p_AtEos2())!=0)){ + c_BlockTrace::m_TraceLog(t_tokeID); + bb_config_Err(String(L"Syntax error - Expecting 'For' iterator to terminate with 'Next', 'End' or 'End For'.",85)); + } break; + }else{ + if((p_CParse(String(L"end",3)))!=0){ + if(m__toke!=String(L"for",3)){ + if(m__tokeType==2 && p_ParseIdent()!=t_varid){ + bb_config_Err(String(L"Syntax error - Next variable name does not match For variable name",66)); + } + if(!((p_AtEos2())!=0)){ + c_BlockTrace::m_TraceLog(t_tokeID); + bb_config_Err(String(L"Syntax error - Expecting 'For' iterator to terminate with 'Next', 'End' or 'End For'.",85)); + } + }else{ + p_NextToke(); + if(m__tokeType==2 && p_ParseIdent()!=t_varid){ + bb_config_Err(String(L"Syntax error - Next variable name does not match For variable name",66)); + } + if(!((p_AtEos2())!=0)){ + c_BlockTrace::m_TraceLog(t_tokeID); + bb_config_Err(String(L"Syntax error - Expecting 'For' iterator to terminate with 'Next', 'End' or 'End For'.",85)); + } + } + break; + } } p_ParseStmt(); } - if(m__tokeType==2 && p_ParseIdent()!=t_varid){ - bb_config_Err(String(L"Next variable name does not match For variable name",51)); - } p_PopBlock(); + c_TraceRecord* t_blkTrace=c_BlockTrace::m_Pop(); c_ForEachinStmt* t_stmt=(new c_ForEachinStmt)->m_new(t_varid,t_varty,t_varlocal,t_expr,t_block); m__block->p_AddStmt(t_stmt); return 0; @@ -11949,32 +24670,68 @@ int c_Parser::p_ParseForStmt(){ t_expr2=((new c_BinaryCompareExpr)->m_new(t_op,((new c_IdentExpr)->m_new(t_varid,0)),t_term)); t_incr=((new c_AssignStmt)->m_new(String(L"=",1),((new c_IdentExpr)->m_new(t_varid,0)),((new c_BinaryMathExpr)->m_new(String(L"+",1),((new c_IdentExpr)->m_new(t_varid,0)),t_stp)))); c_BlockDecl* t_block2=(new c_BlockDecl)->m_new(m__block); + c_BlockTrace::m_Push(t_tokeID,t_lineStart); p_PushBlock(t_block2); - while(!((p_CParse(String(L"next",4)))!=0)){ - if((p_CParse(String(L"end",3)))!=0){ - p_CParse(String(L"for",3)); + while(true){ + if(m__tokeType==0){ + p_AtEOF(t_tokeID,String(L"For/Next/End For",16)); + } + if((p_CParse(String(L"next",4)))!=0){ + if(m__tokeType==2 && p_ParseIdent()!=t_varid){ + bb_config_Err(String(L"Syntax error - Next variable name does not match For variable name",66)); + } + if(!((p_AtEos2())!=0)){ + c_BlockTrace::m_TraceLog(t_tokeID); + bb_config_Err(String(L"Syntax error - Expecting 'For' iterator to terminate with 'Next', 'End' or 'End For'.",85)); + } break; + }else{ + if((p_CParse(String(L"end",3)))!=0){ + if(m__toke!=String(L"for",3)){ + if(m__tokeType==2 && p_ParseIdent()!=t_varid){ + bb_config_Err(String(L"Syntax error - Next variable name does not match For variable name",66)); + } + if(!((p_AtEos2())!=0)){ + c_BlockTrace::m_TraceLog(t_tokeID); + bb_config_Err(String(L"Syntax error - Expecting 'For' iterator to terminate with 'Next', 'End' or 'End For'.",85)); + } + }else{ + p_NextToke(); + if(m__tokeType==2 && p_ParseIdent()!=t_varid){ + bb_config_Err(String(L"Syntax error - Next variable name does not match For variable name",66)); + } + if(!((p_AtEos2())!=0)){ + c_BlockTrace::m_TraceLog(t_tokeID); + bb_config_Err(String(L"Syntax error - Expecting 'For' iterator to terminate with 'Next', 'End' or 'End For'.",85)); + } + } + break; + } } p_ParseStmt(); } - if(m__tokeType==2 && p_ParseIdent()!=t_varid){ - bb_config_Err(String(L"Next variable name does not match For variable name",51)); - } p_PopBlock(); + c_TraceRecord* t_blkTrace2=c_BlockTrace::m_Pop(); c_ForStmt* t_stmt2=(new c_ForStmt)->m_new(t_init,t_expr2,t_incr,t_block2); m__block->p_AddStmt(t_stmt2); return 0; } int c_Parser::p_ParseSelectStmt(){ p_Parse(String(L"select",6)); + int t_lineStart=m__toker->p_Line(); + int t_tokeID=9; c_Expr* t_expr=p_ParseExpr(); c_BlockDecl* t_block=m__block; + c_BlockTrace::m_Push(t_tokeID,t_lineStart); m__selTmpId+=1; String t_tmpId=String(m__selTmpId); t_block->p_AddStmt((new c_DeclStmt)->m_new2(t_tmpId,0,t_expr)); c_IdentExpr* t_tmpExpr=(new c_IdentExpr)->m_new(t_tmpId,0); while(m__toke!=String(L"end",3) && m__toke!=String(L"default",7)){ - p_SetErr(); + p_SetErr(-1); + if(m__tokeType==0){ + break; + } String t_17=m__toke; if(t_17==String(L"\n",1)){ p_NextToke(); @@ -12003,7 +24760,7 @@ int c_Parser::p_ParseSelectStmt(){ p_PopBlock(); t_block=t_elseBlock; }else{ - bb_config_Err(String(L"Syntax error - expecting 'Case', 'Default' or 'End'.",52)); + bb_config_Err(String(L"Syntax error - Expecting 'Case', 'Default' or 'End'.",52)); } } } @@ -12011,7 +24768,10 @@ int c_Parser::p_ParseSelectStmt(){ p_NextToke(); p_PushBlock(t_block); while(m__toke!=String(L"end",3)){ - p_SetErr(); + if(m__tokeType==0){ + break; + } + p_SetErr(-1); String t_18=m__toke; if(t_18==String(L"case",4)){ bb_config_Err(String(L"Case can not appear after default.",34)); @@ -12024,24 +24784,34 @@ int c_Parser::p_ParseSelectStmt(){ } p_PopBlock(); } - p_SetErr(); + if(m__tokeType==0){ + p_AtEOF(t_tokeID,String(L"Selec/Case",10)); + } + p_SetErr(-1); p_Parse(String(L"end",3)); - p_CParse(String(L"select",6)); + p_ParseBlockEnd(String(L"select",6),String(L"Syntax error -Expecting 'Select' block to terminate with 'End' or 'End Select'.",79),0); + c_BlockTrace::m_Pop(); return 0; } int c_Parser::p_ParseTryStmt(){ + int t_lineStart=m__toker->p_Line(); + int t_tokeID=6; p_Parse(String(L"try",3)); c_BlockDecl* t_block=(new c_BlockDecl)->m_new(m__block); - c_Stack7* t_catches=(new c_Stack7)->m_new(); + c_Stack8* t_catches=(new c_Stack8)->m_new(); + c_BlockTrace::m_Push(t_tokeID,t_lineStart); p_PushBlock(t_block); while(m__toke!=String(L"end",3)){ + if(m__tokeType==0){ + p_AtEOF(t_tokeID,String(L"Try/End Try",11)); + } if((p_CParse(String(L"catch",5)))!=0){ String t_id=p_ParseIdent(); p_Parse(String(L":",1)); c_Type* t_ty=p_ParseType(); c_LocalDecl* t_init=(new c_LocalDecl)->m_new(t_id,0,t_ty,0); c_BlockDecl* t_block2=(new c_BlockDecl)->m_new(m__block); - t_catches->p_Push19((new c_CatchStmt)->m_new(t_init,t_block2)); + t_catches->p_Push22((new c_CatchStmt)->m_new(t_init,t_block2)); p_PopBlock(); p_PushBlock(t_block2); }else{ @@ -12052,8 +24822,9 @@ int c_Parser::p_ParseTryStmt(){ bb_config_Err(String(L"Try block must have at least one catch block",44)); } p_PopBlock(); + c_TraceRecord* t_record=c_BlockTrace::m_Pop(); p_NextToke(); - p_CParse(String(L"try",3)); + p_ParseBlockEnd(String(L"try",3),String(L"Expecting 'Try' block must terminate with 'End' or 'End Try'.",61),0); m__block->p_AddStmt((new c_TryStmt)->m_new(t_block,t_catches->p_ToArray())); return 0; } @@ -12063,7 +24834,7 @@ int c_Parser::p_ParseThrowStmt(){ return 0; } int c_Parser::p_ParseStmt(){ - p_SetErr(); + p_SetErr(-1); String t_19=m__toke; if(t_19==String(L";",1) || t_19==String(L"\n",1)){ p_NextToke(); @@ -12145,9 +24916,12 @@ int c_Parser::p_ParseStmt(){ return 0; } c_FuncDecl* c_Parser::p_ParseFuncDecl(int t_attrs){ - p_SetErr(); + int t_lineStart=m__toker->p_Line(); + int t_tokeID=2; + p_SetErr(-1); if((p_CParse(String(L"method",6)))!=0){ t_attrs|=1; + t_tokeID=3; }else{ if(!((p_CParse(String(L"function",8)))!=0)){ bb_config_InternalErr(String(L"Internal error",14)); @@ -12173,7 +24947,7 @@ c_FuncDecl* c_Parser::p_ParseFuncDecl(int t_attrs){ t_id=p_ParseIdent(); t_ty=p_ParseDeclType(); } - c_Stack6* t_args=(new c_Stack6)->m_new(); + c_Stack7* t_args=(new c_Stack7)->m_new(); p_Parse(String(L"(",1)); p_SkipEols(); if(m__toke!=String(L")",1)){ @@ -12184,7 +24958,7 @@ c_FuncDecl* c_Parser::p_ParseFuncDecl(int t_attrs){ if((p_CParse(String(L"=",1)))!=0){ t_init=p_ParseExpr(); } - t_args->p_Push16((new c_ArgDecl)->m_new(t_id2,0,t_ty2,t_init)); + t_args->p_Push19((new c_ArgDecl)->m_new(t_id2,0,t_ty2,t_init)); if(m__toke==String(L")",1)){ break; } @@ -12244,36 +25018,49 @@ c_FuncDecl* c_Parser::p_ParseFuncDecl(int t_attrs){ if(((t_funcDecl->p_IsExtern())!=0) || ((t_funcDecl->p_IsAbstract())!=0)){ return t_funcDecl; } + c_BlockTrace::m_Push(t_tokeID,t_lineStart); p_PushBlock(t_funcDecl); while(m__toke!=String(L"end",3)){ p_ParseStmt(); } p_PopBlock(); - p_NextToke(); - if((t_attrs&3)!=0){ - p_CParse(String(L"method",6)); + c_TraceRecord* t_blkTrace=c_BlockTrace::m_Pop(); + if(m__toke==String(L"end",3)){ + p_NextToke(); + String t_blkend=String(L"function",8); + String t_msg=String(L"Syntax error - Expecting Function block to terminate with 'End' or 'End Function'.",82); + if((t_attrs&3)!=0){ + t_blkend=String(L"method",6); + t_msg=String(L"Syntax error - Expecting Method block to terminate with 'End' Or 'End Method'.",78); + } + p_SetErr(-1); + p_ParseBlockEnd(t_blkend,t_msg,0); }else{ - p_CParse(String(L"function",8)); + p_NextToke(); } return t_funcDecl; } c_ClassDecl* c_Parser::p_ParseClassDecl(int t_attrs){ - p_SetErr(); + p_SetErr(-1); String t_toke=m__toke; + int t_lineStart=m__toker->p_Line(); + int t_tokeID=7; if((p_CParse(String(L"interface",9)))!=0){ if((t_attrs&256)!=0){ bb_config_Err(String(L"Interfaces cannot be extern.",28)); } t_attrs|=5120; + t_tokeID=8; }else{ if(!((p_CParse(String(L"class",5)))!=0)){ bb_config_InternalErr(String(L"Internal error",14)); } } + c_BlockTrace::m_Push(t_tokeID,t_lineStart); String t_id=p_ParseIdent(); c_StringStack* t_args=(new c_StringStack)->m_new2(); c_IdentType* t_superTy=c_Type::m_objectType; - c_Stack5* t_imps=(new c_Stack5)->m_new(); + c_Stack6* t_imps=(new c_Stack6)->m_new(); if((p_CParse(String(L"<",1)))!=0){ if((t_attrs&256)!=0){ bb_config_Err(String(L"Extern classes cannot be generic.",33)); @@ -12295,7 +25082,7 @@ c_ClassDecl* c_Parser::p_ParseClassDecl(int t_attrs){ }else{ if((t_attrs&4096)!=0){ do{ - t_imps->p_Push13(p_ParseIdentType()); + t_imps->p_Push16(p_ParseIdentType()); }while(!(!((p_CParse(String(L",",1)))!=0))); t_superTy=c_Type::m_objectType; }else{ @@ -12311,7 +25098,7 @@ c_ClassDecl* c_Parser::p_ParseClassDecl(int t_attrs){ bb_config_Err(String(L"Implements cannot be used with interfaces.",42)); } do{ - t_imps->p_Push13(p_ParseIdentType()); + t_imps->p_Push16(p_ParseIdentType()); }while(!(!((p_CParse(String(L",",1)))!=0))); } do{ @@ -12350,51 +25137,358 @@ c_ClassDecl* c_Parser::p_ParseClassDecl(int t_attrs){ t_classDecl->m_munged=p_ParseStringLit(); } } - int t_decl_attrs=t_attrs&256; - int t_func_attrs=0; - if((t_attrs&4096)!=0){ - t_func_attrs|=1024; + int t_decl_attrs=t_attrs&256; + int t_func_attrs=0; + if((t_attrs&4096)!=0){ + t_func_attrs|=1024; + } + do{ + p_SkipEols(); + String t_22=m__toke; + if(t_22==String(L"end",3)){ + p_NextToke(); + break; + }else{ + if(t_22==String(L"public",6)){ + p_NextToke(); + t_decl_attrs&=-16897; + }else{ + if(t_22==String(L"private",7)){ + p_NextToke(); + t_decl_attrs&=-16897; + t_decl_attrs|=512; + }else{ + if(t_22==String(L"protected",9)){ + p_NextToke(); + t_decl_attrs&=-16897; + t_decl_attrs|=16384; + }else{ + if(t_22==String(L"const",5) || t_22==String(L"global",6) || t_22==String(L"field",5)){ + if(((t_attrs&4096)!=0) && m__toke!=String(L"const",5)){ + bb_config_Err(String(L"Interfaces can only contain constants and methods.",50)); + } + t_classDecl->p_InsertDecls(p_ParseDecls(m__toke,t_decl_attrs)); + }else{ + if(t_22==String(L"enumerate",9)){ + t_classDecl->p_InsertDecls(p_ParseEnum(m__toke,t_decl_attrs)); + }else{ + if(t_22==String(L"method",6)){ + t_classDecl->p_InsertDecl(p_ParseFuncDecl(t_decl_attrs|t_func_attrs)); + }else{ + if(t_22==String(L"function",8)){ + if((t_attrs&4096)!=0){ + bb_config_Err(String(L"Interfaces can only contain constants and methods.",50)); + } + t_classDecl->p_InsertDecl(p_ParseFuncDecl(t_decl_attrs|t_func_attrs)); + }else{ + if(m__tokeType==0){ + p_AtEOF(0,String(L"Code",4)); + } + bb_config_Err(String(L"Syntax error - Expecting class member declaration.",50)); + } + } + } + } + } + } + } + } + }while(!(false)); + if((t_toke).Length()!=0){ + String t_msg=String(); + if(t_toke==String(L"class",5)){ + t_msg=String(L"Syntax error - Expecting 'Class' to terminate with 'End' or 'End Class'.",72); + }else{ + if(t_toke==String(L"interface",9)){ + t_msg=String(L"Syntax error - Expecting 'Interface' to terminate with 'End' or 'End Interface'.",80); + } + } + if(t_msg!=String()){ + p_SetErr(-1); + p_ParseBlockEnd(t_toke,t_msg,1); + } + } + c_TraceRecord* t_recor=c_BlockTrace::m_Pop(); + return t_classDecl; +} +int c_Parser::p_ParseMain(){ + p_SkipEols(); + if((p_CParse(String(L"strict",6)))!=0){ + m__module->m_attrs|=1; + } + int t_attrs=0; + c_BlockTrace::m_Clear(); + while((m__toke).Length()!=0){ + p_SetErr(-1); + String t_23=m__toke; + if(t_23==String(L"\n",1)){ + p_NextToke(); + }else{ + if(t_23==String(L"public",6)){ + p_NextToke(); + t_attrs=0; + }else{ + if(t_23==String(L"private",7)){ + p_NextToke(); + t_attrs=512; + }else{ + if(t_23==String(L"protected",9)){ + bb_config_Err(String(L"Protected may only be used within classes.",42)); + }else{ + if(t_23==String(L"import",6)){ + p_NextToke(); + if(m__tokeType==6){ + p_ImportFile(bb_config_EvalConfigTags(p_ParseStringLit())); + }else{ + p_ImportModule(p_ParseModPath(),t_attrs); + } + }else{ + if(t_23==String(L"include",7)){ + p_NextToke(); + String t_filepath=p_ParseStringLit(); + int t_iOpt=t_filepath.Find(String(L" ",1),0); + if(t_iOpt>1){ + t_filepath=p_RealPath(t_filepath.Slice(0,t_iOpt))+t_filepath.Slice(t_iOpt); + }else{ + t_filepath=p_RealPath(t_filepath); + } + m__app->m_fileIncludes->p_AddLast(t_filepath); + }else{ + if(t_23==String(L"friend",6)){ + p_NextToke(); + String t_modpath=p_ParseModPath(); + m__module->m_friends->p_Insert(t_modpath); + }else{ + if(t_23==String(L"alias",5)){ + p_NextToke(); + do{ + String t_ident=p_ParseIdent(); + p_Parse(String(L"=",1)); + Object* t_decl=0; + String t_24=m__toke; + if(t_24==String(L"int",3)){ + t_decl=(c_Type::m_intType); + }else{ + if(t_24==String(L"float",5)){ + t_decl=(c_Type::m_floatType); + }else{ + if(t_24==String(L"string",6)){ + t_decl=(c_Type::m_stringType); + } + } + } + if((t_decl)!=0){ + m__module->p_InsertDecl((new c_AliasDecl)->m_new(t_ident,t_attrs,t_decl)); + p_NextToke(); + continue; + } + c_ScopeDecl* t_scope=(m__module); + bb_decl_PushEnv(m__module); + do{ + String t_id=p_ParseIdent(); + t_decl=t_scope->p_FindDecl(t_id); + if(!((t_decl)!=0)){ + bb_config_Err(String(L"Identifier '",12)+t_id+String(L"' not found.",12)); + } + if(!((p_CParse(String(L".",1)))!=0)){ + break; + } + t_scope=dynamic_cast(t_decl); + if(!((t_scope)!=0) || ((dynamic_cast(t_scope))!=0)){ + bb_config_Err(String(L"Invalid scope '",15)+t_id+String(L"'.",2)); + } + }while(!(false)); + bb_decl_PopEnv(); + m__module->p_InsertDecl((new c_AliasDecl)->m_new(t_ident,t_attrs,t_decl)); + }while(!(!((p_CParse(String(L",",1)))!=0))); + }else{ + break; + } + } + } + } + } + } + } + } + } + while((m__toke).Length()!=0){ + p_SetErr(-1); + String t_25=m__toke; + if(t_25==String(L"\n",1)){ + p_NextToke(); + }else{ + if(t_25==String(L"public",6)){ + p_NextToke(); + t_attrs=0; + }else{ + if(t_25==String(L"private",7)){ + p_NextToke(); + t_attrs=512; + }else{ + if(t_25==String(L"extern",6)){ + if((bb_config_ENV_SAFEMODE)!=0){ + if(m__app->m_mainModule==m__module){ + bb_config_Err(String(L"Extern not permitted in safe mode.",34)); + } + } + p_NextToke(); + t_attrs=256; + if((p_CParse(String(L"private",7)))!=0){ + t_attrs|=512; + } + }else{ + if(t_25==String(L"const",5) || t_25==String(L"global",6)){ + m__module->p_InsertDecls(p_ParseDecls(m__toke,t_attrs)); + }else{ + if(t_25==String(L"enumerate",9)){ + m__module->p_InsertDecls(p_ParseEnum(m__toke,t_attrs)); + }else{ + if(t_25==String(L"class",5)){ + m__module->p_InsertDecl(p_ParseClassDecl(t_attrs)); + }else{ + if(t_25==String(L"interface",9)){ + m__module->p_InsertDecl(p_ParseClassDecl(t_attrs)); + }else{ + if(t_25==String(L"function",8)){ + m__module->p_InsertDecl(p_ParseFuncDecl(t_attrs)); + }else{ + bb_config_Err(String(L"Syntax error - Expecting declaration.",37)); + } + } + } + } + } + } + } + } + } + } + bb_config__errInfo=String(); + return 0; +} +void c_Parser::mark(){ + Object::mark(); +} +c_BlockTrace::c_BlockTrace(){ + m__map=(new c_IntMap)->m_new(); + m__record=(new c_List4)->m_new(); +} +c_BlockTrace* c_BlockTrace::m_new(){ + return this; +} +c_BlockTrace* c_BlockTrace::m__Blocks; +int c_BlockTrace::m_Clear(){ + m__Blocks->m__map->p_Clear(); + m__Blocks->m__record->p_Clear(); + return 0; +} +c_TraceRecord* c_BlockTrace::p_LastBlockItem(){ + if(m__record->p_IsEmpty()){ + return 0; + } + return m__record->p_Last(); +} +c_IntList* c_BlockTrace::p_BlockLineList(int t_token){ + c_IntList* t_blklines=(new c_IntList)->m_new2(); + int t_lastblkline=0; + if(p_LastBlockItem()!=0){ + t_lastblkline=p_LastBlockItem()->p_Line(); + } + if(t_token>0){ + c_IntList* t_tokelines=m__map->p_Get2(t_token); + if(t_lastblkline>0){ + t_blklines->p_AddLast3(t_lastblkline); + } + c_Enumerator2* t_=t_tokelines->p_ObjectEnumerator(); + while(t_->p_HasNext()){ + int t_i=t_->p_NextObject(); + if(t_i>t_lastblkline){ + t_blklines->p_AddLast3(t_i); + } + } + }else{ + if(t_lastblkline>0){ + t_blklines->p_AddLast3(t_lastblkline); + } + c_KeyEnumerator* t_2=m__map->p_Keys()->p_ObjectEnumerator(); + while(t_2->p_HasNext()){ + int t_i2=t_2->p_NextObject(); + c_Enumerator2* t_3=m__map->p_Get2(t_i2)->p_ObjectEnumerator(); + while(t_3->p_HasNext()){ + int t_j=t_3->p_NextObject(); + if(t_j>t_lastblkline){ + t_blklines->p_AddLast3(t_j); + } + } + } + t_blklines->p_Sort(1); + } + return t_blklines; +} +int c_BlockTrace::p_Unwind(int t_token){ + Array t_blklines=m__Blocks->p_BlockLineList(t_token)->p_ToArray(); + String t_path=bb_config__errInfo.Slice(0,bb_config__errInfo.FindLast(String(L"<",1))); + bbPrint(String(L"\n\t------------ BLOCK TRACE ------------",39)); + bbPrint(String(L"FILE: ",6)+t_path); + int t_i=0; + while(t_i=t_blklines.Length()){ + break; + } + t_str=t_str+(String(t_blklines[t_i])+String(L", ",2)); + t_i+=1; + t_col+=1; + } + bbPrint(String(L"Statement Blocks at lines: ",27)+t_str.Slice(0,t_str.Length()-2)); + } + bbPrint(String()); + if(t_blklines.Length()>0){ + return t_blklines[0]; + }else{ + return 0; } - do{ - p_SkipEols(); - String t_22=m__toke; - if(t_22==String(L"end",3)){ - p_NextToke(); - break; +} +int c_BlockTrace::m_TraceLog(int t_token){ + return m__Blocks->p_Unwind(t_token); +} +int c_BlockTrace::m_Str2Code(String t_toke){ + String t_2=t_toke.ToLower(); + if(t_2==String(L"for",3)){ + return 1; + }else{ + if(t_2==String(L"function",8)){ + return 2; }else{ - if(t_22==String(L"public",6)){ - p_NextToke(); - t_decl_attrs&=-16897; + if(t_2==String(L"method",6)){ + return 3; }else{ - if(t_22==String(L"private",7)){ - p_NextToke(); - t_decl_attrs&=-16897; - t_decl_attrs|=512; + if(t_2==String(L"if",2)){ + return 4; }else{ - if(t_22==String(L"protected",9)){ - p_NextToke(); - t_decl_attrs&=-16897; - t_decl_attrs|=16384; + if(t_2==String(L"repeat",6)){ + return 5; }else{ - if(t_22==String(L"const",5) || t_22==String(L"global",6) || t_22==String(L"field",5)){ - if(((t_attrs&4096)!=0) && m__toke!=String(L"const",5)){ - bb_config_Err(String(L"Interfaces can only contain constants and methods.",50)); - } - t_classDecl->p_InsertDecls(p_ParseDecls(m__toke,t_decl_attrs)); + if(t_2==String(L"while",5)){ + return 6; }else{ - if(t_22==String(L"enumerate",9)){ - t_classDecl->p_InsertDecls(p_ParseEnum(m__toke,t_decl_attrs)); + if(t_2==String(L"try",3)){ + return 6; }else{ - if(t_22==String(L"method",6)){ - t_classDecl->p_InsertDecl(p_ParseFuncDecl(t_decl_attrs|t_func_attrs)); + if(t_2==String(L"class",5)){ + return 7; }else{ - if(t_22==String(L"function",8)){ - if((t_attrs&4096)!=0){ - bb_config_Err(String(L"Interfaces can only contain constants and methods.",50)); - } - t_classDecl->p_InsertDecl(p_ParseFuncDecl(t_decl_attrs|t_func_attrs)); + if(t_2==String(L"interface",9)){ + return 8; }else{ - bb_config_Err(String(L"Syntax error - expecting class member declaration.",50)); + if(t_2==String(L"select",6)){ + return 9; + }else{ + return 0; + } } } } @@ -12403,92 +25497,55 @@ c_ClassDecl* c_Parser::p_ParseClassDecl(int t_attrs){ } } } - }while(!(false)); - if((t_toke).Length()!=0){ - p_CParse(t_toke); } - return t_classDecl; } -int c_Parser::p_ParseMain(){ - p_SkipEols(); - if((p_CParse(String(L"strict",6)))!=0){ - m__module->m_attrs|=1; +int c_BlockTrace::m_TraceLog2(String t_token){ + return m__Blocks->p_Unwind(m_Str2Code(t_token)); +} +c_TraceRecord* c_BlockTrace::p_RemoveRecord(){ + if(m__record->p_IsEmpty()){ + return 0; } - int t_attrs=0; - while((m__toke).Length()!=0){ - p_SetErr(); - String t_23=m__toke; - if(t_23==String(L"\n",1)){ - p_NextToke(); + return m__record->p_RemoveLast(); +} +c_TraceRecord* c_BlockTrace::m_Pop(){ + return m__Blocks->p_RemoveRecord(); +} +String c_BlockTrace::m_Code2Str(int t_code){ + int t_1=t_code; + if(t_1==1){ + return String(L"For",3); + }else{ + if(t_1==2){ + return String(L"Function",8); }else{ - if(t_23==String(L"public",6)){ - p_NextToke(); - t_attrs=0; + if(t_1==3){ + return String(L"Method",6); }else{ - if(t_23==String(L"private",7)){ - p_NextToke(); - t_attrs=512; + if(t_1==4){ + return String(L"If",2); }else{ - if(t_23==String(L"protected",9)){ - bb_config_Err(String(L"Protected may only be used within classes.",42)); + if(t_1==5){ + return String(L"Repeat",6); }else{ - if(t_23==String(L"import",6)){ - p_NextToke(); - if(m__tokeType==6){ - p_ImportFile(bb_config_EvalConfigTags(p_ParseStringLit())); - }else{ - p_ImportModule(p_ParseModPath(),t_attrs); - } + if(t_1==6){ + return String(L"While",5); }else{ - if(t_23==String(L"friend",6)){ - p_NextToke(); - String t_modpath=p_ParseModPath(); - m__module->m_friends->p_Insert(t_modpath); + if(t_1==6){ + return String(L"Try",3); }else{ - if(t_23==String(L"alias",5)){ - p_NextToke(); - do{ - String t_ident=p_ParseIdent(); - p_Parse(String(L"=",1)); - Object* t_decl=0; - String t_24=m__toke; - if(t_24==String(L"int",3)){ - t_decl=(c_Type::m_intType); + if(t_1==7){ + return String(L"Class",5); + }else{ + if(t_1==8){ + return String(L"Try",3); + }else{ + if(t_1==9){ + return String(L"Select",6); }else{ - if(t_24==String(L"float",5)){ - t_decl=(c_Type::m_floatType); - }else{ - if(t_24==String(L"string",6)){ - t_decl=(c_Type::m_stringType); - } - } + return String(); } - if((t_decl)!=0){ - m__module->p_InsertDecl((new c_AliasDecl)->m_new(t_ident,t_attrs,t_decl)); - p_NextToke(); - continue; - } - c_ScopeDecl* t_scope=(m__module); - bb_decl_PushEnv(m__module); - do{ - String t_id=p_ParseIdent(); - t_decl=t_scope->p_FindDecl(t_id); - if(!((t_decl)!=0)){ - bb_config_Err(String(L"Identifier '",12)+t_id+String(L"' not found.",12)); - } - if(!((p_CParse(String(L".",1)))!=0)){ - break; - } - t_scope=dynamic_cast(t_decl); - if(!((t_scope)!=0) || ((dynamic_cast(t_scope))!=0)){ - bb_config_Err(String(L"Invalid scope '",15)+t_id+String(L"'.",2)); - } - }while(!(false)); - bb_decl_PopEnv(); - m__module->p_InsertDecl((new c_AliasDecl)->m_new(t_ident,t_attrs,t_decl)); - }while(!(!((p_CParse(String(L",",1)))!=0))); - }else{ - break; + } } } } @@ -12497,64 +25554,482 @@ int c_Parser::p_ParseMain(){ } } } - while((m__toke).Length()!=0){ - p_SetErr(); - String t_25=m__toke; - if(t_25==String(L"\n",1)){ - p_NextToke(); +} +int c_BlockTrace::p_AddRecord(c_TraceRecord* t_record){ + int t_token=t_record->p_Toke(); + if(!m__map->p_Contains2(t_token)){ + c_IntList* t_newlist=(new c_IntList)->m_new2(); + t_newlist->p_AddLast3(t_record->p_Line()); + m__map->p_Add(t_token,t_newlist); + }else{ + m__map->p_Get2(t_token)->p_AddLast3(t_record->p_Line()); + } + m__record->p_AddLast4(t_record); + return 0; +} +int c_BlockTrace::m_Push(int t_toke,int t_line){ + m__Blocks->p_AddRecord((new c_TraceRecord)->m_new(t_toke,t_line)); + return 0; +} +int c_BlockTrace::m_Push2(String t_toke,int t_line){ + m__Blocks->p_AddRecord((new c_TraceRecord)->m_new(m_Str2Code(t_toke),t_line)); + return 0; +} +void c_BlockTrace::mark(){ + Object::mark(); +} +c_List3::c_List3(){ + m__head=((new c_HeadNode7)->m_new()); +} +c_List3* c_List3::m_new(){ + return this; +} +c_Node13* c_List3::p_AddLast3(int t_data){ + return (new c_Node13)->m_new(m__head,m__head->m__pred,t_data); +} +c_List3* c_List3::m_new2(Array t_data){ + Array t_=t_data; + int t_2=0; + while(t_2m_new(this); +} +int c_List3::p_Compare2(int t_lhs,int t_rhs){ + bbError(String(L"Unable to compare items",23)); + return 0; +} +int c_List3::p_Sort(int t_ascending){ + int t_ccsgn=-1; + if((t_ascending)!=0){ + t_ccsgn=1; + } + int t_insize=1; + do{ + int t_merges=0; + c_Node13* t_tail=m__head; + c_Node13* t_p=m__head->m__succ; + while(t_p!=m__head){ + t_merges+=1; + c_Node13* t_q=t_p->m__succ; + int t_qsize=t_insize; + int t_psize=1; + while(t_psizem__succ; + } + do{ + c_Node13* t_t=0; + if(((t_psize)!=0) && ((t_qsize)!=0) && t_q!=m__head){ + int t_cc=p_Compare2(t_p->m__data,t_q->m__data)*t_ccsgn; + if(t_cc<=0){ + t_t=t_p; + t_p=t_p->m__succ; + t_psize-=1; + }else{ + t_t=t_q; + t_q=t_q->m__succ; + t_qsize-=1; + } + }else{ + if((t_psize)!=0){ + t_t=t_p; + t_p=t_p->m__succ; + t_psize-=1; + }else{ + if(((t_qsize)!=0) && t_q!=m__head){ + t_t=t_q; + t_q=t_q->m__succ; + t_qsize-=1; + }else{ + break; + } + } + } + t_t->m__pred=t_tail; + t_tail->m__succ=t_t; + t_tail=t_t; + }while(!(false)); + t_p=t_q; + } + t_tail->m__succ=m__head; + m__head->m__pred=t_tail; + if(t_merges<=1){ + return 0; + } + t_insize*=2; + }while(!(false)); +} +int c_List3::p_Count(){ + int t_n=0; + c_Node13* t_node=m__head->m__succ; + while(t_node!=m__head){ + t_node=t_node->m__succ; + t_n+=1; + } + return t_n; +} +Array c_List3::p_ToArray(){ + Array t_arr=Array(p_Count()); + int t_i=0; + c_Enumerator2* t_=this->p_ObjectEnumerator(); + while(t_->p_HasNext()){ + int t_t=t_->p_NextObject(); + t_arr[t_i]=t_t; + t_i+=1; + } + return t_arr; +} +void c_List3::mark(){ + Object::mark(); +} +c_IntList::c_IntList(){ +} +c_IntList* c_IntList::m_new(Array t_data){ + c_List3::m_new2(t_data); + return this; +} +c_IntList* c_IntList::m_new2(){ + c_List3::m_new(); + return this; +} +int c_IntList::p_Compare2(int t_lhs,int t_rhs){ + return t_lhs-t_rhs; +} +void c_IntList::mark(){ + c_List3::mark(); +} +c_Map6::c_Map6(){ + m_root=0; +} +c_Map6* c_Map6::m_new(){ + return this; +} +int c_Map6::p_Clear(){ + m_root=0; + return 0; +} +c_Node8* c_Map6::p_FindNode2(int t_key){ + c_Node8* t_node=m_root; + while((t_node)!=0){ + int t_cmp=p_Compare2(t_key,t_node->m_key); + if(t_cmp>0){ + t_node=t_node->m_right; + }else{ + if(t_cmp<0){ + t_node=t_node->m_left; + }else{ + return t_node; + } + } + } + return t_node; +} +c_IntList* c_Map6::p_Get2(int t_key){ + c_Node8* t_node=p_FindNode2(t_key); + if((t_node)!=0){ + return t_node->m_value; + } + return 0; +} +c_MapKeys* c_Map6::p_Keys(){ + return (new c_MapKeys)->m_new(this); +} +c_Node8* c_Map6::p_FirstNode(){ + if(!((m_root)!=0)){ + return 0; + } + c_Node8* t_node=m_root; + while((t_node->m_left)!=0){ + t_node=t_node->m_left; + } + return t_node; +} +bool c_Map6::p_Contains2(int t_key){ + return p_FindNode2(t_key)!=0; +} +int c_Map6::p_RotateLeft6(c_Node8* t_node){ + c_Node8* t_child=t_node->m_right; + t_node->m_right=t_child->m_left; + if((t_child->m_left)!=0){ + t_child->m_left->m_parent=t_node; + } + t_child->m_parent=t_node->m_parent; + if((t_node->m_parent)!=0){ + if(t_node==t_node->m_parent->m_left){ + t_node->m_parent->m_left=t_child; + }else{ + t_node->m_parent->m_right=t_child; + } + }else{ + m_root=t_child; + } + t_child->m_left=t_node; + t_node->m_parent=t_child; + return 0; +} +int c_Map6::p_RotateRight6(c_Node8* t_node){ + c_Node8* t_child=t_node->m_left; + t_node->m_left=t_child->m_right; + if((t_child->m_right)!=0){ + t_child->m_right->m_parent=t_node; + } + t_child->m_parent=t_node->m_parent; + if((t_node->m_parent)!=0){ + if(t_node==t_node->m_parent->m_right){ + t_node->m_parent->m_right=t_child; + }else{ + t_node->m_parent->m_left=t_child; + } + }else{ + m_root=t_child; + } + t_child->m_right=t_node; + t_node->m_parent=t_child; + return 0; +} +int c_Map6::p_InsertFixup6(c_Node8* t_node){ + while(((t_node->m_parent)!=0) && t_node->m_parent->m_color==-1 && ((t_node->m_parent->m_parent)!=0)){ + if(t_node->m_parent==t_node->m_parent->m_parent->m_left){ + c_Node8* t_uncle=t_node->m_parent->m_parent->m_right; + if(((t_uncle)!=0) && t_uncle->m_color==-1){ + t_node->m_parent->m_color=1; + t_uncle->m_color=1; + t_uncle->m_parent->m_color=-1; + t_node=t_uncle->m_parent; + }else{ + if(t_node==t_node->m_parent->m_right){ + t_node=t_node->m_parent; + p_RotateLeft6(t_node); + } + t_node->m_parent->m_color=1; + t_node->m_parent->m_parent->m_color=-1; + p_RotateRight6(t_node->m_parent->m_parent); + } + }else{ + c_Node8* t_uncle2=t_node->m_parent->m_parent->m_left; + if(((t_uncle2)!=0) && t_uncle2->m_color==-1){ + t_node->m_parent->m_color=1; + t_uncle2->m_color=1; + t_uncle2->m_parent->m_color=-1; + t_node=t_uncle2->m_parent; + }else{ + if(t_node==t_node->m_parent->m_left){ + t_node=t_node->m_parent; + p_RotateRight6(t_node); + } + t_node->m_parent->m_color=1; + t_node->m_parent->m_parent->m_color=-1; + p_RotateLeft6(t_node->m_parent->m_parent); + } + } + } + m_root->m_color=1; + return 0; +} +bool c_Map6::p_Add(int t_key,c_IntList* t_value){ + c_Node8* t_node=m_root; + c_Node8* t_parent=0; + int t_cmp=0; + while((t_node)!=0){ + t_parent=t_node; + t_cmp=p_Compare2(t_key,t_node->m_key); + if(t_cmp>0){ + t_node=t_node->m_right; }else{ - if(t_25==String(L"public",6)){ - p_NextToke(); - t_attrs=0; + if(t_cmp<0){ + t_node=t_node->m_left; }else{ - if(t_25==String(L"private",7)){ - p_NextToke(); - t_attrs=512; - }else{ - if(t_25==String(L"extern",6)){ - if((bb_config_ENV_SAFEMODE)!=0){ - if(m__app->m_mainModule==m__module){ - bb_config_Err(String(L"Extern not permitted in safe mode.",34)); - } - } - p_NextToke(); - t_attrs=256; - if((p_CParse(String(L"private",7)))!=0){ - t_attrs|=512; - } - }else{ - if(t_25==String(L"const",5) || t_25==String(L"global",6)){ - m__module->p_InsertDecls(p_ParseDecls(m__toke,t_attrs)); - }else{ - if(t_25==String(L"enumerate",9)){ - m__module->p_InsertDecls(p_ParseEnum(m__toke,t_attrs)); - }else{ - if(t_25==String(L"class",5)){ - m__module->p_InsertDecl(p_ParseClassDecl(t_attrs)); - }else{ - if(t_25==String(L"interface",9)){ - m__module->p_InsertDecl(p_ParseClassDecl(t_attrs)); - }else{ - if(t_25==String(L"function",8)){ - m__module->p_InsertDecl(p_ParseFuncDecl(t_attrs)); - }else{ - bb_config_Err(String(L"Syntax error - expecting declaration.",37)); - } - } - } - } - } - } - } + return false; } } } - bb_config__errInfo=String(); + t_node=(new c_Node8)->m_new(t_key,t_value,-1,t_parent); + if((t_parent)!=0){ + if(t_cmp>0){ + t_parent->m_right=t_node; + }else{ + t_parent->m_left=t_node; + } + p_InsertFixup6(t_node); + }else{ + m_root=t_node; + } + return true; +} +void c_Map6::mark(){ + Object::mark(); +} +c_IntMap::c_IntMap(){ +} +c_IntMap* c_IntMap::m_new(){ + c_Map6::m_new(); + return this; +} +int c_IntMap::p_Compare2(int t_lhs,int t_rhs){ + return t_lhs-t_rhs; +} +void c_IntMap::mark(){ + c_Map6::mark(); +} +c_Node8::c_Node8(){ + m_key=0; + m_right=0; + m_left=0; + m_value=0; + m_parent=0; + m_color=0; +} +c_Node8* c_Node8::p_NextNode(){ + c_Node8* t_node=0; + if((m_right)!=0){ + t_node=m_right; + while((t_node->m_left)!=0){ + t_node=t_node->m_left; + } + return t_node; + } + t_node=this; + c_Node8* t_parent=this->m_parent; + while(((t_parent)!=0) && t_node==t_parent->m_right){ + t_node=t_parent; + t_parent=t_parent->m_parent; + } + return t_parent; +} +c_Node8* c_Node8::m_new(int t_key,c_IntList* t_value,int t_color,c_Node8* t_parent){ + this->m_key=t_key; + this->m_value=t_value; + this->m_color=t_color; + this->m_parent=t_parent; + return this; +} +c_Node8* c_Node8::m_new2(){ + return this; +} +void c_Node8::mark(){ + Object::mark(); +} +c_TraceRecord::c_TraceRecord(){ + m__line=0; + m__toke=0; +} +int c_TraceRecord::p_Line(){ + return m__line; +} +int c_TraceRecord::p_Toke(){ + return m__toke; +} +c_TraceRecord* c_TraceRecord::m_new(int t_toke,int t_line){ + m__toke=t_toke; + m__line=t_line; + return this; +} +c_TraceRecord* c_TraceRecord::m_new2(){ + return this; +} +void c_TraceRecord::mark(){ + Object::mark(); +} +c_List4::c_List4(){ + m__head=((new c_HeadNode3)->m_new()); +} +c_List4* c_List4::m_new(){ + return this; +} +c_Node9* c_List4::p_AddLast4(c_TraceRecord* t_data){ + return (new c_Node9)->m_new(m__head,m__head->m__pred,t_data); +} +c_List4* c_List4::m_new2(Array t_data){ + Array t_=t_data; + int t_2=0; + while(t_2m__succ=m__head; + m__head->m__pred=m__head; return 0; } -void c_Parser::mark(){ +bool c_List4::p_IsEmpty(){ + return m__head->m__succ==m__head; +} +c_TraceRecord* c_List4::p_Last(){ + return m__head->m__pred->m__data; +} +c_TraceRecord* c_List4::p_RemoveLast(){ + c_TraceRecord* t_data=m__head->m__pred->m__data; + m__head->m__pred->p_Remove(); + return t_data; +} +bool c_List4::p_Equals3(c_TraceRecord* t_lhs,c_TraceRecord* t_rhs){ + return t_lhs==t_rhs; +} +c_Node9* c_List4::p_FindLast5(c_TraceRecord* t_value,c_Node9* t_start){ + while(t_start!=m__head){ + if(p_Equals3(t_value,t_start->m__data)){ + return t_start; + } + t_start=t_start->m__pred; + } + return 0; +} +c_Node9* c_List4::p_FindLast6(c_TraceRecord* t_value){ + return p_FindLast5(t_value,m__head->m__pred); +} +void c_List4::p_RemoveLast4(c_TraceRecord* t_value){ + c_Node9* t_node=p_FindLast6(t_value); + if((t_node)!=0){ + t_node->p_Remove(); + } +} +void c_List4::mark(){ + Object::mark(); +} +c_Node9::c_Node9(){ + m__succ=0; + m__pred=0; + m__data=0; +} +c_Node9* c_Node9::m_new(c_Node9* t_succ,c_Node9* t_pred,c_TraceRecord* t_data){ + m__succ=t_succ; + m__pred=t_pred; + m__succ->m__pred=this; + m__pred->m__succ=this; + m__data=t_data; + return this; +} +c_Node9* c_Node9::m_new2(){ + return this; +} +int c_Node9::p_Remove(){ + m__succ->m__pred=m__pred; + m__pred->m__succ=m__succ; + return 0; +} +void c_Node9::mark(){ Object::mark(); } +c_HeadNode3::c_HeadNode3(){ +} +c_HeadNode3* c_HeadNode3::m_new(){ + c_Node9::m_new2(); + m__succ=(this); + m__pred=(this); + return this; +} +void c_HeadNode3::mark(){ + c_Node9::mark(); +} int bb_config_InternalErr(String t_err){ bbPrint(bb_config__errInfo+String(L" : ",3)+t_err); bbError(bb_config__errInfo+String(L" : ",3)+t_err); @@ -12847,46 +26322,46 @@ int c_AliasDecl::p_OnSemant(){ void c_AliasDecl::mark(){ c_Decl::mark(); } -c_List3::c_List3(){ - m__head=((new c_HeadNode3)->m_new()); +c_List5::c_List5(){ + m__head=((new c_HeadNode4)->m_new()); } -c_List3* c_List3::m_new(){ +c_List5* c_List5::m_new(){ return this; } -c_Node8* c_List3::p_AddLast3(c_Decl* t_data){ - return (new c_Node8)->m_new(m__head,m__head->m__pred,t_data); +c_Node10* c_List5::p_AddLast5(c_Decl* t_data){ + return (new c_Node10)->m_new(m__head,m__head->m__pred,t_data); } -c_List3* c_List3::m_new2(Array t_data){ +c_List5* c_List5::m_new2(Array t_data){ Array t_=t_data; int t_2=0; while(t_2m_new(this); +c_Enumerator3* c_List5::p_ObjectEnumerator(){ + return (new c_Enumerator3)->m_new(this); } -int c_List3::p_Count(){ +int c_List5::p_Count(){ int t_n=0; - c_Node8* t_node=m__head->m__succ; + c_Node10* t_node=m__head->m__succ; while(t_node!=m__head){ t_node=t_node->m__succ; t_n+=1; } return t_n; } -void c_List3::mark(){ +void c_List5::mark(){ Object::mark(); } -c_Node8::c_Node8(){ +c_Node10::c_Node10(){ m__succ=0; m__pred=0; m__data=0; } -c_Node8* c_Node8::m_new(c_Node8* t_succ,c_Node8* t_pred,c_Decl* t_data){ +c_Node10* c_Node10::m_new(c_Node10* t_succ,c_Node10* t_pred,c_Decl* t_data){ m__succ=t_succ; m__pred=t_pred; m__succ->m__pred=this; @@ -12894,28 +26369,28 @@ c_Node8* c_Node8::m_new(c_Node8* t_succ,c_Node8* t_pred,c_Decl* t_data){ m__data=t_data; return this; } -c_Node8* c_Node8::m_new2(){ +c_Node10* c_Node10::m_new2(){ return this; } -void c_Node8::mark(){ +void c_Node10::mark(){ Object::mark(); } -c_HeadNode3::c_HeadNode3(){ +c_HeadNode4::c_HeadNode4(){ } -c_HeadNode3* c_HeadNode3::m_new(){ - c_Node8::m_new2(); +c_HeadNode4* c_HeadNode4::m_new(){ + c_Node10::m_new2(); m__succ=(this); m__pred=(this); return this; } -void c_HeadNode3::mark(){ - c_Node8::mark(); +void c_HeadNode4::mark(){ + c_Node10::mark(); } c_BlockDecl::c_BlockDecl(){ - m_stmts=(new c_List5)->m_new(); + m_stmts=(new c_List7)->m_new(); } int c_BlockDecl::p_AddStmt(c_Stmt* t_stmt){ - m_stmts->p_AddLast5(t_stmt); + m_stmts->p_AddLast7(t_stmt); return 0; } c_BlockDecl* c_BlockDecl::m_new(c_ScopeDecl* t_scope){ @@ -12929,7 +26404,7 @@ c_BlockDecl* c_BlockDecl::m_new2(){ } c_Decl* c_BlockDecl::p_OnCopy(){ c_BlockDecl* t_t=(new c_BlockDecl)->m_new2(); - c_Enumerator5* t_=m_stmts->p_ObjectEnumerator(); + c_Enumerator6* t_=m_stmts->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_Stmt* t_stmt=t_->p_NextObject(); t_t->p_AddStmt(t_stmt->p_Copy2(t_t)); @@ -12938,7 +26413,7 @@ c_Decl* c_BlockDecl::p_OnCopy(){ } int c_BlockDecl::p_OnSemant(){ bb_decl_PushEnv(this); - c_Enumerator5* t_=m_stmts->p_ObjectEnumerator(); + c_Enumerator6* t_=m_stmts->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_Stmt* t_stmt=t_->p_NextObject(); t_stmt->p_Semant(); @@ -13023,7 +26498,7 @@ c_Decl* c_FuncDecl::p_OnCopy(){ t_args[t_i]=dynamic_cast(t_args[t_i]->p_Copy()); } c_FuncDecl* t_t=(new c_FuncDecl)->m_new(m_ident,m_attrs,m_retType,t_args); - c_Enumerator5* t_=m_stmts->p_ObjectEnumerator(); + c_Enumerator6* t_=m_stmts->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_Stmt* t_stmt=t_->p_NextObject(); t_t->p_AddStmt(t_stmt->p_Copy2(t_t)); @@ -13049,7 +26524,7 @@ int c_FuncDecl::p_OnSemant(){ p_InsertDecl(t_arg); t_arg->p_Semant(); } - c_Enumerator3* t_3=m_scope->p_SemantedFuncs(m_ident)->p_ObjectEnumerator(); + c_Enumerator4* t_3=m_scope->p_SemantedFuncs(m_ident)->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_FuncDecl* t_decl=t_3->p_NextObject(); if(t_decl!=this && p_EqualsArgs(t_decl)){ @@ -13065,7 +26540,7 @@ int c_FuncDecl::p_OnSemant(){ if(((t_sclass)!=0) && p_IsMethod()){ while((t_sclass)!=0){ int t_found=0; - c_Enumerator3* t_4=t_sclass->p_MethodDecls(m_ident)->p_ObjectEnumerator(); + c_Enumerator4* t_4=t_sclass->p_MethodDecls(m_ident)->p_ObjectEnumerator(); while(t_4->p_HasNext()){ c_FuncDecl* t_decl2=t_4->p_NextObject(); t_found=1; @@ -13110,46 +26585,46 @@ bool c_FuncDecl::p_IsVirtual(){ void c_FuncDecl::mark(){ c_BlockDecl::mark(); } -c_List4::c_List4(){ - m__head=((new c_HeadNode4)->m_new()); +c_List6::c_List6(){ + m__head=((new c_HeadNode5)->m_new()); } -c_List4* c_List4::m_new(){ +c_List6* c_List6::m_new(){ return this; } -c_Node9* c_List4::p_AddLast4(c_FuncDecl* t_data){ - return (new c_Node9)->m_new(m__head,m__head->m__pred,t_data); +c_Node11* c_List6::p_AddLast6(c_FuncDecl* t_data){ + return (new c_Node11)->m_new(m__head,m__head->m__pred,t_data); } -c_List4* c_List4::m_new2(Array t_data){ +c_List6* c_List6::m_new2(Array t_data){ Array t_=t_data; int t_2=0; while(t_2m_new(this); +c_Enumerator4* c_List6::p_ObjectEnumerator(){ + return (new c_Enumerator4)->m_new(this); } -void c_List4::mark(){ +void c_List6::mark(){ Object::mark(); } c_FuncDeclList::c_FuncDeclList(){ } c_FuncDeclList* c_FuncDeclList::m_new(){ - c_List4::m_new(); + c_List6::m_new(); return this; } void c_FuncDeclList::mark(){ - c_List4::mark(); + c_List6::mark(); } -c_Node9::c_Node9(){ +c_Node11::c_Node11(){ m__succ=0; m__pred=0; m__data=0; } -c_Node9* c_Node9::m_new(c_Node9* t_succ,c_Node9* t_pred,c_FuncDecl* t_data){ +c_Node11* c_Node11::m_new(c_Node11* t_succ,c_Node11* t_pred,c_FuncDecl* t_data){ m__succ=t_succ; m__pred=t_pred; m__succ->m__pred=this; @@ -13157,22 +26632,22 @@ c_Node9* c_Node9::m_new(c_Node9* t_succ,c_Node9* t_pred,c_FuncDecl* t_data){ m__data=t_data; return this; } -c_Node9* c_Node9::m_new2(){ +c_Node11* c_Node11::m_new2(){ return this; } -void c_Node9::mark(){ +void c_Node11::mark(){ Object::mark(); } -c_HeadNode4::c_HeadNode4(){ +c_HeadNode5::c_HeadNode5(){ } -c_HeadNode4* c_HeadNode4::m_new(){ - c_Node9::m_new2(); +c_HeadNode5* c_HeadNode5::m_new(){ + c_Node11::m_new2(); m__succ=(this); m__pred=(this); return this; } -void c_HeadNode4::mark(){ - c_Node9::mark(); +void c_HeadNode5::mark(){ + c_Node11::mark(); } c_ClassDecl::c_ClassDecl(){ m_superClass=0; @@ -13195,7 +26670,7 @@ c_ClassDecl* c_ClassDecl::m_new(String t_ident,int t_attrs,Array t_args this->m_impltys=t_impls; this->m_objectType=(new c_ObjectType)->m_new(this); if((t_args).Length()!=0){ - m_instances=(new c_List6)->m_new(); + m_instances=(new c_List8)->m_new(); } return this; } @@ -13288,7 +26763,7 @@ c_ClassDecl* c_ClassDecl::p_GenClassInstance(Array t_instArgs){ if(!((m_args).Length()!=0)){ return this; } - c_Enumerator4* t_=m_instances->p_ObjectEnumerator(); + c_Enumerator5* t_=m_instances->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_ClassDecl* t_inst=t_->p_NextObject(); if(bb_decl__env->p_ClassScope()==t_inst){ @@ -13299,7 +26774,7 @@ c_ClassDecl* c_ClassDecl::p_GenClassInstance(Array t_instArgs){ if(m_args.Length()!=t_instArgs.Length()){ bb_config_Err(String(L"Wrong number of type arguments for class ",41)+p_ToString()); } - c_Enumerator4* t_2=m_instances->p_ObjectEnumerator(); + c_Enumerator5* t_2=m_instances->p_ObjectEnumerator(); while(t_2->p_HasNext()){ c_ClassDecl* t_inst2=t_2->p_NextObject(); int t_equal=1; @@ -13320,11 +26795,11 @@ c_ClassDecl* c_ClassDecl::p_GenClassInstance(Array t_instArgs){ t_inst3->m_scope=m_scope; t_inst3->m_instanceof=this; t_inst3->m_instArgs=t_instArgs; - m_instances->p_AddLast6(t_inst3); + m_instances->p_AddLast8(t_inst3); for(int t_i2=0;t_i2p_InsertDecl((new c_AliasDecl)->m_new(m_args[t_i2],0,(t_instArgs[t_i2]))); } - c_Enumerator2* t_3=m_decls->p_ObjectEnumerator(); + c_Enumerator3* t_3=m_decls->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_Decl* t_decl=t_3->p_NextObject(); t_inst3->p_InsertDecl(t_decl->p_Copy()); @@ -13345,24 +26820,24 @@ int c_ClassDecl::p_UpdateLiveMethods(){ return 0; } int t_n=0; - c_Enumerator3* t_=p_MethodDecls(String())->p_ObjectEnumerator(); + c_Enumerator4* t_=p_MethodDecls(String())->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_FuncDecl* t_decl=t_->p_NextObject(); if((t_decl->p_IsSemanted())!=0){ continue; } int t_live=0; - c_List4* t_unsem=(new c_List4)->m_new(); - t_unsem->p_AddLast4(t_decl); + c_List6* t_unsem=(new c_List6)->m_new(); + t_unsem->p_AddLast6(t_decl); c_ClassDecl* t_sclass=m_superClass; while((t_sclass)!=0){ - c_Enumerator3* t_2=t_sclass->p_MethodDecls(t_decl->m_ident)->p_ObjectEnumerator(); + c_Enumerator4* t_2=t_sclass->p_MethodDecls(t_decl->m_ident)->p_ObjectEnumerator(); while(t_2->p_HasNext()){ c_FuncDecl* t_decl2=t_2->p_NextObject(); if((t_decl2->p_IsSemanted())!=0){ t_live=1; }else{ - t_unsem->p_AddLast4(t_decl2); + t_unsem->p_AddLast6(t_decl2); if((t_decl2->p_IsExtern())!=0){ t_live=1; } @@ -13381,13 +26856,13 @@ int c_ClassDecl::p_UpdateLiveMethods(){ while(t_4p_MethodDecls(t_decl->m_ident)->p_ObjectEnumerator(); + c_Enumerator4* t_5=t_iface->p_MethodDecls(t_decl->m_ident)->p_ObjectEnumerator(); while(t_5->p_HasNext()){ c_FuncDecl* t_decl22=t_5->p_NextObject(); if((t_decl22->p_IsSemanted())!=0){ t_live=1; }else{ - t_unsem->p_AddLast4(t_decl22); + t_unsem->p_AddLast6(t_decl22); if((t_decl22->p_IsExtern())!=0){ t_live=1; } @@ -13403,7 +26878,7 @@ int c_ClassDecl::p_UpdateLiveMethods(){ if(!((t_live)!=0)){ continue; } - c_Enumerator3* t_6=t_unsem->p_ObjectEnumerator(); + c_Enumerator4* t_6=t_unsem->p_ObjectEnumerator(); while(t_6->p_HasNext()){ c_FuncDecl* t_decl3=t_6->p_NextObject(); t_decl3->p_Semant(); @@ -13424,7 +26899,7 @@ int c_ClassDecl::p_FinalizeClass(){ return 0; } bb_config_PushErr(m_errInfo); - c_Enumerator2* t_=p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_=p_Semanted()->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_Decl* t_decl=t_->p_NextObject(); c_FieldDecl* t_fdecl=dynamic_cast(t_decl); @@ -13433,7 +26908,7 @@ int c_ClassDecl::p_FinalizeClass(){ } c_ClassDecl* t_cdecl=m_superClass; while((t_cdecl)!=0){ - c_Enumerator2* t_2=t_cdecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_2=t_cdecl->p_Semanted()->p_ObjectEnumerator(); while(t_2->p_HasNext()){ c_Decl* t_decl2=t_2->p_NextObject(); if(t_decl2->m_ident==t_fdecl->m_ident){ @@ -13450,14 +26925,14 @@ int c_ClassDecl::p_FinalizeClass(){ } }else{ c_ClassDecl* t_cdecl2=this; - c_List4* t_impls=(new c_List4)->m_new(); + c_List6* t_impls=(new c_List6)->m_new(); while(((t_cdecl2)!=0) && !((p_IsAbstract())!=0)){ - c_Enumerator3* t_3=t_cdecl2->p_SemantedMethods(String())->p_ObjectEnumerator(); + c_Enumerator4* t_3=t_cdecl2->p_SemantedMethods(String())->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_FuncDecl* t_decl3=t_3->p_NextObject(); if((t_decl3->p_IsAbstract())!=0){ int t_found=0; - c_Enumerator3* t_4=t_impls->p_ObjectEnumerator(); + c_Enumerator4* t_4=t_impls->p_ObjectEnumerator(); while(t_4->p_HasNext()){ c_FuncDecl* t_decl22=t_4->p_NextObject(); if(t_decl3->m_ident==t_decl22->m_ident && t_decl3->p_EqualsFunc(t_decl22)){ @@ -13473,7 +26948,7 @@ int c_ClassDecl::p_FinalizeClass(){ break; } }else{ - t_impls->p_AddLast4(t_decl3); + t_impls->p_AddLast6(t_decl3); } } t_cdecl2=t_cdecl2->m_superClass; @@ -13506,11 +26981,11 @@ int c_ClassDecl::p_FinalizeClass(){ if(t_found2){ continue; } - c_Enumerator3* t_9=t_iface->p_SemantedMethods(String())->p_ObjectEnumerator(); + c_Enumerator4* t_9=t_iface->p_SemantedMethods(String())->p_ObjectEnumerator(); while(t_9->p_HasNext()){ c_FuncDecl* t_decl4=t_9->p_NextObject(); bool t_found3=false; - c_Enumerator3* t_10=p_SemantedMethods(t_decl4->m_ident)->p_ObjectEnumerator(); + c_Enumerator4* t_10=p_SemantedMethods(t_decl4->m_ident)->p_ObjectEnumerator(); while(t_10->p_HasNext()){ c_FuncDecl* t_decl23=t_10->p_NextObject(); if(t_decl4->p_EqualsFunc(t_decl23)){ @@ -13575,7 +27050,7 @@ int c_ClassDecl::p_OnSemant(){ } } Array t_impls=Array(m_impltys.Length()); - c_Stack8* t_implsall=(new c_Stack8)->m_new(); + c_Stack9* t_implsall=(new c_Stack9)->m_new(); for(int t_i=0;t_ip_SemantClass(); if(!((t_cdecl->p_IsInterface())!=0)){ @@ -13587,13 +27062,13 @@ int c_ClassDecl::p_OnSemant(){ } } t_impls[t_i]=t_cdecl; - t_implsall->p_Push22(t_cdecl); + t_implsall->p_Push25(t_cdecl); Array t_=t_cdecl->m_implmentsAll; int t_2=0; while(t_2p_Push22(t_tdecl); + t_implsall->p_Push25(t_tdecl); } } m_implmentsAll=Array(t_implsall->p_Length2()); @@ -13603,7 +27078,7 @@ int c_ClassDecl::p_OnSemant(){ m_implments=t_impls; bb_decl_PopEnv(); if(!((p_IsAbstract())!=0)){ - c_Enumerator2* t_3=m_decls->p_ObjectEnumerator(); + c_Enumerator3* t_3=m_decls->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_Decl* t_decl=t_3->p_NextObject(); c_FuncDecl* t_fdecl=dynamic_cast(t_decl); @@ -13615,7 +27090,7 @@ int c_ClassDecl::p_OnSemant(){ } if(!((p_IsExtern())!=0) && !((p_IsInterface())!=0)){ c_FuncDecl* t_fdecl2=0; - c_Enumerator3* t_4=p_FuncDecls(String())->p_ObjectEnumerator(); + c_Enumerator4* t_4=p_FuncDecls(String())->p_ObjectEnumerator(); while(t_4->p_HasNext()){ c_FuncDecl* t_decl2=t_4->p_NextObject(); if(!t_decl2->p_IsCtor()){ @@ -13643,7 +27118,7 @@ int c_ClassDecl::p_OnSemant(){ p_InsertDecl(t_fdecl2); } } - p_AppScope()->m_semantedClasses->p_AddLast6(this); + p_AppScope()->m_semantedClasses->p_AddLast8(this); return 0; } int c_ClassDecl::p_ExtendsClass(c_ClassDecl* t_cdecl){ @@ -13772,41 +27247,41 @@ String c_IdentType::p_ToString(){ void c_IdentType::mark(){ c_Type::mark(); } -c_Stack3::c_Stack3(){ +c_Stack4::c_Stack4(){ m_data=Array(); m_length=0; } -c_Stack3* c_Stack3::m_new(){ +c_Stack4* c_Stack4::m_new(){ return this; } -c_Stack3* c_Stack3::m_new2(Array t_data){ +c_Stack4* c_Stack4::m_new2(Array t_data){ this->m_data=t_data.Slice(0); this->m_length=t_data.Length(); return this; } -void c_Stack3::p_Push7(c_Type* t_value){ +void c_Stack4::p_Push10(c_Type* t_value){ if(m_length==m_data.Length()){ m_data=m_data.Resize(m_length*2+10); } m_data[m_length]=t_value; m_length+=1; } -void c_Stack3::p_Push8(Array t_values,int t_offset,int t_count){ +void c_Stack4::p_Push11(Array t_values,int t_offset,int t_count){ for(int t_i=0;t_i t_values,int t_offset){ - p_Push8(t_values,t_offset,t_values.Length()-t_offset); +void c_Stack4::p_Push12(Array t_values,int t_offset){ + p_Push11(t_values,t_offset,t_values.Length()-t_offset); } -Array c_Stack3::p_ToArray(){ +Array c_Stack4::p_ToArray(){ Array t_t=Array(m_length); for(int t_i=0;t_i(); m_length=0; } -c_Stack4* c_Stack4::m_new(){ +c_Stack5* c_Stack5::m_new(){ return this; } -c_Stack4* c_Stack4::m_new2(Array t_data){ +c_Stack5* c_Stack5::m_new2(Array t_data){ this->m_data=t_data.Slice(0); this->m_length=t_data.Length(); return this; } -void c_Stack4::p_Push10(c_Expr* t_value){ +void c_Stack5::p_Push13(c_Expr* t_value){ if(m_length==m_data.Length()){ m_data=m_data.Resize(m_length*2+10); } m_data[m_length]=t_value; m_length+=1; } -void c_Stack4::p_Push11(Array t_values,int t_offset,int t_count){ +void c_Stack5::p_Push14(Array t_values,int t_offset,int t_count){ for(int t_i=0;t_i t_values,int t_offset){ - p_Push11(t_values,t_offset,t_values.Length()-t_offset); +void c_Stack5::p_Push15(Array t_values,int t_offset){ + p_Push14(t_values,t_offset,t_values.Length()-t_offset); } -Array c_Stack4::p_ToArray(){ +Array c_Stack5::p_ToArray(){ Array t_t=Array(m_length); for(int t_i=0;t_ip_Decls()->p_ObjectEnumerator(); + c_Enumerator3* t_=m_scope->p_Decls()->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_Decl* t_decl=t_->p_NextObject(); if(m_ident.ToLower()==t_decl->m_ident.ToLower()){ @@ -14566,43 +28041,43 @@ int c_Stmt::p_Semant(){ void c_Stmt::mark(){ Object::mark(); } -c_List5::c_List5(){ - m__head=((new c_HeadNode5)->m_new()); +c_List7::c_List7(){ + m__head=((new c_HeadNode6)->m_new()); } -c_List5* c_List5::m_new(){ +c_List7* c_List7::m_new(){ return this; } -c_Node10* c_List5::p_AddLast5(c_Stmt* t_data){ - return (new c_Node10)->m_new(m__head,m__head->m__pred,t_data); +c_Node12* c_List7::p_AddLast7(c_Stmt* t_data){ + return (new c_Node12)->m_new(m__head,m__head->m__pred,t_data); } -c_List5* c_List5::m_new2(Array t_data){ +c_List7* c_List7::m_new2(Array t_data){ Array t_=t_data; int t_2=0; while(t_2m__succ==m__head; } -c_Enumerator5* c_List5::p_ObjectEnumerator(){ - return (new c_Enumerator5)->m_new(this); +c_Enumerator6* c_List7::p_ObjectEnumerator(){ + return (new c_Enumerator6)->m_new(this); } -c_Node10* c_List5::p_AddFirst(c_Stmt* t_data){ - return (new c_Node10)->m_new(m__head->m__succ,m__head,t_data); +c_Node12* c_List7::p_AddFirst(c_Stmt* t_data){ + return (new c_Node12)->m_new(m__head->m__succ,m__head,t_data); } -void c_List5::mark(){ +void c_List7::mark(){ Object::mark(); } -c_Node10::c_Node10(){ +c_Node12::c_Node12(){ m__succ=0; m__pred=0; m__data=0; } -c_Node10* c_Node10::m_new(c_Node10* t_succ,c_Node10* t_pred,c_Stmt* t_data){ +c_Node12* c_Node12::m_new(c_Node12* t_succ,c_Node12* t_pred,c_Stmt* t_data){ m__succ=t_succ; m__pred=t_pred; m__succ->m__pred=this; @@ -14610,22 +28085,22 @@ c_Node10* c_Node10::m_new(c_Node10* t_succ,c_Node10* t_pred,c_Stmt* t_data){ m__data=t_data; return this; } -c_Node10* c_Node10::m_new2(){ +c_Node12* c_Node12::m_new2(){ return this; } -void c_Node10::mark(){ +void c_Node12::mark(){ Object::mark(); } -c_HeadNode5::c_HeadNode5(){ +c_HeadNode6::c_HeadNode6(){ } -c_HeadNode5* c_HeadNode5::m_new(){ - c_Node10::m_new2(); +c_HeadNode6* c_HeadNode6::m_new(){ + c_Node12::m_new2(); m__succ=(this); m__pred=(this); return this; } -void c_HeadNode5::mark(){ - c_Node10::mark(); +void c_HeadNode6::mark(){ + c_Node12::mark(); } c_InvokeSuperExpr::c_InvokeSuperExpr(){ m_ident=String(); @@ -14721,6 +28196,99 @@ c_Expr* c_IdentTypeExpr::p_SemantFunc(Array t_args){ void c_IdentTypeExpr::mark(){ c_Expr::mark(); } +c_Node13::c_Node13(){ + m__succ=0; + m__pred=0; + m__data=0; +} +c_Node13* c_Node13::m_new(c_Node13* t_succ,c_Node13* t_pred,int t_data){ + m__succ=t_succ; + m__pred=t_pred; + m__succ->m__pred=this; + m__pred->m__succ=this; + m__data=t_data; + return this; +} +c_Node13* c_Node13::m_new2(){ + return this; +} +void c_Node13::mark(){ + Object::mark(); +} +c_HeadNode7::c_HeadNode7(){ +} +c_HeadNode7* c_HeadNode7::m_new(){ + c_Node13::m_new2(); + m__succ=(this); + m__pred=(this); + return this; +} +void c_HeadNode7::mark(){ + c_Node13::mark(); +} +c_Enumerator2::c_Enumerator2(){ + m__list=0; + m__curr=0; +} +c_Enumerator2* c_Enumerator2::m_new(c_List3* t_list){ + m__list=t_list; + m__curr=t_list->m__head->m__succ; + return this; +} +c_Enumerator2* c_Enumerator2::m_new2(){ + return this; +} +bool c_Enumerator2::p_HasNext(){ + while(m__curr->m__succ->m__pred!=m__curr){ + m__curr=m__curr->m__succ; + } + return m__curr!=m__list->m__head; +} +int c_Enumerator2::p_NextObject(){ + int t_data=m__curr->m__data; + m__curr=m__curr->m__succ; + return t_data; +} +void c_Enumerator2::mark(){ + Object::mark(); +} +c_MapKeys::c_MapKeys(){ + m_map=0; +} +c_MapKeys* c_MapKeys::m_new(c_Map6* t_map){ + this->m_map=t_map; + return this; +} +c_MapKeys* c_MapKeys::m_new2(){ + return this; +} +c_KeyEnumerator* c_MapKeys::p_ObjectEnumerator(){ + return (new c_KeyEnumerator)->m_new(m_map->p_FirstNode()); +} +void c_MapKeys::mark(){ + Object::mark(); +} +c_KeyEnumerator::c_KeyEnumerator(){ + m_node=0; +} +c_KeyEnumerator* c_KeyEnumerator::m_new(c_Node8* t_node){ + this->m_node=t_node; + return this; +} +c_KeyEnumerator* c_KeyEnumerator::m_new2(){ + return this; +} +bool c_KeyEnumerator::p_HasNext(){ + return m_node!=0; +} +int c_KeyEnumerator::p_NextObject(){ + c_Node8* t_t=m_node; + m_node=m_node->p_NextNode(); + return t_t->m_key; +} +void c_KeyEnumerator::mark(){ + Object::mark(); +} c_FuncCallExpr::c_FuncCallExpr(){ m_expr=0; m_args=Array(); @@ -15325,30 +28893,30 @@ c_Decl* c_LocalDecl::p_OnCopy(){ void c_LocalDecl::mark(){ c_VarDecl::mark(); } -c_Enumerator2::c_Enumerator2(){ +c_Enumerator3::c_Enumerator3(){ m__list=0; m__curr=0; } -c_Enumerator2* c_Enumerator2::m_new(c_List3* t_list){ +c_Enumerator3* c_Enumerator3::m_new(c_List5* t_list){ m__list=t_list; m__curr=t_list->m__head->m__succ; return this; } -c_Enumerator2* c_Enumerator2::m_new2(){ +c_Enumerator3* c_Enumerator3::m_new2(){ return this; } -bool c_Enumerator2::p_HasNext(){ +bool c_Enumerator3::p_HasNext(){ while(m__curr->m__succ->m__pred!=m__curr){ m__curr=m__curr->m__succ; } return m__curr!=m__list->m__head; } -c_Decl* c_Enumerator2::p_NextObject(){ +c_Decl* c_Enumerator3::p_NextObject(){ c_Decl* t_data=m__curr->m__data; m__curr=m__curr->m__succ; return t_data; } -void c_Enumerator2::mark(){ +void c_Enumerator3::mark(){ Object::mark(); } c_DeclStmt::c_DeclStmt(){ @@ -15382,41 +28950,41 @@ String c_DeclStmt::p_Trans(){ void c_DeclStmt::mark(){ c_Stmt::mark(); } -c_Stack5::c_Stack5(){ +c_Stack6::c_Stack6(){ m_data=Array(); m_length=0; } -c_Stack5* c_Stack5::m_new(){ +c_Stack6* c_Stack6::m_new(){ return this; } -c_Stack5* c_Stack5::m_new2(Array t_data){ +c_Stack6* c_Stack6::m_new2(Array t_data){ this->m_data=t_data.Slice(0); this->m_length=t_data.Length(); return this; } -void c_Stack5::p_Push13(c_IdentType* t_value){ +void c_Stack6::p_Push16(c_IdentType* t_value){ if(m_length==m_data.Length()){ m_data=m_data.Resize(m_length*2+10); } m_data[m_length]=t_value; m_length+=1; } -void c_Stack5::p_Push14(Array t_values,int t_offset,int t_count){ +void c_Stack6::p_Push17(Array t_values,int t_offset,int t_count){ for(int t_i=0;t_i t_values,int t_offset){ - p_Push14(t_values,t_offset,t_values.Length()-t_offset); +void c_Stack6::p_Push18(Array t_values,int t_offset){ + p_Push17(t_values,t_offset,t_values.Length()-t_offset); } -Array c_Stack5::p_ToArray(){ +Array c_Stack6::p_ToArray(){ Array t_t=Array(m_length); for(int t_i=0;t_im_new()); +c_List8::c_List8(){ + m__head=((new c_HeadNode8)->m_new()); } -c_List6* c_List6::m_new(){ +c_List8* c_List8::m_new(){ return this; } -c_Node11* c_List6::p_AddLast6(c_ClassDecl* t_data){ - return (new c_Node11)->m_new(m__head,m__head->m__pred,t_data); +c_Node14* c_List8::p_AddLast8(c_ClassDecl* t_data){ + return (new c_Node14)->m_new(m__head,m__head->m__pred,t_data); } -c_List6* c_List6::m_new2(Array t_data){ +c_List8* c_List8::m_new2(Array t_data){ Array t_=t_data; int t_2=0; while(t_2m_new(this); +c_Enumerator5* c_List8::p_ObjectEnumerator(){ + return (new c_Enumerator5)->m_new(this); } -void c_List6::mark(){ +void c_List8::mark(){ Object::mark(); } -c_Node11::c_Node11(){ +c_Node14::c_Node14(){ m__succ=0; m__pred=0; m__data=0; } -c_Node11* c_Node11::m_new(c_Node11* t_succ,c_Node11* t_pred,c_ClassDecl* t_data){ +c_Node14* c_Node14::m_new(c_Node14* t_succ,c_Node14* t_pred,c_ClassDecl* t_data){ m__succ=t_succ; m__pred=t_pred; m__succ->m__pred=this; @@ -15508,22 +29076,22 @@ c_Node11* c_Node11::m_new(c_Node11* t_succ,c_Node11* t_pred,c_ClassDecl* t_data) m__data=t_data; return this; } -c_Node11* c_Node11::m_new2(){ +c_Node14* c_Node14::m_new2(){ return this; } -void c_Node11::mark(){ +void c_Node14::mark(){ Object::mark(); } -c_HeadNode6::c_HeadNode6(){ +c_HeadNode8::c_HeadNode8(){ } -c_HeadNode6* c_HeadNode6::m_new(){ - c_Node11::m_new2(); +c_HeadNode8* c_HeadNode8::m_new(){ + c_Node14::m_new2(); m__succ=(this); m__pred=(this); return this; } -void c_HeadNode6::mark(){ - c_Node11::mark(); +void c_HeadNode8::mark(){ + c_Node14::mark(); } c_ArgDecl::c_ArgDecl(){ } @@ -15548,97 +29116,97 @@ c_Decl* c_ArgDecl::p_OnCopy(){ void c_ArgDecl::mark(){ c_LocalDecl::mark(); } -c_Stack6::c_Stack6(){ +c_Stack7::c_Stack7(){ m_data=Array(); m_length=0; } -c_Stack6* c_Stack6::m_new(){ +c_Stack7* c_Stack7::m_new(){ return this; } -c_Stack6* c_Stack6::m_new2(Array t_data){ +c_Stack7* c_Stack7::m_new2(Array t_data){ this->m_data=t_data.Slice(0); this->m_length=t_data.Length(); return this; } -void c_Stack6::p_Push16(c_ArgDecl* t_value){ +void c_Stack7::p_Push19(c_ArgDecl* t_value){ if(m_length==m_data.Length()){ m_data=m_data.Resize(m_length*2+10); } m_data[m_length]=t_value; m_length+=1; } -void c_Stack6::p_Push17(Array t_values,int t_offset,int t_count){ +void c_Stack7::p_Push20(Array t_values,int t_offset,int t_count){ for(int t_i=0;t_i t_values,int t_offset){ - p_Push17(t_values,t_offset,t_values.Length()-t_offset); +void c_Stack7::p_Push21(Array t_values,int t_offset){ + p_Push20(t_values,t_offset,t_values.Length()-t_offset); } -Array c_Stack6::p_ToArray(){ +Array c_Stack7::p_ToArray(){ Array t_t=Array(m_length); for(int t_i=0;t_im_new()); +c_List9::c_List9(){ + m__head=((new c_HeadNode9)->m_new()); } -c_List7* c_List7::m_new(){ +c_List9* c_List9::m_new(){ return this; } -c_Node12* c_List7::p_AddLast7(c_BlockDecl* t_data){ - return (new c_Node12)->m_new(m__head,m__head->m__pred,t_data); +c_Node15* c_List9::p_AddLast9(c_BlockDecl* t_data){ + return (new c_Node15)->m_new(m__head,m__head->m__pred,t_data); } -c_List7* c_List7::m_new2(Array t_data){ +c_List9* c_List9::m_new2(Array t_data){ Array t_=t_data; int t_2=0; while(t_2m__pred->m__data; m__head->m__pred->p_Remove(); return t_data; } -bool c_List7::p_Equals3(c_BlockDecl* t_lhs,c_BlockDecl* t_rhs){ +bool c_List9::p_Equals4(c_BlockDecl* t_lhs,c_BlockDecl* t_rhs){ return t_lhs==t_rhs; } -c_Node12* c_List7::p_FindLast5(c_BlockDecl* t_value,c_Node12* t_start){ +c_Node15* c_List9::p_FindLast7(c_BlockDecl* t_value,c_Node15* t_start){ while(t_start!=m__head){ - if(p_Equals3(t_value,t_start->m__data)){ + if(p_Equals4(t_value,t_start->m__data)){ return t_start; } t_start=t_start->m__pred; } return 0; } -c_Node12* c_List7::p_FindLast6(c_BlockDecl* t_value){ - return p_FindLast5(t_value,m__head->m__pred); +c_Node15* c_List9::p_FindLast8(c_BlockDecl* t_value){ + return p_FindLast7(t_value,m__head->m__pred); } -void c_List7::p_RemoveLast4(c_BlockDecl* t_value){ - c_Node12* t_node=p_FindLast6(t_value); +void c_List9::p_RemoveLast5(c_BlockDecl* t_value){ + c_Node15* t_node=p_FindLast8(t_value); if((t_node)!=0){ t_node->p_Remove(); } } -void c_List7::mark(){ +void c_List9::mark(){ Object::mark(); } -c_Node12::c_Node12(){ +c_Node15::c_Node15(){ m__succ=0; m__pred=0; m__data=0; } -c_Node12* c_Node12::m_new(c_Node12* t_succ,c_Node12* t_pred,c_BlockDecl* t_data){ +c_Node15* c_Node15::m_new(c_Node15* t_succ,c_Node15* t_pred,c_BlockDecl* t_data){ m__succ=t_succ; m__pred=t_pred; m__succ->m__pred=this; @@ -15646,27 +29214,27 @@ c_Node12* c_Node12::m_new(c_Node12* t_succ,c_Node12* t_pred,c_BlockDecl* t_data) m__data=t_data; return this; } -c_Node12* c_Node12::m_new2(){ +c_Node15* c_Node15::m_new2(){ return this; } -int c_Node12::p_Remove(){ +int c_Node15::p_Remove(){ m__succ->m__pred=m__pred; m__pred->m__succ=m__succ; return 0; } -void c_Node12::mark(){ +void c_Node15::mark(){ Object::mark(); } -c_HeadNode7::c_HeadNode7(){ +c_HeadNode9::c_HeadNode9(){ } -c_HeadNode7* c_HeadNode7::m_new(){ - c_Node12::m_new2(); +c_HeadNode9* c_HeadNode9::m_new(){ + c_Node15::m_new2(); m__succ=(this); m__pred=(this); return this; } -void c_HeadNode7::mark(){ - c_Node12::mark(); +void c_HeadNode9::mark(){ + c_Node15::mark(); } c_ReturnStmt::c_ReturnStmt(){ m_expr=0; @@ -16111,35 +29679,35 @@ String c_CatchStmt::p_Trans(){ void c_CatchStmt::mark(){ c_Stmt::mark(); } -c_Stack7::c_Stack7(){ +c_Stack8::c_Stack8(){ m_data=Array(); m_length=0; } -c_Stack7* c_Stack7::m_new(){ +c_Stack8* c_Stack8::m_new(){ return this; } -c_Stack7* c_Stack7::m_new2(Array t_data){ +c_Stack8* c_Stack8::m_new2(Array t_data){ this->m_data=t_data.Slice(0); this->m_length=t_data.Length(); return this; } -void c_Stack7::p_Push19(c_CatchStmt* t_value){ +void c_Stack8::p_Push22(c_CatchStmt* t_value){ if(m_length==m_data.Length()){ m_data=m_data.Resize(m_length*2+10); } m_data[m_length]=t_value; m_length+=1; } -void c_Stack7::p_Push20(Array t_values,int t_offset,int t_count){ +void c_Stack8::p_Push23(Array t_values,int t_offset,int t_count){ for(int t_i=0;t_i t_values,int t_offset){ - p_Push20(t_values,t_offset,t_values.Length()-t_offset); +void c_Stack8::p_Push24(Array t_values,int t_offset){ + p_Push23(t_values,t_offset,t_values.Length()-t_offset); } -c_CatchStmt* c_Stack7::m_NIL; -void c_Stack7::p_Length(int t_newlength){ +c_CatchStmt* c_Stack8::m_NIL; +void c_Stack8::p_Length(int t_newlength){ if(t_newlength c_Stack7::p_ToArray(){ +Array c_Stack8::p_ToArray(){ Array t_t=Array(m_length); for(int t_i=0;t_ip_ParseMain(); return t_parser->m__module; } -c_Enumerator3::c_Enumerator3(){ +c_Enumerator4::c_Enumerator4(){ m__list=0; m__curr=0; } -c_Enumerator3* c_Enumerator3::m_new(c_List4* t_list){ +c_Enumerator4* c_Enumerator4::m_new(c_List6* t_list){ m__list=t_list; m__curr=t_list->m__head->m__succ; return this; } -c_Enumerator3* c_Enumerator3::m_new2(){ +c_Enumerator4* c_Enumerator4::m_new2(){ return this; } -bool c_Enumerator3::p_HasNext(){ +bool c_Enumerator4::p_HasNext(){ while(m__curr->m__succ->m__pred!=m__curr){ m__curr=m__curr->m__succ; } return m__curr!=m__list->m__head; } -c_FuncDecl* c_Enumerator3::p_NextObject(){ +c_FuncDecl* c_Enumerator4::p_NextObject(){ c_FuncDecl* t_data=m__curr->m__data; m__curr=m__curr->m__succ; return t_data; } -void c_Enumerator3::mark(){ +void c_Enumerator4::mark(){ Object::mark(); } c_StringList* bb_config__errStack; @@ -16320,37 +29888,37 @@ int bb_config_PushErr(String t_errInfo){ bb_config__errInfo=t_errInfo; return 0; } -c_List8::c_List8(){ - m__head=((new c_HeadNode8)->m_new()); +c_List10::c_List10(){ + m__head=((new c_HeadNode10)->m_new()); } -c_List8* c_List8::m_new(){ +c_List10* c_List10::m_new(){ return this; } -c_Node13* c_List8::p_AddLast8(c_GlobalDecl* t_data){ - return (new c_Node13)->m_new(m__head,m__head->m__pred,t_data); +c_Node16* c_List10::p_AddLast10(c_GlobalDecl* t_data){ + return (new c_Node16)->m_new(m__head,m__head->m__pred,t_data); } -c_List8* c_List8::m_new2(Array t_data){ +c_List10* c_List10::m_new2(Array t_data){ Array t_=t_data; int t_2=0; while(t_2m_new(this); +c_Enumerator7* c_List10::p_ObjectEnumerator(){ + return (new c_Enumerator7)->m_new(this); } -void c_List8::mark(){ +void c_List10::mark(){ Object::mark(); } -c_Node13::c_Node13(){ +c_Node16::c_Node16(){ m__succ=0; m__pred=0; m__data=0; } -c_Node13* c_Node13::m_new(c_Node13* t_succ,c_Node13* t_pred,c_GlobalDecl* t_data){ +c_Node16* c_Node16::m_new(c_Node16* t_succ,c_Node16* t_pred,c_GlobalDecl* t_data){ m__succ=t_succ; m__pred=t_pred; m__succ->m__pred=this; @@ -16358,22 +29926,22 @@ c_Node13* c_Node13::m_new(c_Node13* t_succ,c_Node13* t_pred,c_GlobalDecl* t_data m__data=t_data; return this; } -c_Node13* c_Node13::m_new2(){ +c_Node16* c_Node16::m_new2(){ return this; } -void c_Node13::mark(){ +void c_Node16::mark(){ Object::mark(); } -c_HeadNode8::c_HeadNode8(){ +c_HeadNode10::c_HeadNode10(){ } -c_HeadNode8* c_HeadNode8::m_new(){ - c_Node13::m_new2(); +c_HeadNode10* c_HeadNode10::m_new(){ + c_Node16::m_new2(); m__succ=(this); m__pred=(this); return this; } -void c_HeadNode8::mark(){ - c_Node13::mark(); +void c_HeadNode10::mark(){ + c_Node16::mark(); } int bb_config_PopErr(){ bb_config__errInfo=bb_config__errStack->p_RemoveLast(); @@ -16444,6 +30012,9 @@ c_Expr* bb_preprocessor_EvalExpr(c_Toker* t_toker){ return t_expr; } bool bb_preprocessor_EvalBool(c_Toker* t_toker){ + if(c_Toker::m_Remarks()){ + return false; + } c_Expr* t_expr=bb_preprocessor_EvalExpr(t_toker); if(!((dynamic_cast(t_expr->m_exprType))!=0)){ t_expr=t_expr->p_Cast((c_Type::m_boolType),1); @@ -16482,6 +30053,8 @@ String bb_preprocessor_PreProcess(String t_path,c_ModuleDecl* t_mdecl){ int t_ifnest=0; int t_line=0; c_StringStack* t_source=(new c_StringStack)->m_new2(); + c_IntStack* t_tracknesting=(new c_IntStack)->m_new2(); + c_IntStack* t_trace=(new c_IntStack)->m_new2(); bb_decl_PushEnv(bb_config_GetConfigScope()); String t_p_cd=bb_config_GetConfigVar(String(L"CD",2)); String t_p_modpath=bb_config_GetConfigVar(String(L"MODPATH",7)); @@ -16572,7 +30145,12 @@ String bb_preprocessor_PreProcess(String t_path,c_ModuleDecl* t_mdecl){ } String t_2=t_stm; if(t_2==String(L"rem",3)){ - t_ifnest+=1; + if(!c_Toker::m_Remarks()){ + c_Toker::m_RemarksOn(); + t_ifnest+=1; + t_tracknesting->p_Push7(t_line); + t_trace->p_Push7(t_line); + } }else{ if(t_2==String(L"if",2)){ t_ifnest+=1; @@ -16581,6 +30159,8 @@ String bb_preprocessor_PreProcess(String t_path,c_ModuleDecl* t_mdecl){ t_cnest=t_ifnest; } } + t_tracknesting->p_Push7(t_line); + t_trace->p_Push7(t_line); }else{ if(t_2==String(L"else",4)){ if(!((t_ifnest)!=0)){ @@ -16593,6 +30173,7 @@ String bb_preprocessor_PreProcess(String t_path,c_ModuleDecl* t_mdecl){ t_cnest=t_ifnest; } } + t_trace->p_Push7(t_line); }else{ if(t_2==String(L"elseif",6)){ if(!((t_ifnest)!=0)){ @@ -16607,6 +30188,7 @@ String bb_preprocessor_PreProcess(String t_path,c_ModuleDecl* t_mdecl){ } } } + t_trace->p_Push7(t_line); }else{ if(t_2==String(L"end",3) || t_2==String(L"endif",5)){ if(!((t_ifnest)!=0)){ @@ -16616,6 +30198,12 @@ String bb_preprocessor_PreProcess(String t_path,c_ModuleDecl* t_mdecl){ if(t_ifnest<(t_cnest&65535)){ t_cnest=t_ifnest; } + if(!t_tracknesting->p_IsEmpty()){ + t_tracknesting->p_Pop(); + } + if(c_Toker::m_Remarks()){ + c_Toker::m_RemarksOff(); + } }else{ if(t_2==String(L"print",5)){ if(t_cnest==t_ifnest){ @@ -16682,6 +30270,29 @@ String bb_preprocessor_PreProcess(String t_path,c_ModuleDecl* t_mdecl){ } } }while(!(false)); + if(t_toker->p_TokeType()==0){ + if(!t_tracknesting->p_IsEmpty()){ + if(!t_trace->p_IsEmpty()){ + bbPrint(String(L"\t\t-------------- Preprocessor Trace Log --------------",54)); + String t_s=String(L" : Starts here.....",19); + for(int t_i=0;t_ip_Length2()-1;t_i=t_i+1){ + if(t_i>0){ + t_s=String(); + } + bbPrint(bb_config__errInfo.Slice(0,bb_config__errInfo.FindLast(String(L"<",1))+1)+String(t_trace->p_Get2(t_i))+String(L">",1)+t_s); + } + bbPrint(String()); + } + if(t_trace->p_IsEmpty()){ + bb_config__errInfo=bb_config__errInfo.Slice(0,bb_config__errInfo.FindLast(String(L"<",1)))+String(L"<",1)+String(t_tracknesting->p_Pop())+String(L">",1); + }else{ + bb_config__errInfo=bb_config__errInfo.Slice(0,bb_config__errInfo.FindLast(String(L"<",1)))+String(L"<",1)+String(t_trace->p_Pop())+String(L">",1); + } + bb_config_Err(String(L"End of file reached. Preprocessor Conditional or Remark block preprocess not closed.",84)); + } + t_trace->p_Clear(); + t_tracknesting->p_Clear(); + } bb_config_SetConfigVar2(String(L"MODPATH",7),t_p_modpath); bb_config_SetConfigVar2(String(L"CD",2),t_p_cd); bb_decl_PopEnv(); @@ -16706,14 +30317,14 @@ c_Target* c_Target::m_new2(){ void c_Target::mark(){ Object::mark(); } -c_Map6::c_Map6(){ +c_Map7::c_Map7(){ m_root=0; } -c_Map6* c_Map6::m_new(){ +c_Map7* c_Map7::m_new(){ return this; } -int c_Map6::p_RotateLeft6(c_Node14* t_node){ - c_Node14* t_child=t_node->m_right; +int c_Map7::p_RotateLeft7(c_Node17* t_node){ + c_Node17* t_child=t_node->m_right; t_node->m_right=t_child->m_left; if((t_child->m_left)!=0){ t_child->m_left->m_parent=t_node; @@ -16732,8 +30343,8 @@ int c_Map6::p_RotateLeft6(c_Node14* t_node){ t_node->m_parent=t_child; return 0; } -int c_Map6::p_RotateRight6(c_Node14* t_node){ - c_Node14* t_child=t_node->m_left; +int c_Map7::p_RotateRight7(c_Node17* t_node){ + c_Node17* t_child=t_node->m_left; t_node->m_left=t_child->m_right; if((t_child->m_right)!=0){ t_child->m_right->m_parent=t_node; @@ -16752,10 +30363,10 @@ int c_Map6::p_RotateRight6(c_Node14* t_node){ t_node->m_parent=t_child; return 0; } -int c_Map6::p_InsertFixup6(c_Node14* t_node){ +int c_Map7::p_InsertFixup7(c_Node17* t_node){ while(((t_node->m_parent)!=0) && t_node->m_parent->m_color==-1 && ((t_node->m_parent->m_parent)!=0)){ if(t_node->m_parent==t_node->m_parent->m_parent->m_left){ - c_Node14* t_uncle=t_node->m_parent->m_parent->m_right; + c_Node17* t_uncle=t_node->m_parent->m_parent->m_right; if(((t_uncle)!=0) && t_uncle->m_color==-1){ t_node->m_parent->m_color=1; t_uncle->m_color=1; @@ -16764,14 +30375,14 @@ int c_Map6::p_InsertFixup6(c_Node14* t_node){ }else{ if(t_node==t_node->m_parent->m_right){ t_node=t_node->m_parent; - p_RotateLeft6(t_node); + p_RotateLeft7(t_node); } t_node->m_parent->m_color=1; t_node->m_parent->m_parent->m_color=-1; - p_RotateRight6(t_node->m_parent->m_parent); + p_RotateRight7(t_node->m_parent->m_parent); } }else{ - c_Node14* t_uncle2=t_node->m_parent->m_parent->m_left; + c_Node17* t_uncle2=t_node->m_parent->m_parent->m_left; if(((t_uncle2)!=0) && t_uncle2->m_color==-1){ t_node->m_parent->m_color=1; t_uncle2->m_color=1; @@ -16780,20 +30391,20 @@ int c_Map6::p_InsertFixup6(c_Node14* t_node){ }else{ if(t_node==t_node->m_parent->m_left){ t_node=t_node->m_parent; - p_RotateRight6(t_node); + p_RotateRight7(t_node); } t_node->m_parent->m_color=1; t_node->m_parent->m_parent->m_color=-1; - p_RotateLeft6(t_node->m_parent->m_parent); + p_RotateLeft7(t_node->m_parent->m_parent); } } } m_root->m_color=1; return 0; } -bool c_Map6::p_Set6(String t_key,c_Target* t_value){ - c_Node14* t_node=m_root; - c_Node14* t_parent=0; +bool c_Map7::p_Set6(String t_key,c_Target* t_value){ + c_Node17* t_node=m_root; + c_Node17* t_parent=0; int t_cmp=0; while((t_node)!=0){ t_parent=t_node; @@ -16809,34 +30420,34 @@ bool c_Map6::p_Set6(String t_key,c_Target* t_value){ } } } - t_node=(new c_Node14)->m_new(t_key,t_value,-1,t_parent); + t_node=(new c_Node17)->m_new(t_key,t_value,-1,t_parent); if((t_parent)!=0){ if(t_cmp>0){ t_parent->m_right=t_node; }else{ t_parent->m_left=t_node; } - p_InsertFixup6(t_node); + p_InsertFixup7(t_node); }else{ m_root=t_node; } return true; } -c_Node14* c_Map6::p_FirstNode(){ +c_Node17* c_Map7::p_FirstNode(){ if(!((m_root)!=0)){ return 0; } - c_Node14* t_node=m_root; + c_Node17* t_node=m_root; while((t_node->m_left)!=0){ t_node=t_node->m_left; } return t_node; } -c_NodeEnumerator2* c_Map6::p_ObjectEnumerator(){ +c_NodeEnumerator2* c_Map7::p_ObjectEnumerator(){ return (new c_NodeEnumerator2)->m_new(p_FirstNode()); } -c_Node14* c_Map6::p_FindNode(String t_key){ - c_Node14* t_node=m_root; +c_Node17* c_Map7::p_FindNode(String t_key){ + c_Node17* t_node=m_root; while((t_node)!=0){ int t_cmp=p_Compare(t_key,t_node->m_key); if(t_cmp>0){ @@ -16851,29 +30462,29 @@ c_Node14* c_Map6::p_FindNode(String t_key){ } return t_node; } -c_Target* c_Map6::p_Get(String t_key){ - c_Node14* t_node=p_FindNode(t_key); +c_Target* c_Map7::p_Get(String t_key){ + c_Node17* t_node=p_FindNode(t_key); if((t_node)!=0){ return t_node->m_value; } return 0; } -void c_Map6::mark(){ +void c_Map7::mark(){ Object::mark(); } c_StringMap6::c_StringMap6(){ } c_StringMap6* c_StringMap6::m_new(){ - c_Map6::m_new(); + c_Map7::m_new(); return this; } int c_StringMap6::p_Compare(String t_lhs,String t_rhs){ return t_lhs.Compare(t_rhs); } void c_StringMap6::mark(){ - c_Map6::mark(); + c_Map7::mark(); } -c_Node14::c_Node14(){ +c_Node17::c_Node17(){ m_key=String(); m_right=0; m_left=0; @@ -16881,18 +30492,18 @@ c_Node14::c_Node14(){ m_color=0; m_parent=0; } -c_Node14* c_Node14::m_new(String t_key,c_Target* t_value,int t_color,c_Node14* t_parent){ +c_Node17* c_Node17::m_new(String t_key,c_Target* t_value,int t_color,c_Node17* t_parent){ this->m_key=t_key; this->m_value=t_value; this->m_color=t_color; this->m_parent=t_parent; return this; } -c_Node14* c_Node14::m_new2(){ +c_Node17* c_Node17::m_new2(){ return this; } -c_Node14* c_Node14::p_NextNode(){ - c_Node14* t_node=0; +c_Node17* c_Node17::p_NextNode(){ + c_Node17* t_node=0; if((m_right)!=0){ t_node=m_right; while((t_node->m_left)!=0){ @@ -16901,17 +30512,17 @@ c_Node14* c_Node14::p_NextNode(){ return t_node; } t_node=this; - c_Node14* t_parent=this->m_parent; + c_Node17* t_parent=this->m_parent; while(((t_parent)!=0) && t_node==t_parent->m_right){ t_node=t_parent; t_parent=t_parent->m_parent; } return t_parent; } -String c_Node14::p_Key(){ +String c_Node17::p_Key(){ return m_key; } -void c_Node14::mark(){ +void c_Node17::mark(){ Object::mark(); } void bb_config_PopConfigScope(){ @@ -16920,7 +30531,7 @@ void bb_config_PopConfigScope(){ c_NodeEnumerator2::c_NodeEnumerator2(){ m_node=0; } -c_NodeEnumerator2* c_NodeEnumerator2::m_new(c_Node14* t_node){ +c_NodeEnumerator2* c_NodeEnumerator2::m_new(c_Node17* t_node){ this->m_node=t_node; return this; } @@ -16930,8 +30541,8 @@ c_NodeEnumerator2* c_NodeEnumerator2::m_new2(){ bool c_NodeEnumerator2::p_HasNext(){ return m_node!=0; } -c_Node14* c_NodeEnumerator2::p_NextObject(){ - c_Node14* t_t=m_node; +c_Node17* c_NodeEnumerator2::p_NextObject(){ + c_Node17* t_t=m_node; m_node=m_node->p_NextNode(); return t_t; } @@ -16960,7 +30571,7 @@ c_Reflector::c_Reflector(){ m_munged=(new c_StringMap7)->m_new(); m_modexprs=(new c_StringMap2)->m_new(); m_refmods=(new c_StringSet)->m_new(); - m_classdecls=(new c_Stack8)->m_new(); + m_classdecls=(new c_Stack9)->m_new(); m_classids=(new c_StringMap7)->m_new(); m_output=(new c_StringStack)->m_new2(); } @@ -17165,7 +30776,7 @@ String c_Reflector::p_TypeInfo(c_Type* t_ty){ } c_Type* t_[]={t_elemType}; c_ClassDecl* t_cdecl=m_boxesmod->p_FindType(String(L"ArrayObject",11),Array(t_,1))->p_GetClass(); - c_Enumerator2* t_2=t_cdecl->p_Decls()->p_ObjectEnumerator(); + c_Enumerator3* t_2=t_cdecl->p_Decls()->p_ObjectEnumerator(); while(t_2->p_HasNext()){ c_Decl* t_decl=t_2->p_NextObject(); if(!((dynamic_cast(t_decl))!=0)){ @@ -17174,7 +30785,7 @@ String c_Reflector::p_TypeInfo(c_Type* t_ty){ } int t_id=m_classdecls->p_Length2(); m_classids->p_Set7(t_name,t_id); - m_classdecls->p_Push22(t_cdecl); + m_classdecls->p_Push25(t_cdecl); return String(L"_classes[",9)+String(t_id)+String(L"]",1); } if((dynamic_cast(t_ty))!=0){ @@ -17274,7 +30885,7 @@ String c_Reflector::p_Emit3(c_ClassDecl* t_cdecl){ c_StringStack* t_methods=(new c_StringStack)->m_new2(); c_StringStack* t_functions=(new c_StringStack)->m_new2(); c_StringStack* t_ctors=(new c_StringStack)->m_new2(); - c_Enumerator2* t_3=t_cdecl->p_Decls()->p_ObjectEnumerator(); + c_Enumerator3* t_3=t_cdecl->p_Decls()->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_Decl* t_decl=t_3->p_NextObject(); if((dynamic_cast(t_decl))!=0){ @@ -17577,7 +31188,7 @@ int c_Reflector::p_Semant3(c_AppDecl* t_app){ bbPrint(String(L"Semanting more: ",16)+String(t_n)); } }while(!(false)); - c_Enumerator2* t_4=t_app->m_allSemantedDecls->p_ObjectEnumerator(); + c_Enumerator3* t_4=t_app->m_allSemantedDecls->p_ObjectEnumerator(); while(t_4->p_HasNext()){ c_Decl* t_decl=t_4->p_NextObject(); if(!m_refmods->p_Contains(t_decl->p_ModuleScope()->m_filepath)){ @@ -17586,7 +31197,7 @@ int c_Reflector::p_Semant3(c_AppDecl* t_app){ c_ClassDecl* t_cdecl=dynamic_cast(t_decl); if(((t_cdecl)!=0) && p_ValidClass(t_cdecl)){ m_classids->p_Set7(p_DeclExpr((t_cdecl),true),m_classdecls->p_Length2()); - m_classdecls->p_Push22(t_cdecl); + m_classdecls->p_Push25(t_cdecl); continue; } } @@ -17597,7 +31208,7 @@ int c_Reflector::p_Semant3(c_AppDecl* t_app){ if(m_debug){ bbPrint(String(L"Generating reflection info",26)); } - c_Enumerator2* t_5=t_app->m_allSemantedDecls->p_ObjectEnumerator(); + c_Enumerator3* t_5=t_app->m_allSemantedDecls->p_ObjectEnumerator(); while(t_5->p_HasNext()){ c_Decl* t_decl2=t_5->p_NextObject(); if(!m_refmods->p_Contains(t_decl2->p_ModuleScope()->m_filepath)){ @@ -17678,7 +31289,7 @@ int c_Reflector::p_Semant3(c_AppDecl* t_app){ p_Emit(String(L" Return _unknownClass",22)); p_Emit(String(L" End",4)); p_Emit(String(L"End",3)); - String t_source=m_output->p_Join(String(L"\n",1)); + String t_source=m_output->p_Join(String(L"\n",1))+String(L"\n",1); int t_attrs=8388608; if(m_debug){ bbPrint(String(L"Reflection source:\n",19)+t_source); @@ -17730,14 +31341,14 @@ c_ModuleDecl* c_ValueEnumerator::p_NextObject(){ void c_ValueEnumerator::mark(){ Object::mark(); } -c_Map7::c_Map7(){ +c_Map8::c_Map8(){ m_root=0; } -c_Map7* c_Map7::m_new(){ +c_Map8* c_Map8::m_new(){ return this; } -c_Node15* c_Map7::p_FindNode(String t_key){ - c_Node15* t_node=m_root; +c_Node18* c_Map8::p_FindNode(String t_key){ + c_Node18* t_node=m_root; while((t_node)!=0){ int t_cmp=p_Compare(t_key,t_node->m_key); if(t_cmp>0){ @@ -17752,18 +31363,18 @@ c_Node15* c_Map7::p_FindNode(String t_key){ } return t_node; } -bool c_Map7::p_Contains(String t_key){ +bool c_Map8::p_Contains(String t_key){ return p_FindNode(t_key)!=0; } -int c_Map7::p_Get(String t_key){ - c_Node15* t_node=p_FindNode(t_key); +int c_Map8::p_Get(String t_key){ + c_Node18* t_node=p_FindNode(t_key); if((t_node)!=0){ return t_node->m_value; } return 0; } -int c_Map7::p_RotateLeft7(c_Node15* t_node){ - c_Node15* t_child=t_node->m_right; +int c_Map8::p_RotateLeft8(c_Node18* t_node){ + c_Node18* t_child=t_node->m_right; t_node->m_right=t_child->m_left; if((t_child->m_left)!=0){ t_child->m_left->m_parent=t_node; @@ -17782,8 +31393,8 @@ int c_Map7::p_RotateLeft7(c_Node15* t_node){ t_node->m_parent=t_child; return 0; } -int c_Map7::p_RotateRight7(c_Node15* t_node){ - c_Node15* t_child=t_node->m_left; +int c_Map8::p_RotateRight8(c_Node18* t_node){ + c_Node18* t_child=t_node->m_left; t_node->m_left=t_child->m_right; if((t_child->m_right)!=0){ t_child->m_right->m_parent=t_node; @@ -17802,10 +31413,10 @@ int c_Map7::p_RotateRight7(c_Node15* t_node){ t_node->m_parent=t_child; return 0; } -int c_Map7::p_InsertFixup7(c_Node15* t_node){ +int c_Map8::p_InsertFixup8(c_Node18* t_node){ while(((t_node->m_parent)!=0) && t_node->m_parent->m_color==-1 && ((t_node->m_parent->m_parent)!=0)){ if(t_node->m_parent==t_node->m_parent->m_parent->m_left){ - c_Node15* t_uncle=t_node->m_parent->m_parent->m_right; + c_Node18* t_uncle=t_node->m_parent->m_parent->m_right; if(((t_uncle)!=0) && t_uncle->m_color==-1){ t_node->m_parent->m_color=1; t_uncle->m_color=1; @@ -17814,14 +31425,14 @@ int c_Map7::p_InsertFixup7(c_Node15* t_node){ }else{ if(t_node==t_node->m_parent->m_right){ t_node=t_node->m_parent; - p_RotateLeft7(t_node); + p_RotateLeft8(t_node); } t_node->m_parent->m_color=1; t_node->m_parent->m_parent->m_color=-1; - p_RotateRight7(t_node->m_parent->m_parent); + p_RotateRight8(t_node->m_parent->m_parent); } }else{ - c_Node15* t_uncle2=t_node->m_parent->m_parent->m_left; + c_Node18* t_uncle2=t_node->m_parent->m_parent->m_left; if(((t_uncle2)!=0) && t_uncle2->m_color==-1){ t_node->m_parent->m_color=1; t_uncle2->m_color=1; @@ -17830,20 +31441,20 @@ int c_Map7::p_InsertFixup7(c_Node15* t_node){ }else{ if(t_node==t_node->m_parent->m_left){ t_node=t_node->m_parent; - p_RotateRight7(t_node); + p_RotateRight8(t_node); } t_node->m_parent->m_color=1; t_node->m_parent->m_parent->m_color=-1; - p_RotateLeft7(t_node->m_parent->m_parent); + p_RotateLeft8(t_node->m_parent->m_parent); } } } m_root->m_color=1; return 0; } -bool c_Map7::p_Set7(String t_key,int t_value){ - c_Node15* t_node=m_root; - c_Node15* t_parent=0; +bool c_Map8::p_Set7(String t_key,int t_value){ + c_Node18* t_node=m_root; + c_Node18* t_parent=0; int t_cmp=0; while((t_node)!=0){ t_parent=t_node; @@ -17859,35 +31470,35 @@ bool c_Map7::p_Set7(String t_key,int t_value){ } } } - t_node=(new c_Node15)->m_new(t_key,t_value,-1,t_parent); + t_node=(new c_Node18)->m_new(t_key,t_value,-1,t_parent); if((t_parent)!=0){ if(t_cmp>0){ t_parent->m_right=t_node; }else{ t_parent->m_left=t_node; } - p_InsertFixup7(t_node); + p_InsertFixup8(t_node); }else{ m_root=t_node; } return true; } -void c_Map7::mark(){ +void c_Map8::mark(){ Object::mark(); } c_StringMap7::c_StringMap7(){ } c_StringMap7* c_StringMap7::m_new(){ - c_Map7::m_new(); + c_Map8::m_new(); return this; } int c_StringMap7::p_Compare(String t_lhs,String t_rhs){ return t_lhs.Compare(t_rhs); } void c_StringMap7::mark(){ - c_Map7::mark(); + c_Map8::mark(); } -c_Node15::c_Node15(){ +c_Node18::c_Node18(){ m_key=String(); m_right=0; m_left=0; @@ -17895,59 +31506,59 @@ c_Node15::c_Node15(){ m_color=0; m_parent=0; } -c_Node15* c_Node15::m_new(String t_key,int t_value,int t_color,c_Node15* t_parent){ +c_Node18* c_Node18::m_new(String t_key,int t_value,int t_color,c_Node18* t_parent){ this->m_key=t_key; this->m_value=t_value; this->m_color=t_color; this->m_parent=t_parent; return this; } -c_Node15* c_Node15::m_new2(){ +c_Node18* c_Node18::m_new2(){ return this; } -void c_Node15::mark(){ +void c_Node18::mark(){ Object::mark(); } -c_Enumerator4::c_Enumerator4(){ +c_Enumerator5::c_Enumerator5(){ m__list=0; m__curr=0; } -c_Enumerator4* c_Enumerator4::m_new(c_List6* t_list){ +c_Enumerator5* c_Enumerator5::m_new(c_List8* t_list){ m__list=t_list; m__curr=t_list->m__head->m__succ; return this; } -c_Enumerator4* c_Enumerator4::m_new2(){ +c_Enumerator5* c_Enumerator5::m_new2(){ return this; } -bool c_Enumerator4::p_HasNext(){ +bool c_Enumerator5::p_HasNext(){ while(m__curr->m__succ->m__pred!=m__curr){ m__curr=m__curr->m__succ; } return m__curr!=m__list->m__head; } -c_ClassDecl* c_Enumerator4::p_NextObject(){ +c_ClassDecl* c_Enumerator5::p_NextObject(){ c_ClassDecl* t_data=m__curr->m__data; m__curr=m__curr->m__succ; return t_data; } -void c_Enumerator4::mark(){ +void c_Enumerator5::mark(){ Object::mark(); } -c_Stack8::c_Stack8(){ +c_Stack9::c_Stack9(){ m_data=Array(); m_length=0; } -c_Stack8* c_Stack8::m_new(){ +c_Stack9* c_Stack9::m_new(){ return this; } -c_Stack8* c_Stack8::m_new2(Array t_data){ +c_Stack9* c_Stack9::m_new2(Array t_data){ this->m_data=t_data.Slice(0); this->m_length=t_data.Length(); return this; } -c_ClassDecl* c_Stack8::m_NIL; -void c_Stack8::p_Length(int t_newlength){ +c_ClassDecl* c_Stack9::m_NIL; +void c_Stack9::p_Length(int t_newlength){ if(t_newlength t_values,int t_offset,int t_count){ +void c_Stack9::p_Push26(Array t_values,int t_offset,int t_count){ for(int t_i=0;t_i t_values,int t_offset){ - p_Push23(t_values,t_offset,t_values.Length()-t_offset); +void c_Stack9::p_Push27(Array t_values,int t_offset){ + p_Push26(t_values,t_offset,t_values.Length()-t_offset); } -c_ClassDecl* c_Stack8::p_Get2(int t_index){ +c_ClassDecl* c_Stack9::p_Get2(int t_index){ return m_data[t_index]; } -void c_Stack8::mark(){ +void c_Stack9::mark(){ Object::mark(); } int bb_parser_ParseSource(String t_source,c_AppDecl* t_app,c_ModuleDecl* t_mdecl,int t_defattrs){ @@ -18101,7 +31712,7 @@ int c_CTranslator::p_MungMethodDecl(c_FuncDecl* t_fdecl){ } c_FuncDeclList* t_funcs=m_funcMungs->p_Get(t_fdecl->m_ident); if((t_funcs)!=0){ - c_Enumerator3* t_=t_funcs->p_ObjectEnumerator(); + c_Enumerator4* t_=t_funcs->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_FuncDecl* t_tdecl=t_->p_NextObject(); if(t_fdecl->p_EqualsArgs(t_tdecl)){ @@ -18123,7 +31734,7 @@ int c_CTranslator::p_MungMethodDecl(c_FuncDecl* t_fdecl){ } m_mungedFuncs->p_Set9(t_id,t_fdecl); t_fdecl->m_munged=String(L"p_",2)+t_id; - t_funcs->p_AddLast4(t_fdecl); + t_funcs->p_AddLast6(t_fdecl); return 0; } int c_CTranslator::p_MungDecl(c_Decl* t_decl){ @@ -18277,7 +31888,7 @@ int c_CTranslator::p_EmitBlock(c_BlockDecl* t_block,bool t_realBlock){ } } c_Stmt* t_lastStmt=0; - c_Enumerator5* t_=t_block->m_stmts->p_ObjectEnumerator(); + c_Enumerator6* t_=t_block->m_stmts->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_Stmt* t_stmt=t_->p_NextObject(); bb_config__errInfo=t_stmt->m_errInfo; @@ -18836,7 +32447,7 @@ int c_JavaTranslator::p_EmitClassDecl(c_ClassDecl* t_classDecl){ t_bases=t_bases+t_iface->m_munged; } p_Emit(String(L"interface ",10)+t_classid+t_bases+String(L"{",1)); - c_Enumerator2* t_3=t_classDecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_3=t_classDecl->p_Semanted()->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_Decl* t_decl=t_3->p_NextObject(); c_FuncDecl* t_fdecl=dynamic_cast(t_decl); @@ -18870,7 +32481,7 @@ int c_JavaTranslator::p_EmitClassDecl(c_ClassDecl* t_classDecl){ } } p_Emit(t_q+String(L"class ",6)+t_classid+String(L" extends ",9)+t_superid+t_bases2+String(L"{",1)); - c_Enumerator2* t_6=t_classDecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_6=t_classDecl->p_Semanted()->p_ObjectEnumerator(); while(t_6->p_HasNext()){ c_Decl* t_decl2=t_6->p_NextObject(); c_FieldDecl* t_tdecl=dynamic_cast(t_decl2); @@ -18923,7 +32534,7 @@ String c_JavaTranslator::p_TransApp(c_AppDecl* t_app){ c_ModuleDecl* t_decl=t_->p_NextObject(); p_MungDecl(t_decl); } - c_Enumerator2* t_2=t_app->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_2=t_app->p_Semanted()->p_ObjectEnumerator(); while(t_2->p_HasNext()){ c_Decl* t_decl2=t_2->p_NextObject(); p_MungDecl(t_decl2); @@ -18931,7 +32542,7 @@ String c_JavaTranslator::p_TransApp(c_AppDecl* t_app){ if(!((t_cdecl)!=0)){ continue; } - c_Enumerator2* t_3=t_cdecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_3=t_cdecl->p_Semanted()->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_Decl* t_decl3=t_3->p_NextObject(); if(((dynamic_cast(t_decl3))!=0) && dynamic_cast(t_decl3)->p_IsCtor()){ @@ -18940,7 +32551,7 @@ String c_JavaTranslator::p_TransApp(c_AppDecl* t_app){ p_MungDecl(t_decl3); } } - c_Enumerator2* t_4=t_app->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_4=t_app->p_Semanted()->p_ObjectEnumerator(); while(t_4->p_HasNext()){ c_Decl* t_decl4=t_4->p_NextObject(); c_ClassDecl* t_cdecl2=dynamic_cast(t_decl4); @@ -18952,7 +32563,7 @@ String c_JavaTranslator::p_TransApp(c_AppDecl* t_app){ while(t_5->p_HasNext()){ c_ModuleDecl* t_mdecl=t_5->p_NextObject(); p_Emit(String(L"class ",6)+t_mdecl->m_munged+String(L"{",1)); - c_Enumerator2* t_6=t_mdecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_6=t_mdecl->p_Semanted()->p_ObjectEnumerator(); while(t_6->p_HasNext()){ c_Decl* t_decl5=t_6->p_NextObject(); if(((t_decl5->p_IsExtern())!=0) || ((t_decl5->m_scope->p_ClassScope())!=0)){ @@ -18972,7 +32583,7 @@ String c_JavaTranslator::p_TransApp(c_AppDecl* t_app){ if(t_mdecl==t_app->m_mainModule){ p_BeginLocalScope(); p_Emit(String(L"public static int bbInit(){",27)); - c_Enumerator6* t_7=t_app->m_semantedGlobals->p_ObjectEnumerator(); + c_Enumerator7* t_7=t_app->m_semantedGlobals->p_ObjectEnumerator(); while(t_7->p_HasNext()){ c_GlobalDecl* t_decl6=t_7->p_NextObject(); p_Emit(p_TransGlobal(t_decl6)+String(L"=",1)+t_decl6->m_init->p_Trans()+String(L";",1)); @@ -19588,7 +33199,7 @@ String bb_config_Enquote(String t_str,String t_lang){ c_CppTranslator::c_CppTranslator(){ m_unsafe=false; m_gc_mode=0; - m_dbgLocals=(new c_Stack9)->m_new(); + m_dbgLocals=(new c_Stack10)->m_new(); m_lastDbgInfo=String(); m_pure=0; } @@ -19743,7 +33354,7 @@ int c_CppTranslator::p_EmitSetErr(String t_info){ return 0; } m_lastDbgInfo=t_info; - c_Enumerator7* t_=m_dbgLocals->p_ObjectEnumerator(); + c_Enumerator8* t_=m_dbgLocals->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_LocalDecl* t_decl=t_->p_NextObject(); if(((t_decl->m_ident).Length()!=0) && p_IsDebuggable(t_decl->m_type)){ @@ -19829,7 +33440,7 @@ int c_CppTranslator::p_EmitClassProto(c_ClassDecl* t_classDecl){ } p_Emit(String(L"class ",6)+t_classid+t_bases+String(L"{",1)); p_Emit(String(L"public:",7)); - c_Enumerator2* t_3=t_classDecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_3=t_classDecl->p_Semanted()->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_Decl* t_decl=t_3->p_NextObject(); c_FuncDecl* t_fdecl=dynamic_cast(t_decl); @@ -19851,7 +33462,7 @@ int c_CppTranslator::p_EmitClassProto(c_ClassDecl* t_classDecl){ } p_Emit(String(L"class ",6)+t_classid+t_bases2+String(L"{",1)); p_Emit(String(L"public:",7)); - c_Enumerator2* t_6=t_classDecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_6=t_classDecl->p_Semanted()->p_ObjectEnumerator(); while(t_6->p_HasNext()){ c_Decl* t_decl2=t_6->p_NextObject(); c_FieldDecl* t_fdecl2=dynamic_cast(t_decl2); @@ -19861,7 +33472,7 @@ int c_CppTranslator::p_EmitClassProto(c_ClassDecl* t_classDecl){ } } p_Emit(t_classid+String(L"();",3)); - c_Enumerator2* t_7=t_classDecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_7=t_classDecl->p_Semanted()->p_ObjectEnumerator(); while(t_7->p_HasNext()){ c_Decl* t_decl3=t_7->p_NextObject(); c_FuncDecl* t_fdecl3=dynamic_cast(t_decl3); @@ -19915,7 +33526,7 @@ int c_CppTranslator::p_EmitFuncDecl(c_FuncDecl* t_decl){ t_args=t_args+String(L",",1); } t_args=t_args+(p_TransType(t_arg->m_type)+String(L" ",1)+t_arg->m_munged); - m_dbgLocals->p_Push25(t_arg); + m_dbgLocals->p_Push28(t_arg); } String t_id=t_decl->m_munged; if((t_decl->p_ClassScope())!=0){ @@ -19964,7 +33575,7 @@ int c_CppTranslator::p_EmitClassDecl(c_ClassDecl* t_classDecl){ if(m_gc_mode==2){ p_Emit(String(L"GC_CTOR",7)); } - c_Enumerator2* t_=t_classDecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_=t_classDecl->p_Semanted()->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_Decl* t_decl=t_->p_NextObject(); c_FieldDecl* t_fdecl=dynamic_cast(t_decl); @@ -19975,7 +33586,7 @@ int c_CppTranslator::p_EmitClassDecl(c_ClassDecl* t_classDecl){ } p_Emit(String(L"}",1)); p_EndLocalScope(); - c_Enumerator2* t_2=t_classDecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_2=t_classDecl->p_Semanted()->p_ObjectEnumerator(); while(t_2->p_HasNext()){ c_Decl* t_decl2=t_2->p_NextObject(); c_FuncDecl* t_fdecl2=dynamic_cast(t_decl2); @@ -19993,7 +33604,7 @@ int c_CppTranslator::p_EmitClassDecl(c_ClassDecl* t_classDecl){ if((t_classDecl->m_superClass)!=0){ p_Emit(t_classDecl->m_superClass->m_munged+String(L"::mark();",9)); } - c_Enumerator2* t_3=t_classDecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_3=t_classDecl->p_Semanted()->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_Decl* t_decl3=t_3->p_NextObject(); c_FieldDecl* t_fdecl3=dynamic_cast(t_decl3); @@ -20008,7 +33619,7 @@ int c_CppTranslator::p_EmitClassDecl(c_ClassDecl* t_classDecl){ if(((t_classDecl->m_superClass)!=0) && !((t_classDecl->m_superClass->p_IsExtern())!=0)){ p_Emit(String(L"t=",2)+t_classDecl->m_superClass->m_munged+String(L"::debug()+t;",12)); } - c_Enumerator2* t_4=t_classDecl->p_Decls()->p_ObjectEnumerator(); + c_Enumerator3* t_4=t_classDecl->p_Decls()->p_ObjectEnumerator(); while(t_4->p_HasNext()){ c_Decl* t_decl4=t_4->p_NextObject(); if(!((t_decl4->p_IsSemanted())!=0)){ @@ -20045,7 +33656,7 @@ String c_CppTranslator::p_TransApp(c_AppDecl* t_app){ c_ModuleDecl* t_decl=t_->p_NextObject(); p_MungDecl(t_decl); } - c_Enumerator2* t_2=t_app->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_2=t_app->p_Semanted()->p_ObjectEnumerator(); while(t_2->p_HasNext()){ c_Decl* t_decl2=t_2->p_NextObject(); p_MungDecl(t_decl2); @@ -20054,13 +33665,13 @@ String c_CppTranslator::p_TransApp(c_AppDecl* t_app){ continue; } p_Emit(String(L"class ",6)+t_decl2->m_munged+String(L";",1)); - c_Enumerator2* t_3=t_cdecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_3=t_cdecl->p_Semanted()->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_Decl* t_decl3=t_3->p_NextObject(); p_MungDecl(t_decl3); } } - c_Enumerator2* t_4=t_app->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_4=t_app->p_Semanted()->p_ObjectEnumerator(); while(t_4->p_HasNext()){ c_Decl* t_decl4=t_4->p_NextObject(); c_GlobalDecl* t_gdecl=dynamic_cast(t_decl4); @@ -20079,7 +33690,7 @@ String c_CppTranslator::p_TransApp(c_AppDecl* t_app){ continue; } } - c_Enumerator2* t_5=t_app->m_allSemantedDecls->p_ObjectEnumerator(); + c_Enumerator3* t_5=t_app->m_allSemantedDecls->p_ObjectEnumerator(); while(t_5->p_HasNext()){ c_Decl* t_decl5=t_5->p_NextObject(); c_ClassDecl* t_cdecl3=dynamic_cast(t_decl5); @@ -20092,7 +33703,7 @@ String c_CppTranslator::p_TransApp(c_AppDecl* t_app){ p_Emit(String(L"String dbg_value( ",18)+t_cdecl3->m_munged+String(L" **p ){ return dbg_ptr_value( *p ); }",37)); } } - c_Enumerator2* t_6=t_app->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_6=t_app->p_Semanted()->p_ObjectEnumerator(); while(t_6->p_HasNext()){ c_Decl* t_decl6=t_6->p_NextObject(); c_GlobalDecl* t_gdecl2=dynamic_cast(t_decl6); @@ -20114,7 +33725,7 @@ String c_CppTranslator::p_TransApp(c_AppDecl* t_app){ p_BeginLocalScope(); p_Emit(String(L"int bbInit(){",13)); p_Emit(String(L"GC_CTOR",7)); - c_Enumerator6* t_7=t_app->m_semantedGlobals->p_ObjectEnumerator(); + c_Enumerator7* t_7=t_app->m_semantedGlobals->p_ObjectEnumerator(); while(t_7->p_HasNext()){ c_GlobalDecl* t_decl7=t_7->p_NextObject(); String t_munged=p_TransGlobal(t_decl7); @@ -20127,7 +33738,7 @@ String c_CppTranslator::p_TransApp(c_AppDecl* t_app){ p_Emit(String(L"}",1)); p_EndLocalScope(); p_Emit(String(L"void gc_mark(){",15)); - c_Enumerator6* t_8=t_app->m_semantedGlobals->p_ObjectEnumerator(); + c_Enumerator7* t_8=t_app->m_semantedGlobals->p_ObjectEnumerator(); while(t_8->p_HasNext()){ c_GlobalDecl* t_decl8=t_8->p_NextObject(); p_EmitMark(p_TransGlobal(t_decl8),t_decl8->m_type,true); @@ -20482,7 +34093,7 @@ String c_CppTranslator::p_TransTryStmt(c_TryStmt* t_stmt){ t_2=t_2+1; p_MungDecl(t_c->m_init); p_Emit(String(L"}catch(",7)+p_TransType(t_c->m_init->m_type)+String(L" ",1)+t_c->m_init->m_munged+String(L"){",2)); - m_dbgLocals->p_Push25(t_c->m_init); + m_dbgLocals->p_Push28(t_c->m_init); int t_unr2=p_EmitBlock(t_c->m_block,true); } p_Emit(String(L"}",1)); @@ -20492,7 +34103,7 @@ String c_CppTranslator::p_TransDeclStmt(c_DeclStmt* t_stmt){ c_LocalDecl* t_decl=dynamic_cast(t_stmt->m_decl); if((t_decl)!=0){ if((t_decl->m_ident).Length()!=0){ - m_dbgLocals->p_Push25(t_decl); + m_dbgLocals->p_Push28(t_decl); } p_MungDecl(t_decl); return p_TransLocalDecl(t_decl->m_munged,t_decl->m_init); @@ -20646,7 +34257,7 @@ int c_JsTranslator::p_EmitClassDecl(c_ClassDecl* t_classDecl){ String t_superid=t_classDecl->m_superClass->m_munged; p_Emit(String(L"function ",9)+t_classid+String(L"(){",3)); p_Emit(t_superid+String(L".call(this);",12)); - c_Enumerator2* t_=t_classDecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_=t_classDecl->p_Semanted()->p_ObjectEnumerator(); while(t_->p_HasNext()){ c_Decl* t_decl=t_->p_NextObject(); c_FieldDecl* t_fdecl=dynamic_cast(t_decl); @@ -20682,7 +34293,7 @@ int c_JsTranslator::p_EmitClassDecl(c_ClassDecl* t_classDecl){ if(t_superid!=String(L"Object",6)){ p_Emit(t_classid+String(L".prototype=extend_class(",24)+t_superid+String(L");",2)); } - c_Enumerator2* t_4=t_classDecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_4=t_classDecl->p_Semanted()->p_ObjectEnumerator(); while(t_4->p_HasNext()){ c_Decl* t_decl2=t_4->p_NextObject(); if((t_decl2->p_IsExtern())!=0){ @@ -20708,7 +34319,7 @@ String c_JsTranslator::p_TransApp(c_AppDecl* t_app){ c_ModuleDecl* t_decl=t_->p_NextObject(); p_MungDecl(t_decl); } - c_Enumerator2* t_2=t_app->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_2=t_app->p_Semanted()->p_ObjectEnumerator(); while(t_2->p_HasNext()){ c_Decl* t_decl2=t_2->p_NextObject(); p_MungDecl(t_decl2); @@ -20716,13 +34327,13 @@ String c_JsTranslator::p_TransApp(c_AppDecl* t_app){ if(!((t_cdecl)!=0)){ continue; } - c_Enumerator2* t_3=t_cdecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_3=t_cdecl->p_Semanted()->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_Decl* t_decl3=t_3->p_NextObject(); p_MungDecl(t_decl3); } } - c_Enumerator2* t_4=t_app->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_4=t_app->p_Semanted()->p_ObjectEnumerator(); while(t_4->p_HasNext()){ c_Decl* t_decl4=t_4->p_NextObject(); c_GlobalDecl* t_gdecl=dynamic_cast(t_decl4); @@ -20742,7 +34353,7 @@ String c_JsTranslator::p_TransApp(c_AppDecl* t_app){ } } p_Emit(String(L"function bbInit(){",18)); - c_Enumerator6* t_5=t_app->m_semantedGlobals->p_ObjectEnumerator(); + c_Enumerator7* t_5=t_app->m_semantedGlobals->p_ObjectEnumerator(); while(t_5->p_HasNext()){ c_GlobalDecl* t_decl5=t_5->p_NextObject(); p_Emit(p_TransGlobal(t_decl5)+String(L"=",1)+t_decl5->m_init->p_Trans()+String(L";",1)); @@ -21463,7 +35074,7 @@ int c_AsTranslator::p_EmitClassDecl(c_ClassDecl* t_classDecl){ t_bases=t_bases+t_iface->m_munged; } p_Emit(String(L"interface ",10)+t_classid+t_bases+String(L"{",1)); - c_Enumerator2* t_3=t_classDecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_3=t_classDecl->p_Semanted()->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_Decl* t_decl=t_3->p_NextObject(); c_FuncDecl* t_fdecl=dynamic_cast(t_decl); @@ -21489,7 +35100,7 @@ int c_AsTranslator::p_EmitClassDecl(c_ClassDecl* t_classDecl){ t_bases2=t_bases2+t_iface2->m_munged; } p_Emit(String(L"class ",6)+t_classid+String(L" extends ",9)+t_superid+t_bases2+String(L"{",1)); - c_Enumerator2* t_6=t_classDecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_6=t_classDecl->p_Semanted()->p_ObjectEnumerator(); while(t_6->p_HasNext()){ c_Decl* t_decl2=t_6->p_NextObject(); c_FieldDecl* t_tdecl=dynamic_cast(t_decl2); @@ -21518,7 +35129,7 @@ String c_AsTranslator::p_TransApp(c_AppDecl* t_app){ c_ModuleDecl* t_decl=t_->p_NextObject(); p_MungDecl(t_decl); } - c_Enumerator2* t_2=t_app->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_2=t_app->p_Semanted()->p_ObjectEnumerator(); while(t_2->p_HasNext()){ c_Decl* t_decl2=t_2->p_NextObject(); p_MungDecl(t_decl2); @@ -21526,7 +35137,7 @@ String c_AsTranslator::p_TransApp(c_AppDecl* t_app){ if(!((t_cdecl)!=0)){ continue; } - c_Enumerator2* t_3=t_cdecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_3=t_cdecl->p_Semanted()->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_Decl* t_decl3=t_3->p_NextObject(); if(((dynamic_cast(t_decl3))!=0) && dynamic_cast(t_decl3)->p_IsCtor()){ @@ -21535,7 +35146,7 @@ String c_AsTranslator::p_TransApp(c_AppDecl* t_app){ p_MungDecl(t_decl3); } } - c_Enumerator2* t_4=t_app->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_4=t_app->p_Semanted()->p_ObjectEnumerator(); while(t_4->p_HasNext()){ c_Decl* t_decl4=t_4->p_NextObject(); c_GlobalDecl* t_gdecl=dynamic_cast(t_decl4); @@ -21556,7 +35167,7 @@ String c_AsTranslator::p_TransApp(c_AppDecl* t_app){ } p_BeginLocalScope(); p_Emit(String(L"function bbInit():void{",23)); - c_Enumerator6* t_5=t_app->m_semantedGlobals->p_ObjectEnumerator(); + c_Enumerator7* t_5=t_app->m_semantedGlobals->p_ObjectEnumerator(); while(t_5->p_HasNext()){ c_GlobalDecl* t_decl5=t_5->p_NextObject(); p_Emit(p_TransGlobal(t_decl5)+String(L"=",1)+t_decl5->m_init->p_Trans()+String(L";",1)); @@ -22117,7 +35728,7 @@ int c_CsTranslator::p_EmitClassDecl(c_ClassDecl* t_classDecl){ t_bases=t_bases+t_iface->m_munged; } p_Emit(String(L"interface ",10)+t_classid+t_bases+String(L"{",1)); - c_Enumerator2* t_3=t_classDecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_3=t_classDecl->p_Semanted()->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_Decl* t_decl=t_3->p_NextObject(); c_FuncDecl* t_fdecl=dynamic_cast(t_decl); @@ -22147,7 +35758,7 @@ int c_CsTranslator::p_EmitClassDecl(c_ClassDecl* t_classDecl){ } } p_Emit(t_q+String(L"class ",6)+t_classid+t_bases2+String(L"{",1)); - c_Enumerator2* t_6=t_classDecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_6=t_classDecl->p_Semanted()->p_ObjectEnumerator(); while(t_6->p_HasNext()){ c_Decl* t_decl2=t_6->p_NextObject(); c_FieldDecl* t_tdecl=dynamic_cast(t_decl2); @@ -22177,7 +35788,7 @@ String c_CsTranslator::p_TransApp(c_AppDecl* t_app){ c_ModuleDecl* t_decl=t_->p_NextObject(); p_MungDecl(t_decl); } - c_Enumerator2* t_2=t_app->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_2=t_app->p_Semanted()->p_ObjectEnumerator(); while(t_2->p_HasNext()){ c_Decl* t_decl2=t_2->p_NextObject(); p_MungDecl(t_decl2); @@ -22185,7 +35796,7 @@ String c_CsTranslator::p_TransApp(c_AppDecl* t_app){ if(!((t_cdecl)!=0)){ continue; } - c_Enumerator2* t_3=t_cdecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_3=t_cdecl->p_Semanted()->p_ObjectEnumerator(); while(t_3->p_HasNext()){ c_Decl* t_decl3=t_3->p_NextObject(); if(((dynamic_cast(t_decl3))!=0) && dynamic_cast(t_decl3)->p_IsCtor()){ @@ -22194,7 +35805,7 @@ String c_CsTranslator::p_TransApp(c_AppDecl* t_app){ p_MungDecl(t_decl3); } } - c_Enumerator2* t_4=t_app->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_4=t_app->p_Semanted()->p_ObjectEnumerator(); while(t_4->p_HasNext()){ c_Decl* t_decl4=t_4->p_NextObject(); c_ClassDecl* t_cdecl2=dynamic_cast(t_decl4); @@ -22207,7 +35818,7 @@ String c_CsTranslator::p_TransApp(c_AppDecl* t_app){ while(t_5->p_HasNext()){ c_ModuleDecl* t_mdecl=t_5->p_NextObject(); p_Emit(String(L"class ",6)+t_mdecl->m_munged+String(L"{",1)); - c_Enumerator2* t_6=t_mdecl->p_Semanted()->p_ObjectEnumerator(); + c_Enumerator3* t_6=t_mdecl->p_Semanted()->p_ObjectEnumerator(); while(t_6->p_HasNext()){ c_Decl* t_decl5=t_6->p_NextObject(); if(((t_decl5->p_IsExtern())!=0) || ((t_decl5->m_scope->p_ClassScope())!=0)){ @@ -22227,7 +35838,7 @@ String c_CsTranslator::p_TransApp(c_AppDecl* t_app){ if(t_mdecl==t_app->m_mainModule){ p_BeginLocalScope(); p_Emit(String(L"public static int bbInit(){",27)); - c_Enumerator6* t_7=t_app->m_semantedGlobals->p_ObjectEnumerator(); + c_Enumerator7* t_7=t_app->m_semantedGlobals->p_ObjectEnumerator(); while(t_7->p_HasNext()){ c_GlobalDecl* t_decl6=t_7->p_NextObject(); p_Emit(p_TransGlobal(t_decl6)+String(L"=",1)+t_decl6->m_init->p_Trans()+String(L";",1)); @@ -22592,63 +36203,63 @@ String c_CsTranslator::p_TransTryStmt(c_TryStmt* t_stmt){ void c_CsTranslator::mark(){ c_CTranslator::mark(); } -c_List9::c_List9(){ - m__head=((new c_HeadNode9)->m_new()); +c_List11::c_List11(){ + m__head=((new c_HeadNode11)->m_new()); } -c_List9* c_List9::m_new(){ +c_List11* c_List11::m_new(){ return this; } -c_Node16* c_List9::p_AddLast9(c_ModuleDecl* t_data){ - return (new c_Node16)->m_new(m__head,m__head->m__pred,t_data); +c_Node19* c_List11::p_AddLast11(c_ModuleDecl* t_data){ + return (new c_Node19)->m_new(m__head,m__head->m__pred,t_data); } -c_List9* c_List9::m_new2(Array t_data){ +c_List11* c_List11::m_new2(Array t_data){ Array t_=t_data; int t_2=0; while(t_2m__succ==m__head; } -c_ModuleDecl* c_List9::p_RemoveLast(){ +c_ModuleDecl* c_List11::p_RemoveLast(){ c_ModuleDecl* t_data=m__head->m__pred->m__data; m__head->m__pred->p_Remove(); return t_data; } -bool c_List9::p_Equals4(c_ModuleDecl* t_lhs,c_ModuleDecl* t_rhs){ +bool c_List11::p_Equals5(c_ModuleDecl* t_lhs,c_ModuleDecl* t_rhs){ return t_lhs==t_rhs; } -c_Node16* c_List9::p_FindLast7(c_ModuleDecl* t_value,c_Node16* t_start){ +c_Node19* c_List11::p_FindLast9(c_ModuleDecl* t_value,c_Node19* t_start){ while(t_start!=m__head){ - if(p_Equals4(t_value,t_start->m__data)){ + if(p_Equals5(t_value,t_start->m__data)){ return t_start; } t_start=t_start->m__pred; } return 0; } -c_Node16* c_List9::p_FindLast8(c_ModuleDecl* t_value){ - return p_FindLast7(t_value,m__head->m__pred); +c_Node19* c_List11::p_FindLast10(c_ModuleDecl* t_value){ + return p_FindLast9(t_value,m__head->m__pred); } -void c_List9::p_RemoveLast5(c_ModuleDecl* t_value){ - c_Node16* t_node=p_FindLast8(t_value); +void c_List11::p_RemoveLast6(c_ModuleDecl* t_value){ + c_Node19* t_node=p_FindLast10(t_value); if((t_node)!=0){ t_node->p_Remove(); } } -void c_List9::mark(){ +void c_List11::mark(){ Object::mark(); } -c_Node16::c_Node16(){ +c_Node19::c_Node19(){ m__succ=0; m__pred=0; m__data=0; } -c_Node16* c_Node16::m_new(c_Node16* t_succ,c_Node16* t_pred,c_ModuleDecl* t_data){ +c_Node19* c_Node19::m_new(c_Node19* t_succ,c_Node19* t_pred,c_ModuleDecl* t_data){ m__succ=t_succ; m__pred=t_pred; m__succ->m__pred=this; @@ -22656,52 +36267,52 @@ c_Node16* c_Node16::m_new(c_Node16* t_succ,c_Node16* t_pred,c_ModuleDecl* t_data m__data=t_data; return this; } -c_Node16* c_Node16::m_new2(){ +c_Node19* c_Node19::m_new2(){ return this; } -int c_Node16::p_Remove(){ +int c_Node19::p_Remove(){ m__succ->m__pred=m__pred; m__pred->m__succ=m__succ; return 0; } -void c_Node16::mark(){ +void c_Node19::mark(){ Object::mark(); } -c_HeadNode9::c_HeadNode9(){ +c_HeadNode11::c_HeadNode11(){ } -c_HeadNode9* c_HeadNode9::m_new(){ - c_Node16::m_new2(); +c_HeadNode11* c_HeadNode11::m_new(){ + c_Node19::m_new2(); m__succ=(this); m__pred=(this); return this; } -void c_HeadNode9::mark(){ - c_Node16::mark(); +void c_HeadNode11::mark(){ + c_Node19::mark(); } -c_Enumerator5::c_Enumerator5(){ +c_Enumerator6::c_Enumerator6(){ m__list=0; m__curr=0; } -c_Enumerator5* c_Enumerator5::m_new(c_List5* t_list){ +c_Enumerator6* c_Enumerator6::m_new(c_List7* t_list){ m__list=t_list; m__curr=t_list->m__head->m__succ; return this; } -c_Enumerator5* c_Enumerator5::m_new2(){ +c_Enumerator6* c_Enumerator6::m_new2(){ return this; } -bool c_Enumerator5::p_HasNext(){ +bool c_Enumerator6::p_HasNext(){ while(m__curr->m__succ->m__pred!=m__curr){ m__curr=m__curr->m__succ; } return m__curr!=m__list->m__head; } -c_Stmt* c_Enumerator5::p_NextObject(){ +c_Stmt* c_Enumerator6::p_NextObject(){ c_Stmt* t_data=m__curr->m__data; m__curr=m__curr->m__succ; return t_data; } -void c_Enumerator5::mark(){ +void c_Enumerator6::mark(){ Object::mark(); } c_InvokeExpr::c_InvokeExpr(){ @@ -22866,14 +36477,14 @@ void c_VarExpr::mark(){ c_Expr::mark(); } int bb_decl__loopnest; -c_Map8::c_Map8(){ +c_Map9::c_Map9(){ m_root=0; } -c_Map8* c_Map8::m_new(){ +c_Map9* c_Map9::m_new(){ return this; } -c_Node17* c_Map8::p_FindNode(String t_key){ - c_Node17* t_node=m_root; +c_Node20* c_Map9::p_FindNode(String t_key){ + c_Node20* t_node=m_root; while((t_node)!=0){ int t_cmp=p_Compare(t_key,t_node->m_key); if(t_cmp>0){ @@ -22888,15 +36499,15 @@ c_Node17* c_Map8::p_FindNode(String t_key){ } return t_node; } -c_FuncDeclList* c_Map8::p_Get(String t_key){ - c_Node17* t_node=p_FindNode(t_key); +c_FuncDeclList* c_Map9::p_Get(String t_key){ + c_Node20* t_node=p_FindNode(t_key); if((t_node)!=0){ return t_node->m_value; } return 0; } -int c_Map8::p_RotateLeft8(c_Node17* t_node){ - c_Node17* t_child=t_node->m_right; +int c_Map9::p_RotateLeft9(c_Node20* t_node){ + c_Node20* t_child=t_node->m_right; t_node->m_right=t_child->m_left; if((t_child->m_left)!=0){ t_child->m_left->m_parent=t_node; @@ -22915,8 +36526,8 @@ int c_Map8::p_RotateLeft8(c_Node17* t_node){ t_node->m_parent=t_child; return 0; } -int c_Map8::p_RotateRight8(c_Node17* t_node){ - c_Node17* t_child=t_node->m_left; +int c_Map9::p_RotateRight9(c_Node20* t_node){ + c_Node20* t_child=t_node->m_left; t_node->m_left=t_child->m_right; if((t_child->m_right)!=0){ t_child->m_right->m_parent=t_node; @@ -22935,10 +36546,10 @@ int c_Map8::p_RotateRight8(c_Node17* t_node){ t_node->m_parent=t_child; return 0; } -int c_Map8::p_InsertFixup8(c_Node17* t_node){ +int c_Map9::p_InsertFixup9(c_Node20* t_node){ while(((t_node->m_parent)!=0) && t_node->m_parent->m_color==-1 && ((t_node->m_parent->m_parent)!=0)){ if(t_node->m_parent==t_node->m_parent->m_parent->m_left){ - c_Node17* t_uncle=t_node->m_parent->m_parent->m_right; + c_Node20* t_uncle=t_node->m_parent->m_parent->m_right; if(((t_uncle)!=0) && t_uncle->m_color==-1){ t_node->m_parent->m_color=1; t_uncle->m_color=1; @@ -22947,14 +36558,14 @@ int c_Map8::p_InsertFixup8(c_Node17* t_node){ }else{ if(t_node==t_node->m_parent->m_right){ t_node=t_node->m_parent; - p_RotateLeft8(t_node); + p_RotateLeft9(t_node); } t_node->m_parent->m_color=1; t_node->m_parent->m_parent->m_color=-1; - p_RotateRight8(t_node->m_parent->m_parent); + p_RotateRight9(t_node->m_parent->m_parent); } }else{ - c_Node17* t_uncle2=t_node->m_parent->m_parent->m_left; + c_Node20* t_uncle2=t_node->m_parent->m_parent->m_left; if(((t_uncle2)!=0) && t_uncle2->m_color==-1){ t_node->m_parent->m_color=1; t_uncle2->m_color=1; @@ -22963,20 +36574,20 @@ int c_Map8::p_InsertFixup8(c_Node17* t_node){ }else{ if(t_node==t_node->m_parent->m_left){ t_node=t_node->m_parent; - p_RotateRight8(t_node); + p_RotateRight9(t_node); } t_node->m_parent->m_color=1; t_node->m_parent->m_parent->m_color=-1; - p_RotateLeft8(t_node->m_parent->m_parent); + p_RotateLeft9(t_node->m_parent->m_parent); } } } m_root->m_color=1; return 0; } -bool c_Map8::p_Set8(String t_key,c_FuncDeclList* t_value){ - c_Node17* t_node=m_root; - c_Node17* t_parent=0; +bool c_Map9::p_Set8(String t_key,c_FuncDeclList* t_value){ + c_Node20* t_node=m_root; + c_Node20* t_parent=0; int t_cmp=0; while((t_node)!=0){ t_parent=t_node; @@ -22992,35 +36603,35 @@ bool c_Map8::p_Set8(String t_key,c_FuncDeclList* t_value){ } } } - t_node=(new c_Node17)->m_new(t_key,t_value,-1,t_parent); + t_node=(new c_Node20)->m_new(t_key,t_value,-1,t_parent); if((t_parent)!=0){ if(t_cmp>0){ t_parent->m_right=t_node; }else{ t_parent->m_left=t_node; } - p_InsertFixup8(t_node); + p_InsertFixup9(t_node); }else{ m_root=t_node; } return true; } -void c_Map8::mark(){ +void c_Map9::mark(){ Object::mark(); } c_StringMap8::c_StringMap8(){ } c_StringMap8* c_StringMap8::m_new(){ - c_Map8::m_new(); + c_Map9::m_new(); return this; } int c_StringMap8::p_Compare(String t_lhs,String t_rhs){ return t_lhs.Compare(t_rhs); } void c_StringMap8::mark(){ - c_Map8::mark(); + c_Map9::mark(); } -c_Node17::c_Node17(){ +c_Node20::c_Node20(){ m_key=String(); m_right=0; m_left=0; @@ -23028,27 +36639,27 @@ c_Node17::c_Node17(){ m_color=0; m_parent=0; } -c_Node17* c_Node17::m_new(String t_key,c_FuncDeclList* t_value,int t_color,c_Node17* t_parent){ +c_Node20* c_Node20::m_new(String t_key,c_FuncDeclList* t_value,int t_color,c_Node20* t_parent){ this->m_key=t_key; this->m_value=t_value; this->m_color=t_color; this->m_parent=t_parent; return this; } -c_Node17* c_Node17::m_new2(){ +c_Node20* c_Node20::m_new2(){ return this; } -void c_Node17::mark(){ +void c_Node20::mark(){ Object::mark(); } -c_Map9::c_Map9(){ +c_Map10::c_Map10(){ m_root=0; } -c_Map9* c_Map9::m_new(){ +c_Map10* c_Map10::m_new(){ return this; } -c_Node18* c_Map9::p_FindNode(String t_key){ - c_Node18* t_node=m_root; +c_Node21* c_Map10::p_FindNode(String t_key){ + c_Node21* t_node=m_root; while((t_node)!=0){ int t_cmp=p_Compare(t_key,t_node->m_key); if(t_cmp>0){ @@ -23063,11 +36674,11 @@ c_Node18* c_Map9::p_FindNode(String t_key){ } return t_node; } -bool c_Map9::p_Contains(String t_key){ +bool c_Map10::p_Contains(String t_key){ return p_FindNode(t_key)!=0; } -int c_Map9::p_RotateLeft9(c_Node18* t_node){ - c_Node18* t_child=t_node->m_right; +int c_Map10::p_RotateLeft10(c_Node21* t_node){ + c_Node21* t_child=t_node->m_right; t_node->m_right=t_child->m_left; if((t_child->m_left)!=0){ t_child->m_left->m_parent=t_node; @@ -23086,8 +36697,8 @@ int c_Map9::p_RotateLeft9(c_Node18* t_node){ t_node->m_parent=t_child; return 0; } -int c_Map9::p_RotateRight9(c_Node18* t_node){ - c_Node18* t_child=t_node->m_left; +int c_Map10::p_RotateRight10(c_Node21* t_node){ + c_Node21* t_child=t_node->m_left; t_node->m_left=t_child->m_right; if((t_child->m_right)!=0){ t_child->m_right->m_parent=t_node; @@ -23106,10 +36717,10 @@ int c_Map9::p_RotateRight9(c_Node18* t_node){ t_node->m_parent=t_child; return 0; } -int c_Map9::p_InsertFixup9(c_Node18* t_node){ +int c_Map10::p_InsertFixup10(c_Node21* t_node){ while(((t_node->m_parent)!=0) && t_node->m_parent->m_color==-1 && ((t_node->m_parent->m_parent)!=0)){ if(t_node->m_parent==t_node->m_parent->m_parent->m_left){ - c_Node18* t_uncle=t_node->m_parent->m_parent->m_right; + c_Node21* t_uncle=t_node->m_parent->m_parent->m_right; if(((t_uncle)!=0) && t_uncle->m_color==-1){ t_node->m_parent->m_color=1; t_uncle->m_color=1; @@ -23118,14 +36729,14 @@ int c_Map9::p_InsertFixup9(c_Node18* t_node){ }else{ if(t_node==t_node->m_parent->m_right){ t_node=t_node->m_parent; - p_RotateLeft9(t_node); + p_RotateLeft10(t_node); } t_node->m_parent->m_color=1; t_node->m_parent->m_parent->m_color=-1; - p_RotateRight9(t_node->m_parent->m_parent); + p_RotateRight10(t_node->m_parent->m_parent); } }else{ - c_Node18* t_uncle2=t_node->m_parent->m_parent->m_left; + c_Node21* t_uncle2=t_node->m_parent->m_parent->m_left; if(((t_uncle2)!=0) && t_uncle2->m_color==-1){ t_node->m_parent->m_color=1; t_uncle2->m_color=1; @@ -23134,20 +36745,20 @@ int c_Map9::p_InsertFixup9(c_Node18* t_node){ }else{ if(t_node==t_node->m_parent->m_left){ t_node=t_node->m_parent; - p_RotateRight9(t_node); + p_RotateRight10(t_node); } t_node->m_parent->m_color=1; t_node->m_parent->m_parent->m_color=-1; - p_RotateLeft9(t_node->m_parent->m_parent); + p_RotateLeft10(t_node->m_parent->m_parent); } } } m_root->m_color=1; return 0; } -bool c_Map9::p_Set9(String t_key,c_FuncDecl* t_value){ - c_Node18* t_node=m_root; - c_Node18* t_parent=0; +bool c_Map10::p_Set9(String t_key,c_FuncDecl* t_value){ + c_Node21* t_node=m_root; + c_Node21* t_parent=0; int t_cmp=0; while((t_node)!=0){ t_parent=t_node; @@ -23163,35 +36774,35 @@ bool c_Map9::p_Set9(String t_key,c_FuncDecl* t_value){ } } } - t_node=(new c_Node18)->m_new(t_key,t_value,-1,t_parent); + t_node=(new c_Node21)->m_new(t_key,t_value,-1,t_parent); if((t_parent)!=0){ if(t_cmp>0){ t_parent->m_right=t_node; }else{ t_parent->m_left=t_node; } - p_InsertFixup9(t_node); + p_InsertFixup10(t_node); }else{ m_root=t_node; } return true; } -void c_Map9::mark(){ +void c_Map10::mark(){ Object::mark(); } c_StringMap9::c_StringMap9(){ } c_StringMap9* c_StringMap9::m_new(){ - c_Map9::m_new(); + c_Map10::m_new(); return this; } int c_StringMap9::p_Compare(String t_lhs,String t_rhs){ return t_lhs.Compare(t_rhs); } void c_StringMap9::mark(){ - c_Map9::mark(); + c_Map10::mark(); } -c_Node18::c_Node18(){ +c_Node21::c_Node21(){ m_key=String(); m_right=0; m_left=0; @@ -23199,27 +36810,27 @@ c_Node18::c_Node18(){ m_color=0; m_parent=0; } -c_Node18* c_Node18::m_new(String t_key,c_FuncDecl* t_value,int t_color,c_Node18* t_parent){ +c_Node21* c_Node21::m_new(String t_key,c_FuncDecl* t_value,int t_color,c_Node21* t_parent){ this->m_key=t_key; this->m_value=t_value; this->m_color=t_color; this->m_parent=t_parent; return this; } -c_Node18* c_Node18::m_new2(){ +c_Node21* c_Node21::m_new2(){ return this; } -void c_Node18::mark(){ +void c_Node21::mark(){ Object::mark(); } -c_Map10::c_Map10(){ +c_Map11::c_Map11(){ m_root=0; } -c_Map10* c_Map10::m_new(){ +c_Map11* c_Map11::m_new(){ return this; } -c_Node19* c_Map10::p_FindNode(String t_key){ - c_Node19* t_node=m_root; +c_Node22* c_Map11::p_FindNode(String t_key){ + c_Node22* t_node=m_root; while((t_node)!=0){ int t_cmp=p_Compare(t_key,t_node->m_key); if(t_cmp>0){ @@ -23234,15 +36845,15 @@ c_Node19* c_Map10::p_FindNode(String t_key){ } return t_node; } -c_StringSet* c_Map10::p_Get(String t_key){ - c_Node19* t_node=p_FindNode(t_key); +c_StringSet* c_Map11::p_Get(String t_key){ + c_Node22* t_node=p_FindNode(t_key); if((t_node)!=0){ return t_node->m_value; } return 0; } -int c_Map10::p_RotateLeft10(c_Node19* t_node){ - c_Node19* t_child=t_node->m_right; +int c_Map11::p_RotateLeft11(c_Node22* t_node){ + c_Node22* t_child=t_node->m_right; t_node->m_right=t_child->m_left; if((t_child->m_left)!=0){ t_child->m_left->m_parent=t_node; @@ -23261,8 +36872,8 @@ int c_Map10::p_RotateLeft10(c_Node19* t_node){ t_node->m_parent=t_child; return 0; } -int c_Map10::p_RotateRight10(c_Node19* t_node){ - c_Node19* t_child=t_node->m_left; +int c_Map11::p_RotateRight11(c_Node22* t_node){ + c_Node22* t_child=t_node->m_left; t_node->m_left=t_child->m_right; if((t_child->m_right)!=0){ t_child->m_right->m_parent=t_node; @@ -23281,10 +36892,10 @@ int c_Map10::p_RotateRight10(c_Node19* t_node){ t_node->m_parent=t_child; return 0; } -int c_Map10::p_InsertFixup10(c_Node19* t_node){ +int c_Map11::p_InsertFixup11(c_Node22* t_node){ while(((t_node->m_parent)!=0) && t_node->m_parent->m_color==-1 && ((t_node->m_parent->m_parent)!=0)){ if(t_node->m_parent==t_node->m_parent->m_parent->m_left){ - c_Node19* t_uncle=t_node->m_parent->m_parent->m_right; + c_Node22* t_uncle=t_node->m_parent->m_parent->m_right; if(((t_uncle)!=0) && t_uncle->m_color==-1){ t_node->m_parent->m_color=1; t_uncle->m_color=1; @@ -23293,14 +36904,14 @@ int c_Map10::p_InsertFixup10(c_Node19* t_node){ }else{ if(t_node==t_node->m_parent->m_right){ t_node=t_node->m_parent; - p_RotateLeft10(t_node); + p_RotateLeft11(t_node); } t_node->m_parent->m_color=1; t_node->m_parent->m_parent->m_color=-1; - p_RotateRight10(t_node->m_parent->m_parent); + p_RotateRight11(t_node->m_parent->m_parent); } }else{ - c_Node19* t_uncle2=t_node->m_parent->m_parent->m_left; + c_Node22* t_uncle2=t_node->m_parent->m_parent->m_left; if(((t_uncle2)!=0) && t_uncle2->m_color==-1){ t_node->m_parent->m_color=1; t_uncle2->m_color=1; @@ -23309,20 +36920,20 @@ int c_Map10::p_InsertFixup10(c_Node19* t_node){ }else{ if(t_node==t_node->m_parent->m_left){ t_node=t_node->m_parent; - p_RotateRight10(t_node); + p_RotateRight11(t_node); } t_node->m_parent->m_color=1; t_node->m_parent->m_parent->m_color=-1; - p_RotateLeft10(t_node->m_parent->m_parent); + p_RotateLeft11(t_node->m_parent->m_parent); } } } m_root->m_color=1; return 0; } -bool c_Map10::p_Set10(String t_key,c_StringSet* t_value){ - c_Node19* t_node=m_root; - c_Node19* t_parent=0; +bool c_Map11::p_Set10(String t_key,c_StringSet* t_value){ + c_Node22* t_node=m_root; + c_Node22* t_parent=0; int t_cmp=0; while((t_node)!=0){ t_parent=t_node; @@ -23338,35 +36949,35 @@ bool c_Map10::p_Set10(String t_key,c_StringSet* t_value){ } } } - t_node=(new c_Node19)->m_new(t_key,t_value,-1,t_parent); + t_node=(new c_Node22)->m_new(t_key,t_value,-1,t_parent); if((t_parent)!=0){ if(t_cmp>0){ t_parent->m_right=t_node; }else{ t_parent->m_left=t_node; } - p_InsertFixup10(t_node); + p_InsertFixup11(t_node); }else{ m_root=t_node; } return true; } -void c_Map10::mark(){ +void c_Map11::mark(){ Object::mark(); } c_StringMap10::c_StringMap10(){ } c_StringMap10* c_StringMap10::m_new(){ - c_Map10::m_new(); + c_Map11::m_new(); return this; } int c_StringMap10::p_Compare(String t_lhs,String t_rhs){ return t_lhs.Compare(t_rhs); } void c_StringMap10::mark(){ - c_Map10::mark(); + c_Map11::mark(); } -c_Node19::c_Node19(){ +c_Node22::c_Node22(){ m_key=String(); m_right=0; m_left=0; @@ -23374,68 +36985,68 @@ c_Node19::c_Node19(){ m_color=0; m_parent=0; } -c_Node19* c_Node19::m_new(String t_key,c_StringSet* t_value,int t_color,c_Node19* t_parent){ +c_Node22* c_Node22::m_new(String t_key,c_StringSet* t_value,int t_color,c_Node22* t_parent){ this->m_key=t_key; this->m_value=t_value; this->m_color=t_color; this->m_parent=t_parent; return this; } -c_Node19* c_Node19::m_new2(){ +c_Node22* c_Node22::m_new2(){ return this; } -void c_Node19::mark(){ +void c_Node22::mark(){ Object::mark(); } -c_Enumerator6::c_Enumerator6(){ +c_Enumerator7::c_Enumerator7(){ m__list=0; m__curr=0; } -c_Enumerator6* c_Enumerator6::m_new(c_List8* t_list){ +c_Enumerator7* c_Enumerator7::m_new(c_List10* t_list){ m__list=t_list; m__curr=t_list->m__head->m__succ; return this; } -c_Enumerator6* c_Enumerator6::m_new2(){ +c_Enumerator7* c_Enumerator7::m_new2(){ return this; } -bool c_Enumerator6::p_HasNext(){ +bool c_Enumerator7::p_HasNext(){ while(m__curr->m__succ->m__pred!=m__curr){ m__curr=m__curr->m__succ; } return m__curr!=m__list->m__head; } -c_GlobalDecl* c_Enumerator6::p_NextObject(){ +c_GlobalDecl* c_Enumerator7::p_NextObject(){ c_GlobalDecl* t_data=m__curr->m__data; m__curr=m__curr->m__succ; return t_data; } -void c_Enumerator6::mark(){ +void c_Enumerator7::mark(){ Object::mark(); } -c_Stack9::c_Stack9(){ +c_Stack10::c_Stack10(){ m_data=Array(); m_length=0; } -c_Stack9* c_Stack9::m_new(){ +c_Stack10* c_Stack10::m_new(){ return this; } -c_Stack9* c_Stack9::m_new2(Array t_data){ +c_Stack10* c_Stack10::m_new2(Array t_data){ this->m_data=t_data.Slice(0); this->m_length=t_data.Length(); return this; } -c_LocalDecl* c_Stack9::m_NIL; -void c_Stack9::p_Clear(){ +c_LocalDecl* c_Stack10::m_NIL; +void c_Stack10::p_Clear(){ for(int t_i=0;t_im_new(this); +c_Enumerator8* c_Stack10::p_ObjectEnumerator(){ + return (new c_Enumerator8)->m_new(this); } -void c_Stack9::p_Length(int t_newlength){ +void c_Stack10::p_Length(int t_newlength){ if(t_newlength t_values,int t_offset,int t_count){ +void c_Stack10::p_Push29(Array t_values,int t_offset,int t_count){ for(int t_i=0;t_i t_values,int t_offset){ - p_Push26(t_values,t_offset,t_values.Length()-t_offset); +void c_Stack10::p_Push30(Array t_values,int t_offset){ + p_Push29(t_values,t_offset,t_values.Length()-t_offset); } -void c_Stack9::mark(){ +void c_Stack10::mark(){ Object::mark(); } -c_Enumerator7::c_Enumerator7(){ +c_Enumerator8::c_Enumerator8(){ m_stack=0; m_index=0; } -c_Enumerator7* c_Enumerator7::m_new(c_Stack9* t_stack){ +c_Enumerator8* c_Enumerator8::m_new(c_Stack10* t_stack){ this->m_stack=t_stack; return this; } -c_Enumerator7* c_Enumerator7::m_new2(){ +c_Enumerator8* c_Enumerator8::m_new2(){ return this; } -bool c_Enumerator7::p_HasNext(){ +bool c_Enumerator8::p_HasNext(){ return m_indexp_Length2(); } -c_LocalDecl* c_Enumerator7::p_NextObject(){ +c_LocalDecl* c_Enumerator8::p_NextObject(){ m_index+=1; return m_stack->m_data[m_index-1]; } -void c_Enumerator7::mark(){ +void c_Enumerator8::mark(){ Object::mark(); } int bbInit(){ @@ -23499,9 +37110,11 @@ int bbInit(){ bb_decl__envStack=(new c_List2)->m_new(); c_Toker::m__keywords=0; c_Toker::m__symbols=0; + c_Toker::m__tokenFlags=0; bb_config_ENV_MODPATH=String(); bb_parser_FILE_EXT=String(L".cxs",4); bb_parser_FILE_EXT_OLD=String(L".monkey",7); + c_BlockTrace::m__Blocks=(new c_BlockTrace)->m_new(); bb_config_ENV_SAFEMODE=0; c_Type::m_intType=(new c_IntType)->m_new(); c_Type::m_floatType=(new c_FloatType)->m_new(); @@ -23511,21 +37124,22 @@ int bbInit(){ c_Type::m_throwableType=(new c_IdentType)->m_new(String(L"cerberus.throwable",18),Array()); c_Type::m_emptyArrayType=(new c_ArrayType)->m_new(c_Type::m_voidType); c_Type::m_nullObjectType=(new c_IdentType)->m_new(String(),Array()); - c_Stack7::m_NIL=0; + c_Stack8::m_NIL=0; bb_config__errStack=(new c_StringList)->m_new2(); + c_Stack3::m_NIL=0; c_Stack2::m_NIL=0; bb_config_ENV_HOST=String(); bb_config_ENV_CONFIG=String(); bb_config_ENV_TARGET=String(); bb_config_ENV_LANG=String(); - c_Stack8::m_NIL=0; + c_Stack9::m_NIL=0; c_Stack::m_NIL=String(); bb_translator__trans=0; bb_html5_Info_Width=0; bb_html5_Info_Height=0; c_ClassDecl::m_nullObjectClass=(new c_ClassDecl)->m_new(String(L"{NULL}",6),1280,Array(),0,Array()); bb_decl__loopnest=0; - c_Stack9::m_NIL=0; + c_Stack10::m_NIL=0; return 0; } void gc_mark(){ diff --git a/src/transcc/transcc.cxs b/src/transcc/transcc.cxs index 7212cf8d..c3ddae05 100644 --- a/src/transcc/transcc.cxs +++ b/src/transcc/transcc.cxs @@ -7,7 +7,7 @@ Import trans Import builders -Const VERSION:="2019-10-13" +Const VERSION:="2020-05-09" Function Main() Local tcc:=New TransCC diff --git a/targets/android/modules/native/androidgame.java b/targets/android/modules/native/androidgame.java index e7cd2b2b..08999b39 100644 --- a/targets/android/modules/native/androidgame.java +++ b/targets/android/modules/native/androidgame.java @@ -654,8 +654,8 @@ public void onSensorChanged( SensorEvent event ){ float x,y,z; switch( sensor.getType() ){ case Sensor.TYPE_ACCELEROMETER: -// switch( _display.getRotation() ){ - switch( _display.getOrientation() ){ //deprecated in API 8, but we support 3... + switch( _display.getRotation() ){ +// switch( _display.getOrientation() ){ //deprecated in API 8, but we support 3... case Surface.ROTATION_0: x=event.values[0]/-9.81f; y=event.values[1]/9.81f; diff --git a/targets/android/template/config.cxs b/targets/android/template/config.cxs index 28c9e3ad..1564da2c 100644 --- a/targets/android/template/config.cxs +++ b/targets/android/template/config.cxs @@ -14,7 +14,14 @@ #ANDROID_GAMEPAD_ENABLED=False #ANDROID_MIN_SDK_VERSION="16" #ANDROID_TARGET_SDK_VERSION="28" -#ANDROID_BUILD_TOOLS_VERSION="28.0.1" +#ANDROID_BUILD_TOOLS_VERSION="28.0.3" +#ANDROID_GRADLE_VERSION="3.2.1" +#ANDROID_GRADLE_DISTRIBUTION="gradle-4.6-all.zip" +#ANDROID_REPOSITORIES="" +#ANDROID_JAVA_SOURCE_VERSION="VERSION_1_8" +#ANDROID_JAVA_TARGET_VERSION="VERSION_1_8" +#ANDROID_APPLICATION_EXTRAS="" + #ANDROID_VERSION_CODE="1" #ANDROID_VERSION_NAME="1.0" diff --git a/targets/android/template/gradletemplate/app/build.gradle b/targets/android/template/gradletemplate/app/build.gradle index 16e89b75..99a307fa 100644 --- a/targets/android/template/gradletemplate/app/build.gradle +++ b/targets/android/template/gradletemplate/app/build.gradle @@ -4,6 +4,11 @@ android { compileSdkVersion ${ANDROID_TARGET_SDK_VERSION} buildToolsVersion "${ANDROID_BUILD_TOOLS_VERSION}" + compileOptions { + sourceCompatibility JavaVersion.${ANDROID_JAVA_SOURCE_VERSION} + targetCompatibility JavaVersion.${ANDROID_JAVA_TARGET_VERSION} + } + defaultConfig { applicationId "${ANDROID_APP_PACKAGE}" minSdkVersion ${ANDROID_MIN_SDK_VERSION} @@ -37,6 +42,5 @@ android { dependencies { ${ANDROID_LIBRARY_REFERENCE_1} ${ANDROID_LIBRARY_REFERENCE_2} - implementation 'com.android.support:appcompat-v7:27.1.1' - implementation 'com.google.android.ads.consent:consent-library:1.0.3' + implementation 'com.android.support:appcompat-v7:28.0.0' } diff --git a/targets/android/template/gradletemplate/app/src/main/AndroidManifest.xml b/targets/android/template/gradletemplate/app/src/main/AndroidManifest.xml index adbd7944..dab31fd0 100644 --- a/targets/android/template/gradletemplate/app/src/main/AndroidManifest.xml +++ b/targets/android/template/gradletemplate/app/src/main/AndroidManifest.xml @@ -8,11 +8,11 @@ - ${ANDROID_MANIFEST_MAIN} + _________ +/ \ tiny file dialogs ( cross-platform C C++ ) +|tiny file| v2.9.3 [July 12, 2017] zlib licence +| dialogs | InputBox PasswordBox MessageBox ColorPicker +\____ ___/ OpenFileDialog SaveFileDialog SelectFolderDialog + \| ASCII UTF-8 (and also MBCS UTF-16 for windows) + Native dialog library for WINDOWS MAC OSX GTK+ QT CONSOLE + +SSH supported via automatic switch to console mode or X11 forwarding + +tested with C & C++ compilers on + Visual Studio MinGW OSX LINUX FREEBSD OPENBSD ILLUMOS SOLARIS MINIX RASPBIAN +using + Gnome Kde Mate Cinnamon Unity Lxde Lxqt Xfce Enlightenment + WindowMaker IceWm Cde Jds OpenBox Awesome Jwm + +bindings for LUA and C# dll +included in LWJGL(java), rust, Allegrobasic + + http://tinyfiledialogs.sourceforge.net + git://git.code.sf.net/p/tinyfiledialogs/code + _________________________________________________________________________ +| | +| CONTACT me directly via the email address at the top of the header file | +|_________________________________________________________________________| + +if you absolutely want them, the windows only wchar_t prototypes are in the header file + +int tinyfd_messageBox ( + char const * const aTitle , // "" + char const * const aMessage , // "" may contain \n \t + char const * const aDialogType , // "ok" "okcancel" "yesno" "yesnocancel" + char const * const aIconType , // "info" "warning" "error" "question" + int const aDefaultButton ) ; + // 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel + +char const * tinyfd_inputBox ( + char const * const aTitle , // "" + char const * const aMessage , // "" may NOT contain \n \t on windows + char const * const aDefaultInput ) ; // "" , if NULL it's a passwordBox + // returns NULL on cancel + +char const * tinyfd_saveFileDialog ( + char const * const aTitle , // "" + char const * const aDefaultPathAndFile , // "" + int const aNumOfFilterPatterns , // 0 + char const * const * const aFilterPatterns , // NULL | {"*.txt"} + char const * const aSingleFilterDescription ) ; // NULL | "text files" + // returns NULL on cancel + +char const * tinyfd_openFileDialog ( + char const * const aTitle , // "" + char const * const aDefaultPathAndFile , // "" + int const aNumOfFilterPatterns , // 0 + char const * const * const aFilterPatterns , // NULL {"*.jpg","*.png"} + char const * const aSingleFilterDescription , // NULL | "image files" + int const aAllowMultipleSelects ) ; // 0 + // in case of multiple files, the separator is | + // returns NULL on cancel + +char const * tinyfd_selectFolderDialog ( + char const * const aTitle , // "" + char const * const aDefaultPath ) ; // "" + // returns NULL on cancel + +char const * tinyfd_colorChooser( + char const * const aTitle , // "" + char const * const aDefaultHexRGB , // NULL or "#FF0000” + unsigned char const aDefaultRGB[3] , // { 0 , 255 , 255 } + unsigned char aoResultRGB[3] ) ; // { 0 , 0 , 0 } + // returns the hexcolor as a string "#FF0000" + // aoResultRGB also contains the result + // aDefaultRGB is used only if aDefaultHexRGB is NULL + // aDefaultRGB and aoResultRGB can be the same array + // returns NULL on cancel + +- This is not for android nor ios. +- The code is pure C, perfectly compatible with C++. +- the windows only wchar_t (utf-16) prototypes are in the header file +- windows is fully supported from XP to 10 (maybe even older versions) +- C# & LUA via dll, see files in the folder EXTRAS +- OSX supported from 10.4 to 10.12 (maybe even older versions) +- Avoid using " and ' in titles and messages. +- There's one file filter only, it may contain several patterns. +- If no filter description is provided, + the list of patterns will become the description. +- char const * filterPatterns[3] = { "*.obj" , "*.stl" , "*.dxf" } ; +- On windows link against Comdlg32.lib and Ole32.lib + (on windows the no linking claim is a lie) + This linking is not compulsary for console mode (see header file). +- On unix: it tries command line calls, so no such need (NO LINKING). +- On unix you need applescript, zenity, matedialog, qarma, kdialog, Xdialog, + python2/tkinter or dialog (will open a terminal if running without console). +- One of those is already included on most (if not all) desktops. +- In the absence of those it will use gdialog, gxmessage or whiptail + with a textinputbox. +- If nothing is found, it switches to basic console input, + it opens a console if needed (requires xterm + bash). +- Use windows separators on windows and unix separators on unix. +- String memory is preallocated statically for all the returned values. +- File and path names are tested before return, they are valid. +- If you pass only a path instead of path + filename, + make sure it ends with a separator. +- tinyfd_forceConsole=1; at run time, forces dialogs into console mode. +- On windows, console mode only make sense for console applications. +- Mutiple selects are not allowed in console mode. +- The package dialog must be installed to run in enhanced console mode. + It is already installed on most unix systems. +- On osx, the package dialog can be installed via http://macports.org +- On windows, for enhanced console mode, + dialog.exe should be copied somewhere on your executable path. + It can be found at the bottom of the following page: + http://andrear.altervista.org/home/cdialog.php +- If dialog is missing, it will switch to basic console input. +- You can query the type of dialog that will be use. +- MinGW needs gcc >= v4.9 otherwise some headers are incomplete. + +- Here is the Hello World: + if a console is missing, it will use graphic dialogs + if a graphical display is absent, it will use console dialogs + + +hello.c +#include +#include +#include "tinyfiledialogs.h" +int main() +{ + char const * lTmp; + char const * lTheSaveFileName; + char const * lTheOpenFileName; + char const * lTheSelectFolderName; + char const * lTheHexColor; + char const * lWillBeGraphicMode; + unsigned char lRgbColor[3]; + FILE * lIn; + char lBuffer[1024]; + char lThePassword[1024]; + char const * lFilterPatterns[2] = { "*.txt", "*.text" }; + + lWillBeGraphicMode = tinyfd_inputBox("tinyfd_query", NULL, NULL); + + if (lWillBeGraphicMode) + { + strcpy(lBuffer, "graphic mode: "); + } + else + { + strcpy(lBuffer, "console mode: "); + } + + strcat(lBuffer, tinyfd_response); + strcpy(lThePassword, "tinyfiledialogs v"); + strcat(lThePassword, tinyfd_version); + tinyfd_messageBox(lThePassword, lBuffer, "ok", "info", 0); + + if ( lWillBeGraphicMode && ! tinyfd_forceConsole ) + { + tinyfd_forceConsole = ! tinyfd_messageBox("Hello World", + "graphic dialogs [yes] / console mode [no]?", + "yesno", "question", 1); + } + + lTmp = tinyfd_inputBox( + "a password box", "your password will be revealed", NULL); + + if (!lTmp) return 1 ; + + /* copy lTmp because saveDialog would overwrites + inputBox static buffer in basicinput mode */ + + strcpy(lThePassword, lTmp); + + lTheSaveFileName = tinyfd_saveFileDialog( + "let us save this password", + "passwordFile.txt", + 2, + lFilterPatterns, + NULL); + + if (! lTheSaveFileName) + { + tinyfd_messageBox( + "Error", + "Save file name is NULL", + "ok", + "error", + 1); + return 1 ; + } + + lIn = fopen(lTheSaveFileName, "w"); + if (!lIn) + { + tinyfd_messageBox( + "Error", + "Can not open this file in write mode", + "ok", + "error", + 1); + return 1 ; + } + fputs(lThePassword, lIn); + fclose(lIn); + + lTheOpenFileName = tinyfd_openFileDialog( + "let us read the password back", + "", + 2, + lFilterPatterns, + NULL, + 0); + + if (! lTheOpenFileName) + { + tinyfd_messageBox( + "Error", + "Open file name is NULL", + "ok", + "error", + 1); + return 1 ; + } + + lIn = fopen(lTheOpenFileName, "r"); + + if (!lIn) + { + tinyfd_messageBox( + "Error", + "Can not open this file in read mode", + "ok", + "error", + 1); + return(1); + } + lBuffer[0] = '\0'; + fgets(lBuffer, sizeof(lBuffer), lIn); + fclose(lIn); + + tinyfd_messageBox("your password is", + lBuffer, "ok", "info", 1); + + lTheSelectFolderName = tinyfd_selectFolderDialog( + "let us just select a directory", NULL); + + if (!lTheSelectFolderName) + { + tinyfd_messageBox( + "Error", + "Select folder name is NULL", + "ok", + "error", + 1); + return 1; + } + + tinyfd_messageBox("The selected folder is", + lTheSelectFolderName, "ok", "info", 1); + + lTheHexColor = tinyfd_colorChooser( + "choose a nice color", + "#FF0077", + lRgbColor, + lRgbColor); + + if (!lTheHexColor) + { + tinyfd_messageBox( + "Error", + "hexcolor is NULL", + "ok", + "error", + 1); + return 1; + } + + tinyfd_messageBox("The selected hexcolor is", + lTheHexColor, "ok", "info", 1); + + return 0; +} + + +OSX : +$ gcc -o hello.app hello.c tinyfiledialogs.c + +UNIX : +$ gcc -o hello hello.c tinyfiledialogs.c +( or clang tcc cc CC ) + +MinGW (needs gcc >= v4.9 otherwise some headers are incomplete): +> gcc -o hello.exe hello.c tinyfiledialogs.c -LC:/mingw/lib -lcomdlg32 -lole32 +(unfortunately some headers are missing with tcc) + +VisualStudio : + Create a console application project, + it links against Comdlg32.lib & Ole32.lib. + + diff --git a/targets/glfw3/template/tinyfiledialogs/files.xml b/targets/glfw3/template/tinyfiledialogs/files.xml new file mode 100644 index 00000000..6a79cc87 --- /dev/null +++ b/targets/glfw3/template/tinyfiledialogs/files.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/targets/glfw3/template/tinyfiledialogs/tinyfiledialogs.c b/targets/glfw3/template/tinyfiledialogs/tinyfiledialogs.c new file mode 100644 index 00000000..e34f4311 --- /dev/null +++ b/targets/glfw3/template/tinyfiledialogs/tinyfiledialogs.c @@ -0,0 +1,6072 @@ +/*_________ + / \ tinyfiledialogs.c v2.9.3 [July 12, 2017] zlib licence + |tiny file| Unique code file created [November 9, 2014] + | dialogs | Copyright (c) 2014 - 2017 Guillaume Vareille http://ysengrin.com + \____ ___/ http://tinyfiledialogs.sourceforge.net + \| + git://git.code.sf.net/p/tinyfiledialogs/code + ______________________________________________ + | | + | email: tinyfiledialogs@ysengrin.com | + |______________________________________________| + +A big thank you to Don Heyse http://ldglite.sf.net for + his code contributions, bug corrections & thorough testing! + +Please + 1) let me know + - if you are including tiny file dialogs, + I'll be happy to add your link to the list of projects using it. + - If you are using it on different hardware / OS / compiler. + 2) leave a review on Sourceforge. Thanks. + +tiny file dialogs (cross-platform C C++) +InputBox PasswordBox MessageBox ColorPicker +OpenFileDialog SaveFileDialog SelectFolderDialog +Native dialog library for WINDOWS MAC OSX GTK+ QT CONSOLE & more +SSH supported via automatic switch to console mode or X11 forwarding + +One C file (add it to your C or C++ project) with 6 functions: +- message & question +- input & password +- save file +- open file(s) +- select folder +- color picker + +Complements OpenGL GLFW GLUT GLUI VTK SFML TGUI SDL Ogre Unity3d ION OpenCV +CEGUI MathGL GLM CPW GLOW IMGUI MyGUI GLT NGL STB & GUI less programs + +NO INIT +NO MAIN LOOP +NO LINKING +NO INCLUDE + +The dialogs can be forced into console mode + +Windows (XP to 10) ASCII MBCS UTF-8 UTF-16 +- native code & vbs create the graphic dialogs +- enhanced console mode can use dialog.exe from +http://andrear.altervista.org/home/cdialog.php +- basic console input + +Unix (command line calls) ASCII UTF-8 +- applescript +- zenity / matedialog / qarma (zenity for qt) +- kdialog +- Xdialog +- python2 tkinter +- dialog (opens a console if needed) +- basic console input +The same executable can run across desktops & distributions + +tested with C & C++ compilers +on VisualStudio MinGW Mac Linux Bsd Solaris Minix Raspbian +using Gnome Kde Enlightenment Mate Cinnamon Unity +Lxde Lxqt Xfce WindowMaker IceWm Cde Jds OpenBox Awesome Jwm + +bindings for LUA and C# dll +included in LWJGL(java), rust, Allegrobasic + +- License - + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include +#include +#include +#include +#include + +#include "tinyfiledialogs.h" +/* #define TINYFD_NOLIB */ + +#ifdef _WIN32 + #ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0500 + #endif + #ifndef TINYFD_NOLIB + #include + /*#define TINYFD_NOSELECTFOLDERWIN*/ + #ifndef TINYFD_NOSELECTFOLDERWIN + #include + #endif /*TINYFD_NOSELECTFOLDERWIN*/ + #endif + #include + /*#include */ + #define SLASH "\\" + int tinyfd_winUtf8 = 0 ; /* on windows string char can be 0:MBSC or 1:UTF-8 */ +#else + #include + #include + #include /* on old systems try instead */ + #include + #include + #define SLASH "/" +#endif /* _WIN32 */ + +#define MAX_PATH_OR_CMD 1024 /* _MAX_PATH or MAX_PATH */ +#define MAX_MULTIPLE_FILES 32 + +char tinyfd_version [8] = "2.9.3"; + +static int tinyfd_verbose = 0 ; /* print on unix the command line calls */ + +#if defined(TINYFD_NOLIB) && defined(_WIN32) +int tinyfd_forceConsole = 1 ; +#else +int tinyfd_forceConsole = 0 ; /* 0 (default) or 1 */ +#endif +/* for unix & windows: 0 (graphic mode) or 1 (console mode). +0: try to use a graphic solution, if it fails then it uses console mode. +1: forces all dialogs into console mode even when the X server is present, + if the package dialog (and a console is present) or dialog.exe is installed. + on windows it only make sense for console applications */ + +char tinyfd_response[1024]; +/* if you pass "tinyfd_query" as aTitle, +the functions will not display the dialogs +but and return 0 for console mode, 1 for graphic mode. +tinyfd_response is then filled with the retain solution. +possible values for tinyfd_response are (all lowercase) +for the graphic mode: + windows applescript zenity zenity3 matedialog qarma kdialog + tkinter gxmessage gmessage xmessage xdialog gdialog +for the console mode: + dialog whiptail basicinput */ + +#if defined(TINYFD_NOLIB) && defined(_WIN32) +static int gWarningDisplayed = 1 ; +#else +static int gWarningDisplayed = 0 ; +#endif + +static char gTitle[]="missing software! (we will try basic console input)"; + +#ifdef _WIN32 +static char gMessageWin[] = "\ + ___________\n\ +/ \\ \n\ +| tiny file |\n\ +| dialogs |\n\ +\\_____ ____/\n\ + \\|\ +tiny file dialogs on Windows needs:\ +\n\ta graphic display\ +\nor\tdialog.exe (enhanced console mode)\ +\nor\ta console for basic input"; +#else +static char gMessageUnix[] = "\ + ___________\n\ +/ \\ \n\ +| tiny file |\n\ +| dialogs |\n\ +\\_____ ____/\n\ + \\|\ +\ntiny file dialogs on UNIX needs:\n\tapplescript\ +\nor\tzenity / matedialog\ +\nor\tqarma (zenity for qt)\ +\nor\tkdialog\ +\nor\tXdialog\ +\nor\tpython 2 + tkinter\ +\nor\tdialog (opens a console xterm if needed)\ +\nor\txterm + bash (opens a console for basic input)\ +\nor\tit will use the existing console for basic input"; +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4996) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */ +#pragma warning(disable:4100) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */ +#pragma warning(disable:4706) /* allows usage of strncpy, strcpy, strcat, sprintf, fopen */ +#endif + +static char * getPathWithoutFinalSlash( + char * const aoDestination, /* make sure it is allocated, use _MAX_PATH */ + char const * const aSource) /* aoDestination and aSource can be the same */ +{ + char const * lTmp ; + if ( aSource ) + { + lTmp = strrchr(aSource, '/'); + if (!lTmp) + { + lTmp = strrchr(aSource, '\\'); + } + if (lTmp) + { + strncpy(aoDestination, aSource, lTmp - aSource ); + aoDestination[lTmp - aSource] = '\0'; + } + else + { + * aoDestination = '\0'; + } + } + else + { + * aoDestination = '\0'; + } + return aoDestination; +} + + +static char * getLastName( + char * const aoDestination, /* make sure it is allocated */ + char const * const aSource) +{ + /* copy the last name after '/' or '\' */ + char const * lTmp ; + if ( aSource ) + { + lTmp = strrchr(aSource, '/'); + if (!lTmp) + { + lTmp = strrchr(aSource, '\\'); + } + if (lTmp) + { + strcpy(aoDestination, lTmp + 1); + } + else + { + strcpy(aoDestination, aSource); + } + } + else + { + * aoDestination = '\0'; + } + return aoDestination; +} + + +static void ensureFinalSlash ( char * const aioString ) +{ + if ( aioString && strlen ( aioString ) ) + { + char * lastcar = aioString + strlen ( aioString ) - 1 ; + if ( strncmp ( lastcar , SLASH , 1 ) ) + { + strcat ( lastcar , SLASH ) ; + } + } +} + + +static void Hex2RGB( char const aHexRGB [8] , + unsigned char aoResultRGB [3] ) +{ + char lColorChannel [8] ; + if ( aoResultRGB ) + { + if ( aHexRGB ) + { + strcpy(lColorChannel, aHexRGB ) ; + aoResultRGB[2] = (unsigned char)strtoul(lColorChannel+5,NULL,16); + lColorChannel[5] = '\0'; + aoResultRGB[1] = (unsigned char)strtoul(lColorChannel+3,NULL,16); + lColorChannel[3] = '\0'; + aoResultRGB[0] = (unsigned char)strtoul(lColorChannel+1,NULL,16); +/* printf("%d %d %d\n", aoResultRGB[0], aoResultRGB[1], aoResultRGB[2]); */ + } + else + { + aoResultRGB[0]=0; + aoResultRGB[1]=0; + aoResultRGB[2]=0; + } + } +} + +static void RGB2Hex( unsigned char const aRGB [3] , + char aoResultHexRGB [8] ) +{ + if ( aoResultHexRGB ) + { + if ( aRGB ) + { +#if defined(__GNUC__) && defined(_WIN32) + sprintf(aoResultHexRGB, "#%02hx%02hx%02hx", +#else + sprintf(aoResultHexRGB, "#%02hhx%02hhx%02hhx", +#endif + aRGB[0], aRGB[1], aRGB[2]); + /* printf("aoResultHexRGB %s\n", aoResultHexRGB); */ + } + else + { + aoResultHexRGB[0]=0; + aoResultHexRGB[1]=0; + aoResultHexRGB[2]=0; + } + } +} + + +static void replaceSubStr ( char const * const aSource , + char const * const aOldSubStr , + char const * const aNewSubStr , + char * const aoDestination ) +{ + char const * pOccurence ; + char const * p ; + char const * lNewSubStr = "" ; + int lOldSubLen = strlen ( aOldSubStr ) ; + + if ( ! aSource ) + { + * aoDestination = '\0' ; + return ; + } + if ( ! aOldSubStr ) + { + strcpy ( aoDestination , aSource ) ; + return ; + } + if ( aNewSubStr ) + { + lNewSubStr = aNewSubStr ; + } + p = aSource ; + * aoDestination = '\0' ; + while ( ( pOccurence = strstr ( p , aOldSubStr ) ) != NULL ) + { + strncat ( aoDestination , p , pOccurence - p ) ; + strcat ( aoDestination , lNewSubStr ) ; + p = pOccurence + lOldSubLen ; + } + strcat ( aoDestination , p ) ; +} + + +static int filenameValid( char const * const aFileNameWithoutPath ) +{ + if ( ! aFileNameWithoutPath + || ! strlen(aFileNameWithoutPath) + || strpbrk(aFileNameWithoutPath , "\\/:*?\"<>|") ) + { + return 0 ; + } + return 1 ; +} + + +static int fileExists( char const * const aFilePathAndName ) +{ + FILE * lIn ; + if ( ! aFilePathAndName || ! strlen(aFilePathAndName) ) + { + return 0 ; + } + lIn = fopen( aFilePathAndName , "r" ) ; + if ( ! lIn ) + { + return 0 ; + } + fclose ( lIn ) ; + return 1 ; +} + + +/* source and destination can be the same or ovelap*/ +static char const * ensureFilesExist( char * const aDestination , + char const * const aSourcePathsAndNames) +{ + char * lDestination = aDestination ; + char const * p ; + char const * p2 ; + int lLen ; + + if ( ! aSourcePathsAndNames ) + { + return NULL ; + } + lLen = strlen( aSourcePathsAndNames ) ; + if ( ! lLen ) + { + return NULL ; + } + + p = aSourcePathsAndNames ; + while ( (p2 = strchr(p, '|')) != NULL ) + { + lLen = p2-p ; + memmove(lDestination,p,lLen); + lDestination[lLen] = '\0'; + if ( fileExists ( lDestination ) ) + { + lDestination += lLen ; + * lDestination = '|'; + lDestination ++ ; + } + p = p2 + 1 ; + } + if ( fileExists ( p ) ) + { + lLen = strlen(p) ; + memmove(lDestination,p,lLen); + lDestination[lLen] = '\0'; + } + else + { + * (lDestination-1) = '\0'; + } + return aDestination ; +} + + +static void wipefile(char const * const aFilename) +{ + int i; + struct stat st; + FILE * lIn; + + if (stat(aFilename, &st) == 0) + { + if ((lIn = fopen(aFilename, "w"))) + { + for (i = 0; i < st.st_size; i++) + { + fputc('A', lIn); + } + } + fclose(lIn); + } +} + +#ifdef _WIN32 + +static int replaceChr ( char * const aString , + char const aOldChr , + char const aNewChr ) +{ + char * p ; + int lRes = 0 ; + + if ( ! aString ) + { + return 0 ; + } + + if ( aOldChr == aNewChr ) + { + return 0 ; + } + + p = aString ; + while ( (p = strchr ( p , aOldChr )) ) + { + * p = aNewChr ; + p ++ ; + lRes = 1 ; + } + return lRes ; +} + + +static int dirExists ( char const * const aDirPath ) +{ + struct stat lInfo; + if ( ! aDirPath || ! strlen ( aDirPath ) ) + return 0 ; + if ( stat ( aDirPath , & lInfo ) != 0 ) + return 0 ; + else if ( lInfo.st_mode & S_IFDIR ) + return 1 ; + else + return 0 ; +} + +#ifndef TINYFD_NOLIB + +static wchar_t * getPathWithoutFinalSlashW( + wchar_t * const aoDestination, /* make sure it is allocated, use _MAX_PATH */ + wchar_t const * const aSource) /* aoDestination and aSource can be the same */ +{ + wchar_t const * lTmp; + if (aSource) + { + lTmp = wcsrchr(aSource, L'/'); + if (!lTmp) + { + lTmp = wcsrchr(aSource, L'\\'); + } + if (lTmp) + { + wcsncpy(aoDestination, aSource, lTmp - aSource); + aoDestination[lTmp - aSource] = L'\0'; + } + else + { + *aoDestination = L'\0'; + } + } + else + { + *aoDestination = L'\0'; + } + return aoDestination; +} + + +static wchar_t * getLastNameW( + wchar_t * const aoDestination, /* make sure it is allocated */ + wchar_t const * const aSource) +{ + /* copy the last name after '/' or '\' */ + wchar_t const * lTmp; + if (aSource) + { + lTmp = wcsrchr(aSource, L'/'); + if (!lTmp) + { + lTmp = wcsrchr(aSource, L'\\'); + } + if (lTmp) + { + wcscpy(aoDestination, lTmp + 1); + } + else + { + wcscpy(aoDestination, aSource); + } + } + else + { + *aoDestination = L'\0'; + } + return aoDestination; +} + + +static void Hex2RGBW(wchar_t const aHexRGB[8], + unsigned char aoResultRGB[3]) +{ + wchar_t lColorChannel[8]; + if (aoResultRGB) + { + if (aHexRGB) + { + wcscpy(lColorChannel, aHexRGB); + aoResultRGB[2] = (unsigned char)wcstoul(lColorChannel + 5, NULL, 16); + lColorChannel[5] = '\0'; + aoResultRGB[1] = (unsigned char)wcstoul(lColorChannel + 3, NULL, 16); + lColorChannel[3] = '\0'; + aoResultRGB[0] = (unsigned char)wcstoul(lColorChannel + 1, NULL, 16); + /* printf("%d %d %d\n", aoResultRGB[0], aoResultRGB[1], aoResultRGB[2]); */ + } + else + { + aoResultRGB[0] = 0; + aoResultRGB[1] = 0; + aoResultRGB[2] = 0; + } + } +} + + +static void RGB2HexW( + unsigned char const aRGB[3], + wchar_t aoResultHexRGB[8]) +{ + if (aoResultHexRGB) + { + if (aRGB) + { +#if defined(__GNUC__) && __GNUC__ < 5 +swprintf(aoResultHexRGB, L"#%02hhx%02hhx%02hhx", aRGB[0], aRGB[1], aRGB[2]); +#else +swprintf(aoResultHexRGB, 8, L"#%02hhx%02hhx%02hhx", aRGB[0], aRGB[1], aRGB[2]); +#endif + /* wprintf(L"aoResultHexRGB %s\n", aoResultHexRGB); */ + } + else + { + aoResultHexRGB[0] = 0; + aoResultHexRGB[1] = 0; + aoResultHexRGB[2] = 0; + } + } +} + + +#if !defined(WC_ERR_INVALID_CHARS) +/* undefined prior to Vista, so not yet in MINGW header file */ +#define WC_ERR_INVALID_CHARS 0x00000080 +#endif + + +static int sizeUtf16(char const * const aUtf8string) +{ + return MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + aUtf8string, -1, NULL, 0); +} + + +static int sizeUtf8(wchar_t const * const aUtf16string) +{ + return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, + aUtf16string, -1, NULL, 0, NULL, NULL); +} + + +static wchar_t * utf8to16(char const * const aUtf8string) +{ + wchar_t * lUtf16string ; + int lSize = sizeUtf16(aUtf8string); + lUtf16string = (wchar_t *) malloc( lSize * sizeof(wchar_t) ); + lSize = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + aUtf8string, -1, lUtf16string, lSize); + if (lSize == 0) + { + free(lUtf16string); + return NULL; + } + return lUtf16string; +} + + +static char * utf16to8(wchar_t const * const aUtf16string) +{ + char * lUtf8string ; + int lSize = sizeUtf8(aUtf16string); + lUtf8string = (char *) malloc( lSize ); + lSize = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, + aUtf16string, -1, lUtf8string, lSize, NULL, NULL); + if (lSize == 0) + { + free(lUtf8string); + return NULL; + } + return lUtf8string; +} + + +static void runSilentA(char const * const aString) +{ + STARTUPINFOA StartupInfo; + PROCESS_INFORMATION ProcessInfo; + char * lArgs; + char * pEnvCMD = NULL; + char * pDefaultCMD = "CMD.EXE"; + ULONG rc; + int lStringLen = 0; + + memset(&StartupInfo, 0, sizeof(StartupInfo)); + StartupInfo.cb = sizeof(STARTUPINFOA); + StartupInfo.dwFlags = STARTF_USESHOWWINDOW; + StartupInfo.wShowWindow = SW_HIDE; + + if ( aString ) + { + lStringLen = strlen(aString); + } + lArgs = (char *) malloc( MAX_PATH_OR_CMD + lStringLen ); + + pEnvCMD = getenv("COMSPEC"); + + if (pEnvCMD){ + + strcpy(lArgs, pEnvCMD); + } + else{ + strcpy(lArgs, pDefaultCMD); + } + + /* c to execute then terminate the command window */ + strcat(lArgs, " /c "); + + /* application and parameters to run from the command window */ + strcat(lArgs, aString); + + if (!CreateProcessA(NULL, lArgs, NULL, NULL, FALSE, + CREATE_NEW_CONSOLE, NULL, NULL, + &StartupInfo, &ProcessInfo)) + { + free(lArgs); + return; /* GetLastError(); */ + } + + WaitForSingleObject(ProcessInfo.hProcess, INFINITE); + if (!GetExitCodeProcess(ProcessInfo.hProcess, &rc)) + rc = 0; + + CloseHandle(ProcessInfo.hThread); + CloseHandle(ProcessInfo.hProcess); + + free(lArgs); + return; /* rc */ +} + + +static void runSilentW(wchar_t const * const aString) +{ + STARTUPINFOW StartupInfo; + PROCESS_INFORMATION ProcessInfo; + ULONG rc; + wchar_t * lArgs; + wchar_t * pEnvCMD; + wchar_t * pDefaultCMD = L"CMD.EXE"; + int lStringLen = 0; + + memset(&StartupInfo, 0, sizeof(StartupInfo)); + StartupInfo.cb = sizeof(STARTUPINFOW); + StartupInfo.dwFlags = STARTF_USESHOWWINDOW; + StartupInfo.wShowWindow = SW_HIDE; + + if ( aString ) + { + lStringLen = wcslen(aString); + } + lArgs = (wchar_t *) malloc( (MAX_PATH_OR_CMD + lStringLen) * sizeof(wchar_t) ); + + pEnvCMD = utf8to16( getenv("COMSPEC") ); + if (pEnvCMD) + { + wcscpy(lArgs, pEnvCMD); + free(pEnvCMD); + } + else + { + wcscpy(lArgs, pDefaultCMD); + } + + /* c to execute then terminate the command window */ + wcscat(lArgs, L" /c "); + + /* application and parameters to run from the command window */ + wcscat(lArgs, aString); + + if (!CreateProcessW(NULL, lArgs, NULL, NULL, FALSE, + CREATE_NEW_CONSOLE, NULL, NULL, + &StartupInfo, &ProcessInfo)) + { + free(lArgs); + return; /* GetLastError(); */ + } + + WaitForSingleObject(ProcessInfo.hProcess, INFINITE); + if (!GetExitCodeProcess(ProcessInfo.hProcess, &rc)) + { + rc = 0; + } + + CloseHandle(ProcessInfo.hThread); + CloseHandle(ProcessInfo.hProcess); + + free(lArgs); + return; /* rc */ +} + + +int tinyfd_messageBoxW( + wchar_t const * const aTitle, /* NULL or "" */ + wchar_t const * const aMessage, /* NULL or "" may contain \n and \t */ + wchar_t const * const aDialogType, /* "ok" "okcancel" "yesno" "yesnocancel" */ + wchar_t const * const aIconType, /* "info" "warning" "error" "question" */ + int const aDefaultButton) /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ +{ + int lBoxReturnValue; + UINT aCode; + + if (aIconType && !wcscmp(L"warning", aIconType)) + { + aCode = MB_ICONWARNING; + } + else if (aIconType && !wcscmp(L"error", aIconType)) + { + aCode = MB_ICONERROR; + } + else if (aIconType && !wcscmp(L"question", aIconType)) + { + aCode = MB_ICONQUESTION; + } + else + { + aCode = MB_ICONINFORMATION; + } + + if (aDialogType && !wcscmp(L"okcancel", aDialogType)) + { + aCode += MB_OKCANCEL; + if (!aDefaultButton) + { + aCode += MB_DEFBUTTON2; + } + } + else if (aDialogType && !wcscmp(L"yesno", aDialogType)) + { + aCode += MB_YESNO; + if (!aDefaultButton) + { + aCode += MB_DEFBUTTON2; + } + } + else + { + aCode += MB_OK; + } + + lBoxReturnValue = MessageBoxW(NULL, aMessage, aTitle, aCode); + if (((aDialogType + && wcscmp(L"okcancel", aDialogType) + && wcscmp(L"yesno", aDialogType))) + || (lBoxReturnValue == IDOK) + || (lBoxReturnValue == IDYES)) + { + return 1; + } + else + { + return 0; + } +} + + +static int messageBoxWinGui8( + char const * const aTitle, /* NULL or "" */ + char const * const aMessage, /* NULL or "" may contain \n and \t */ + char const * const aDialogType, /* "ok" "okcancel" "yesno" "yesnocancel" */ + char const * const aIconType, /* "info" "warning" "error" "question" */ + int const aDefaultButton) /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ +{ + int lIntRetVal; + wchar_t * lTitle; + wchar_t * lMessage; + wchar_t * lDialogType; + wchar_t * lIconType; + + lTitle = utf8to16(aTitle); + lMessage = utf8to16(aMessage); + lDialogType = utf8to16(aDialogType); + lIconType = utf8to16(aIconType); + + lIntRetVal = tinyfd_messageBoxW(lTitle, lMessage, + lDialogType, lIconType, aDefaultButton ); + + free(lTitle); + free(lMessage); + free(lDialogType); + free(lIconType); + + return lIntRetVal ; +} + + +static char const * inputBoxWinGui( + char * const aoBuff , + char const * const aTitle , /* NULL or "" */ + char const * const aMessage , /* NULL or "" may NOT contain \n nor \t */ + char const * const aDefaultInput ) /* "" , if NULL it's a passwordBox */ +{ + char * lDialogString; + FILE * lIn; + int lResult; + int lTitleLen; + int lMessageLen; + wchar_t * lDialogStringW; + + lTitleLen = aTitle ? strlen(aTitle) : 0 ; + lMessageLen = aMessage ? strlen(aMessage) : 0 ; + lDialogString = (char *)malloc(3 * MAX_PATH_OR_CMD + lTitleLen + lMessageLen); + + if (aDefaultInput) + { + sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.vbs", + getenv("USERPROFILE")); + } + else + { + sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.hta", + getenv("USERPROFILE")); + } + lIn = fopen(lDialogString, "w"); + if (!lIn) + { + free(lDialogString); + return NULL; + } + + if ( aDefaultInput ) + { + strcpy(lDialogString, "Dim result:result=InputBox(\""); + if (aMessage && strlen(aMessage)) + { + strcat(lDialogString, aMessage); + } + strcat(lDialogString, "\",\""); + if (aTitle && strlen(aTitle)) + { + strcat(lDialogString, aTitle); + } + strcat(lDialogString, "\",\""); + if (aDefaultInput && strlen(aDefaultInput)) + { + strcat(lDialogString, aDefaultInput); + } + strcat(lDialogString, "\"):If IsEmpty(result) then:WScript.Echo 0"); + strcat(lDialogString, ":Else: WScript.Echo \"1\" & result : End If"); + } + else + { + sprintf(lDialogString, "\n\ +\n\ +\n\ +%s\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +
    \n\ +%s\n\ +\n\ +\n\ +\n\ +
    \n\ +

    \n\ +\n\ +
    \n\ +
    \n\ +\n\ +\n\ +\n\ +\n\ +
    \n\ +
    \n\ +
    \n\ +\n\ +\n\ +" , aTitle ? aTitle : "", aMessage ? aMessage : "") ; + } + fputs(lDialogString, lIn); + fclose(lIn); + + strcpy(lDialogString, ""); + + if (aDefaultInput) + { + strcat(lDialogString, "cscript.exe "); + strcat(lDialogString, "//Nologo "); + strcat(lDialogString,"%USERPROFILE%\\AppData\\Local\\Temp\\tinyfd.vbs"); + strcat(lDialogString, " > %USERPROFILE%\\AppData\\Local\\Temp\\tinyfd.txt"); + } + else + { + strcat(lDialogString, + "mshta.exe %USERPROFILE%\\AppData\\Local\\Temp\\tinyfd.hta"); + } + + /* printf ( "lDialogString: %s\n" , lDialogString ) ; */ + + if (tinyfd_winUtf8) + { + lDialogStringW = utf8to16(lDialogString); + runSilentW(lDialogStringW); + free(lDialogStringW); + } + else + { + runSilentA(lDialogString); + } + + /* + if (!(lIn = _popen(lDialogString, "r"))) + { + free(lDialogString); + return NULL; + } + while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL) + { + } + _pclose(lIn); + if (aoBuff[strlen(aoBuff) - 1] == '\n') + { + aoBuff[strlen(aoBuff) - 1] = '\0'; + } + */ + + if (aDefaultInput) + { + sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.txt", + getenv("USERPROFILE")); + if (!(lIn = fopen(lDialogString, "r"))) + { + remove(lDialogString); + free(lDialogString); + return NULL; + } + while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL) + {} + fclose(lIn); + remove(lDialogString); + + sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.vbs", + getenv("USERPROFILE")); + } + else + { + sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.txt", + getenv("USERPROFILE")); + if (!(lIn = fopen(lDialogString, "r"))) + { + remove(lDialogString); + free(lDialogString); + return NULL; + } + while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL) + {} + fclose(lIn); + + wipefile(lDialogString); + remove(lDialogString); + sprintf(lDialogString, "%s\\AppData\\Local\\Temp\\tinyfd.hta", + getenv("USERPROFILE")); + } + remove(lDialogString); + free(lDialogString); + /* printf ( "aoBuff: %s\n" , aoBuff ) ; */ + lResult = strncmp(aoBuff, "1", 1) ? 0 : 1; + /* printf ( "lResult: %d \n" , lResult ) ; */ + if (!lResult) + { + return NULL ; + } + + if (aoBuff[strlen(aoBuff) - 1] == '\n') + { + aoBuff[strlen(aoBuff) - 1] = '\0'; + } + + /* printf ( "aoBuff+1: %s\n" , aoBuff+1 ) ; */ + return aoBuff + 1; +} + + +wchar_t const * tinyfd_saveFileDialogW( + wchar_t const * const aTitle, /* NULL or "" */ + wchar_t const * const aDefaultPathAndFile, /* NULL or "" */ + int const aNumOfFilterPatterns, /* 0 */ + wchar_t const * const * const aFilterPatterns, /* NULL or {"*.jpg","*.png"} */ + wchar_t const * const aSingleFilterDescription) /* NULL or "image files" */ +{ + static wchar_t lBuff[MAX_PATH_OR_CMD]; + wchar_t lDirname[MAX_PATH_OR_CMD]; + wchar_t lDialogString[MAX_PATH_OR_CMD]; + wchar_t lFilterPatterns[MAX_PATH_OR_CMD] = L""; + wchar_t * p; + wchar_t * lRetval; + int i; + HRESULT lHResult; + OPENFILENAMEW ofn = {0}; + + lHResult = CoInitializeEx(NULL, 0); + + getPathWithoutFinalSlashW(lDirname, aDefaultPathAndFile); + getLastNameW(lBuff, aDefaultPathAndFile); + + if (aNumOfFilterPatterns > 0) + { + if (aSingleFilterDescription && wcslen(aSingleFilterDescription)) + { + wcscpy(lFilterPatterns, aSingleFilterDescription); + wcscat(lFilterPatterns, L"\n"); + } + wcscat(lFilterPatterns, aFilterPatterns[0]); + for (i = 1; i < aNumOfFilterPatterns; i++) + { + wcscat(lFilterPatterns, L";"); + wcscat(lFilterPatterns, aFilterPatterns[i]); + } + wcscat(lFilterPatterns, L"\n"); + if (!(aSingleFilterDescription && wcslen(aSingleFilterDescription))) + { + wcscpy(lDialogString, lFilterPatterns); + wcscat(lFilterPatterns, lDialogString); + } + wcscat(lFilterPatterns, L"All Files\n*.*\n"); + p = lFilterPatterns; + while ((p = wcschr(p, L'\n')) != NULL) + { + *p = L'\0'; + p++; + } + } + + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.hwndOwner = 0; + ofn.hInstance = 0; + ofn.lpstrFilter = lFilterPatterns && wcslen(lFilterPatterns) ? lFilterPatterns : NULL; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = lBuff; + + ofn.nMaxFile = MAX_PATH_OR_CMD; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT; + ofn.lpstrInitialDir = lDirname && wcslen(lDirname) ? lDirname : NULL; + ofn.lpstrTitle = aTitle && wcslen(aTitle) ? aTitle : NULL; + ofn.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR; + ofn.nFileOffset = 0; + ofn.nFileExtension = 0; + ofn.lpstrDefExt = NULL; + ofn.lCustData = 0L; + ofn.lpfnHook = NULL; + ofn.lpTemplateName = NULL; + + if (GetSaveFileNameW(&ofn) == 0) + { + lRetval = NULL; + } + else + { + lRetval = lBuff; + } + + if (lHResult == S_OK || lHResult == S_FALSE) + { + CoUninitialize(); + } + return lRetval; +} + + +static char const * saveFileDialogWinGui8( + char * const aoBuff, + char const * const aTitle, /* NULL or "" */ + char const * const aDefaultPathAndFile, /* NULL or "" */ + int const aNumOfFilterPatterns, /* 0 */ + char const * const * const aFilterPatterns, /* NULL or {"*.jpg","*.png"} */ + char const * const aSingleFilterDescription) /* NULL or "image files" */ +{ + wchar_t * lTitle; + wchar_t * lDefaultPathAndFile; + wchar_t * lSingleFilterDescription; + wchar_t * * lFilterPatterns; + wchar_t const * lTmpWChar; + char * lTmpChar; + int i ; + + lFilterPatterns = (wchar_t **) malloc(aNumOfFilterPatterns*sizeof(wchar_t *)); + for (i = 0; i < aNumOfFilterPatterns; i++) + { + lFilterPatterns[i] = utf8to16(aFilterPatterns[i]); + } + + lTitle = utf8to16(aTitle); + lDefaultPathAndFile = utf8to16(aDefaultPathAndFile); + lSingleFilterDescription = utf8to16(aSingleFilterDescription); + + lTmpWChar = tinyfd_saveFileDialogW( + lTitle, + lDefaultPathAndFile, + aNumOfFilterPatterns, + (wchar_t const** ) /*stupid cast for gcc*/ + lFilterPatterns, + lSingleFilterDescription); + + free(lTitle); + free(lDefaultPathAndFile); + free(lSingleFilterDescription); + for (i = 0; i < aNumOfFilterPatterns; i++) + { + free(lFilterPatterns[i]); + } + free(lFilterPatterns); + + if (!lTmpWChar) + { + return NULL; + } + + lTmpChar = utf16to8(lTmpWChar); + strcpy(aoBuff, lTmpChar); + free(lTmpChar); + + return aoBuff; +} + + +wchar_t const * tinyfd_openFileDialogW( + wchar_t const * const aTitle, /* NULL or "" */ + wchar_t const * const aDefaultPathAndFile, /* NULL or "" */ + int const aNumOfFilterPatterns, /* 0 */ + wchar_t const * const * const aFilterPatterns, /* NULL or {"*.jpg","*.png"} */ + wchar_t const * const aSingleFilterDescription, /* NULL or "image files" */ + int const aAllowMultipleSelects) /* 0 or 1 */ +{ + static wchar_t lBuff[MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD]; + + size_t lLengths[MAX_MULTIPLE_FILES]; + wchar_t lDirname[MAX_PATH_OR_CMD]; + wchar_t lFilterPatterns[MAX_PATH_OR_CMD] = L""; + wchar_t lDialogString[MAX_PATH_OR_CMD]; + wchar_t * lPointers[MAX_MULTIPLE_FILES]; + wchar_t * lRetval, * p; + int i, j; + size_t lBuffLen; + HRESULT lHResult; + OPENFILENAMEW ofn = { 0 }; + + lHResult = CoInitializeEx(NULL, 0); + + getPathWithoutFinalSlashW(lDirname, aDefaultPathAndFile); + getLastNameW(lBuff, aDefaultPathAndFile); + + if (aNumOfFilterPatterns > 0) + { + if (aSingleFilterDescription && wcslen(aSingleFilterDescription)) + { + wcscpy(lFilterPatterns, aSingleFilterDescription); + wcscat(lFilterPatterns, L"\n"); + } + wcscat(lFilterPatterns, aFilterPatterns[0]); + for (i = 1; i < aNumOfFilterPatterns; i++) + { + wcscat(lFilterPatterns, L";"); + wcscat(lFilterPatterns, aFilterPatterns[i]); + } + wcscat(lFilterPatterns, L"\n"); + if (!(aSingleFilterDescription && wcslen(aSingleFilterDescription))) + { + wcscpy(lDialogString, lFilterPatterns); + wcscat(lFilterPatterns, lDialogString); + } + wcscat(lFilterPatterns, L"All Files\n*.*\n"); + p = lFilterPatterns; + while ((p = wcschr(p, L'\n')) != NULL) + { + *p = L'\0'; + p++; + } + } + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = 0; + ofn.hInstance = 0; + ofn.lpstrFilter = lFilterPatterns && wcslen(lFilterPatterns) ? lFilterPatterns : NULL; + ofn.lpstrCustomFilter = NULL; + ofn.nMaxCustFilter = 0; + ofn.nFilterIndex = 1; + ofn.lpstrFile = lBuff; + ofn.nMaxFile = MAX_PATH_OR_CMD; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT; + ofn.lpstrInitialDir = lDirname && wcslen(lDirname) ? lDirname : NULL; + ofn.lpstrTitle = aTitle && wcslen(aTitle) ? aTitle : NULL; + ofn.Flags = OFN_EXPLORER | OFN_NOCHANGEDIR; + ofn.nFileOffset = 0; + ofn.nFileExtension = 0; + ofn.lpstrDefExt = NULL; + ofn.lCustData = 0L; + ofn.lpfnHook = NULL; + ofn.lpTemplateName = NULL; + + if (aAllowMultipleSelects) + { + ofn.Flags |= OFN_ALLOWMULTISELECT; + } + + if (GetOpenFileNameW(&ofn) == 0) + { + lRetval = NULL; + } + else + { + lBuffLen = wcslen(lBuff); + lPointers[0] = lBuff + lBuffLen + 1; + if (!aAllowMultipleSelects || (lPointers[0][0] == L'\0')) + { + lRetval = lBuff; + } + else + { + i = 0; + do + { + lLengths[i] = wcslen(lPointers[i]); + lPointers[i + 1] = lPointers[i] + lLengths[i] + 1; + i++; + } while (lPointers[i][0] != L'\0'); + i--; + p = lBuff + MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD - 1; + *p = L'\0'; + for (j = i; j >= 0; j--) + { + p -= lLengths[j]; + memmove(p, lPointers[j], lLengths[j]*sizeof(wchar_t)); + p--; + *p = L'\\'; + p -= lBuffLen; + memmove(p, lBuff, lBuffLen*sizeof(wchar_t)); + p--; + *p = L'|'; + } + p++; + lRetval = p; + } + } + + if (lHResult == S_OK || lHResult == S_FALSE) + { + CoUninitialize(); + } + return lRetval; +} + + +static char const * openFileDialogWinGui8( + char * const aoBuff, + char const * const aTitle, /* NULL or "" */ + char const * const aDefaultPathAndFile, /* NULL or "" */ + int const aNumOfFilterPatterns, /* 0 */ + char const * const * const aFilterPatterns, /* NULL or {"*.jpg","*.png"} */ + char const * const aSingleFilterDescription, /* NULL or "image files" */ + int const aAllowMultipleSelects) /* 0 or 1 */ +{ + wchar_t * lTitle; + wchar_t * lDefaultPathAndFile; + wchar_t * lSingleFilterDescription; + wchar_t * * lFilterPatterns; + wchar_t const * lTmpWChar; + char * lTmpChar; + int i; + + lFilterPatterns = (wchar_t * *) malloc(aNumOfFilterPatterns*sizeof(wchar_t *)); + for (i = 0; i < aNumOfFilterPatterns; i++) + { + lFilterPatterns[i] = utf8to16(aFilterPatterns[i]); + } + + lTitle = utf8to16(aTitle); + lDefaultPathAndFile = utf8to16(aDefaultPathAndFile); + lSingleFilterDescription = utf8to16(aSingleFilterDescription); + + lTmpWChar = tinyfd_openFileDialogW( + lTitle, + lDefaultPathAndFile, + aNumOfFilterPatterns, + (wchar_t const**) /*stupid cast for gcc*/ + lFilterPatterns, + lSingleFilterDescription, + aAllowMultipleSelects); + + free(lTitle); + free(lDefaultPathAndFile); + free(lSingleFilterDescription); + for (i = 0; i < aNumOfFilterPatterns; i++) + { + free(lFilterPatterns[i]); + } + free(lFilterPatterns); + + if (!lTmpWChar) + { + return NULL; + } + + lTmpChar = utf16to8(lTmpWChar); + strcpy(aoBuff, lTmpChar); + free(lTmpChar); + + return aoBuff; +} + +#ifndef TINYFD_NOSELECTFOLDERWIN +static int __stdcall BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) +{ + if (uMsg == BFFM_INITIALIZED) + { + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, pData); + } + return 0; +} + +static int __stdcall BrowseCallbackProcW(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) +{ + if (uMsg == BFFM_INITIALIZED) + { + SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, (LPARAM)pData); + } + return 0; +} + +wchar_t const * tinyfd_selectFolderDialogW( + wchar_t const * const aTitle, /* NULL or "" */ + wchar_t const * const aDefaultPath) /* NULL or "" */ +{ + static wchar_t lBuff[MAX_PATH_OR_CMD]; + + BROWSEINFOW bInfo; + LPITEMIDLIST lpItem; + HRESULT lHResult; + + lHResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + bInfo.hwndOwner = 0; + bInfo.pidlRoot = NULL; + bInfo.pszDisplayName = lBuff; + bInfo.lpszTitle = aTitle && wcslen(aTitle) ? aTitle : NULL; + if (lHResult == S_OK || lHResult == S_FALSE) + { + bInfo.ulFlags = BIF_USENEWUI; + } + bInfo.lpfn = BrowseCallbackProcW; + bInfo.lParam = (LPARAM)aDefaultPath; + bInfo.iImage = -1; + + lpItem = SHBrowseForFolderW(&bInfo); + if (lpItem) + { + SHGetPathFromIDListW(lpItem, lBuff); + } + + if (lHResult == S_OK || lHResult == S_FALSE) + { + CoUninitialize(); + } + + if (lpItem) + { + return lBuff; + } + else + { + return NULL; + } +} + + +static char const * selectFolderDialogWinGui8 ( + char * const aoBuff , + char const * const aTitle , /* NULL or "" */ + char const * const aDefaultPath ) /* NULL or "" */ +{ + wchar_t * lTitle; + wchar_t * lDefaultPath; + wchar_t const * lTmpWChar; + char * lTmpChar; + + lTitle = utf8to16(aTitle); + lDefaultPath = utf8to16(aDefaultPath); + + lTmpWChar = tinyfd_selectFolderDialogW( + lTitle, + lDefaultPath); + + free(lTitle); + free(lDefaultPath); + if (!lTmpWChar) + { + return NULL; + } + + lTmpChar = utf16to8(lTmpWChar); + strcpy(aoBuff, lTmpChar); + free(lTmpChar); + + return aoBuff; +} +#endif /*TINYFD_NOSELECTFOLDERWIN*/ + + +wchar_t const * tinyfd_colorChooserW( + wchar_t const * const aTitle, /* NULL or "" */ + wchar_t const * const aDefaultHexRGB, /* NULL or "#FF0000"*/ + unsigned char const aDefaultRGB[3], /* { 0 , 255 , 255 } */ + unsigned char aoResultRGB[3]) /* { 0 , 0 , 0 } */ +{ + static wchar_t lResultHexRGB[8]; + CHOOSECOLORW cc; + COLORREF crCustColors[16]; + unsigned char lDefaultRGB[3]; + int lRet; + + HRESULT lHResult; + lHResult = CoInitializeEx(NULL, 0); + + if (aDefaultHexRGB) + { + Hex2RGBW(aDefaultHexRGB, lDefaultRGB); + } + else + { + lDefaultRGB[0] = aDefaultRGB[0]; + lDefaultRGB[1] = aDefaultRGB[1]; + lDefaultRGB[2] = aDefaultRGB[2]; + } + + /* we can't use aTitle */ + cc.lStructSize = sizeof(CHOOSECOLOR); + cc.hwndOwner = NULL; + cc.hInstance = NULL; + cc.rgbResult = RGB(lDefaultRGB[0], lDefaultRGB[1], lDefaultRGB[2]); + cc.lpCustColors = crCustColors; + cc.Flags = CC_RGBINIT | CC_FULLOPEN; + cc.lCustData = 0; + cc.lpfnHook = NULL; + cc.lpTemplateName = NULL; + + lRet = ChooseColorW(&cc); + + if (!lRet) + { + return NULL; + } + + aoResultRGB[0] = GetRValue(cc.rgbResult); + aoResultRGB[1] = GetGValue(cc.rgbResult); + aoResultRGB[2] = GetBValue(cc.rgbResult); + + RGB2HexW(aoResultRGB, lResultHexRGB); + + if (lHResult == S_OK || lHResult == S_FALSE) + { + CoUninitialize(); + } + + return lResultHexRGB; +} + + +static char const * colorChooserWinGui8( + char const * const aTitle, /* NULL or "" */ + char const * const aDefaultHexRGB, /* NULL or "#FF0000"*/ + unsigned char const aDefaultRGB[3], /* { 0 , 255 , 255 } */ + unsigned char aoResultRGB[3]) /* { 0 , 0 , 0 } */ +{ + static char lResultHexRGB[8]; + + wchar_t * lTitle; + wchar_t * lDefaultHexRGB; + wchar_t const * lTmpWChar; + char * lTmpChar; + + lTitle = utf8to16(aTitle); + lDefaultHexRGB = utf8to16(aDefaultHexRGB); + + lTmpWChar = tinyfd_colorChooserW( + lTitle, + lDefaultHexRGB, + aDefaultRGB, + aoResultRGB ); + + free(lTitle); + free(lDefaultHexRGB); + if (!lTmpWChar) + { + return NULL; + } + + lTmpChar = utf16to8(lTmpWChar); + strcpy(lResultHexRGB, lTmpChar); + free(lTmpChar); + + return lResultHexRGB; +} + + +static int messageBoxWinGuiA ( + char const * const aTitle , /* NULL or "" */ + char const * const aMessage , /* NULL or "" may contain \n and \t */ + char const * const aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */ + char const * const aIconType , /* "info" "warning" "error" "question" */ + int const aDefaultButton ) /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ +{ + int lBoxReturnValue; + UINT aCode ; + + if ( aIconType && ! strcmp( "warning" , aIconType ) ) + { + aCode = MB_ICONWARNING ; + } + else if ( aIconType && ! strcmp("error", aIconType)) + { + aCode = MB_ICONERROR ; + } + else if ( aIconType && ! strcmp("question", aIconType)) + { + aCode = MB_ICONQUESTION ; + } + else + { + aCode = MB_ICONINFORMATION ; + } + + if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) ) + { + aCode += MB_OKCANCEL ; + if ( ! aDefaultButton ) + { + aCode += MB_DEFBUTTON2 ; + } + } + else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) ) + { + aCode += MB_YESNO ; + if ( ! aDefaultButton ) + { + aCode += MB_DEFBUTTON2 ; + } + } + else if (aDialogType && !strcmp("yesnocancel", aDialogType)) + { + aCode += MB_YESNOCANCEL; + if (!aDefaultButton) + { + aCode += MB_DEFBUTTON3; + } + else if (aDefaultButton == 2) + { + aCode += MB_DEFBUTTON2; + } + } + else + { + aCode += MB_OK ; + } + + lBoxReturnValue = MessageBoxA(NULL, aMessage, aTitle, aCode); + + if (((aDialogType && !strcmp("yesnocancel", aDialogType)) + && (lBoxReturnValue == IDNO))) + { + return 2; + } + + if ( ( ( aDialogType + && strcmp("yesnocancel", aDialogType) + && strcmp("okcancel", aDialogType) + && strcmp("yesno", aDialogType))) + || (lBoxReturnValue == IDOK) + || (lBoxReturnValue == IDYES) ) + { + return 1 ; + } + else + { + return 0 ; + } +} + + +static char const * saveFileDialogWinGuiA ( + char * const aoBuff , + char const * const aTitle , /* NULL or "" */ + char const * const aDefaultPathAndFile , /* NULL or "" */ + int const aNumOfFilterPatterns , /* 0 */ + char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */ + char const * const aSingleFilterDescription ) /* NULL or "image files" */ +{ + char lDirname [MAX_PATH_OR_CMD] ; + char lDialogString[MAX_PATH_OR_CMD]; + char lFilterPatterns[MAX_PATH_OR_CMD] = ""; + int i ; + char * p; + char * lRetval; + HRESULT lHResult; + OPENFILENAMEA ofn = { 0 }; + + lHResult = CoInitializeEx(NULL,0); + + getPathWithoutFinalSlash(lDirname, aDefaultPathAndFile); + getLastName(aoBuff, aDefaultPathAndFile); + + if (aNumOfFilterPatterns > 0) + { + if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) + { + strcpy(lFilterPatterns, aSingleFilterDescription); + strcat(lFilterPatterns, "\n"); + } + strcat(lFilterPatterns, aFilterPatterns[0]); + for (i = 1; i < aNumOfFilterPatterns; i++) + { + strcat(lFilterPatterns, ";"); + strcat(lFilterPatterns, aFilterPatterns[i]); + } + strcat(lFilterPatterns, "\n"); + if ( ! (aSingleFilterDescription && strlen(aSingleFilterDescription) ) ) + { + strcpy(lDialogString, lFilterPatterns); + strcat(lFilterPatterns, lDialogString); + } + strcat(lFilterPatterns, "All Files\n*.*\n"); + p = lFilterPatterns; + while ((p = strchr(p, '\n')) != NULL) + { + *p = '\0'; + p ++ ; + } + } + + ofn.lStructSize = sizeof(OPENFILENAME) ; + ofn.hwndOwner = 0 ; + ofn.hInstance = 0 ; + ofn.lpstrFilter = lFilterPatterns && strlen(lFilterPatterns) ? lFilterPatterns : NULL; + ofn.lpstrCustomFilter = NULL ; + ofn.nMaxCustFilter = 0 ; + ofn.nFilterIndex = 1 ; + ofn.lpstrFile = aoBuff; + + ofn.nMaxFile = MAX_PATH_OR_CMD ; + ofn.lpstrFileTitle = NULL ; + ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT ; + ofn.lpstrInitialDir = lDirname && strlen(lDirname) ? lDirname : NULL; + ofn.lpstrTitle = aTitle && strlen(aTitle) ? aTitle : NULL; + ofn.Flags = OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR ; + ofn.nFileOffset = 0 ; + ofn.nFileExtension = 0 ; + ofn.lpstrDefExt = NULL ; + ofn.lCustData = 0L ; + ofn.lpfnHook = NULL ; + ofn.lpTemplateName = NULL ; + + if ( GetSaveFileNameA ( & ofn ) == 0 ) + { + lRetval = NULL ; + } + else + { + lRetval = aoBuff ; + } + + if (lHResult==S_OK || lHResult==S_FALSE) + { + CoUninitialize(); + } + return lRetval ; +} + + +static char const * openFileDialogWinGuiA ( + char * const aoBuff , + char const * const aTitle , /* NULL or "" */ + char const * const aDefaultPathAndFile , /* NULL or "" */ + int const aNumOfFilterPatterns , /* 0 */ + char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */ + char const * const aSingleFilterDescription , /* NULL or "image files" */ + int const aAllowMultipleSelects ) /* 0 or 1 */ +{ + char lDirname [MAX_PATH_OR_CMD] ; + char lFilterPatterns[MAX_PATH_OR_CMD] = ""; + char lDialogString[MAX_PATH_OR_CMD] ; + char * lPointers[MAX_MULTIPLE_FILES]; + size_t lLengths[MAX_MULTIPLE_FILES]; + int i , j ; + char * p; + size_t lBuffLen ; + char * lRetval; + HRESULT lHResult; + OPENFILENAMEA ofn = {0}; + + lHResult = CoInitializeEx(NULL,0); + + getPathWithoutFinalSlash(lDirname, aDefaultPathAndFile); + getLastName(aoBuff, aDefaultPathAndFile); + + if (aNumOfFilterPatterns > 0) + { + if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) + { + strcpy(lFilterPatterns, aSingleFilterDescription); + strcat(lFilterPatterns, "\n"); + } + strcat(lFilterPatterns, aFilterPatterns[0]); + for (i = 1; i < aNumOfFilterPatterns; i++) + { + strcat(lFilterPatterns, ";"); + strcat(lFilterPatterns, aFilterPatterns[i]); + } + strcat(lFilterPatterns, "\n"); + if ( ! (aSingleFilterDescription && strlen(aSingleFilterDescription) ) ) + { + strcpy(lDialogString, lFilterPatterns); + strcat(lFilterPatterns, lDialogString); + } + strcat(lFilterPatterns, "All Files\n*.*\n"); + p = lFilterPatterns; + while ((p = strchr(p, '\n')) != NULL) + { + *p = '\0'; + p ++ ; + } + } + + ofn.lStructSize = sizeof ( OPENFILENAME ) ; + ofn.hwndOwner = 0 ; + ofn.hInstance = 0 ; + ofn.lpstrFilter = lFilterPatterns && strlen(lFilterPatterns) ? lFilterPatterns : NULL; + ofn.lpstrCustomFilter = NULL ; + ofn.nMaxCustFilter = 0 ; + ofn.nFilterIndex = 1 ; + ofn.lpstrFile = aoBuff ; + ofn.nMaxFile = MAX_PATH_OR_CMD ; + ofn.lpstrFileTitle = NULL ; + ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT ; + ofn.lpstrInitialDir = lDirname && strlen(lDirname) ? lDirname : NULL; + ofn.lpstrTitle = aTitle && strlen(aTitle) ? aTitle : NULL; + ofn.Flags = OFN_EXPLORER | OFN_NOCHANGEDIR ; + ofn.nFileOffset = 0 ; + ofn.nFileExtension = 0 ; + ofn.lpstrDefExt = NULL ; + ofn.lCustData = 0L ; + ofn.lpfnHook = NULL ; + ofn.lpTemplateName = NULL ; + + if ( aAllowMultipleSelects ) + { + ofn.Flags |= OFN_ALLOWMULTISELECT; + } + + if ( GetOpenFileNameA ( & ofn ) == 0 ) + { + lRetval = NULL ; + } + else + { + lBuffLen = strlen(aoBuff) ; + lPointers[0] = aoBuff + lBuffLen + 1 ; + if ( !aAllowMultipleSelects || (lPointers[0][0] == '\0') ) + { + lRetval = aoBuff ; + } + else + { + i = 0 ; + do + { + lLengths[i] = strlen(lPointers[i]); + lPointers[i+1] = lPointers[i] + lLengths[i] + 1 ; + i ++ ; + } + while ( lPointers[i][0] != '\0' ); + i--; + p = aoBuff + MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD - 1 ; + * p = '\0'; + for ( j = i ; j >=0 ; j-- ) + { + p -= lLengths[j]; + memmove(p, lPointers[j], lLengths[j]); + p--; + *p = '\\'; + p -= lBuffLen ; + memmove(p, aoBuff, lBuffLen); + p--; + *p = '|'; + } + p++; + lRetval = p ; + } + } + + if (lHResult==S_OK || lHResult==S_FALSE) + { + CoUninitialize(); + } + return lRetval; +} + +#ifndef TINYFD_NOSELECTFOLDERWIN +static char const * selectFolderDialogWinGuiA ( + char * const aoBuff , + char const * const aTitle , /* NULL or "" */ + char const * const aDefaultPath ) /* NULL or "" */ +{ + BROWSEINFOA bInfo ; + LPITEMIDLIST lpItem ; + HRESULT lHResult; + + lHResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + /* we can't use aDefaultPath */ + bInfo.hwndOwner = 0 ; + bInfo.pidlRoot = NULL ; + bInfo.pszDisplayName = aoBuff ; + bInfo.lpszTitle = aTitle && strlen(aTitle) ? aTitle : NULL; + if (lHResult == S_OK || lHResult == S_FALSE) + { + bInfo.ulFlags = BIF_USENEWUI; + } + bInfo.lpfn = BrowseCallbackProc; + bInfo.lParam = (LPARAM)aDefaultPath; + bInfo.iImage = -1 ; + + lpItem = SHBrowseForFolderA ( & bInfo ) ; + if ( lpItem ) + { + SHGetPathFromIDListA ( lpItem , aoBuff ) ; + } + + if (lHResult==S_OK || lHResult==S_FALSE) + { + CoUninitialize(); + } + return aoBuff ; +} +#endif /*TINYFD_NOSELECTFOLDERWIN*/ + + +static char const * colorChooserWinGuiA( + char const * const aTitle, /* NULL or "" */ + char const * const aDefaultHexRGB, /* NULL or "#FF0000"*/ + unsigned char const aDefaultRGB[3], /* { 0 , 255 , 255 } */ + unsigned char aoResultRGB[3]) /* { 0 , 0 , 0 } */ +{ + static char lResultHexRGB[8]; + + CHOOSECOLORA cc; + COLORREF crCustColors[16]; + unsigned char lDefaultRGB[3]; + int lRet; + + if ( aDefaultHexRGB ) + { + Hex2RGB(aDefaultHexRGB, lDefaultRGB); + } + else + { + lDefaultRGB[0]=aDefaultRGB[0]; + lDefaultRGB[1]=aDefaultRGB[1]; + lDefaultRGB[2]=aDefaultRGB[2]; + } + + /* we can't use aTitle */ + cc.lStructSize = sizeof ( CHOOSECOLOR ) ; + cc.hwndOwner = NULL ; + cc.hInstance = NULL ; + cc.rgbResult = RGB(lDefaultRGB[0], lDefaultRGB[1], lDefaultRGB[2]); + cc.lpCustColors = crCustColors; + cc.Flags = CC_RGBINIT | CC_FULLOPEN; + cc.lCustData = 0; + cc.lpfnHook = NULL; + cc.lpTemplateName = NULL; + + lRet = ChooseColorA(&cc); + + if ( ! lRet ) + { + return NULL; + } + + aoResultRGB[0] = GetRValue(cc.rgbResult); + aoResultRGB[1] = GetGValue(cc.rgbResult); + aoResultRGB[2] = GetBValue(cc.rgbResult); + + RGB2Hex(aoResultRGB, lResultHexRGB); + + return lResultHexRGB; +} + +#endif /* TINYFD_NOLIB */ + +static int dialogPresent ( ) +{ + static int lDialogPresent = -1 ; + char lBuff [MAX_PATH_OR_CMD] ; + FILE * lIn ; + char const * lString = "dialog.exe"; + if ( lDialogPresent < 0 ) + { + if (!(lIn = _popen("where dialog.exe","r"))) + { + lDialogPresent = 0 ; + return 0 ; + } + while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) + {} + _pclose ( lIn ) ; + if ( lBuff[strlen ( lBuff ) -1] == '\n' ) + { + lBuff[strlen ( lBuff ) -1] = '\0' ; + } + if ( strcmp(lBuff+strlen(lBuff)-strlen(lString),lString) ) + { + lDialogPresent = 0 ; + } + else + { + lDialogPresent = 1 ; + } + } + return lDialogPresent; +} + + +static int messageBoxWinConsole ( + char const * const aTitle , /* NULL or "" */ + char const * const aMessage , /* NULL or "" may contain \n and \t */ + char const * const aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */ + char const * const aIconType , /* "info" "warning" "error" "question" */ + int const aDefaultButton ) /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ +{ + char lDialogString[MAX_PATH_OR_CMD]; + char lDialogFile[MAX_PATH_OR_CMD]; + FILE * lIn; + char lBuff [MAX_PATH_OR_CMD] = ""; + + strcpy ( lDialogString , "dialog " ) ; + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "--title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + + if ( aDialogType && ( !strcmp( "okcancel" , aDialogType ) + || !strcmp("yesno", aDialogType) || !strcmp("yesnocancel", aDialogType) ) ) + { + strcat(lDialogString, "--backtitle \"") ; + strcat(lDialogString, "tab: move focus") ; + strcat(lDialogString, "\" ") ; + } + + if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) ) + { + if ( ! aDefaultButton ) + { + strcat ( lDialogString , "--defaultno " ) ; + } + strcat ( lDialogString , + "--yes-label \"Ok\" --no-label \"Cancel\" --yesno " ) ; + } + else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) ) + { + if ( ! aDefaultButton ) + { + strcat ( lDialogString , "--defaultno " ) ; + } + strcat ( lDialogString , "--yesno " ) ; + } + else if (aDialogType && !strcmp("yesnocancel", aDialogType)) + { + if (!aDefaultButton) + { + strcat(lDialogString, "--defaultno "); + } + strcat(lDialogString, "--menu "); + } + else + { + strcat ( lDialogString , "--msgbox " ) ; + } + + strcat ( lDialogString , "\"" ) ; + if ( aMessage && strlen(aMessage) ) + { + replaceSubStr ( aMessage , "\n" , "\\n" , lBuff ) ; + strcat(lDialogString, lBuff) ; + lBuff[0]='\0'; + } + strcat(lDialogString, "\" "); + + if (aDialogType && !strcmp("yesnocancel", aDialogType)) + { + strcat(lDialogString, "0 60 0 Yes \"\" No \"\""); + strcat(lDialogString, "2>>"); + } + else + { + strcat(lDialogString, "10 60"); + strcat(lDialogString, " && echo 1 > "); + } + + strcpy(lDialogFile, getenv("USERPROFILE")); + strcat(lDialogFile, "\\AppData\\Local\\Temp\\tinyfd.txt"); + strcat(lDialogString, lDialogFile); + + /*if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ;*/ + system ( lDialogString ) ; + + if (!(lIn = fopen(lDialogFile, "r"))) + { + remove(lDialogFile); + return 0 ; + } + while (fgets(lBuff, sizeof(lBuff), lIn) != NULL) + {} + fclose(lIn); + remove(lDialogFile); + if ( lBuff[strlen ( lBuff ) -1] == '\n' ) + { + lBuff[strlen ( lBuff ) -1] = '\0' ; + } + + /* if (tinyfd_verbose) printf("lBuff: %s\n", lBuff); */ + if ( ! strlen(lBuff) ) + { + return 0; + } + + if (aDialogType && !strcmp("yesnocancel", aDialogType)) + { + if (lBuff[0] == 'Y') return 1; + else return 2; + } + + return 1; +} + + +static char const * inputBoxWinConsole( + char * const aoBuff , + char const * const aTitle , /* NULL or "" */ + char const * const aMessage , /* NULL or "" may NOT contain \n nor \t */ + char const * const aDefaultInput ) /* "" , if NULL it's a passwordBox */ +{ + char lDialogString[MAX_PATH_OR_CMD]; + char lDialogFile[MAX_PATH_OR_CMD]; + FILE * lIn; + int lResult; + + strcpy(lDialogFile, getenv("USERPROFILE")); + strcat(lDialogFile, "\\AppData\\Local\\Temp\\tinyfd.txt"); + strcpy(lDialogString , "echo|set /p=1 >" ) ; + strcat(lDialogString, lDialogFile); + strcat( lDialogString , " & " ) ; + + strcat ( lDialogString , "dialog " ) ; + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "--title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + + strcat(lDialogString, "--backtitle \"") ; + strcat(lDialogString, "tab: move focus") ; + if ( ! aDefaultInput ) + { + strcat(lDialogString, " (sometimes nothing, no blink nor star, is shown in text field)") ; + } + + strcat(lDialogString, "\" ") ; + + if ( ! aDefaultInput ) + { + strcat ( lDialogString , "--insecure --passwordbox" ) ; + } + else + { + strcat ( lDialogString , "--inputbox" ) ; + } + strcat ( lDialogString , " \"" ) ; + if ( aMessage && strlen(aMessage) ) + { + strcat(lDialogString, aMessage) ; + } + strcat(lDialogString,"\" 10 60 ") ; + if ( aDefaultInput && strlen(aDefaultInput) ) + { + strcat(lDialogString, "\"") ; + strcat(lDialogString, aDefaultInput) ; + strcat(lDialogString, "\" ") ; + } + + strcat(lDialogString, "2>>"); + strcpy(lDialogFile, getenv("USERPROFILE")); + strcat(lDialogFile, "\\AppData\\Local\\Temp\\tinyfd.txt"); + strcat(lDialogString, lDialogFile); + strcat(lDialogString, " || echo 0 > "); + strcat(lDialogString, lDialogFile); + + /* printf ( "lDialogString: %s\n" , lDialogString ) ; */ + system ( lDialogString ) ; + + if (!(lIn = fopen(lDialogFile, "r"))) + { + remove(lDialogFile); + return 0 ; + } + while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL) + {} + fclose(lIn); + + wipefile(lDialogFile); + remove(lDialogFile); + if ( aoBuff[strlen ( aoBuff ) -1] == '\n' ) + { + aoBuff[strlen ( aoBuff ) -1] = '\0' ; + } + /* printf ( "aoBuff: %s\n" , aoBuff ) ; */ + + /* printf ( "aoBuff: %s len: %lu \n" , aoBuff , strlen(aoBuff) ) ; */ + lResult = strncmp ( aoBuff , "1" , 1) ? 0 : 1 ; + /* printf ( "lResult: %d \n" , lResult ) ; */ + if ( ! lResult ) + { + return NULL ; + } + /* printf ( "aoBuff+1: %s\n" , aoBuff+1 ) ; */ + return aoBuff+3 ; +} + + +static char const * saveFileDialogWinConsole ( + char * const aoBuff , + char const * const aTitle , /* NULL or "" */ + char const * const aDefaultPathAndFile ) /* NULL or "" */ +{ + char lDialogString[MAX_PATH_OR_CMD]; + char lPathAndFile[MAX_PATH_OR_CMD] = ""; + FILE * lIn; + + strcpy ( lDialogString , "dialog " ) ; + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "--title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + + strcat(lDialogString, "--backtitle \"") ; + strcat(lDialogString, + "tab: focus | /: populate | spacebar: fill text field | ok: TEXT FIELD ONLY") ; + strcat(lDialogString, "\" ") ; + + strcat ( lDialogString , "--fselect \"" ) ; + if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) + { + /* dialog.exe uses unix separators even on windows */ + strcpy(lPathAndFile, aDefaultPathAndFile); + replaceChr ( lPathAndFile , '\\' , '/' ) ; + } + + /* dialog.exe needs at least one separator */ + if ( ! strchr(lPathAndFile, '/') ) + { + strcat(lDialogString, "./") ; + } + strcat(lDialogString, lPathAndFile) ; + strcat(lDialogString, "\" 0 60 2>"); + strcpy(lPathAndFile, getenv("USERPROFILE")); + strcat(lPathAndFile, "\\AppData\\Local\\Temp\\tinyfd.txt"); + strcat(lDialogString, lPathAndFile); + + /* printf ( "lDialogString: %s\n" , lDialogString ) ; */ + system ( lDialogString ) ; + + if (!(lIn = fopen(lPathAndFile, "r"))) + { + remove(lPathAndFile); + return NULL; + } + while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL) + {} + fclose(lIn); + remove(lPathAndFile); + replaceChr ( aoBuff , '/' , '\\' ) ; + /* printf ( "aoBuff: %s\n" , aoBuff ) ; */ + getLastName(lDialogString,aoBuff); + if ( ! strlen(lDialogString) ) + { + return NULL; + } + return aoBuff; +} + + +static char const * openFileDialogWinConsole ( + char * const aoBuff , + char const * const aTitle , /* NULL or "" */ + char const * const aDefaultPathAndFile , /* NULL or "" */ + int const aAllowMultipleSelects ) /* 0 or 1 */ +{ + char lFilterPatterns[MAX_PATH_OR_CMD] = ""; + char lDialogString[MAX_PATH_OR_CMD] ; + FILE * lIn; + + strcpy ( lDialogString , "dialog " ) ; + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "--title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + + strcat(lDialogString, "--backtitle \"") ; + strcat(lDialogString, + "tab: focus | /: populate | spacebar: fill text field | ok: TEXT FIELD ONLY") ; + strcat(lDialogString, "\" ") ; + + strcat ( lDialogString , "--fselect \"" ) ; + if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) + { + /* dialog.exe uses unix separators even on windows */ + strcpy(lFilterPatterns, aDefaultPathAndFile); + replaceChr ( lFilterPatterns , '\\' , '/' ) ; + } + + /* dialog.exe needs at least one separator */ + if ( ! strchr(lFilterPatterns, '/') ) + { + strcat(lDialogString, "./") ; + } + strcat(lDialogString, lFilterPatterns) ; + strcat(lDialogString, "\" 0 60 2>"); + strcpy(lFilterPatterns, getenv("USERPROFILE")); + strcat(lFilterPatterns, "\\AppData\\Local\\Temp\\tinyfd.txt"); + strcat(lDialogString, lFilterPatterns); + + /* printf ( "lDialogString: %s\n" , lDialogString ) ; */ + system ( lDialogString ) ; + + if (!(lIn = fopen(lFilterPatterns, "r"))) + { + remove(lFilterPatterns); + return NULL; + } + while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL) + {} + fclose(lIn); + remove(lFilterPatterns); + replaceChr ( aoBuff , '/' , '\\' ) ; + /* printf ( "aoBuff: %s\n" , aoBuff ) ; */ + return aoBuff; +} + + +static char const * selectFolderDialogWinConsole ( + char * const aoBuff , + char const * const aTitle , /* NULL or "" */ + char const * const aDefaultPath ) /* NULL or "" */ +{ + char lDialogString [MAX_PATH_OR_CMD] ; + char lString [MAX_PATH_OR_CMD] ; + FILE * lIn ; + + strcpy ( lDialogString , "dialog " ) ; + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "--title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + + strcat(lDialogString, "--backtitle \"") ; + strcat(lDialogString, + "tab: focus | /: populate | spacebar: fill text field | ok: TEXT FIELD ONLY") ; + strcat(lDialogString, "\" ") ; + + strcat ( lDialogString , "--dselect \"" ) ; + if ( aDefaultPath && strlen(aDefaultPath) ) + { + /* dialog.exe uses unix separators even on windows */ + strcpy(lString, aDefaultPath) ; + ensureFinalSlash(lString); + replaceChr ( lString , '\\' , '/' ) ; + strcat(lDialogString, lString) ; + } + else + { + /* dialog.exe needs at least one separator */ + strcat(lDialogString, "./") ; + } + strcat(lDialogString, "\" 0 60 2>"); + strcpy(lString, getenv("USERPROFILE")); + strcat(lString, "\\AppData\\Local\\Temp\\tinyfd.txt"); + strcat(lDialogString, lString); + + /* printf ( "lDialogString: %s\n" , lDialogString ) ; */ + system ( lDialogString ) ; + + if (!(lIn = fopen(lString, "r"))) + { + remove(lString); + return NULL; + } + while (fgets(aoBuff, MAX_PATH_OR_CMD, lIn) != NULL) + {} + fclose(lIn); + remove(lString); + replaceChr ( aoBuff , '/' , '\\' ) ; + /* printf ( "aoBuff: %s\n" , aoBuff ) ; */ + return aoBuff; +} + + +int tinyfd_messageBox ( + char const * const aTitle , /* NULL or "" */ + char const * const aMessage , /* NULL or "" may contain \n and \t */ + char const * const aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */ + char const * const aIconType , /* "info" "warning" "error" "question" */ + int const aDefaultButton ) /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ +{ + char lChar ; + +#ifndef TINYFD_NOLIB + if ((!tinyfd_forceConsole || !(GetConsoleWindow() || dialogPresent())) + && (!getenv("SSH_CLIENT") || getenv("DISPLAY"))) + { + if (aTitle&&!strcmp(aTitle, "tinyfd_query")){ strcpy(tinyfd_response, "windows"); return 1; } + if (tinyfd_winUtf8) + { + return messageBoxWinGui8( + aTitle, aMessage, aDialogType, aIconType, aDefaultButton); + } + else + { + return messageBoxWinGuiA( + aTitle, aMessage, aDialogType, aIconType, aDefaultButton); + } + } + else +#endif /* TINYFD_NOLIB */ + if ( dialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return 0;} + return messageBoxWinConsole( + aTitle,aMessage,aDialogType,aIconType,aDefaultButton); + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return 0;} + if (!gWarningDisplayed && !tinyfd_forceConsole ) + { + gWarningDisplayed = 1; + printf("\n\n%s\n", gTitle); + printf("%s\n\n", gMessageWin); + } + if ( aTitle && strlen(aTitle) ) + { + printf ("\n%s\n\n", aTitle); + } + if ( aDialogType && !strcmp("yesno",aDialogType) ) + { + do + { + if ( aMessage && strlen(aMessage) ) + { + printf("%s\n",aMessage); + } + printf("y/n: "); + lChar = (char) tolower ( _getch() ) ; + printf("\n\n"); + } + while ( lChar != 'y' && lChar != 'n' ) ; + return lChar == 'y' ? 1 : 0 ; + } + else if ( aDialogType && !strcmp("okcancel",aDialogType) ) + { + do + { + if ( aMessage && strlen(aMessage) ) + { + printf("%s\n",aMessage); + } + printf("[O]kay/[C]ancel: "); + lChar = (char) tolower ( _getch() ) ; + printf("\n\n"); + } + while ( lChar != 'o' && lChar != 'c' ) ; + return lChar == 'o' ? 1 : 0 ; + } + else if (aDialogType && !strcmp("yesnocancel", aDialogType)) + { + do + { + if (aMessage && strlen(aMessage)) + { + printf("%s\n", aMessage); + } + printf("[Y]es/[N]o/[C]ancel: "); + lChar = (char)tolower(_getch()); + printf("\n\n"); + } while (lChar != 'y' && lChar != 'n' && lChar != 'c'); + return (lChar == 'y') ? 1 : (lChar == 'n') ? 2 : 0 ; + } + else + { + if ( aMessage && strlen(aMessage) ) + { + printf("%s\n\n",aMessage); + } + printf("press enter to continue "); + lChar = (char) _getch() ; + printf("\n\n"); + return 1 ; + } + } +} + + +/* returns NULL on cancel */ +char const * tinyfd_inputBox( + char const * const aTitle , /* NULL or "" */ + char const * const aMessage , /* NULL or "" may NOT contain \n nor \t */ + char const * const aDefaultInput ) /* "" , if NULL it's a passwordBox */ +{ + static char lBuff [MAX_PATH_OR_CMD] ; + char * lEOF; + +#ifndef TINYFD_NOLIB + DWORD mode = 0; + HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); + + if ((!tinyfd_forceConsole || !( + GetConsoleWindow() || + dialogPresent())) + && ( !getenv("SSH_CLIENT") || getenv("DISPLAY") ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;} + lBuff[0]='\0'; + return inputBoxWinGui(lBuff,aTitle,aMessage,aDefaultInput); + } + else +#endif /* TINYFD_NOLIB */ + if ( dialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} + lBuff[0]='\0'; + return inputBoxWinConsole(lBuff,aTitle,aMessage,aDefaultInput); + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;} + lBuff[0]='\0'; + if (!gWarningDisplayed && !tinyfd_forceConsole) + { + gWarningDisplayed = 1 ; + printf("\n\n%s\n", gTitle); + printf("%s\n\n", gMessageWin); + } + if ( aTitle && strlen(aTitle) ) + { + printf ("\n%s\n\n", aTitle); + } + if ( aMessage && strlen(aMessage) ) + { + printf("%s\n",aMessage); + } + printf("(ctrl-Z + enter to cancel): "); +#ifndef TINYFD_NOLIB + if ( ! aDefaultInput ) + { + GetConsoleMode(hStdin,&mode); + SetConsoleMode(hStdin,mode & (~ENABLE_ECHO_INPUT) ); + } +#endif /* TINYFD_NOLIB */ + lEOF = fgets(lBuff, MAX_PATH_OR_CMD, stdin); + if ( ! lEOF ) + { + return NULL; + } +#ifndef TINYFD_NOLIB + if ( ! aDefaultInput ) + { + SetConsoleMode(hStdin,mode); + printf ("\n"); + } +#endif /* TINYFD_NOLIB */ + printf ("\n"); + if ( strchr(lBuff,27) ) + { + return NULL ; + } + if ( lBuff[strlen ( lBuff ) -1] == '\n' ) + { + lBuff[strlen ( lBuff ) -1] = '\0' ; + } + return lBuff ; + } +} + + +char const * tinyfd_saveFileDialog ( + char const * const aTitle , /* NULL or "" */ + char const * const aDefaultPathAndFile , /* NULL or "" */ + int const aNumOfFilterPatterns , /* 0 */ + char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */ + char const * const aSingleFilterDescription ) /* NULL or "image files" */ +{ + static char lBuff [MAX_PATH_OR_CMD] ; + char lString[MAX_PATH_OR_CMD] ; + char const * p ; + lBuff[0]='\0'; +#ifndef TINYFD_NOLIB + if ( ( !tinyfd_forceConsole || !( GetConsoleWindow() || dialogPresent() ) ) + && ( !getenv("SSH_CLIENT") || getenv("DISPLAY") ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;} + if (tinyfd_winUtf8) + { + p = saveFileDialogWinGui8(lBuff, + aTitle, aDefaultPathAndFile, aNumOfFilterPatterns, aFilterPatterns, aSingleFilterDescription); + } + else + { + p = saveFileDialogWinGuiA(lBuff, + aTitle, aDefaultPathAndFile, aNumOfFilterPatterns, aFilterPatterns, aSingleFilterDescription); + } + } + else +#endif /* TINYFD_NOLIB */ + if ( dialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} + p = saveFileDialogWinConsole(lBuff,aTitle,aDefaultPathAndFile); + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;} + p = tinyfd_inputBox(aTitle, "Save file",""); + } + + if ( ! p || ! strlen ( p ) ) + { + return NULL; + } + getPathWithoutFinalSlash ( lString , p ) ; + if ( strlen ( lString ) && ! dirExists ( lString ) ) + { + return NULL ; + } + getLastName(lString,p); + if ( ! filenameValid(lString) ) + { + return NULL; + } + return p ; +} + + +/* in case of multiple files, the separator is | */ +char const * tinyfd_openFileDialog ( + char const * const aTitle , /* NULL or "" */ + char const * const aDefaultPathAndFile , /* NULL or "" */ + int const aNumOfFilterPatterns , /* 0 */ + char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */ + char const * const aSingleFilterDescription , /* NULL or "image files" */ + int const aAllowMultipleSelects ) /* 0 or 1 */ +{ + static char lBuff[MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD]; + char const * p ; +#ifndef TINYFD_NOLIB + if ( ( !tinyfd_forceConsole || !( GetConsoleWindow() || dialogPresent() ) ) + && ( !getenv("SSH_CLIENT") || getenv("DISPLAY") ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;} + if (tinyfd_winUtf8) + { + p = openFileDialogWinGui8(lBuff, + aTitle, aDefaultPathAndFile, aNumOfFilterPatterns, + aFilterPatterns, aSingleFilterDescription, aAllowMultipleSelects); + } + else + { + p = openFileDialogWinGuiA(lBuff, + aTitle, aDefaultPathAndFile, aNumOfFilterPatterns, + aFilterPatterns, aSingleFilterDescription, aAllowMultipleSelects); + } + } + else +#endif /* TINYFD_NOLIB */ + if ( dialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} + p = openFileDialogWinConsole(lBuff, + aTitle,aDefaultPathAndFile,aAllowMultipleSelects); + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;} + p = tinyfd_inputBox(aTitle, "Open file",""); + } + + if ( ! p || ! strlen ( p ) ) + { + return NULL; + } + if ( aAllowMultipleSelects && strchr(p, '|') ) + { + p = ensureFilesExist( lBuff , p ) ; + } + else if ( ! fileExists (p) ) + { + return NULL ; + } + /* printf ( "lBuff3: %s\n" , p ) ; */ + return p ; +} + + +char const * tinyfd_selectFolderDialog ( + char const * const aTitle , /* NULL or "" */ + char const * const aDefaultPath ) /* NULL or "" */ +{ + static char lBuff [MAX_PATH_OR_CMD] ; + char const * p ; +#ifndef TINYFD_NOLIB + if ( ( !tinyfd_forceConsole || !( GetConsoleWindow() || dialogPresent() ) ) + && ( !getenv("SSH_CLIENT") || getenv("DISPLAY") ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;} + if (tinyfd_winUtf8) + { +#ifndef TINYFD_NOSELECTFOLDERWIN + p = selectFolderDialogWinGui8(lBuff, aTitle, aDefaultPath); + } + else + { + p = selectFolderDialogWinGuiA(lBuff, aTitle, aDefaultPath); +#endif /*TINYFD_NOSELECTFOLDERWIN*/ + } + } + else +#endif /* TINYFD_NOLIB */ + if ( dialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} + p = selectFolderDialogWinConsole(lBuff,aTitle,aDefaultPath); + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;} + p = tinyfd_inputBox(aTitle, "Select folder",""); + } + + if ( ! p || ! strlen ( p ) || ! dirExists ( p ) ) + { + return NULL ; + } + return p ; +} + + +/* returns the hexcolor as a string "#FF0000" */ +/* aoResultRGB also contains the result */ +/* aDefaultRGB is used only if aDefaultHexRGB is NULL */ +/* aDefaultRGB and aoResultRGB can be the same array */ +char const * tinyfd_colorChooser( + char const * const aTitle, /* NULL or "" */ + char const * const aDefaultHexRGB, /* NULL or "#FF0000"*/ + unsigned char const aDefaultRGB[3], /* { 0 , 255 , 255 } */ + unsigned char aoResultRGB[3]) /* { 0 , 0 , 0 } */ +{ + char lDefaultHexRGB[8]; + char * lpDefaultHexRGB; + int i; + char const * p ; + +#ifndef TINYFD_NOLIB + if ( (!tinyfd_forceConsole || !( GetConsoleWindow() || dialogPresent()) ) + && (!getenv("SSH_CLIENT") || getenv("DISPLAY")) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"windows");return (char const *)1;} + if (tinyfd_winUtf8) + { + return colorChooserWinGui8( + aTitle, aDefaultHexRGB, aDefaultRGB, aoResultRGB); + } + else + { + return colorChooserWinGuiA( + aTitle, aDefaultHexRGB, aDefaultRGB, aoResultRGB); + } + } + else +#endif /* TINYFD_NOLIB */ + if ( aDefaultHexRGB ) + { + lpDefaultHexRGB = (char *) aDefaultHexRGB ; + } + else + { + RGB2Hex( aDefaultRGB , lDefaultHexRGB ) ; + lpDefaultHexRGB = (char *) lDefaultHexRGB ; + } + p = tinyfd_inputBox(aTitle, + "Enter hex rgb color (i.e. #f5ca20)",lpDefaultHexRGB); + if (aTitle&&!strcmp(aTitle,"tinyfd_query")) return p; + + if ( !p || (strlen(p) != 7) || (p[0] != '#') ) + { + return NULL ; + } + for ( i = 1 ; i < 7 ; i ++ ) + { + if ( ! isxdigit( p[i] ) ) + { + return NULL ; + } + } + Hex2RGB(p,aoResultRGB); + return p ; +} + +#else /* unix */ + +static char gPython2Name[16]; + +static int isDarwin ( ) +{ + static int lsIsDarwin = -1 ; + struct utsname lUtsname ; + if ( lsIsDarwin < 0 ) + { + lsIsDarwin = !uname(&lUtsname) && !strcmp(lUtsname.sysname,"Darwin") ; + } + return lsIsDarwin ; +} + + +static int dirExists ( char const * const aDirPath ) +{ + DIR * lDir ; + if ( ! aDirPath || ! strlen ( aDirPath ) ) + return 0 ; + lDir = opendir ( aDirPath ) ; + if ( ! lDir ) + { + return 0 ; + } + closedir ( lDir ) ; + return 1 ; +} + + +static int detectPresence ( char const * const aExecutable ) +{ + char lBuff [MAX_PATH_OR_CMD] ; + char lTestedString [MAX_PATH_OR_CMD] = "which " ; + FILE * lIn ; + + strcat ( lTestedString , aExecutable ) ; + strcat( lTestedString, " 2>/dev/null "); + lIn = popen ( lTestedString , "r" ) ; + if ( ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) + && ( ! strchr ( lBuff , ':' ) ) + && ( strncmp(lBuff, "no ", 3) ) ) + { /* present */ + pclose ( lIn ) ; + if (tinyfd_verbose) printf("detectPresence %s %d\n", aExecutable, 1); + return 1 ; + } + else + { + pclose ( lIn ) ; + if (tinyfd_verbose) printf("detectPresence %s %d\n", aExecutable, 0); + return 0 ; + } +} + + +static char const * getVersion ( char const * const aExecutable ) /*version # must follow :*/ +{ + static char lBuff [MAX_PATH_OR_CMD] ; + char lTestedString [MAX_PATH_OR_CMD] ; + FILE * lIn ; + char * lTmp ; + + strcpy ( lTestedString , aExecutable ) ; + strcat ( lTestedString , " --version" ) ; + + lIn = popen ( lTestedString , "r" ) ; + lTmp = fgets ( lBuff , sizeof ( lBuff ) , lIn ) ; + pclose ( lIn ) ; + if ( ! lTmp || !(lTmp = strchr ( lBuff , ':' )) ) return 0 ; + lTmp ++ ; + /* printf("lTmp %s\n", lTmp); */ + return lTmp ; +} + + +static int tryCommand ( char const * const aCommand ) +{ + char lBuff [MAX_PATH_OR_CMD] ; + FILE * lIn ; + + lIn = popen ( aCommand , "r" ) ; + if ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) == NULL ) + { /* present */ + pclose ( lIn ) ; + return 1 ; + } + else + { + pclose ( lIn ) ; + return 0 ; + } + +} + + +static int isTerminalRunning() +{ + return isatty(1); +} + + +static char const * dialogNameOnly ( ) +{ + static char lDialogName[128] = "*" ; + if ( lDialogName[0] == '*' ) + { + if ( isDarwin() && strcpy(lDialogName , "/opt/local/bin/dialog" ) + && detectPresence ( lDialogName ) ) + {} + else if ( strcpy(lDialogName , "dialog" ) + && detectPresence ( lDialogName ) ) + {} + else + { + strcpy(lDialogName , "" ) ; + } + } + return lDialogName ; +} + + +int isDialogVersionBetter09b ( ) +{ + char const * lDialogName ; + char * lVersion ; + int lMajor ; + int lMinor ; + int lDate ; + int lResult ; + char * lMinorP ; + char * lLetter ; + char lBuff[128] ; + + /*char lTest[128] = " 0.9b-20031126" ;*/ + + lDialogName = dialogNameOnly ( ) ; + if ( ! lDialogName || !(lVersion = (char *) getVersion(lDialogName)) ) return 0 ; + /*lVersion = lTest ;*/ + /*printf("lVersion %s\n", lVersion);*/ + strcpy(lBuff,lVersion); + lMajor = atoi ( strtok(lVersion," ,.-") ) ; + /*printf("lMajor %d\n", lMajor);*/ + lMinorP = strtok(0," ,.-abcdefghijklmnopqrstuvxyz"); + lMinor = atoi ( lMinorP ) ; + /*printf("lMinor %d\n", lMinor );*/ + lDate = atoi ( strtok(0," ,.-") ) ; + if (lDate<0) lDate = - lDate; + /*printf("lDate %d\n", lDate);*/ + lLetter = lMinorP + strlen(lMinorP) ; + strcpy(lVersion,lBuff); + strtok(lLetter," ,.-"); + /*printf("lLetter %s\n", lLetter);*/ + lResult = (lMajor > 0) || ( ( lMinor == 9 ) && (*lLetter == 'b') && (lDate >= 20031126) ); + /*printf("lResult %d\n", lResult);*/ + return lResult; +} + + +static int whiptailPresentOnly ( ) +{ + static int lWhiptailPresent = -1 ; + if ( lWhiptailPresent < 0 ) + { + lWhiptailPresent = detectPresence ( "whiptail" ) ; + } + return lWhiptailPresent ; +} + + +static char const * terminalName ( ) +{ + static char lTerminalName[128] = "*" ; + char lShellName[64] = "*" ; + + if ( lTerminalName[0] == '*' ) + { + if ( detectPresence ( "bash" ) ) + { + strcpy(lShellName , "bash -c " ) ; /*good for basic input*/ + } + else if ( dialogNameOnly() || whiptailPresentOnly() ) + { + strcpy(lShellName , "sh -c " ) ; /*good enough for dialog & whiptail*/ + } + else + { + return NULL ; + } + + if ( isDarwin() ) + { + if ( strcpy(lTerminalName , "/opt/X11/bin/xterm" ) + && detectPresence ( lTerminalName ) ) + { + strcat(lTerminalName , " -fa 'DejaVu Sans Mono' -fs 10 -title tinyfiledialogs -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else + { + strcpy(lTerminalName , "" ) ; + } + } + else if ( strcpy(lTerminalName,"xterm") /*good (small without parameters)*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -fa 'DejaVu Sans Mono' -fs 10 -title tinyfiledialogs -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( strcpy(lTerminalName,"terminator") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -x " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( strcpy(lTerminalName,"lxterminal") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( strcpy(lTerminalName,"konsole") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( strcpy(lTerminalName,"kterm") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( strcpy(lTerminalName,"xfce4-terminal") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -x " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( strcpy(lTerminalName,"mate-terminal") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -x " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( strcpy(lTerminalName,"Eterm") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( strcpy(lTerminalName,"evilvte") /*good*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else if ( strcpy(lTerminalName,"pterm") /*good (only letters)*/ + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " -e " ) ; + strcat(lTerminalName , lShellName ) ; + } + else + { + strcpy(lTerminalName , "" ) ; + } + /*else if ( strcpy(lTerminalName,"gnome-terminal") //bad (good if version < 3) + && detectPresence(lTerminalName) ) + { + strcat(lTerminalName , " --disable-factory -x " ) ; + strcat(lTerminalName , lShellName ) ; + }*/ + /* bad: koi rxterm guake tilda vala-terminal qterminal + aterm Terminal terminology sakura lilyterm weston-terminal + roxterm termit xvt rxvt mrxvt urxvt */ + } + if ( strlen(lTerminalName) ) + { + return lTerminalName ; + } + else + { + return NULL ; + } +} + + +static char const * dialogName ( ) +{ + char const * lDialogName ; + lDialogName = dialogNameOnly ( ) ; + if ( strlen(lDialogName) && ( isTerminalRunning() || terminalName() ) ) + { + return lDialogName ; + } + else + { + return NULL ; + } +} + + +static int whiptailPresent ( ) +{ + int lWhiptailPresent ; + lWhiptailPresent = whiptailPresentOnly ( ) ; + if ( lWhiptailPresent && ( isTerminalRunning() || terminalName() ) ) + { + return lWhiptailPresent ; + } + else + { + return 0 ; + } +} + + + +static int graphicMode() +{ + return !( tinyfd_forceConsole && (isTerminalRunning() || terminalName()) ) + && ( getenv("DISPLAY") + || (isDarwin() && (!getenv("SSH_TTY") || getenv("DISPLAY") ) ) ) ; +} + + +static int xmessagePresent ( ) +{ + static int lXmessagePresent = -1 ; + if ( lXmessagePresent < 0 ) + { + lXmessagePresent = detectPresence("xmessage");/*if not tty,not on osxpath*/ + } + return lXmessagePresent && graphicMode ( ) ; +} + + +static int gxmessagePresent ( ) +{ + static int lGxmessagePresent = -1 ; + if ( lGxmessagePresent < 0 ) + { + lGxmessagePresent = detectPresence("gxmessage") ; + } + return lGxmessagePresent && graphicMode ( ) ; +} + + +static int gmessagePresent ( ) +{ + static int lGmessagePresent = -1 ; + if ( lGmessagePresent < 0 ) + { + lGmessagePresent = detectPresence("gmessage") ; + } + return lGmessagePresent && graphicMode ( ) ; +} + + +static int notifysendPresent ( ) +{ + static int lNotifysendPresent = -1 ; + if ( lNotifysendPresent < 0 ) + { + lNotifysendPresent = detectPresence("notify-send") ; + } + return lNotifysendPresent && graphicMode ( ) ; +} + + +static int xdialogPresent ( ) +{ + static int lXdialogPresent = -1 ; + if ( lXdialogPresent < 0 ) + { + lXdialogPresent = detectPresence("Xdialog") ; + } + return lXdialogPresent && graphicMode ( ) ; +} + + +static int gdialogPresent ( ) +{ + static int lGdialoglPresent = -1 ; + if ( lGdialoglPresent < 0 ) + { + lGdialoglPresent = detectPresence ( "gdialog" ) ; + } + return lGdialoglPresent && graphicMode ( ) ; +} + + +static int osascriptPresent ( ) +{ + static int lOsascriptPresent = -1 ; + if ( lOsascriptPresent < 0 ) + { + gWarningDisplayed |= !!getenv("SSH_TTY"); + lOsascriptPresent = detectPresence ( "osascript" ) ; + } + return lOsascriptPresent && graphicMode() && !getenv("SSH_TTY") ; +} + + +static int kdialogPresent ( ) +{ + static int lKdialogPresent = -1 ; + if ( lKdialogPresent < 0 ) + { + lKdialogPresent = detectPresence("kdialog") ; + } + return lKdialogPresent && graphicMode ( ) ; +} + + +static int qarmaPresent ( ) +{ + static int lQarmaPresent = -1 ; + if ( lQarmaPresent < 0 ) + { + lQarmaPresent = detectPresence("qarma") ; + } + return lQarmaPresent && graphicMode ( ) ; +} + + +static int matedialogPresent ( ) +{ + static int lMatedialogPresent = -1 ; + if ( lMatedialogPresent < 0 ) + { + lMatedialogPresent = detectPresence("matedialog") ; + } + return lMatedialogPresent && graphicMode ( ) ; +} + + +static int zenityPresent ( ) +{ + static int lZenityPresent = -1 ; + if ( lZenityPresent < 0 ) + { + lZenityPresent = detectPresence("zenity") ; + } + return lZenityPresent && graphicMode ( ) ; +} + + +static int osx9orBetter ( ) +{ + static int lOsx9orBetter = -1 ; + char lBuff [MAX_PATH_OR_CMD] ; + FILE * lIn ; + int V,v; + + if ( lOsx9orBetter < 0 ) + { + lOsx9orBetter = 0 ; + lIn = popen ( "osascript -e 'set osver to system version of (system info)'" , "r" ) ; + if ( ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) + && ( 2 == sscanf(lBuff, "%d.%d", &V, &v) ) ) + { + V = V * 100 + v; + if ( V >= 1009 ) + { + lOsx9orBetter = 1 ; + } + } + pclose ( lIn ) ; + /* printf ("Osx10 = %d, %d = <%s>\n", lOsx9orBetter, V, lBuff) ; */ + } + return lOsx9orBetter ; +} + + +static int zenity3Present ( ) +{ + static int lZenity3Present = -1 ; + char lBuff [MAX_PATH_OR_CMD] ; + FILE * lIn ; + + if ( lZenity3Present < 0 ) + { + lZenity3Present = 0 ; + if ( zenityPresent() ) + { + lIn = popen ( "zenity --version" , "r" ) ; + if ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) + { + if ( atoi(lBuff) >= 3 ) + { + lZenity3Present = 3 ; + } + else if ( ( atoi(lBuff) == 2 ) && ( atoi(strtok(lBuff,".")+2 ) >= 32 ) ) + { + lZenity3Present = 2 ; + } + } + pclose ( lIn ) ; + } + } + return lZenity3Present && graphicMode ( ) ; +} + + +static int tkinter2Present ( ) +{ + static int lTkinter2Present = -1 ; + char lPythonCommand[256]; + char lPythonParams[256] = +"-c \"try:\n\timport Tkinter;\nexcept:\n\tprint(0);\""; + int i; + + if ( lTkinter2Present < 0 ) + { + lTkinter2Present = 0 ; + strcpy(gPython2Name , "python" ) ; + sprintf ( lPythonCommand , "%s %s" , gPython2Name , lPythonParams ) ; + if ( ! detectPresence(gPython2Name) + || ! (lTkinter2Present = tryCommand(lPythonCommand)) ) + { + strcpy(gPython2Name , "python2" ) ; + if ( detectPresence(gPython2Name) ) + { + sprintf ( lPythonCommand , "%s %s" , gPython2Name , lPythonParams ) ; + lTkinter2Present = tryCommand(lPythonCommand); + } + else + { + for ( i = 9 ; i >= 0 ; i -- ) + { + sprintf ( gPython2Name , "python2.%d" , i ) ; + if ( detectPresence(gPython2Name) ) + { + sprintf ( lPythonCommand , "%s %s" , gPython2Name , lPythonParams ) ; + lTkinter2Present = tryCommand(lPythonCommand); + break ; + } + } + } + } + } + /* printf ("lTkinter2Present %d\n", lTkinter2Present) ; */ + /* printf ("gPython2Name %s\n", gPython2Name) ; */ + return lTkinter2Present && graphicMode() && !(isDarwin() && getenv("SSH_TTY") ); +} + + +int tinyfd_messageBox ( + char const * const aTitle , /* NULL or "" */ + char const * const aMessage , /* NULL or "" may contain \n and \t */ + char const * const aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */ + char const * const aIconType , /* "info" "warning" "error" "question" */ + int const aDefaultButton ) /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ +{ + char lBuff [MAX_PATH_OR_CMD] ; + char * lDialogString = NULL ; + char * lpDialogString; + FILE * lIn ; + int lWasGraphicDialog = 0 ; + int lWasXterm = 0 ; + int lResult ; + char lChar ; + struct termios infoOri; + struct termios info; + int lTitleLen ; + int lMessageLen ; + + lBuff[0]='\0'; + + lTitleLen = aTitle ? strlen(aTitle) : 0 ; + lMessageLen = aMessage ? strlen(aMessage) : 0 ; + if ( !aTitle || strcmp(aTitle,"tinyfd_query") ) + { + lDialogString = (char *) malloc( MAX_PATH_OR_CMD + lTitleLen + lMessageLen ); + } + + if ( osascriptPresent ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return 1;} + + strcpy ( lDialogString , "osascript "); + if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'"); + strcat ( lDialogString , " -e 'try' -e 'set {vButton} to {button returned} of ( display dialog \"") ; + if ( aMessage && strlen(aMessage) ) + { + strcat(lDialogString, aMessage) ; + } + strcat(lDialogString, "\" ") ; + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "with title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + strcat(lDialogString, "with icon ") ; + if ( aIconType && ! strcmp( "error" , aIconType ) ) + { + strcat(lDialogString, "stop " ) ; + } + else if ( aIconType && ! strcmp( "warning" , aIconType ) ) + { + strcat(lDialogString, "caution " ) ; + } + else /* question or info */ + { + strcat(lDialogString, "note " ) ; + } + if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) ) + { + if ( ! aDefaultButton ) + { + strcat ( lDialogString ,"default button \"Cancel\" " ) ; + } + } + else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) ) + { + strcat ( lDialogString ,"buttons {\"No\", \"Yes\"} " ) ; + if (aDefaultButton) + { + strcat ( lDialogString ,"default button \"Yes\" " ) ; + } + else + { + strcat ( lDialogString ,"default button \"No\" " ) ; + } + strcat ( lDialogString ,"cancel button \"No\"" ) ; + } + else if ( aDialogType && ! strcmp( "yesnocancel" , aDialogType ) ) + { + strcat ( lDialogString ,"buttons {\"No\", \"Yes\", \"Cancel\"} " ) ; + switch (aDefaultButton) + { + case 1: strcat ( lDialogString ,"default button \"Yes\" " ) ; break; + case 2: strcat ( lDialogString ,"default button \"No\" " ) ; break; + case 0: strcat ( lDialogString ,"default button \"Cancel\" " ) ; break; + } + strcat ( lDialogString ,"cancel button \"Cancel\"" ) ; + } + else + { + strcat ( lDialogString ,"buttons {\"OK\"} " ) ; + strcat ( lDialogString ,"default button \"OK\" " ) ; + } + strcat ( lDialogString, ")' ") ; + + strcat ( lDialogString, +"-e 'if vButton is \"Yes\" then' -e 'return 1' -e 'else if vButton is \"No\" then' -e 'return 2' -e 'else' -e 'return 0' -e 'end if' " ); + + strcat ( lDialogString, "-e 'on error number -128' " ) ; + strcat ( lDialogString, "-e '0' " ); + + strcat ( lDialogString, "-e 'end try'") ; + if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ; + } + else if ( zenityPresent() || matedialogPresent() || qarmaPresent() ) + { + if ( zenityPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return 1;} + strcpy ( lDialogString , "szAnswer=$(zenity --" ) ; + } + else if ( matedialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return 1;} + strcpy ( lDialogString , "szAnswer=$(matedialog --" ) ; + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"qarma");return 1;} + strcpy ( lDialogString , "szAnswer=$(qarma --" ) ; + } + + if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) ) + { + strcat ( lDialogString , + "question --ok-label=Ok --cancel-label=Cancel" ) ; + } + else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) ) + { + strcat ( lDialogString , "question" ) ; + } + else if ( aDialogType && ! strcmp( "yesnocancel" , aDialogType ) ) + { + strcat ( lDialogString , "list --column \"\" --hide-header \"Yes\" \"No\"" ) ; + } + else if ( aIconType && ! strcmp( "error" , aIconType ) ) + { + strcat ( lDialogString , "error" ) ; + } + else if ( aIconType && ! strcmp( "warning" , aIconType ) ) + { + strcat ( lDialogString , "warning" ) ; + } + else + { + strcat ( lDialogString , "info" ) ; + } + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, " --title=\"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + } + if ( aMessage && strlen(aMessage) ) + { + strcat(lDialogString, " --text=\"") ; + strcat(lDialogString, aMessage) ; + strcat(lDialogString, "\"") ; + } + if ( zenity3Present ( ) >= 3 ) + { + strcat ( lDialogString , " --icon-name=dialog-" ) ; + if ( aIconType && (! strcmp( "question" , aIconType ) + || ! strcmp( "error" , aIconType ) + || ! strcmp( "warning" , aIconType ) ) ) + { + strcat ( lDialogString , aIconType ) ; + } + else + { + strcat ( lDialogString , "information" ) ; + } + } + + if ( ! strcmp( "yesnocancel" , aDialogType ) ) + { + strcat ( lDialogString , +");if [ $? = 1 ];then echo 0;elif [ $szAnswer = \"No\" ];then echo 2;else echo 1;fi"); + } + else + { + strcat ( lDialogString , ");if [ $? = 0 ];then echo 1;else echo 0;fi"); + } + } + else if ( kdialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return 1;} + + strcpy ( lDialogString , "kdialog --" ) ; + if ( aDialogType && ( ! strcmp( "okcancel" , aDialogType ) + || ! strcmp( "yesno" , aDialogType ) || ! strcmp( "yesnocancel" , aDialogType ) ) ) + { + if ( aIconType && ( ! strcmp( "warning" , aIconType ) + || ! strcmp( "error" , aIconType ) ) ) + { + strcat ( lDialogString , "warning" ) ; + } + if ( ! strcmp( "yesnocancel" , aDialogType ) ) + { + strcat ( lDialogString , "yesnocancel" ) ; + } + else + { + strcat ( lDialogString , "yesno" ) ; + } + } + else if ( aIconType && ! strcmp( "error" , aIconType ) ) + { + strcat ( lDialogString , "error" ) ; + } + else if ( aIconType && ! strcmp( "warning" , aIconType ) ) + { + strcat ( lDialogString , "sorry" ) ; + } + else + { + strcat ( lDialogString , "msgbox" ) ; + } + strcat ( lDialogString , " \"" ) ; + if ( aMessage ) + { + strcat ( lDialogString , aMessage ) ; + } + strcat ( lDialogString , "\"" ) ; + if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) ) + { + strcat ( lDialogString , + " --yes-label Ok --no-label Cancel" ) ; + } + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, " --title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + } + + if ( ! strcmp( "yesnocancel" , aDialogType ) ) + { + strcat ( lDialogString , "; x=$? ;if [ $x = 0 ] ;then echo 1;elif [ $x = 1 ] ;then echo 2;else echo 0;fi"); + } + else + { + strcat ( lDialogString , ";if [ $? = 0 ];then echo 1;else echo 0;fi"); + } + } + else if ( !gxmessagePresent() && !gmessagePresent() && !gdialogPresent() && !xdialogPresent() && tkinter2Present ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return 1;} + + strcpy ( lDialogString , gPython2Name ) ; + if ( ! isTerminalRunning ( ) && isDarwin ( ) ) + { + strcat ( lDialogString , " -i" ) ; /* for osx without console */ + } + + strcat ( lDialogString , +" -c \"import Tkinter,tkMessageBox;root=Tkinter.Tk();root.withdraw();"); + + if ( isDarwin ( ) ) + { + strcat ( lDialogString , +"import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set \ +frontmost of process \\\"Python\\\" to true' ''');"); + } + + strcat ( lDialogString ,"res=tkMessageBox." ) ; + if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) ) + { + strcat ( lDialogString , "askokcancel(" ) ; + if ( aDefaultButton ) + { + strcat ( lDialogString , "default=tkMessageBox.OK," ) ; + } + else + { + strcat ( lDialogString , "default=tkMessageBox.CANCEL," ) ; + } + } + else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) ) + { + strcat ( lDialogString , "askyesno(" ) ; + if ( aDefaultButton ) + { + strcat ( lDialogString , "default=tkMessageBox.YES," ) ; + } + else + { + strcat ( lDialogString , "default=tkMessageBox.NO," ) ; + } + } + else if ( aDialogType && ! strcmp( "yesnocancel" , aDialogType ) ) + { + strcat ( lDialogString , "askyesnocancel(" ) ; + switch ( aDefaultButton ) + { + case 1: strcat ( lDialogString , "default=tkMessageBox.YES," ); break; + case 2: strcat ( lDialogString , "default=tkMessageBox.NO," ); break; + case 0: strcat ( lDialogString , "default=tkMessageBox.CANCEL," ); break; + } + } + else + { + strcat ( lDialogString , "showinfo(" ) ; + } + + strcat ( lDialogString , "icon='" ) ; + if ( aIconType && (! strcmp( "question" , aIconType ) + || ! strcmp( "error" , aIconType ) + || ! strcmp( "warning" , aIconType ) ) ) + { + strcat ( lDialogString , aIconType ) ; + } + else + { + strcat ( lDialogString , "info" ) ; + } + + strcat(lDialogString, "',") ; + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "title='") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "',") ; + } + if ( aMessage && strlen(aMessage) ) + { + strcat(lDialogString, "message='") ; + lpDialogString = lDialogString + strlen(lDialogString); + replaceSubStr ( aMessage , "\n" , "\\n" , lpDialogString ) ; + strcat(lDialogString, "'") ; + } + + if ( aDialogType && ! strcmp( "yesnocancel" , aDialogType ) ) + { + strcat(lDialogString, ");\n\ +if res is None :\n\tprint 0\n\ +elif res is False :\n\tprint 2\n\ +else :\n\tprint 1\n\"" ) ; + } + else + { + strcat(lDialogString, ");\n\ +if res is False :\n\tprint 0\n\ +else :\n\tprint 1\n\"" ) ; + } + } + else if ( gxmessagePresent() || gmessagePresent() || (!gdialogPresent() && !xdialogPresent() && xmessagePresent()) ) + { + if ( gxmessagePresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gxmessage");return 1;} + strcpy ( lDialogString , "gxmessage"); + } + else if ( gmessagePresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gmessage");return 1;} + strcpy ( lDialogString , "gmessage"); + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xmessage");return 1;} + strcpy ( lDialogString , "xmessage"); + } + + if ( aDialogType && ! strcmp("okcancel" , aDialogType) ) + { + strcat ( lDialogString , " -buttons Ok:1,Cancel:0"); + switch ( aDefaultButton ) + { + case 1: strcat ( lDialogString , " -default Ok"); break; + case 0: strcat ( lDialogString , " -default Cancel"); break; + } + } + else if ( aDialogType && ! strcmp("yesno" , aDialogType) ) + { + strcat ( lDialogString , " -buttons Yes:1,No:0"); + switch ( aDefaultButton ) + { + case 1: strcat ( lDialogString , " -default Yes"); break; + case 0: strcat ( lDialogString , " -default No"); break; + } + } + else if ( aDialogType && ! strcmp("yesnocancel" , aDialogType) ) + { + strcat ( lDialogString , " -buttons Yes:1,No:2,Cancel:0"); + switch ( aDefaultButton ) + { + case 1: strcat ( lDialogString , " -default Yes"); break; + case 2: strcat ( lDialogString , " -default No"); break; + case 0: strcat ( lDialogString , " -default Cancel"); break; + } + } + else + { + strcat ( lDialogString , " -buttons Ok:1"); + strcat ( lDialogString , " -default Ok"); + } + + strcat ( lDialogString , " -center \""); + if ( aMessage && strlen(aMessage) ) + { + strcat ( lDialogString , aMessage ) ; + } + strcat(lDialogString, "\"" ) ; + if ( aTitle && strlen(aTitle) ) + { + strcat ( lDialogString , " -title \""); + strcat ( lDialogString , aTitle ) ; + strcat ( lDialogString, "\"" ) ; + } + strcat ( lDialogString , " ; echo $? "); + } + else if ( xdialogPresent() || gdialogPresent() || dialogName() || whiptailPresent() ) + { + if ( gdialogPresent ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gdialog");return 1;} + lWasGraphicDialog = 1 ; + strcpy ( lDialogString , "(gdialog " ) ; + } + else if ( xdialogPresent ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return 1;} + lWasGraphicDialog = 1 ; + strcpy ( lDialogString , "(Xdialog " ) ; + } + else if ( dialogName ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return 0;} + if ( isTerminalRunning ( ) ) + { + strcpy ( lDialogString , "(dialog " ) ; + } + else + { + lWasXterm = 1 ; + strcpy ( lDialogString , terminalName() ) ; + strcat ( lDialogString , "'(" ) ; + strcat ( lDialogString , dialogName() ) ; + strcat ( lDialogString , " " ) ; + } + } + else if ( isTerminalRunning ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"whiptail");return 0;} + strcpy ( lDialogString , "(whiptail " ) ; + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"whiptail");return 0;} + lWasXterm = 1 ; + strcpy ( lDialogString , terminalName() ) ; + strcat ( lDialogString , "'(whiptail " ) ; + } + + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "--title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + + if ( !xdialogPresent() && !gdialogPresent() ) + { + if ( aDialogType && ( !strcmp( "okcancel" , aDialogType ) || !strcmp( "yesno" , aDialogType ) + || !strcmp( "yesnocancel" , aDialogType ) ) ) + { + strcat(lDialogString, "--backtitle \"") ; + strcat(lDialogString, "tab: move focus") ; + strcat(lDialogString, "\" ") ; + } + } + + if ( aDialogType && ! strcmp( "okcancel" , aDialogType ) ) + { + if ( ! aDefaultButton ) + { + strcat ( lDialogString , "--defaultno " ) ; + } + strcat ( lDialogString , + "--yes-label \"Ok\" --no-label \"Cancel\" --yesno " ) ; + } + else if ( aDialogType && ! strcmp( "yesno" , aDialogType ) ) + { + if ( ! aDefaultButton ) + { + strcat ( lDialogString , "--defaultno " ) ; + } + strcat ( lDialogString , "--yesno " ) ; + } + else if (aDialogType && !strcmp("yesnocancel", aDialogType)) + { + if (!aDefaultButton) + { + strcat(lDialogString, "--defaultno "); + } + strcat(lDialogString, "--menu "); + } + else + { + strcat ( lDialogString , "--msgbox " ) ; + + } + strcat ( lDialogString , "\"" ) ; + if ( aMessage && strlen(aMessage) ) + { + strcat(lDialogString, aMessage) ; + } + strcat(lDialogString, "\" "); + + if ( lWasGraphicDialog ) + { + if (aDialogType && !strcmp("yesnocancel", aDialogType)) + { + strcat(lDialogString,"0 60 0 Yes \"\" No \"\") 2>/tmp/tinyfd.txt;\ +if [ $? = 0 ];then tinyfdBool=1;else tinyfdBool=0;fi;\ +tinyfdRes=$(cat /tmp/tinyfd.txt);echo $tinyfdBool$tinyfdRes") ; + } + else + { + strcat(lDialogString, + "10 60 ) 2>&1;if [ $? = 0 ];then echo 1;else echo 0;fi"); + } + } + else + { + if (aDialogType && !strcmp("yesnocancel", aDialogType)) + { + strcat(lDialogString,"0 60 0 Yes \"\" No \"\" >/dev/tty ) 2>/tmp/tinyfd.txt;\ + if [ $? = 0 ];then tinyfdBool=1;else tinyfdBool=0;fi;\ + tinyfdRes=$(cat /tmp/tinyfd.txt);echo $tinyfdBool$tinyfdRes") ; + + if ( lWasXterm ) + { + strcat(lDialogString," >/tmp/tinyfd0.txt';cat /tmp/tinyfd0.txt"); + } + else + { + strcat(lDialogString, "; clear >/dev/tty") ; + } + } + else + { + strcat(lDialogString, "10 60 >/dev/tty) 2>&1;if [ $? = 0 ];"); + if ( lWasXterm ) + { + strcat ( lDialogString , +"then\n\techo 1\nelse\n\techo 0\nfi >/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt"); + } + else + { + strcat(lDialogString, + "then echo 1;else echo 0;fi;clear >/dev/tty"); + } + } + } + } + else if ( ! isTerminalRunning ( ) && terminalName() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return 0;} + strcpy ( lDialogString , terminalName() ) ; + strcat ( lDialogString , "'" ) ; + if ( !gWarningDisplayed && !tinyfd_forceConsole) + { + gWarningDisplayed = 1 ; + strcat ( lDialogString , "echo \"" ) ; + strcat ( lDialogString, gTitle) ; + strcat ( lDialogString , "\";" ) ; + strcat ( lDialogString , "echo \"" ) ; + strcat ( lDialogString, gMessageUnix) ; + strcat ( lDialogString , "\";echo;echo;" ) ; + } + if ( aTitle && strlen(aTitle) ) + { + strcat ( lDialogString , "echo \"" ) ; + strcat ( lDialogString, aTitle) ; + strcat ( lDialogString , "\";echo;" ) ; + } + if ( aMessage && strlen(aMessage) ) + { + strcat ( lDialogString , "echo \"" ) ; + strcat ( lDialogString, aMessage) ; + strcat ( lDialogString , "\"; " ) ; + } + if ( aDialogType && !strcmp("yesno",aDialogType) ) + { + strcat ( lDialogString , "echo -n \"y/n: \"; " ) ; + strcat ( lDialogString , "stty sane -echo;" ) ; + strcat ( lDialogString , + "answer=$( while ! head -c 1 | grep -i [ny];do true ;done);"); + strcat ( lDialogString , + "if echo \"$answer\" | grep -iq \"^y\";then\n"); + strcat ( lDialogString , "\techo 1\nelse\n\techo 0\nfi" ) ; + } + else if ( aDialogType && !strcmp("okcancel",aDialogType) ) + { + strcat ( lDialogString , "echo -n \"[O]kay/[C]ancel: \"; " ) ; + strcat ( lDialogString , "stty sane -echo;" ) ; + strcat ( lDialogString , + "answer=$( while ! head -c 1 | grep -i [oc];do true ;done);"); + strcat ( lDialogString , + "if echo \"$answer\" | grep -iq \"^o\";then\n"); + strcat ( lDialogString , "\techo 1\nelse\n\techo 0\nfi" ) ; + } + else if ( aDialogType && !strcmp("yesnocancel",aDialogType) ) + { + strcat ( lDialogString , "echo -n \"[Y]es/[N]o/[C]ancel: \"; " ) ; + strcat ( lDialogString , "stty sane -echo;" ) ; + strcat ( lDialogString , + "answer=$( while ! head -c 1 | grep -i [nyc];do true ;done);"); + strcat ( lDialogString , + "if echo \"$answer\" | grep -iq \"^y\";then\n\techo 1\n"); + strcat ( lDialogString , "elif echo \"$answer\" | grep -iq \"^n\";then\n\techo 2\n" ) ; + strcat ( lDialogString , "else\n\techo 0\nfi" ) ; + } + else + { + strcat(lDialogString , "echo -n \"press enter to continue \"; "); + strcat ( lDialogString , "stty sane -echo;" ) ; + strcat ( lDialogString , + "answer=$( while ! head -c 1;do true ;done);echo 1"); + } + strcat ( lDialogString , + " >/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt"); + } + else if ( !isTerminalRunning() && notifysendPresent() && !strcmp("ok" , aDialogType) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"notify");return 1;} + + strcpy ( lDialogString , "notify-send \"" ) ; + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, aTitle) ; + strcat ( lDialogString , " | " ) ; + } + if ( aMessage && strlen(aMessage) ) + { + strcat(lDialogString, aMessage) ; + } + strcat ( lDialogString , "\"" ) ; + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return 0;} + if ( !gWarningDisplayed && !tinyfd_forceConsole) + { + gWarningDisplayed = 1 ; + printf ("\n\n%s\n", gTitle); + printf ("%s\n\n", gMessageUnix); + } + if ( aTitle && strlen(aTitle) ) + { + printf ("\n%s\n", aTitle); + } + + tcgetattr(0, &infoOri); + tcgetattr(0, &info); + info.c_lflag &= ~ICANON; + info.c_cc[VMIN] = 1; + info.c_cc[VTIME] = 0; + tcsetattr(0, TCSANOW, &info); + if ( aDialogType && !strcmp("yesno",aDialogType) ) + { + do + { + if ( aMessage && strlen(aMessage) ) + { + printf("\n%s\n",aMessage); + } + printf("y/n: "); fflush(stdout); + lChar = tolower ( getchar() ) ; + printf("\n\n"); + } + while ( lChar != 'y' && lChar != 'n' ); + lResult = lChar == 'y' ? 1 : 0 ; + } + else if ( aDialogType && !strcmp("okcancel",aDialogType) ) + { + do + { + if ( aMessage && strlen(aMessage) ) + { + printf("\n%s\n",aMessage); + } + printf("[O]kay/[C]ancel: "); fflush(stdout); + lChar = tolower ( getchar() ) ; + printf("\n\n"); + } + while ( lChar != 'o' && lChar != 'c' ); + lResult = lChar == 'o' ? 1 : 0 ; + } + else if ( aDialogType && !strcmp("yesnocancel",aDialogType) ) + { + do + { + if ( aMessage && strlen(aMessage) ) + { + printf("\n%s\n",aMessage); + } + printf("[Y]es/[N]o/[C]ancel: "); fflush(stdout); + lChar = tolower ( getchar() ) ; + printf("\n\n"); + } + while ( lChar != 'y' && lChar != 'n' && lChar != 'c' ); + lResult = (lChar == 'y') ? 1 : (lChar == 'n') ? 2 : 0 ; + } + else + { + if ( aMessage && strlen(aMessage) ) + { + printf("\n%s\n\n",aMessage); + } + printf("press enter to continue "); fflush(stdout); + getchar() ; + printf("\n\n"); + lResult = 1 ; + } + tcsetattr(0, TCSANOW, &infoOri); + free(lDialogString); + return lResult ; + } + + if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ; + + if ( ! ( lIn = popen ( lDialogString , "r" ) ) ) + { + free(lDialogString); + return 0 ; + } + while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) + {} + + pclose ( lIn ) ; + + /* printf ( "lBuff: %s len: %lu \n" , lBuff , strlen(lBuff) ) ; */ + if ( lBuff[strlen ( lBuff ) -1] == '\n' ) + { + lBuff[strlen ( lBuff ) -1] = '\0' ; + } + /* printf ( "lBuff1: %s len: %lu \n" , lBuff , strlen(lBuff) ) ; */ + + if (aDialogType && !strcmp("yesnocancel", aDialogType)) + { + if ( lBuff[0]=='1' ) + { + if ( !strcmp ( lBuff+1 , "Yes" )) strcpy(lBuff,"1"); + else if ( !strcmp ( lBuff+1 , "No" )) strcpy(lBuff,"2"); + } + } + /* printf ( "lBuff2: %s len: %lu \n" , lBuff , strlen(lBuff) ) ; */ + + lResult = !strcmp ( lBuff , "2" ) ? 2 : !strcmp ( lBuff , "1" ) ? 1 : 0; + + /* printf ( "lResult: %d\n" , lResult ) ; */ + free(lDialogString); + return lResult ; +} + + +/* returns NULL on cancel */ +char const * tinyfd_inputBox( + char const * const aTitle , /* NULL or "" */ + char const * const aMessage , /* NULL or "" may NOT contain \n nor \t */ + char const * const aDefaultInput ) /* "" , if NULL it's a passwordBox */ +{ + static char lBuff[MAX_PATH_OR_CMD]; + char * lDialogString = NULL; + char * lpDialogString; + FILE * lIn ; + int lResult ; + int lWasGdialog = 0 ; + int lWasGraphicDialog = 0 ; + int lWasXterm = 0 ; + int lWasBasicXterm = 0 ; + struct termios oldt ; + struct termios newt ; + char * lEOF; + int lTitleLen ; + int lMessageLen ; + + lBuff[0]='\0'; + + lTitleLen = aTitle ? strlen(aTitle) : 0 ; + lMessageLen = aMessage ? strlen(aMessage) : 0 ; + if ( !aTitle || strcmp(aTitle,"tinyfd_query") ) + { + lDialogString = (char *) malloc( MAX_PATH_OR_CMD + lTitleLen + lMessageLen ); + } + + if ( osascriptPresent ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;} + strcpy ( lDialogString , "osascript "); + if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'"); + strcat ( lDialogString , " -e 'try' -e 'display dialog \"") ; + if ( aMessage && strlen(aMessage) ) + { + strcat(lDialogString, aMessage) ; + } + strcat(lDialogString, "\" ") ; + strcat(lDialogString, "default answer \"") ; + if ( aDefaultInput && strlen(aDefaultInput) ) + { + strcat(lDialogString, aDefaultInput) ; + } + strcat(lDialogString, "\" ") ; + if ( ! aDefaultInput ) + { + strcat(lDialogString, "hidden answer true ") ; + } + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "with title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + strcat(lDialogString, "with icon note' ") ; + strcat(lDialogString, "-e '\"1\" & text returned of result' " ); + strcat(lDialogString, "-e 'on error number -128' " ) ; + strcat(lDialogString, "-e '0' " ); + strcat(lDialogString, "-e 'end try'") ; + if ( ! osx9orBetter() ) strcat(lDialogString, " -e 'end tell'") ; + } + else if ( zenityPresent() || matedialogPresent() || qarmaPresent() ) + { + if ( zenityPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;} + strcpy ( lDialogString , "szAnswer=$(zenity --entry" ) ; + } + else if ( matedialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;} + strcpy ( lDialogString , "szAnswer=$(matedialog --entry" ) ; + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"qarma");return (char const *)1;} + strcpy ( lDialogString , "szAnswer=$(qarma --entry" ) ; + } + + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, " --title=\"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + } + if ( aMessage && strlen(aMessage) ) + { + strcat(lDialogString, " --text=\"") ; + strcat(lDialogString, aMessage) ; + strcat(lDialogString, "\"") ; + } + if ( aDefaultInput && strlen(aDefaultInput) ) + { + strcat(lDialogString, " --entry-text=\"") ; + strcat(lDialogString, aDefaultInput) ; + strcat(lDialogString, "\"") ; + } + else + { + strcat(lDialogString, " --hide-text") ; + } + strcat ( lDialogString , + ");if [ $? = 0 ];then echo 1$szAnswer;else echo 0$szAnswer;fi"); + } + else if ( kdialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;} + strcpy ( lDialogString , "szAnswer=$(kdialog" ) ; + if ( ! aDefaultInput ) + { + strcat(lDialogString, " --password ") ; + } + else + { + strcat(lDialogString, " --inputbox ") ; + + } + strcat(lDialogString, "\"") ; + if ( aMessage && strlen(aMessage) ) + { + strcat(lDialogString, aMessage ) ; + } + strcat(lDialogString , "\" \"" ) ; + if ( aDefaultInput && strlen(aDefaultInput) ) + { + strcat(lDialogString, aDefaultInput ) ; + } + strcat(lDialogString , "\"" ) ; + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, " --title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + } + strcat ( lDialogString , + ");if [ $? = 0 ];then echo 1$szAnswer;else echo 0$szAnswer;fi"); + } + else if ( gxmessagePresent() || gmessagePresent() ) + { + if ( gxmessagePresent() ) { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gxmessage");return (char const *)1;} + strcpy ( lDialogString , "szAnswer=$(gxmessage -buttons Ok:1,Cancel:0 -center \""); + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gmessage");return (char const *)1;} + strcpy ( lDialogString , "szAnswer=$(gmessage -buttons Ok:1,Cancel:0 -center \""); + } + + if ( aMessage && strlen(aMessage) ) + { + strcat ( lDialogString , aMessage ) ; + } + strcat(lDialogString, "\"" ) ; + if ( aTitle && strlen(aTitle) ) + { + strcat ( lDialogString , " -title \""); + strcat ( lDialogString , aTitle ) ; + strcat(lDialogString, "\" " ) ; + } + strcat(lDialogString, " -entrytext \"" ) ; + if ( aDefaultInput && strlen(aDefaultInput) ) + { + strcat ( lDialogString , aDefaultInput ) ; + } + strcat(lDialogString, "\"" ) ; + strcat ( lDialogString , ");echo $?$szAnswer"); + } + else if ( !gdialogPresent() && tkinter2Present ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;} + strcpy ( lDialogString , gPython2Name ) ; + if ( ! isTerminalRunning ( ) && isDarwin ( ) ) + { + strcat ( lDialogString , " -i" ) ; /* for osx without console */ + } + + strcat ( lDialogString , +" -c \"import Tkinter,tkSimpleDialog;root=Tkinter.Tk();root.withdraw();"); + + if ( isDarwin ( ) ) + { + strcat ( lDialogString , +"import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set \ +frontmost of process \\\"Python\\\" to true' ''');"); + } + + strcat ( lDialogString ,"res=tkSimpleDialog.askstring(" ) ; + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "title='") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "',") ; + } + if ( aMessage && strlen(aMessage) ) + { + + strcat(lDialogString, "prompt='") ; + lpDialogString = lDialogString + strlen(lDialogString); + replaceSubStr ( aMessage , "\n" , "\\n" , lpDialogString ) ; + strcat(lDialogString, "',") ; + } + if ( aDefaultInput ) + { + if ( strlen(aDefaultInput) ) + { + strcat(lDialogString, "initialvalue='") ; + strcat(lDialogString, aDefaultInput) ; + strcat(lDialogString, "',") ; + } + } + else + { + strcat(lDialogString, "show='*'") ; + } + strcat(lDialogString, ");\nif res is None :\n\tprint 0"); + strcat(lDialogString, "\nelse :\n\tprint '1'+res\n\"" ) ; + } + else if ( gdialogPresent() || xdialogPresent() + || dialogName() || whiptailPresent() ) + { + if ( gdialogPresent ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"gdialog");return (char const *)1;} + lWasGraphicDialog = 1 ; + lWasGdialog = 1 ; + strcpy ( lDialogString , "(gdialog " ) ; + } + else if ( xdialogPresent ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;} + lWasGraphicDialog = 1 ; + strcpy ( lDialogString , "(Xdialog " ) ; + } + else if ( dialogName ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} + if ( isTerminalRunning ( ) ) + { + strcpy ( lDialogString , "(dialog " ) ; + } + else + { + lWasXterm = 1 ; + strcpy ( lDialogString , terminalName() ) ; + strcat ( lDialogString , "'(" ) ; + strcat ( lDialogString , dialogName() ) ; + strcat ( lDialogString , " " ) ; + } + } + else if ( isTerminalRunning ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"whiptail");return (char const *)0;} + strcpy ( lDialogString , "(whiptail " ) ; + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"whiptail");return (char const *)0;} + lWasXterm = 1 ; + strcpy ( lDialogString , terminalName() ) ; + strcat ( lDialogString , "'(whiptail " ) ; + } + + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "--title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + + if ( !xdialogPresent() && !gdialogPresent() ) + { + strcat(lDialogString, "--backtitle \"") ; + strcat(lDialogString, "tab: move focus") ; + if ( ! aDefaultInput && !lWasGdialog ) + { + strcat(lDialogString, " (sometimes nothing, no blink nor star, is shown in text field)") ; + } + strcat(lDialogString, "\" ") ; + } + + if ( aDefaultInput || lWasGdialog ) + { + strcat ( lDialogString , "--inputbox" ) ; + } + else + { + if ( !lWasGraphicDialog && dialogName() && isDialogVersionBetter09b() ) + { + strcat ( lDialogString , "--insecure " ) ; + } + strcat ( lDialogString , "--passwordbox" ) ; + } + strcat ( lDialogString , " \"" ) ; + if ( aMessage && strlen(aMessage) ) + { + strcat(lDialogString, aMessage) ; + } + strcat(lDialogString,"\" 10 60 ") ; + if ( aDefaultInput && strlen(aDefaultInput) ) + { + strcat(lDialogString, "\"") ; + strcat(lDialogString, aDefaultInput) ; + strcat(lDialogString, "\" ") ; + } + if ( lWasGraphicDialog ) + { + strcat(lDialogString,") 2>/tmp/tinyfd.txt;\ + if [ $? = 0 ];then tinyfdBool=1;else tinyfdBool=0;fi;\ + tinyfdRes=$(cat /tmp/tinyfd.txt);echo $tinyfdBool$tinyfdRes") ; + } + else + { + strcat(lDialogString,">/dev/tty ) 2>/tmp/tinyfd.txt;\ + if [ $? = 0 ];then tinyfdBool=1;else tinyfdBool=0;fi;\ + tinyfdRes=$(cat /tmp/tinyfd.txt);echo $tinyfdBool$tinyfdRes") ; + + if ( lWasXterm ) + { + strcat(lDialogString," >/tmp/tinyfd0.txt';cat /tmp/tinyfd0.txt"); + } + else + { + strcat(lDialogString, "; clear >/dev/tty") ; + } + } + } + else if ( ! isTerminalRunning ( ) && terminalName() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;} + lWasBasicXterm = 1 ; + strcpy ( lDialogString , terminalName() ) ; + strcat ( lDialogString , "'" ) ; + if ( !gWarningDisplayed && !tinyfd_forceConsole) + { + tinyfd_messageBox(gTitle,gMessageUnix,"ok","warning",0); + gWarningDisplayed = 1 ; + } + if ( aTitle && strlen(aTitle) && !tinyfd_forceConsole) + { + strcat ( lDialogString , "echo \"" ) ; + strcat ( lDialogString, aTitle) ; + strcat ( lDialogString , "\";echo;" ) ; + } + + strcat ( lDialogString , "echo \"" ) ; + if ( aMessage && strlen(aMessage) ) + { + strcat ( lDialogString, aMessage) ; + } + strcat ( lDialogString , "\";read " ) ; + if ( ! aDefaultInput ) + { + strcat ( lDialogString , "-s " ) ; + } + strcat ( lDialogString , "-p \"" ) ; + strcat ( lDialogString , "(esc+enter to cancel): \" ANSWER " ) ; + strcat ( lDialogString , ";echo 1$ANSWER >/tmp/tinyfd.txt';" ) ; + strcat ( lDialogString , "cat -v /tmp/tinyfd.txt"); + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"basicinput");return (char const *)0;} + if ( !gWarningDisplayed && !tinyfd_forceConsole) + { + tinyfd_messageBox(gTitle,gMessageUnix,"ok","warning",0); + gWarningDisplayed = 1 ; + } + if ( aTitle && strlen(aTitle) ) + { + printf ("\n%s\n", aTitle); + } + if ( aMessage && strlen(aMessage) ) + { + printf("\n%s\n",aMessage); + } + printf("(esc+enter to cancel): "); fflush(stdout); + if ( ! aDefaultInput ) + { + tcgetattr(STDIN_FILENO, & oldt) ; + newt = oldt ; + newt.c_lflag &= ~ECHO ; + tcsetattr(STDIN_FILENO, TCSANOW, & newt); + } + + lEOF = fgets(lBuff, MAX_PATH_OR_CMD, stdin); + /* printf("lbuff<%c><%d>\n",lBuff[0],lBuff[0]); */ + if ( ! lEOF || (lBuff[0] == '\0') ) + { + free(lDialogString); + return NULL; + } + + if ( lBuff[0] == '\n' ) + { + lEOF = fgets(lBuff, MAX_PATH_OR_CMD, stdin); + /* printf("lbuff<%c><%d>\n",lBuff[0],lBuff[0]); */ + if ( ! lEOF || (lBuff[0] == '\0') ) + { + free(lDialogString); + return NULL; + } + } + + if ( ! aDefaultInput ) + { + tcsetattr(STDIN_FILENO, TCSANOW, & oldt); + printf ("\n"); + } + printf ("\n"); + if ( strchr(lBuff,27) ) + { + free(lDialogString); + return NULL ; + } + if ( lBuff[strlen ( lBuff ) -1] == '\n' ) + { + lBuff[strlen ( lBuff ) -1] = '\0' ; + } + free(lDialogString); + return lBuff ; + } + + if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ; + lIn = popen ( lDialogString , "r" ); + if ( ! lIn ) + { + if ( fileExists("/tmp/tinyfd.txt") ) + { + wipefile("/tmp/tinyfd.txt"); + remove("/tmp/tinyfd.txt"); + } + if ( fileExists("/tmp/tinyfd0.txt") ) + { + wipefile("/tmp/tinyfd0.txt"); + remove("/tmp/tinyfd0.txt"); + } + free(lDialogString); + return NULL ; + } + while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) + {} + + pclose ( lIn ) ; + + if ( fileExists("/tmp/tinyfd.txt") ) + { + wipefile("/tmp/tinyfd.txt"); + remove("/tmp/tinyfd.txt"); + } + if ( fileExists("/tmp/tinyfd0.txt") ) + { + wipefile("/tmp/tinyfd0.txt"); + remove("/tmp/tinyfd0.txt"); + } + + /* printf ( "len Buff: %lu\n" , strlen(lBuff) ) ; */ + /* printf ( "lBuff0: %s\n" , lBuff ) ; */ + if ( lBuff[strlen ( lBuff ) -1] == '\n' ) + { + lBuff[strlen ( lBuff ) -1] = '\0' ; + } + /* printf ( "lBuff1: %s len: %lu \n" , lBuff , strlen(lBuff) ) ; */ + if ( lWasBasicXterm ) + { + if ( strstr(lBuff,"^[") ) /* esc was pressed */ + { + free(lDialogString); + return NULL ; + } + } + + lResult = strncmp ( lBuff , "1" , 1) ? 0 : 1 ; + /* printf ( "lResult: %d \n" , lResult ) ; */ + if ( ! lResult ) + { + free(lDialogString); + return NULL ; + } + /* printf ( "lBuff+1: %s\n" , lBuff+1 ) ; */ + free(lDialogString); + + return lBuff+1 ; +} + + +char const * tinyfd_saveFileDialog ( + char const * const aTitle , /* NULL or "" */ + char const * const aDefaultPathAndFile , /* NULL or "" */ + int const aNumOfFilterPatterns , /* 0 */ + char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */ + char const * const aSingleFilterDescription ) /* NULL or "image files" */ +{ + + static char lBuff [MAX_PATH_OR_CMD] ; + char lDialogString [MAX_PATH_OR_CMD] ; + char lString [MAX_PATH_OR_CMD] ; + int i ; + int lWasGraphicDialog = 0 ; + int lWasXterm = 0 ; + char const * p ; + FILE * lIn ; + lBuff[0]='\0'; + + if ( osascriptPresent ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;} + strcpy ( lDialogString , "osascript "); + if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"Finder\"' -e 'Activate'"); + strcat ( lDialogString , " -e 'try' -e 'POSIX path of ( choose file name " ); + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "with prompt \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + getPathWithoutFinalSlash ( lString , aDefaultPathAndFile ) ; + if ( strlen(lString) ) + { + strcat(lDialogString, "default location \"") ; + strcat(lDialogString, lString ) ; + strcat(lDialogString , "\" " ) ; + } + getLastName ( lString , aDefaultPathAndFile ) ; + if ( strlen(lString) ) + { + strcat(lDialogString, "default name \"") ; + strcat(lDialogString, lString ) ; + strcat(lDialogString , "\" " ) ; + } + strcat ( lDialogString , ")' " ) ; + strcat(lDialogString, "-e 'on error number -128' " ) ; + strcat(lDialogString, "-e 'end try'") ; + if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ; + } + else if ( zenityPresent() || matedialogPresent() || qarmaPresent() ) + { + if ( zenityPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;} + strcpy ( lDialogString , "zenity" ) ; + } + else if ( matedialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;} + strcpy ( lDialogString , "matedialog" ) ; + + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"qarma");return (char const *)1;} + strcpy ( lDialogString , "qarma" ) ; + + } + strcat(lDialogString, " --file-selection --save --confirm-overwrite" ) ; + + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, " --title=\"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + } + if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) + { + strcat(lDialogString, " --filename=\"") ; + strcat(lDialogString, aDefaultPathAndFile) ; + strcat(lDialogString, "\"") ; + } + if ( aNumOfFilterPatterns > 0 ) + { + strcat ( lDialogString , " --file-filter='" ) ; + if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) + { + strcat ( lDialogString , aSingleFilterDescription ) ; + strcat ( lDialogString , " | " ) ; + } + for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ ) + { + strcat ( lDialogString , aFilterPatterns [i] ) ; + strcat ( lDialogString , " " ) ; + } + strcat ( lDialogString , "' --file-filter='All files | *'" ) ; + } + } + else if ( kdialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;} + strcpy ( lDialogString , "kdialog --getsavefilename" ) ; + if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) + { + strcat(lDialogString, " \"") ; + strcat(lDialogString, aDefaultPathAndFile ) ; + strcat(lDialogString , "\"" ) ; + } + else + { + strcat(lDialogString, " :" ) ; + } + if ( aNumOfFilterPatterns > 0 ) + { + strcat(lDialogString , " \"" ) ; + for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ ) + { + strcat ( lDialogString , aFilterPatterns [i] ) ; + strcat ( lDialogString , " " ) ; + } + if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) + { + strcat ( lDialogString , " | " ) ; + strcat ( lDialogString , aSingleFilterDescription ) ; + } + strcat ( lDialogString , "\"" ) ; + } + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, " --title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + } + } + else if ( ! xdialogPresent() && tkinter2Present ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;} + strcpy ( lDialogString , gPython2Name ) ; + if ( ! isTerminalRunning ( ) && isDarwin ( )) + { + strcat ( lDialogString , " -i" ) ; /* for osx without console */ + } + strcat ( lDialogString , +" -c \"import Tkinter,tkFileDialog;root=Tkinter.Tk();root.withdraw();"); + + if ( isDarwin ( ) ) + { + strcat ( lDialogString , +"import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set\ + frontmost of process \\\"Python\\\" to true' ''');"); + } + + strcat ( lDialogString , "print tkFileDialog.asksaveasfilename("); + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "title='") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "',") ; + } + if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) + { + getPathWithoutFinalSlash ( lString , aDefaultPathAndFile ) ; + if ( strlen(lString) ) + { + strcat(lDialogString, "initialdir='") ; + strcat(lDialogString, lString ) ; + strcat(lDialogString , "'," ) ; + } + getLastName ( lString , aDefaultPathAndFile ) ; + if ( strlen(lString) ) + { + strcat(lDialogString, "initialfile='") ; + strcat(lDialogString, lString ) ; + strcat(lDialogString , "'," ) ; + } + } + if ( ( aNumOfFilterPatterns > 1 ) + || ( (aNumOfFilterPatterns == 1) /* test because poor osx behaviour */ + && ( aFilterPatterns[0][strlen(aFilterPatterns[0])-1] != '*' ) ) ) + { + strcat(lDialogString , "filetypes=(" ) ; + strcat ( lDialogString , "('" ) ; + if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) + { + strcat ( lDialogString , aSingleFilterDescription ) ; + } + strcat ( lDialogString , "',(" ) ; + for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ ) + { + strcat ( lDialogString , "'" ) ; + strcat ( lDialogString , aFilterPatterns [i] ) ; + strcat ( lDialogString , "'," ) ; + } + strcat ( lDialogString , "))," ) ; + strcat ( lDialogString , "('All files','*'))" ) ; + } + strcat ( lDialogString , ")\"" ) ; + } + else if ( xdialogPresent() || dialogName() ) + { + if ( xdialogPresent ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;} + lWasGraphicDialog = 1 ; + strcpy ( lDialogString , "(Xdialog " ) ; + } + else if ( isTerminalRunning ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} + strcpy ( lDialogString , "(dialog " ) ; + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} + lWasXterm = 1 ; + strcpy ( lDialogString , terminalName() ) ; + strcat ( lDialogString , "'(" ) ; + strcat ( lDialogString , dialogName() ) ; + strcat ( lDialogString , " " ) ; + } + + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "--title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + + if ( !xdialogPresent() && !gdialogPresent() ) + { + strcat(lDialogString, "--backtitle \"") ; + strcat(lDialogString, + "tab: focus | /: populate | spacebar: fill text field | ok: TEXT FIELD ONLY") ; + strcat(lDialogString, "\" ") ; + } + + strcat ( lDialogString , "--fselect \"" ) ; + if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) + { + if ( ! strchr(aDefaultPathAndFile, '/') ) + { + strcat(lDialogString, "./") ; + } + strcat(lDialogString, aDefaultPathAndFile) ; + } + else if ( ! isTerminalRunning ( ) && !lWasGraphicDialog ) + { + strcat(lDialogString, getenv("HOME")) ; + strcat(lDialogString, "/") ; + } + else + { + strcat(lDialogString, "./") ; + } + + if ( lWasGraphicDialog ) + { + strcat(lDialogString, "\" 0 60 ) 2>&1 ") ; + } + else + { + strcat(lDialogString, "\" 0 60 >/dev/tty) ") ; + if ( lWasXterm ) + { + strcat ( lDialogString , + "2>/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt"); + } + else + { + strcat(lDialogString, "2>&1 ; clear >/dev/tty") ; + } + } + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){return tinyfd_inputBox (aTitle,NULL,NULL);} + p = tinyfd_inputBox ( aTitle , "Save file" , "" ) ; + getPathWithoutFinalSlash ( lString , p ) ; + if ( strlen ( lString ) && ! dirExists ( lString ) ) + { + return NULL ; + } + getLastName(lString,p); + if ( ! strlen(lString) ) + { + return NULL; + } + return p ; + } + + if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ; + if ( ! ( lIn = popen ( lDialogString , "r" ) ) ) + { + return NULL ; + } + while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) + {} + pclose ( lIn ) ; + if ( lBuff[strlen ( lBuff ) -1] == '\n' ) + { + lBuff[strlen ( lBuff ) -1] = '\0' ; + } + /* printf ( "lBuff: %s\n" , lBuff ) ; */ + if ( ! strlen(lBuff) ) + { + return NULL; + } + getPathWithoutFinalSlash ( lString , lBuff ) ; + if ( strlen ( lString ) && ! dirExists ( lString ) ) + { + return NULL ; + } + getLastName(lString,lBuff); + if ( ! filenameValid(lString) ) + { + return NULL; + } + return lBuff ; +} + + +/* in case of multiple files, the separator is | */ +char const * tinyfd_openFileDialog ( + char const * const aTitle , /* NULL or "" */ + char const * const aDefaultPathAndFile , /* NULL or "" */ + int const aNumOfFilterPatterns , /* 0 */ + char const * const * const aFilterPatterns , /* NULL or {"*.jpg","*.png"} */ + char const * const aSingleFilterDescription , /* NULL or "image files" */ + int const aAllowMultipleSelects ) /* 0 or 1 */ +{ + static char lBuff [MAX_MULTIPLE_FILES*MAX_PATH_OR_CMD] ; + char lDialogString [MAX_PATH_OR_CMD] ; + char lString [MAX_PATH_OR_CMD] ; + int i ; + FILE * lIn ; + char * p ; + char const * p2 ; + int lWasKdialog = 0 ; + int lWasGraphicDialog = 0 ; + int lWasXterm = 0 ; + lBuff[0]='\0'; + + if ( osascriptPresent ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;} + strcpy ( lDialogString , "osascript "); + if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'"); + strcat ( lDialogString , " -e 'try' -e '" ); + if ( ! aAllowMultipleSelects ) + { + + + strcat ( lDialogString , "POSIX path of ( " ); + } + else + { + strcat ( lDialogString , "set mylist to " ); + } + strcat ( lDialogString , "choose file " ); + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "with prompt \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + getPathWithoutFinalSlash ( lString , aDefaultPathAndFile ) ; + if ( strlen(lString) ) + { + strcat(lDialogString, "default location \"") ; + strcat(lDialogString, lString ) ; + strcat(lDialogString , "\" " ) ; + } + if ( aNumOfFilterPatterns > 0 ) + { + strcat(lDialogString , "of type {\"" ); + strcat ( lDialogString , aFilterPatterns [0] + 2 ) ; + strcat ( lDialogString , "\"" ) ; + for ( i = 1 ; i < aNumOfFilterPatterns ; i ++ ) + { + strcat ( lDialogString , ",\"" ) ; + strcat ( lDialogString , aFilterPatterns [i] + 2) ; + strcat ( lDialogString , "\"" ) ; + } + strcat ( lDialogString , "} " ) ; + } + if ( aAllowMultipleSelects ) + { + strcat ( lDialogString , "multiple selections allowed true ' " ) ; + strcat ( lDialogString , + "-e 'set mystring to POSIX path of item 1 of mylist' " ); + strcat ( lDialogString , + "-e 'repeat with i from 2 to the count of mylist' " ); + strcat ( lDialogString , "-e 'set mystring to mystring & \"|\"' " ); + strcat ( lDialogString , + "-e 'set mystring to mystring & POSIX path of item i of mylist' " ); + strcat ( lDialogString , "-e 'end repeat' " ); + strcat ( lDialogString , "-e 'mystring' " ); + } + else + { + strcat ( lDialogString , ")' " ) ; + } + strcat(lDialogString, "-e 'on error number -128' " ) ; + strcat(lDialogString, "-e 'end try'") ; + if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ; + } + else if ( zenityPresent() || matedialogPresent() || qarmaPresent() ) + { + if ( zenityPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;} + strcpy ( lDialogString , "zenity --file-selection" ) ; + } + else if ( matedialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;} + strcpy ( lDialogString , "matedialog --file-selection" ) ; + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"qarma");return (char const *)1;} + strcpy ( lDialogString , "qarma --file-selection" ) ; + } + + if ( aAllowMultipleSelects ) + { + strcat ( lDialogString , " --multiple" ) ; + } + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, " --title=\"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + } + if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) + { + strcat(lDialogString, " --filename=\"") ; + strcat(lDialogString, aDefaultPathAndFile) ; + strcat(lDialogString, "\"") ; + } + if ( aNumOfFilterPatterns > 0 ) + { + strcat ( lDialogString , " --file-filter='" ) ; + if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) + { + strcat ( lDialogString , aSingleFilterDescription ) ; + strcat ( lDialogString , " | " ) ; + } + for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ ) + { + strcat ( lDialogString , aFilterPatterns [i] ) ; + strcat ( lDialogString , " " ) ; + } + strcat ( lDialogString , "' --file-filter='All files | *'" ) ; + } + } + else if ( kdialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;} + lWasKdialog = 1 ; + strcpy ( lDialogString , "kdialog --getopenfilename" ) ; + if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) + { + strcat(lDialogString, " \"") ; + strcat(lDialogString, aDefaultPathAndFile ) ; + + strcat(lDialogString , "\"" ) ; + } + else + { + strcat(lDialogString, " :" ) ; + } + if ( aNumOfFilterPatterns > 0 ) + { + strcat(lDialogString , " \"" ) ; + for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ ) + { + strcat ( lDialogString , aFilterPatterns [i] ) ; + strcat ( lDialogString , " " ) ; + } + if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) + { + strcat ( lDialogString , " | " ) ; + strcat ( lDialogString , aSingleFilterDescription ) ; + } + strcat ( lDialogString , "\"" ) ; + } + if ( aAllowMultipleSelects ) + { + strcat ( lDialogString , " --multiple --separate-output" ) ; + } + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, " --title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + } + } + else if ( ! xdialogPresent() && tkinter2Present ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;} + strcpy ( lDialogString , gPython2Name ) ; + if ( ! isTerminalRunning ( ) && isDarwin ( ) ) + { + strcat ( lDialogString , " -i" ) ; /* for osx without console */ + } + strcat ( lDialogString , +" -c \"import Tkinter,tkFileDialog;root=Tkinter.Tk();root.withdraw();"); + + if ( isDarwin ( ) ) + { + strcat ( lDialogString , +"import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set \ +frontmost of process \\\"Python\\\" to true' ''');"); + } + strcat ( lDialogString , "lFiles=tkFileDialog.askopenfilename("); + if ( aAllowMultipleSelects ) + { + strcat ( lDialogString , "multiple=1," ) ; + } + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "title='") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "',") ; + } + if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) + { + getPathWithoutFinalSlash ( lString , aDefaultPathAndFile ) ; + if ( strlen(lString) ) + { + strcat(lDialogString, "initialdir='") ; + strcat(lDialogString, lString ) ; + strcat(lDialogString , "'," ) ; + } + getLastName ( lString , aDefaultPathAndFile ) ; + if ( strlen(lString) ) + { + strcat(lDialogString, "initialfile='") ; + strcat(lDialogString, lString ) ; + strcat(lDialogString , "'," ) ; + } + } + if ( ( aNumOfFilterPatterns > 1 ) + || ( ( aNumOfFilterPatterns == 1 ) /*test because poor osx behaviour*/ + && ( aFilterPatterns[0][strlen(aFilterPatterns[0])-1] != '*' ) ) ) + { + strcat(lDialogString , "filetypes=(" ) ; + strcat ( lDialogString , "('" ) ; + if ( aSingleFilterDescription && strlen(aSingleFilterDescription) ) + { + strcat ( lDialogString , aSingleFilterDescription ) ; + } + strcat ( lDialogString , "',(" ) ; + for ( i = 0 ; i < aNumOfFilterPatterns ; i ++ ) + { + strcat ( lDialogString , "'" ) ; + strcat ( lDialogString , aFilterPatterns [i] ) ; + strcat ( lDialogString , "'," ) ; + } + strcat ( lDialogString , "))," ) ; + strcat ( lDialogString , "('All files','*'))" ) ; + } + strcat ( lDialogString , ");\ +\nif not isinstance(lFiles, tuple):\n\tprint lFiles\nelse:\ +\n\tlFilesString=''\n\tfor lFile in lFiles:\n\t\tlFilesString+=str(lFile)+'|'\ +\n\tprint lFilesString[:-1]\n\"" ) ; + } + else if ( xdialogPresent() || dialogName() ) + { + if ( xdialogPresent ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;} + lWasGraphicDialog = 1 ; + strcpy ( lDialogString , "(Xdialog " ) ; + } + else if ( isTerminalRunning ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} + strcpy ( lDialogString , "(dialog " ) ; + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} + lWasXterm = 1 ; + strcpy ( lDialogString , terminalName() ) ; + strcat ( lDialogString , "'(" ) ; + strcat ( lDialogString , dialogName() ) ; + strcat ( lDialogString , " " ) ; + } + + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "--title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + + if ( !xdialogPresent() && !gdialogPresent() ) + { + strcat(lDialogString, "--backtitle \"") ; + strcat(lDialogString, + "tab: focus | /: populate | spacebar: fill text field | ok: TEXT FIELD ONLY") ; + strcat(lDialogString, "\" ") ; + } + + strcat ( lDialogString , "--fselect \"" ) ; + if ( aDefaultPathAndFile && strlen(aDefaultPathAndFile) ) + { + if ( ! strchr(aDefaultPathAndFile, '/') ) + { + strcat(lDialogString, "./") ; + } + strcat(lDialogString, aDefaultPathAndFile) ; + } + else if ( ! isTerminalRunning ( ) && !lWasGraphicDialog ) + { + strcat(lDialogString, getenv("HOME")) ; + strcat(lDialogString, "/"); + } + else + { + strcat(lDialogString, "./") ; + } + + if ( lWasGraphicDialog ) + { + strcat(lDialogString, "\" 0 60 ) 2>&1 ") ; + } + else + { + strcat(lDialogString, "\" 0 60 >/dev/tty) ") ; + if ( lWasXterm ) + { + strcat ( lDialogString , + "2>/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt"); + } + else + { + strcat(lDialogString, "2>&1 ; clear >/dev/tty") ; + } + } + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){return tinyfd_inputBox (aTitle,NULL,NULL);} + p2 = tinyfd_inputBox(aTitle, "Open file",""); + if ( ! fileExists (p2) ) + { + return NULL ; + } + return p2 ; + } + + if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ; + if ( ! ( lIn = popen ( lDialogString , "r" ) ) ) + { + return NULL ; + } + lBuff[0]='\0'; + p=lBuff; + while ( fgets ( p , sizeof ( lBuff ) , lIn ) != NULL ) + { + p += strlen ( p ); + } + pclose ( lIn ) ; + if ( lBuff[strlen ( lBuff ) -1] == '\n' ) + { + lBuff[strlen ( lBuff ) -1] = '\0' ; + } + /* printf ( "lBuff: %s\n" , lBuff ) ; */ + if ( lWasKdialog && aAllowMultipleSelects ) + { + p = lBuff ; + while ( ( p = strchr ( p , '\n' ) ) ) + * p = '|' ; + } + /* printf ( "lBuff2: %s\n" , lBuff ) ; */ + if ( ! strlen ( lBuff ) ) + { + return NULL; + } + if ( aAllowMultipleSelects && strchr(lBuff, '|') ) + { + p2 = ensureFilesExist( lBuff , lBuff ) ; + } + else if ( fileExists (lBuff) ) + { + p2 = lBuff ; + } + else + { + return NULL ; + } + /* printf ( "lBuff3: %s\n" , p2 ) ; */ + + return p2 ; +} + + +char const * tinyfd_selectFolderDialog ( + char const * const aTitle , /* "" */ + char const * const aDefaultPath ) /* "" */ +{ + static char lBuff [MAX_PATH_OR_CMD] ; + char lDialogString [MAX_PATH_OR_CMD] ; + FILE * lIn ; + char const * p ; + int lWasGraphicDialog = 0 ; + int lWasXterm = 0 ; + lBuff[0]='\0'; + + if ( osascriptPresent ( )) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;} + strcpy ( lDialogString , "osascript "); + if ( ! osx9orBetter() ) strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'"); + strcat ( lDialogString , " -e 'try' -e 'POSIX path of ( choose folder "); + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "with prompt \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + if ( aDefaultPath && strlen(aDefaultPath) ) + { + strcat(lDialogString, "default location \"") ; + strcat(lDialogString, aDefaultPath ) ; + strcat(lDialogString , "\" " ) ; + } + strcat ( lDialogString , ")' " ) ; + strcat(lDialogString, "-e 'on error number -128' " ) ; + strcat(lDialogString, "-e 'end try'") ; + if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ; + } + else if ( zenityPresent() || matedialogPresent() || qarmaPresent() ) + { + if ( zenityPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;} + strcpy ( lDialogString , "zenity --file-selection --directory" ) ; + } + else if ( matedialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;} + strcpy ( lDialogString , "matedialog --file-selection --directory" ) ; + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"qarma");return (char const *)1;} + strcpy ( lDialogString , "qarma --file-selection --directory" ) ; + } + + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, " --title=\"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + } + if ( aDefaultPath && strlen(aDefaultPath) ) + { + strcat(lDialogString, " --filename=\"") ; + strcat(lDialogString, aDefaultPath) ; + strcat(lDialogString, "\"") ; + } + } + else if ( kdialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;} + strcpy ( lDialogString , "kdialog --getexistingdirectory" ) ; + if ( aDefaultPath && strlen(aDefaultPath) ) + { + strcat(lDialogString, " \"") ; + strcat(lDialogString, aDefaultPath ) ; + strcat(lDialogString , "\"" ) ; + } + else + { + strcat(lDialogString, " :" ) ; + } + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, " --title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + } + } + else if ( ! xdialogPresent() && tkinter2Present ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;} + strcpy ( lDialogString , gPython2Name ) ; + if ( ! isTerminalRunning ( ) && isDarwin ( ) ) + { + strcat ( lDialogString , " -i" ) ; /* for osx without console */ + } + strcat ( lDialogString , +" -c \"import Tkinter,tkFileDialog;root=Tkinter.Tk();root.withdraw();"); + + if ( isDarwin ( ) ) + { + strcat ( lDialogString , +"import os;os.system('''/usr/bin/osascript -e 'tell app \\\"Finder\\\" to set \ +frontmost of process \\\"Python\\\" to true' ''');"); + } + + strcat ( lDialogString , "print tkFileDialog.askdirectory("); + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "title='") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "',") ; + } + if ( aDefaultPath && strlen(aDefaultPath) ) + { + strcat(lDialogString, "initialdir='") ; + strcat(lDialogString, aDefaultPath ) ; + strcat(lDialogString , "'" ) ; + } + strcat ( lDialogString , ")\"" ) ; + } + else if ( xdialogPresent() || dialogName() ) + { + if ( xdialogPresent ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;} + lWasGraphicDialog = 1 ; + strcpy ( lDialogString , "(Xdialog " ) ; + } + else if ( isTerminalRunning ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} + strcpy ( lDialogString , "(dialog " ) ; + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"dialog");return (char const *)0;} + lWasXterm = 1 ; + strcpy ( lDialogString , terminalName() ) ; + strcat ( lDialogString , "'(" ) ; + strcat ( lDialogString , dialogName() ) ; + strcat ( lDialogString , " " ) ; + } + + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, "--title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\" ") ; + } + + if ( !xdialogPresent() && !gdialogPresent() ) + { + strcat(lDialogString, "--backtitle \"") ; + strcat(lDialogString, + "tab: focus | /: populate | spacebar: fill text field | ok: TEXT FIELD ONLY") ; + strcat(lDialogString, "\" ") ; + } + + strcat ( lDialogString , "--dselect \"" ) ; + if ( aDefaultPath && strlen(aDefaultPath) ) + { + strcat(lDialogString, aDefaultPath) ; + ensureFinalSlash(lDialogString); + } + else if ( ! isTerminalRunning ( ) && !lWasGraphicDialog ) + { + strcat(lDialogString, getenv("HOME")) ; + strcat(lDialogString, "/"); + } + else + { + strcat(lDialogString, "./") ; + } + + if ( lWasGraphicDialog ) + { + strcat(lDialogString, "\" 0 60 ) 2>&1 ") ; + } + else + { + strcat(lDialogString, "\" 0 60 >/dev/tty) ") ; + if ( lWasXterm ) + { + strcat ( lDialogString , + "2>/tmp/tinyfd.txt';cat /tmp/tinyfd.txt;rm /tmp/tinyfd.txt"); + } + else + { + strcat(lDialogString, "2>&1 ; clear >/dev/tty") ; + } + } + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){return tinyfd_inputBox (aTitle,NULL,NULL);} + p = tinyfd_inputBox(aTitle, "Select folder",""); + if ( !p || ! strlen ( p ) || ! dirExists ( p ) ) + { + return NULL ; + } + return p ; + } + if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ; + if ( ! ( lIn = popen ( lDialogString , "r" ) ) ) + { + return NULL ; + } + while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) + {} + pclose ( lIn ) ; + if ( lBuff[strlen ( lBuff ) -1] == '\n' ) + { + lBuff[strlen ( lBuff ) -1] = '\0' ; + } + /* printf ( "lBuff: %s\n" , lBuff ) ; */ + if ( ! strlen ( lBuff ) || ! dirExists ( lBuff ) ) + { + return NULL ; + } + return lBuff ; +} + + +/* returns the hexcolor as a string "#FF0000" */ +/* aoResultRGB also contains the result */ +/* aDefaultRGB is used only if aDefaultHexRGB is NULL */ +/* aDefaultRGB and aoResultRGB can be the same array */ +char const * tinyfd_colorChooser( + char const * const aTitle , /* NULL or "" */ + char const * const aDefaultHexRGB , /* NULL or "#FF0000"*/ + unsigned char const aDefaultRGB[3] , /* { 0 , 255 , 255 } */ + unsigned char aoResultRGB[3] ) /* { 0 , 0 , 0 } */ +{ + static char lBuff [128] ; + char lTmp [128] ; + char lDialogString [MAX_PATH_OR_CMD] ; + char lDefaultHexRGB[8]; + char * lpDefaultHexRGB; + unsigned char lDefaultRGB[3]; + char const * p; + FILE * lIn ; + int i ; + int lWasZenity3 = 0 ; + int lWasOsascript = 0 ; + int lWasXdialog = 0 ; + lBuff[0]='\0'; + + if ( aDefaultHexRGB ) + { + Hex2RGB ( aDefaultHexRGB , lDefaultRGB ) ; + lpDefaultHexRGB = (char *) aDefaultHexRGB ; + } + else + { + lDefaultRGB[0]=aDefaultRGB[0]; + lDefaultRGB[1]=aDefaultRGB[1]; + lDefaultRGB[2]=aDefaultRGB[2]; + RGB2Hex( aDefaultRGB , lDefaultHexRGB ) ; + lpDefaultHexRGB = (char *) lDefaultHexRGB ; + } + + if ( osascriptPresent ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"applescript");return (char const *)1;} + lWasOsascript = 1 ; + strcpy ( lDialogString , "osascript"); + + if ( ! osx9orBetter() ) + { + strcat ( lDialogString , " -e 'tell application \"System Events\"' -e 'Activate'"); + strcat ( lDialogString , " -e 'try' -e 'set mycolor to choose color default color {"); + } + else + { + strcat ( lDialogString , +" -e 'try' -e 'tell app (path to frontmost application as Unicode text) \ +to set mycolor to choose color default color {"); + } + + sprintf(lTmp, "%d", 256 * lDefaultRGB[0] ) ; + strcat(lDialogString, lTmp ) ; + strcat(lDialogString, "," ) ; + sprintf(lTmp, "%d", 256 * lDefaultRGB[1] ) ; + strcat(lDialogString, lTmp ) ; + strcat(lDialogString, "," ) ; + sprintf(lTmp, "%d", 256 * lDefaultRGB[2] ) ; + strcat(lDialogString, lTmp ) ; + strcat(lDialogString, "}' " ) ; + strcat ( lDialogString , +"-e 'set mystring to ((item 1 of mycolor) div 256 as integer) as string' " ); + strcat ( lDialogString , +"-e 'repeat with i from 2 to the count of mycolor' " ); + strcat ( lDialogString , +"-e 'set mystring to mystring & \" \" & ((item i of mycolor) div 256 as integer) as string' " ); + strcat ( lDialogString , "-e 'end repeat' " ); + strcat ( lDialogString , "-e 'mystring' "); + strcat(lDialogString, "-e 'on error number -128' " ) ; + strcat(lDialogString, "-e 'end try'") ; + if ( ! osx9orBetter() ) strcat ( lDialogString, " -e 'end tell'") ; + } + else if ( zenity3Present() || matedialogPresent() || qarmaPresent() ) + { + lWasZenity3 = 1 ; + if ( zenity3Present() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity3");return (char const *)1;} + sprintf ( lDialogString , +"zenity --color-selection --show-palette --color=%s" , lpDefaultHexRGB ) ; + } + else if ( matedialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"matedialog");return (char const *)1;} + sprintf ( lDialogString , +"matedialog --color-selection --show-palette --color=%s" , lpDefaultHexRGB ) ; + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"qarma");return (char const *)1;} + sprintf ( lDialogString , +"qarma --color-selection --show-palette --color=%s" , lpDefaultHexRGB ) ; + } + + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, " --title=\"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + } + } + else if ( kdialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"kdialog");return (char const *)1;} + sprintf ( lDialogString , +"kdialog --getcolor --default '%s'" , lpDefaultHexRGB ) ; + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, " --title \"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + } + } + else if ( xdialogPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"xdialog");return (char const *)1;} + lWasXdialog = 1 ; + strcpy ( lDialogString , "Xdialog --colorsel \"" ) ; + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, aTitle) ; + } + strcat(lDialogString, "\" 0 60 ") ; + sprintf(lTmp,"%hhu %hhu %hhu",lDefaultRGB[0], + lDefaultRGB[1],lDefaultRGB[2]); + strcat(lDialogString, lTmp) ; + strcat(lDialogString, " 2>&1"); + } + else if ( tkinter2Present ( ) ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"tkinter");return (char const *)1;} + strcpy ( lDialogString , gPython2Name ) ; + if ( ! isTerminalRunning ( ) && isDarwin ( ) ) + { + strcat ( lDialogString , " -i" ) ; /* for osx without console */ + } + + strcat ( lDialogString , +" -c \"import Tkinter,tkColorChooser;root=Tkinter.Tk();root.withdraw();"); + + if ( isDarwin ( ) ) + { + strcat ( lDialogString , +"import os;os.system('''osascript -e 'tell app \\\"Finder\\\" to set \ +frontmost of process \\\"Python\\\" to true' ''');"); + } + + strcat ( lDialogString , "res=tkColorChooser.askcolor(color='" ) ; + strcat(lDialogString, lpDefaultHexRGB ) ; + strcat(lDialogString, "'") ; + + + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, ",title='") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "'") ; + } + strcat ( lDialogString , ");\ +\nif res[1] is not None:\n\tprint res[1]\"" ) ; + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){return tinyfd_inputBox (aTitle,NULL,NULL);} + p = tinyfd_inputBox(aTitle, + "Enter hex rgb color (i.e. #f5ca20)",lpDefaultHexRGB); + if ( !p || (strlen(p) != 7) || (p[0] != '#') ) + { + return NULL ; + } + for ( i = 1 ; i < 7 ; i ++ ) + { + if ( ! isxdigit( p[i] ) ) + { + return NULL ; + } + } + Hex2RGB(p,aoResultRGB); + return p ; + } + + if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ; + if ( ! ( lIn = popen ( lDialogString , "r" ) ) ) + { + return NULL ; + } + while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) + { + } + pclose ( lIn ) ; + if ( ! strlen ( lBuff ) ) + { + return NULL ; + } + /* printf ( "len Buff: %lu\n" , strlen(lBuff) ) ; */ + /* printf ( "lBuff0: %s\n" , lBuff ) ; */ + if ( lBuff[strlen ( lBuff ) -1] == '\n' ) + { + lBuff[strlen ( lBuff ) -1] = '\0' ; + } + if ( lWasZenity3 ) + { + if ( lBuff[0] == '#' ) { + lBuff[3]=lBuff[5]; + lBuff[4]=lBuff[6]; + lBuff[5]=lBuff[9]; + lBuff[6]=lBuff[10]; + lBuff[7]='\0'; + Hex2RGB(lBuff,aoResultRGB); + } + else if ( lBuff[3] == '(' ) { + sscanf(lBuff,"rgb(%hhu,%hhu,%hhu", + & aoResultRGB[0], & aoResultRGB[1],& aoResultRGB[2]); + RGB2Hex(aoResultRGB,lBuff); + } + else if ( lBuff[4] == '(' ) { + sscanf(lBuff,"rgba(%hhu,%hhu,%hhu", + & aoResultRGB[0], & aoResultRGB[1],& aoResultRGB[2]); + RGB2Hex(aoResultRGB,lBuff); + } + } + else if ( lWasOsascript || lWasXdialog ) + { + /* printf ( "lBuff: %s\n" , lBuff ) ; */ + sscanf(lBuff,"%hhu %hhu %hhu", + & aoResultRGB[0], & aoResultRGB[1],& aoResultRGB[2]); + RGB2Hex(aoResultRGB,lBuff); + } + else + { + Hex2RGB(lBuff,aoResultRGB); + } + /* printf("%d %d %d\n", aoResultRGB[0],aoResultRGB[1],aoResultRGB[2]); */ + /* printf ( "lBuff: %s\n" , lBuff ) ; */ + return lBuff ; +} + + +/* not cross platform - zenity only */ +/* contributed by Attila Dusnoki */ +char const * tinyfd_arrayDialog ( + char const * const aTitle , /* "" */ + int const aNumOfColumns , /* 2 */ + char const * const * const aColumns , /* {"Column 1","Column 2"} */ + int const aNumOfRows , /* 2 */ + char const * const * const aCells ) + /* {"Row1 Col1","Row1 Col2","Row2 Col1","Row2 Col2"} */ +{ + static char lBuff [MAX_PATH_OR_CMD] ; + char lDialogString [MAX_PATH_OR_CMD] ; + FILE * lIn ; + lBuff[0]='\0'; + int i ; + + if ( zenityPresent() ) + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"zenity");return (char const *)1;} + strcpy ( lDialogString , "zenity --list --print-column=ALL" ) ; + if ( aTitle && strlen(aTitle) ) + { + strcat(lDialogString, " --title=\"") ; + strcat(lDialogString, aTitle) ; + strcat(lDialogString, "\"") ; + } + + if ( aColumns && (aNumOfColumns > 0) ) + { + for ( i = 0 ; i < aNumOfColumns ; i ++ ) + { + strcat ( lDialogString , " --column=\"" ) ; + strcat ( lDialogString , aColumns [i] ) ; + strcat ( lDialogString , "\"" ) ; + } + } + + if ( aCells && (aNumOfRows > 0) ) + { + strcat ( lDialogString , " " ) ; + for ( i = 0 ; i < aNumOfRows*aNumOfColumns ; i ++ ) + { + strcat ( lDialogString , "\"" ) ; + strcat ( lDialogString , aCells [i] ) ; + strcat ( lDialogString , "\" " ) ; + } + } + } + else + { + if (aTitle&&!strcmp(aTitle,"tinyfd_query")){strcpy(tinyfd_response,"");return (char const *)0;} + return NULL ; + } + + if (tinyfd_verbose) printf ( "lDialogString: %s\n" , lDialogString ) ; + if ( ! ( lIn = popen ( lDialogString , "r" ) ) ) + { + return NULL ; + } + while ( fgets ( lBuff , sizeof ( lBuff ) , lIn ) != NULL ) + {} + pclose ( lIn ) ; + if ( lBuff[strlen ( lBuff ) -1] == '\n' ) + { + lBuff[strlen ( lBuff ) -1] = '\0' ; + } + /* printf ( "lBuff: %s\n" , lBuff ) ; */ + if ( ! strlen ( lBuff ) ) + { + return NULL ; + } + return lBuff ; +} +#endif /* _WIN32 */ + + +/* +int main(void) +{ +char const * lTmp; +char const * lTheSaveFileName; +char const * lTheOpenFileName; +char const * lTheSelectFolderName; +char const * lTheHexColor; +char const * lWillBeGraphicMode; +unsigned char lRgbColor[3]; +FILE * lIn; +char lBuffer[1024]; +char lThePassword[1024]; +char const * lFilterPatterns[2] = { "*.txt", "*.text" }; + +lWillBeGraphicMode = tinyfd_inputBox("tinyfd_query", NULL, NULL); + +if (lWillBeGraphicMode) +{ + strcpy(lBuffer, "graphic mode: "); +} +else +{ + strcpy(lBuffer, "console mode: "); +} + +strcat(lBuffer, tinyfd_response); +strcpy(lThePassword, "tinyfiledialogs v"); +strcat(lThePassword, tinyfd_version); +tinyfd_messageBox(lThePassword, lBuffer, "ok", "info", 0); + +if (lWillBeGraphicMode && !tinyfd_forceConsole) +{ + tinyfd_forceConsole = ! tinyfd_messageBox("Hello World", + "graphic dialogs [yes] / console mode [no]?", + "yesno", "question", 1); +} + +lTmp = tinyfd_inputBox( + "a password box", "your password will be revealed", NULL); + +if (!lTmp) return 1; + +strcpy(lThePassword, lTmp); + +lTheSaveFileName = tinyfd_saveFileDialog( + "let us save this password", + "passwordFile.txt", + 2, + lFilterPatterns, + NULL); + +if (!lTheSaveFileName) +{ + tinyfd_messageBox( + "Error", + "Save file name is NULL", + "ok", + "error", + 1); + return 1; +} + +lIn = fopen(lTheSaveFileName, "w"); +if (!lIn) +{ + tinyfd_messageBox( + "Error", + "Can not open this file in write mode", + "ok", + "error", + 1); + return 1; +} +fputs(lThePassword, lIn); +fclose(lIn); + +lTheOpenFileName = tinyfd_openFileDialog( + "let us read the password back", + "", + 2, + lFilterPatterns, + NULL, + 0); + +if (!lTheOpenFileName) +{ + tinyfd_messageBox( + "Error", + "Open file name is NULL", + "ok", + "error", + 1); + return 1; +} + +lIn = fopen(lTheOpenFileName, "r"); + +if (!lIn) +{ + tinyfd_messageBox( + "Error", + "Can not open this file in read mode", + "ok", + "error", + 1); + return(1); +} +lBuffer[0] = '\0'; +fgets(lBuffer, sizeof(lBuffer), lIn); +fclose(lIn); + +tinyfd_messageBox("your password is", + lBuffer, "ok", "info", 1); + +lTheSelectFolderName = tinyfd_selectFolderDialog( + "let us just select a directory", NULL); + +if (!lTheSelectFolderName) +{ + tinyfd_messageBox( + "Error", + "Select folder name is NULL", + "ok", + "error", + 1); + return 1; +} + +tinyfd_messageBox("The selected folder is", + lTheSelectFolderName, "ok", "info", 1); + +lTheHexColor = tinyfd_colorChooser( + "choose a nice color", + "#FF0077", + lRgbColor, + lRgbColor); + +if (!lTheHexColor) +{ + tinyfd_messageBox( + "Error", + "hexcolor is NULL", + "ok", + "error", + 1); + return 1; +} + +tinyfd_messageBox("The selected hexcolor is", + lTheHexColor, "ok", "info", 1); + + return 0; +} +*/ + +#ifdef _MSC_VER +#pragma warning(default:4996) +#pragma warning(default:4100) +#pragma warning(default:4706) +#endif diff --git a/targets/glfw3/template/tinyfiledialogs/tinyfiledialogs.h b/targets/glfw3/template/tinyfiledialogs/tinyfiledialogs.h new file mode 100644 index 00000000..65e6dffb --- /dev/null +++ b/targets/glfw3/template/tinyfiledialogs/tinyfiledialogs.h @@ -0,0 +1,301 @@ +/*_________ + / \ tinyfiledialogs.h v2.9.3 [July 12, 2017] zlib licence + |tiny file| Unique header file created [November 9, 2014] + | dialogs | Copyright (c) 2014 - 2017 Guillaume Vareille http://ysengrin.com + \____ ___/ http://tinyfiledialogs.sourceforge.net + \| + git://git.code.sf.net/p/tinyfiledialogs/code + ______________________________________________ + | | + | email: tinyfiledialogs@ysengrin.com | + |______________________________________________| + +A big thank you to Don Heyse http://ldglite.sf.net for + his code contributions, bug corrections & thorough testing! + + git://git.code.sf.net/p/tinyfiledialogs/code + +Please + 1) let me know + - if you are including tiny file dialogs, + I'll be happy to add your link to the list of projects using it. + - If you are using it on different hardware / OS / compiler. + 2) leave a review on Sourceforge. Thanks. + +tiny file dialogs (cross-platform C C++) +InputBox PasswordBox MessageBox ColorPicker +OpenFileDialog SaveFileDialog SelectFolderDialog +Native dialog library for WINDOWS MAC OSX GTK+ QT CONSOLE & more +SSH supported via automatic switch to console mode or X11 forwarding + +One C file (add it to your C or C++ project) with 6 functions: +- message & question +- input & password +- save file +- open file(s) +- select folder +- color picker + +Complements OpenGL GLFW GLUT GLUI VTK SFML TGUI SDL Ogre Unity3d ION OpenCV +CEGUI MathGL GLM CPW GLOW IMGUI MyGUI GLT NGL STB & GUI less programs + +NO INIT +NO MAIN LOOP +NO LINKING +NO INCLUDE + +The dialogs can be forced into console mode + +Windows (XP to 10) ASCII MBCS UTF-8 UTF-16 +- native code & vbs create the graphic dialogs +- enhanced console mode can use dialog.exe from +http://andrear.altervista.org/home/cdialog.php +- basic console input + +Unix (command line calls) ASCII UTF-8 +- applescript +- zenity / matedialog / qarma (zenity for qt) +- kdialog +- Xdialog +- python2 tkinter +- dialog (opens a console if needed) +- basic console input +The same executable can run across desktops & distributions + +tested with C & C++ compilers +on VisualStudio MinGW Mac Linux Bsd Solaris Minix Raspbian +using Gnome Kde Enlightenment Mate Cinnamon Unity +Lxde Lxqt Xfce WindowMaker IceWm Cde Jds OpenBox Awesome Jwm + +bindings for LUA and C# dll +included in LWJGL(java), rust, Allegrobasic + +- License - + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef TINYFILEDIALOGS_H +#define TINYFILEDIALOGS_H + +/* #define TINYFD_NOLIB */ +/* On windows, define TINYFD_NOLIB here +if you don't want to include the code creating the graphic dialogs. +Then you won't need to link against Comdlg32.lib and Ole32.lib */ + +/* if tinydialogs.c is compiled with a C++ compiler rather than with a C compiler +(ie. you change the extension from .c to .cpp), you need to comment out: +extern "C" { +and the corresponding closing bracket near the end of this file: +} +*/ +#ifdef __cplusplus +extern "C" { +#endif + +extern char tinyfd_version[8]; /* contains tinyfd current version number */ + +#ifdef _WIN32 +/* for UTF-16 use the functions at the end of this files */ +extern int tinyfd_winUtf8; /* 0 (default) or 1 */ +/* on windows string char can be 0:MBSC or 1:UTF-8 +unless your code is really prepared for UTF-8 on windows, leave this on MBSC. +Or you can use the UTF-16 (wchar) prototypes at the end of ths file.*/ +#endif + +extern int tinyfd_forceConsole ; /* 0 (default) or 1 */ +/* for unix & windows: 0 (graphic mode) or 1 (console mode). +0: try to use a graphic solution, if it fails then it uses console mode. +1: forces all dialogs into console mode even when an X server is present, + if the package dialog (and a console is present) or dialog.exe is installed. + on windows it only make sense for console applications */ + +extern char tinyfd_response[1024]; +/* if you pass "tinyfd_query" as aTitle, +the functions will not display the dialogs +but will return 0 for console mode, 1 for graphic mode. +tinyfd_response is then filled with the retain solution. +possible values for tinyfd_response are (all lowercase) +for the graphic mode: + windows applescript zenity zenity3 matedialog qarma kdialog + xdialog tkinter gdialog gxmessage xmessage +for the console mode: + dialog whiptail basicinput */ + +int tinyfd_messageBox ( + char const * const aTitle , /* "" */ + char const * const aMessage , /* "" may contain \n \t */ + char const * const aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */ + char const * const aIconType , /* "info" "warning" "error" "question" */ + int const aDefaultButton ) ; + /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ + +char const * tinyfd_inputBox ( + char const * const aTitle , /* "" */ + char const * const aMessage , /* "" may NOT contain \n \t on windows */ + char const * const aDefaultInput ) ; /* "" , if NULL it's a passwordBox */ + /* returns NULL on cancel */ + +char const * tinyfd_saveFileDialog ( + char const * const aTitle , /* "" */ + char const * const aDefaultPathAndFile , /* "" */ + int const aNumOfFilterPatterns , /* 0 */ + char const * const * const aFilterPatterns , /* NULL | {"*.jpg","*.png"} */ + char const * const aSingleFilterDescription ) ; /* NULL | "text files" */ + /* returns NULL on cancel */ + +char const * tinyfd_openFileDialog ( + char const * const aTitle , /* "" */ + char const * const aDefaultPathAndFile , /* "" */ + int const aNumOfFilterPatterns , /* 0 */ + char const * const * const aFilterPatterns , /* NULL {"*.jpg","*.png"} */ + char const * const aSingleFilterDescription , /* NULL | "image files" */ + int const aAllowMultipleSelects ) ; /* 0 or 1 */ + /* in case of multiple files, the separator is | */ + /* returns NULL on cancel */ + +char const * tinyfd_selectFolderDialog ( + char const * const aTitle , /* "" */ + char const * const aDefaultPath ) ; /* "" */ + /* returns NULL on cancel */ + +char const * tinyfd_colorChooser( + char const * const aTitle , /* "" */ + char const * const aDefaultHexRGB , /* NULL or "#FF0000" */ + unsigned char const aDefaultRGB[3] , /* { 0 , 255 , 255 } */ + unsigned char aoResultRGB[3] ) ; /* { 0 , 0 , 0 } */ + /* returns the hexcolor as a string "#FF0000" */ + /* aoResultRGB also contains the result */ + /* aDefaultRGB is used only if aDefaultHexRGB is NULL */ + /* aDefaultRGB and aoResultRGB can be the same array */ + /* returns NULL on cancel */ + + +/************ NOT CROSS PLATFORM SECTION STARTS HERE ************************/ +#ifdef _WIN32 +#ifndef TINYFD_NOLIB + +/* windows only - utf-16 version */ +int tinyfd_messageBoxW( + wchar_t const * const aTitle , + wchar_t const * const aMessage, /* "" may contain \n \t */ + wchar_t const * const aDialogType, /* "ok" "okcancel" "yesno" */ + wchar_t const * const aIconType, /* "info" "warning" "error" "question" */ + int const aDefaultButton ); /* 0 for cancel/no , 1 for ok/yes */ + /* returns 0 for cancel/no , 1 for ok/yes */ + +/* windows only - utf-16 version */ +wchar_t const * tinyfd_saveFileDialogW( + wchar_t const * const aTitle, /* NULL or "" */ + wchar_t const * const aDefaultPathAndFile, /* NULL or "" */ + int const aNumOfFilterPatterns, /* 0 */ + wchar_t const * const * const aFilterPatterns, /* NULL or {"*.jpg","*.png"} */ + wchar_t const * const aSingleFilterDescription); /* NULL or "image files" */ + /* returns NULL on cancel */ + +/* windows only - utf-16 version */ +wchar_t const * tinyfd_openFileDialogW( + wchar_t const * const aTitle, /* "" */ + wchar_t const * const aDefaultPathAndFile, /* "" */ + int const aNumOfFilterPatterns , /* 0 */ + wchar_t const * const * const aFilterPatterns, /* NULL {"*.jpg","*.png"} */ + wchar_t const * const aSingleFilterDescription, /* NULL | "image files" */ + int const aAllowMultipleSelects ) ; /* 0 or 1 */ + /* in case of multiple files, the separator is | */ + /* returns NULL on cancel */ + +/* windows only - utf-16 version */ + wchar_t const * tinyfd_selectFolderDialogW( + wchar_t const * const aTitle, /* "" */ + wchar_t const * const aDefaultPath); /* "" */ + /* returns NULL on cancel */ + +/* windows only - utf-16 version */ +wchar_t const * tinyfd_colorChooserW( + wchar_t const * const aTitle, /* "" */ + wchar_t const * const aDefaultHexRGB, /* NULL or "#FF0000" */ + unsigned char const aDefaultRGB[3] , /* { 0 , 255 , 255 } */ + unsigned char aoResultRGB[3] ) ; /* { 0 , 0 , 0 } */ + /* returns the hexcolor as a string "#FF0000" */ + /* aoResultRGB also contains the result */ + /* aDefaultRGB is used only if aDefaultHexRGB is NULL */ + /* aDefaultRGB and aoResultRGB can be the same array */ + /* returns NULL on cancel */ + + +#endif /*TINYFD_NOLIB*/ +#else /*_WIN32*/ + +/* unix zenity only */ +char const * tinyfd_arrayDialog( + char const * const aTitle , /* "" */ + int const aNumOfColumns , /* 2 */ + char const * const * const aColumns, /* {"Column 1","Column 2"} */ + int const aNumOfRows, /* 2*/ + char const * const * const aCells); + /* {"Row1 Col1","Row1 Col2","Row2 Col1","Row2 Col2"} */ + +#endif /*_WIN32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* TINYFILEDIALOGS_H */ + +/* +- This is not for android nor ios. +- The code is pure C, perfectly compatible with C++. +- the windows only wchar_t (utf-16) prototypes are in the header file +- windows is fully supported from XP to 10 (maybe even older versions) +- C# & LUA via dll, see example files +- OSX supported from 10.4 to 10.11 (maybe even older versions) +- Avoid using " and ' in titles and messages. +- There's one file filter only, it may contain several patterns. +- If no filter description is provided, + the list of patterns will become the description. +- char const * filterPatterns[3] = { "*.obj" , "*.stl" , "*.dxf" } ; +- On windows link against Comdlg32.lib and Ole32.lib + This linking is not compulsary for console mode (see above). +- On unix: it tries command line calls, so no such need. +- On unix you need applescript, zenity, matedialog, qarma, kdialog, Xdialog, + python2/tkinter or dialog (will open a terminal if running without console). +- One of those is already included on most (if not all) desktops. +- In the absence of those it will use gdialog, gxmessage or whiptail + with a textinputbox. +- If nothing is found, it switches to basic console input, + it opens a console if needed (requires xterm + bash). +- Use windows separators on windows and unix separators on unix. +- String memory is preallocated statically for all the returned values. +- File and path names are tested before return, they are valid. +- If you pass only a path instead of path + filename, + make sure it ends with a separator. +- tinyfd_forceConsole=1; at run time, forces dialogs into console mode. +- On windows, console mode only make sense for console applications. +- Mutiple selects are not allowed in console mode. +- The package dialog must be installed to run in enhanced console mode. + It is already installed on most unix systems. +- On osx, the package dialog can be installed via http://macports.org +- On windows, for enhanced console mode, + dialog.exe should be copied somewhere on your executable path. + It can be found at the bottom of the following page: + http://andrear.altervista.org/home/cdialog.php +- If dialog is missing, it will switch to basic console input. +- You can query the type of dialog that will be use. +- MinGW needs gcc >= v4.9 otherwise some headers are incomplete. +- The Hello World (and a bit more) is on the sourceforge site: +*/ diff --git a/targets/glfw3/template/xcode/CerberusGame-Info.plist b/targets/glfw3/template/xcode/CerberusGame-Info.plist index 0a1c8107..af487695 100755 --- a/targets/glfw3/template/xcode/CerberusGame-Info.plist +++ b/targets/glfw3/template/xcode/CerberusGame-Info.plist @@ -1,32 +1,32 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIconFile - - CFBundleIdentifier - com.yourcompany.${PRODUCT_NAME:rfc1034identifier} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSMinimumSystemVersion - ${MACOSX_DEPLOYMENT_TARGET} - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + cerberus.icns + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/targets/glfw3/template/xcode/CerberusGame.xcodeproj/project.pbxproj b/targets/glfw3/template/xcode/CerberusGame.xcodeproj/project.pbxproj index 6919af34..fae5659e 100755 --- a/targets/glfw3/template/xcode/CerberusGame.xcodeproj/project.pbxproj +++ b/targets/glfw3/template/xcode/CerberusGame.xcodeproj/project.pbxproj @@ -1,429 +1,441 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 5B5444E21F0BC72800A09B8D /* cocoa_joystick.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B5444D31F0BC72800A09B8D /* cocoa_joystick.m */; }; - 5B5444E31F0BC72800A09B8D /* cocoa_time.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5444D41F0BC72800A09B8D /* cocoa_time.c */; }; - 5B5444E41F0BC72800A09B8D /* egl_context.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5444D51F0BC72800A09B8D /* egl_context.c */; }; - 5B5444E51F0BC72800A09B8D /* osmesa_context.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5444D71F0BC72800A09B8D /* osmesa_context.c */; }; - 5B5444E81F0BC72800A09B8D /* vulkan.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5444DD1F0BC72800A09B8D /* vulkan.c */; }; - 5B5444F01F0BC88300A09B8D /* posix_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5444EE1F0BC88300A09B8D /* posix_thread.c */; }; - 5B9A66EA1F2F246600EF062C /* include in Resources */ = {isa = PBXBuildFile; fileRef = 5B9A66E91F2F246600EF062C /* include */; }; - 5BD341471F2F293200608B7B /* libcurl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD341461F2F293200608B7B /* libcurl.a */; }; - 7C17EE5212BAD553007B72A6 /* stb_image.c in Sources */ = {isa = PBXBuildFile; fileRef = 7C17EE5112BAD553007B72A6 /* stb_image.c */; }; - 7C83FECA15730D2B007D5B80 /* stb_vorbis.c in Sources */ = {isa = PBXBuildFile; fileRef = 7C83FEC915730D2B007D5B80 /* stb_vorbis.c */; }; - 7C8AF373199985960016C22B /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C8AF372199985960016C22B /* CoreVideo.framework */; }; - 7C8DB52F12AF2C210090FC6E /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C8DB52E12AF2C210090FC6E /* OpenGL.framework */; }; - 7CACF7FC12B5BBD4002E52F2 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7CACF7FB12B5BBD4002E52F2 /* OpenAL.framework */; }; - 7CACF8E812B5D1AF002E52F2 /* data in Resources */ = {isa = PBXBuildFile; fileRef = 7CACF8E612B5D1AF002E52F2 /* data */; }; - 7CCA8A3F1B1A8672003926E3 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7CCA8A3E1B1A8672003926E3 /* main.mm */; }; - 7CD5046E165B1A60009581D7 /* external in Resources */ = {isa = PBXBuildFile; fileRef = 7CD5046C165B1A60009581D7 /* external */; }; - 7CD5046F165B1A60009581D7 /* internal in Resources */ = {isa = PBXBuildFile; fileRef = 7CD5046D165B1A60009581D7 /* internal */; }; - 7CDF25461602B81600B598F3 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7CDF25451602B81600B598F3 /* IOKit.framework */; }; - 7CE1AA7B17E154F600D079FE /* cocoa_init.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA6717E154F600D079FE /* cocoa_init.m */; }; - 7CE1AA7D17E154F600D079FE /* cocoa_monitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA6917E154F600D079FE /* cocoa_monitor.m */; }; - 7CE1AA7F17E154F600D079FE /* cocoa_window.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA6C17E154F600D079FE /* cocoa_window.m */; }; - 7CE1AA8017E154F600D079FE /* context.c in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA6E17E154F600D079FE /* context.c */; }; - 7CE1AA8217E154F600D079FE /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA7017E154F600D079FE /* init.c */; }; - 7CE1AA8317E154F600D079FE /* input.c in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA7117E154F600D079FE /* input.c */; }; - 7CE1AA8517E154F600D079FE /* monitor.c in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA7417E154F600D079FE /* monitor.c */; }; - 7CE1AA8617E154F600D079FE /* nsgl_context.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA7517E154F600D079FE /* nsgl_context.m */; }; - 7CE1AA8817E154F600D079FE /* window.c in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA7817E154F600D079FE /* window.c */; }; - 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; - 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; - 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; - 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; - 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; - 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; - 5B5444D21F0BC72800A09B8D /* cocoa_joystick.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cocoa_joystick.h; path = ../glfw3/src/cocoa_joystick.h; sourceTree = ""; }; - 5B5444D31F0BC72800A09B8D /* cocoa_joystick.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = cocoa_joystick.m; path = ../glfw3/src/cocoa_joystick.m; sourceTree = ""; }; - 5B5444D41F0BC72800A09B8D /* cocoa_time.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cocoa_time.c; path = ../glfw3/src/cocoa_time.c; sourceTree = ""; }; - 5B5444D51F0BC72800A09B8D /* egl_context.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = egl_context.c; path = ../glfw3/src/egl_context.c; sourceTree = ""; }; - 5B5444D61F0BC72800A09B8D /* egl_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = egl_context.h; path = ../glfw3/src/egl_context.h; sourceTree = ""; }; - 5B5444D71F0BC72800A09B8D /* osmesa_context.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = osmesa_context.c; path = ../glfw3/src/osmesa_context.c; sourceTree = ""; }; - 5B5444D81F0BC72800A09B8D /* osmesa_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = osmesa_context.h; path = ../glfw3/src/osmesa_context.h; sourceTree = ""; }; - 5B5444DD1F0BC72800A09B8D /* vulkan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vulkan.c; path = ../glfw3/src/vulkan.c; sourceTree = ""; }; - 5B5444EE1F0BC88300A09B8D /* posix_thread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = posix_thread.c; path = ../glfw3/src/posix_thread.c; sourceTree = ""; }; - 5B5444EF1F0BC88300A09B8D /* posix_thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = posix_thread.h; path = ../glfw3/src/posix_thread.h; sourceTree = ""; }; - 5B9A66E91F2F246600EF062C /* include */ = {isa = PBXFileReference; lastKnownFileType = folder; name = include; path = ../curl/include; sourceTree = ""; }; - 5BD341461F2F293200608B7B /* libcurl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcurl.a; path = ../curl/lib/MacOS/libcurl.a; sourceTree = ""; }; - 7C17EE5112BAD553007B72A6 /* stb_image.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = stb_image.c; path = ../stb/stb_image.c; sourceTree = SOURCE_ROOT; }; - 7C73309C1999832400988833 /* glfw_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = glfw_config.h; path = ../glfw3/src/glfw_config.h; sourceTree = ""; }; - 7C7330A01999832400988833 /* nsgl_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nsgl_context.h; path = ../glfw3/src/nsgl_context.h; sourceTree = ""; }; - 7C83FEC915730D2B007D5B80 /* stb_vorbis.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = stb_vorbis.c; path = ../stb/stb_vorbis.c; sourceTree = SOURCE_ROOT; }; - 7C8AF372199985960016C22B /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; }; - 7C8DB52E12AF2C210090FC6E /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; - 7CACF7FB12B5BBD4002E52F2 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; }; - 7CACF8E612B5D1AF002E52F2 /* data */ = {isa = PBXFileReference; lastKnownFileType = folder; path = data; sourceTree = ""; }; - 7CCA8A3E1B1A8672003926E3 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = main.mm; path = ../main.mm; sourceTree = ""; }; - 7CD5046C165B1A60009581D7 /* external */ = {isa = PBXFileReference; lastKnownFileType = folder; path = external; sourceTree = ""; }; - 7CD5046D165B1A60009581D7 /* internal */ = {isa = PBXFileReference; lastKnownFileType = folder; path = internal; sourceTree = ""; }; - 7CDF25451602B81600B598F3 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; - 7CE1AA6717E154F600D079FE /* cocoa_init.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = cocoa_init.m; path = ../glfw3/src/cocoa_init.m; sourceTree = ""; }; - 7CE1AA6917E154F600D079FE /* cocoa_monitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = cocoa_monitor.m; path = ../glfw3/src/cocoa_monitor.m; sourceTree = ""; }; - 7CE1AA6A17E154F600D079FE /* cocoa_platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cocoa_platform.h; path = ../glfw3/src/cocoa_platform.h; sourceTree = ""; }; - 7CE1AA6C17E154F600D079FE /* cocoa_window.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = cocoa_window.m; path = ../glfw3/src/cocoa_window.m; sourceTree = ""; }; - 7CE1AA6E17E154F600D079FE /* context.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = context.c; path = ../glfw3/src/context.c; sourceTree = ""; }; - 7CE1AA7017E154F600D079FE /* init.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = init.c; path = ../glfw3/src/init.c; sourceTree = ""; }; - 7CE1AA7117E154F600D079FE /* input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = input.c; path = ../glfw3/src/input.c; sourceTree = ""; }; - 7CE1AA7217E154F600D079FE /* internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = internal.h; path = ../glfw3/src/internal.h; sourceTree = ""; }; - 7CE1AA7417E154F600D079FE /* monitor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = monitor.c; path = ../glfw3/src/monitor.c; sourceTree = ""; }; - 7CE1AA7517E154F600D079FE /* nsgl_context.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = nsgl_context.m; path = ../glfw3/src/nsgl_context.m; sourceTree = ""; }; - 7CE1AA7817E154F600D079FE /* window.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = window.c; path = ../glfw3/src/window.c; sourceTree = ""; }; - 7CE1AA8B17E16F2900D079FE /* glfw3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = glfw3.h; path = ../glfw3/include/GLFW/glfw3.h; sourceTree = ""; }; - 8D1107310486CEB800E47090 /* CerberusGame-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "CerberusGame-Info.plist"; sourceTree = ""; }; - 8D1107320486CEB800E47090 /* CerberusGame.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CerberusGame.app; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 8D11072E0486CEB800E47090 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 5BD341471F2F293200608B7B /* libcurl.a in Frameworks */, - 7C8AF373199985960016C22B /* CoreVideo.framework in Frameworks */, - 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, - 7C8DB52F12AF2C210090FC6E /* OpenGL.framework in Frameworks */, - 7CACF7FC12B5BBD4002E52F2 /* OpenAL.framework in Frameworks */, - 7CDF25461602B81600B598F3 /* IOKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 080E96DDFE201D6D7F000001 /* Classes */ = { - isa = PBXGroup; - children = ( - ); - name = Classes; - sourceTree = ""; - }; - 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { - isa = PBXGroup; - children = ( - 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, - ); - name = "Linked Frameworks"; - sourceTree = ""; - }; - 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { - isa = PBXGroup; - children = ( - 29B97324FDCFA39411CA2CEA /* AppKit.framework */, - 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */, - 29B97325FDCFA39411CA2CEA /* Foundation.framework */, - ); - name = "Other Frameworks"; - sourceTree = ""; - }; - 19C28FACFE9D520D11CA2CBB /* Products */ = { - isa = PBXGroup; - children = ( - 8D1107320486CEB800E47090 /* CerberusGame.app */, - ); - name = Products; - sourceTree = ""; - }; - 29B97314FDCFA39411CA2CEA /* CerberusGame */ = { - isa = PBXGroup; - children = ( - 080E96DDFE201D6D7F000001 /* Classes */, - 29B97315FDCFA39411CA2CEA /* Other Sources */, - 29B97317FDCFA39411CA2CEA /* Resources */, - 29B97323FDCFA39411CA2CEA /* Frameworks */, - 19C28FACFE9D520D11CA2CBB /* Products */, - ); - name = CerberusGame; - sourceTree = ""; - }; - 29B97315FDCFA39411CA2CEA /* Other Sources */ = { - isa = PBXGroup; - children = ( - 5B9A66E91F2F246600EF062C /* include */, - 5B5444EE1F0BC88300A09B8D /* posix_thread.c */, - 5B5444EF1F0BC88300A09B8D /* posix_thread.h */, - 5B5444D21F0BC72800A09B8D /* cocoa_joystick.h */, - 5B5444D31F0BC72800A09B8D /* cocoa_joystick.m */, - 5B5444D41F0BC72800A09B8D /* cocoa_time.c */, - 5B5444D51F0BC72800A09B8D /* egl_context.c */, - 5B5444D61F0BC72800A09B8D /* egl_context.h */, - 5B5444D71F0BC72800A09B8D /* osmesa_context.c */, - 5B5444D81F0BC72800A09B8D /* osmesa_context.h */, - 5B5444DD1F0BC72800A09B8D /* vulkan.c */, - 7CCA8A3E1B1A8672003926E3 /* main.mm */, - 7C73309C1999832400988833 /* glfw_config.h */, - 7CE1AA7517E154F600D079FE /* nsgl_context.m */, - 7C7330A01999832400988833 /* nsgl_context.h */, - 7CE1AA8B17E16F2900D079FE /* glfw3.h */, - 7CE1AA6717E154F600D079FE /* cocoa_init.m */, - 7CE1AA6917E154F600D079FE /* cocoa_monitor.m */, - 7CE1AA6A17E154F600D079FE /* cocoa_platform.h */, - 7CE1AA6C17E154F600D079FE /* cocoa_window.m */, - 7CE1AA6E17E154F600D079FE /* context.c */, - 7CE1AA7017E154F600D079FE /* init.c */, - 7CE1AA7117E154F600D079FE /* input.c */, - 7CE1AA7217E154F600D079FE /* internal.h */, - 7CE1AA7417E154F600D079FE /* monitor.c */, - 7CE1AA7817E154F600D079FE /* window.c */, - 7C17EE5112BAD553007B72A6 /* stb_image.c */, - 7C83FEC915730D2B007D5B80 /* stb_vorbis.c */, - ); - name = "Other Sources"; - sourceTree = ""; - }; - 29B97317FDCFA39411CA2CEA /* Resources */ = { - isa = PBXGroup; - children = ( - 7CD5046C165B1A60009581D7 /* external */, - 7CD5046D165B1A60009581D7 /* internal */, - 7CACF8E612B5D1AF002E52F2 /* data */, - 8D1107310486CEB800E47090 /* CerberusGame-Info.plist */, - 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, - ); - name = Resources; - sourceTree = ""; - }; - 29B97323FDCFA39411CA2CEA /* Frameworks */ = { - isa = PBXGroup; - children = ( - 5BD341461F2F293200608B7B /* libcurl.a */, - 7C8AF372199985960016C22B /* CoreVideo.framework */, - 7CDF25451602B81600B598F3 /* IOKit.framework */, - 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, - 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, - 7C8DB52E12AF2C210090FC6E /* OpenGL.framework */, - 7CACF7FB12B5BBD4002E52F2 /* OpenAL.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 8D1107260486CEB800E47090 /* CerberusGame */ = { - isa = PBXNativeTarget; - buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "CerberusGame" */; - buildPhases = ( - 8D1107290486CEB800E47090 /* Resources */, - 8D11072C0486CEB800E47090 /* Sources */, - 8D11072E0486CEB800E47090 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = CerberusGame; - productInstallPath = "$(HOME)/Applications"; - productName = CerberusGame; - productReference = 8D1107320486CEB800E47090 /* CerberusGame.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 29B97313FDCFA39411CA2CEA /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0460; - }; - buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "CerberusGame" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 1; - knownRegions = ( - English, - Japanese, - French, - German, - ); - mainGroup = 29B97314FDCFA39411CA2CEA /* CerberusGame */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 8D1107260486CEB800E47090 /* CerberusGame */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 8D1107290486CEB800E47090 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, - 7CACF8E812B5D1AF002E52F2 /* data in Resources */, - 7CD5046E165B1A60009581D7 /* external in Resources */, - 5B9A66EA1F2F246600EF062C /* include in Resources */, - 7CD5046F165B1A60009581D7 /* internal in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 8D11072C0486CEB800E47090 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 5B5444E51F0BC72800A09B8D /* osmesa_context.c in Sources */, - 5B5444E41F0BC72800A09B8D /* egl_context.c in Sources */, - 5B5444E31F0BC72800A09B8D /* cocoa_time.c in Sources */, - 7C17EE5212BAD553007B72A6 /* stb_image.c in Sources */, - 7C83FECA15730D2B007D5B80 /* stb_vorbis.c in Sources */, - 5B5444F01F0BC88300A09B8D /* posix_thread.c in Sources */, - 7CCA8A3F1B1A8672003926E3 /* main.mm in Sources */, - 7CE1AA7B17E154F600D079FE /* cocoa_init.m in Sources */, - 7CE1AA7D17E154F600D079FE /* cocoa_monitor.m in Sources */, - 7CE1AA7F17E154F600D079FE /* cocoa_window.m in Sources */, - 7CE1AA8017E154F600D079FE /* context.c in Sources */, - 7CE1AA8217E154F600D079FE /* init.c in Sources */, - 7CE1AA8317E154F600D079FE /* input.c in Sources */, - 5B5444E81F0BC72800A09B8D /* vulkan.c in Sources */, - 7CE1AA8517E154F600D079FE /* monitor.c in Sources */, - 7CE1AA8617E154F600D079FE /* nsgl_context.m in Sources */, - 7CE1AA8817E154F600D079FE /* window.c in Sources */, - 5B5444E21F0BC72800A09B8D /* cocoa_joystick.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 089C165DFE840E0CC02AAC07 /* English */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - C01FCF4B08A954540054247B /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - COMBINE_HIDPI_IMAGES = YES; - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_MODEL_TUNING = G5; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = CerberusGame_Prefix.pch; - GCC_VERSION = ""; - HEADER_SEARCH_PATHS = ( - ../glfw3/include, - ../openal/include, - ../stb, - ); - INFOPLIST_FILE = "CerberusGame-Info.plist"; - INSTALL_PATH = "$(HOME)/Applications"; - MACOSX_DEPLOYMENT_TARGET = 10.6; - OTHER_CFLAGS = "-Wno-logical-op-parentheses"; - PRODUCT_NAME = CerberusGame; - SDKROOT = macosx; - }; - name = Debug; - }; - C01FCF4C08A954540054247B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - COMBINE_HIDPI_IMAGES = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_MODEL_TUNING = G5; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = CerberusGame_Prefix.pch; - GCC_VERSION = ""; - HEADER_SEARCH_PATHS = ( - ../glfw3/include, - ../openal/include, - ../stb, - ); - INFOPLIST_FILE = "CerberusGame-Info.plist"; - INSTALL_PATH = "$(HOME)/Applications"; - MACOSX_DEPLOYMENT_TARGET = 10.6; - OTHER_CFLAGS = "-Wno-logical-op-parentheses"; - PRODUCT_NAME = CerberusGame; - SDKROOT = macosx; - }; - name = Release; - }; - C01FCF4F08A954540054247B /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_VERSION = com.apple.compilers.llvmgcc42; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ( - ../glfw/include, - ../glfw/lib, - ../openal/include, - ../glfw/lib/cocoa, - ../stb, - ); - ONLY_ACTIVE_ARCH = YES; - PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO; - SDKROOT = ""; - }; - name = Debug; - }; - C01FCF5008A954540054247B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_VERSION = com.apple.compilers.llvmgcc42; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ( - ../glfw/include, - ../glfw/lib, - ../openal/include, - ../glfw/lib/cocoa, - ../stb, - ); - PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO; - SDKROOT = ""; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "CerberusGame" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C01FCF4B08A954540054247B /* Debug */, - C01FCF4C08A954540054247B /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - C01FCF4E08A954540054247B /* Build configuration list for PBXProject "CerberusGame" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C01FCF4F08A954540054247B /* Debug */, - C01FCF5008A954540054247B /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; -} +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5B5444E21F0BC72800A09B8D /* cocoa_joystick.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B5444D31F0BC72800A09B8D /* cocoa_joystick.m */; }; + 5B5444E31F0BC72800A09B8D /* cocoa_time.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5444D41F0BC72800A09B8D /* cocoa_time.c */; }; + 5B5444E41F0BC72800A09B8D /* egl_context.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5444D51F0BC72800A09B8D /* egl_context.c */; }; + 5B5444E51F0BC72800A09B8D /* osmesa_context.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5444D71F0BC72800A09B8D /* osmesa_context.c */; }; + 5B5444E81F0BC72800A09B8D /* vulkan.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5444DD1F0BC72800A09B8D /* vulkan.c */; }; + 5B5444F01F0BC88300A09B8D /* posix_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5444EE1F0BC88300A09B8D /* posix_thread.c */; }; + 5B9A66EA1F2F246600EF062C /* include in Resources */ = {isa = PBXBuildFile; fileRef = 5B9A66E91F2F246600EF062C /* include */; }; + 5BD341471F2F293200608B7B /* libcurl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD341461F2F293200608B7B /* libcurl.a */; }; + 7C17EE5212BAD553007B72A6 /* stb_image.c in Sources */ = {isa = PBXBuildFile; fileRef = 7C17EE5112BAD553007B72A6 /* stb_image.c */; }; + 7C83FECA15730D2B007D5B80 /* stb_vorbis.c in Sources */ = {isa = PBXBuildFile; fileRef = 7C83FEC915730D2B007D5B80 /* stb_vorbis.c */; }; + 7C8AF373199985960016C22B /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C8AF372199985960016C22B /* CoreVideo.framework */; }; + 7C8DB52F12AF2C210090FC6E /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C8DB52E12AF2C210090FC6E /* OpenGL.framework */; }; + 7CACF7FC12B5BBD4002E52F2 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7CACF7FB12B5BBD4002E52F2 /* OpenAL.framework */; }; + 7CACF8E812B5D1AF002E52F2 /* data in Resources */ = {isa = PBXBuildFile; fileRef = 7CACF8E612B5D1AF002E52F2 /* data */; }; + 7CCA8A3F1B1A8672003926E3 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7CCA8A3E1B1A8672003926E3 /* main.mm */; }; + 7CD5046E165B1A60009581D7 /* external in Resources */ = {isa = PBXBuildFile; fileRef = 7CD5046C165B1A60009581D7 /* external */; }; + 7CD5046F165B1A60009581D7 /* internal in Resources */ = {isa = PBXBuildFile; fileRef = 7CD5046D165B1A60009581D7 /* internal */; }; + 7CDF25461602B81600B598F3 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7CDF25451602B81600B598F3 /* IOKit.framework */; }; + 7CE1AA7B17E154F600D079FE /* cocoa_init.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA6717E154F600D079FE /* cocoa_init.m */; }; + 7CE1AA7D17E154F600D079FE /* cocoa_monitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA6917E154F600D079FE /* cocoa_monitor.m */; }; + 7CE1AA7F17E154F600D079FE /* cocoa_window.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA6C17E154F600D079FE /* cocoa_window.m */; }; + 7CE1AA8017E154F600D079FE /* context.c in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA6E17E154F600D079FE /* context.c */; }; + 7CE1AA8217E154F600D079FE /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA7017E154F600D079FE /* init.c */; }; + 7CE1AA8317E154F600D079FE /* input.c in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA7117E154F600D079FE /* input.c */; }; + 7CE1AA8517E154F600D079FE /* monitor.c in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA7417E154F600D079FE /* monitor.c */; }; + 7CE1AA8617E154F600D079FE /* nsgl_context.m in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA7517E154F600D079FE /* nsgl_context.m */; }; + 7CE1AA8817E154F600D079FE /* window.c in Sources */ = {isa = PBXBuildFile; fileRef = 7CE1AA7817E154F600D079FE /* window.c */; }; + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; + D56BBAB62465D8E50020D5F1 /* cerberus.icns in Resources */ = {isa = PBXBuildFile; fileRef = D56BBAB52465D8E50020D5F1 /* cerberus.icns */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; + 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; + 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 5B5444D21F0BC72800A09B8D /* cocoa_joystick.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cocoa_joystick.h; path = ../glfw3/src/cocoa_joystick.h; sourceTree = ""; }; + 5B5444D31F0BC72800A09B8D /* cocoa_joystick.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = cocoa_joystick.m; path = ../glfw3/src/cocoa_joystick.m; sourceTree = ""; }; + 5B5444D41F0BC72800A09B8D /* cocoa_time.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cocoa_time.c; path = ../glfw3/src/cocoa_time.c; sourceTree = ""; }; + 5B5444D51F0BC72800A09B8D /* egl_context.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = egl_context.c; path = ../glfw3/src/egl_context.c; sourceTree = ""; }; + 5B5444D61F0BC72800A09B8D /* egl_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = egl_context.h; path = ../glfw3/src/egl_context.h; sourceTree = ""; }; + 5B5444D71F0BC72800A09B8D /* osmesa_context.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = osmesa_context.c; path = ../glfw3/src/osmesa_context.c; sourceTree = ""; }; + 5B5444D81F0BC72800A09B8D /* osmesa_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = osmesa_context.h; path = ../glfw3/src/osmesa_context.h; sourceTree = ""; }; + 5B5444DD1F0BC72800A09B8D /* vulkan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vulkan.c; path = ../glfw3/src/vulkan.c; sourceTree = ""; }; + 5B5444EE1F0BC88300A09B8D /* posix_thread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = posix_thread.c; path = ../glfw3/src/posix_thread.c; sourceTree = ""; }; + 5B5444EF1F0BC88300A09B8D /* posix_thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = posix_thread.h; path = ../glfw3/src/posix_thread.h; sourceTree = ""; }; + 5B9A66E91F2F246600EF062C /* include */ = {isa = PBXFileReference; lastKnownFileType = folder; name = include; path = ../curl/include; sourceTree = ""; }; + 5BD341461F2F293200608B7B /* libcurl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcurl.a; path = ../curl/lib/MacOS/libcurl.a; sourceTree = ""; }; + 7C17EE5112BAD553007B72A6 /* stb_image.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = stb_image.c; path = ../stb/stb_image.c; sourceTree = SOURCE_ROOT; }; + 7C73309C1999832400988833 /* glfw_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = glfw_config.h; path = ../glfw3/src/glfw_config.h; sourceTree = ""; }; + 7C7330A01999832400988833 /* nsgl_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nsgl_context.h; path = ../glfw3/src/nsgl_context.h; sourceTree = ""; }; + 7C83FEC915730D2B007D5B80 /* stb_vorbis.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = stb_vorbis.c; path = ../stb/stb_vorbis.c; sourceTree = SOURCE_ROOT; }; + 7C8AF372199985960016C22B /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; }; + 7C8DB52E12AF2C210090FC6E /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 7CACF7FB12B5BBD4002E52F2 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; }; + 7CACF8E612B5D1AF002E52F2 /* data */ = {isa = PBXFileReference; lastKnownFileType = folder; path = data; sourceTree = ""; }; + 7CCA8A3E1B1A8672003926E3 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = main.mm; path = ../main.mm; sourceTree = ""; }; + 7CD5046C165B1A60009581D7 /* external */ = {isa = PBXFileReference; lastKnownFileType = folder; path = external; sourceTree = ""; }; + 7CD5046D165B1A60009581D7 /* internal */ = {isa = PBXFileReference; lastKnownFileType = folder; path = internal; sourceTree = ""; }; + 7CDF25451602B81600B598F3 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 7CE1AA6717E154F600D079FE /* cocoa_init.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = cocoa_init.m; path = ../glfw3/src/cocoa_init.m; sourceTree = ""; }; + 7CE1AA6917E154F600D079FE /* cocoa_monitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = cocoa_monitor.m; path = ../glfw3/src/cocoa_monitor.m; sourceTree = ""; }; + 7CE1AA6A17E154F600D079FE /* cocoa_platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cocoa_platform.h; path = ../glfw3/src/cocoa_platform.h; sourceTree = ""; }; + 7CE1AA6C17E154F600D079FE /* cocoa_window.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = cocoa_window.m; path = ../glfw3/src/cocoa_window.m; sourceTree = ""; }; + 7CE1AA6E17E154F600D079FE /* context.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = context.c; path = ../glfw3/src/context.c; sourceTree = ""; }; + 7CE1AA7017E154F600D079FE /* init.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = init.c; path = ../glfw3/src/init.c; sourceTree = ""; }; + 7CE1AA7117E154F600D079FE /* input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = input.c; path = ../glfw3/src/input.c; sourceTree = ""; }; + 7CE1AA7217E154F600D079FE /* internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = internal.h; path = ../glfw3/src/internal.h; sourceTree = ""; }; + 7CE1AA7417E154F600D079FE /* monitor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = monitor.c; path = ../glfw3/src/monitor.c; sourceTree = ""; }; + 7CE1AA7517E154F600D079FE /* nsgl_context.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = nsgl_context.m; path = ../glfw3/src/nsgl_context.m; sourceTree = ""; }; + 7CE1AA7817E154F600D079FE /* window.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = window.c; path = ../glfw3/src/window.c; sourceTree = ""; }; + 7CE1AA8B17E16F2900D079FE /* glfw3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = glfw3.h; path = ../glfw3/include/GLFW/glfw3.h; sourceTree = ""; }; + 8D1107310486CEB800E47090 /* CerberusGame-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "CerberusGame-Info.plist"; sourceTree = ""; }; + 8D1107320486CEB800E47090 /* CerberusGame.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CerberusGame.app; sourceTree = BUILT_PRODUCTS_DIR; }; + D56BBAB52465D8E50020D5F1 /* cerberus.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = cerberus.icns; sourceTree = ""; }; + D56E880E2465D45F0048BE3E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D11072E0486CEB800E47090 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5BD341471F2F293200608B7B /* libcurl.a in Frameworks */, + 7C8AF373199985960016C22B /* CoreVideo.framework in Frameworks */, + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, + 7C8DB52F12AF2C210090FC6E /* OpenGL.framework in Frameworks */, + 7CACF7FC12B5BBD4002E52F2 /* OpenAL.framework in Frameworks */, + 7CDF25461602B81600B598F3 /* IOKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Classes */ = { + isa = PBXGroup; + children = ( + ); + name = Classes; + sourceTree = ""; + }; + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, + ); + name = "Linked Frameworks"; + sourceTree = ""; + }; + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 29B97324FDCFA39411CA2CEA /* AppKit.framework */, + 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */, + 29B97325FDCFA39411CA2CEA /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D1107320486CEB800E47090 /* CerberusGame.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* CerberusGame */ = { + isa = PBXGroup; + children = ( + 080E96DDFE201D6D7F000001 /* Classes */, + 29B97315FDCFA39411CA2CEA /* Other Sources */, + 29B97317FDCFA39411CA2CEA /* Resources */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + ); + name = CerberusGame; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + 5B9A66E91F2F246600EF062C /* include */, + 5B5444EE1F0BC88300A09B8D /* posix_thread.c */, + 5B5444EF1F0BC88300A09B8D /* posix_thread.h */, + 5B5444D21F0BC72800A09B8D /* cocoa_joystick.h */, + 5B5444D31F0BC72800A09B8D /* cocoa_joystick.m */, + 5B5444D41F0BC72800A09B8D /* cocoa_time.c */, + 5B5444D51F0BC72800A09B8D /* egl_context.c */, + 5B5444D61F0BC72800A09B8D /* egl_context.h */, + 5B5444D71F0BC72800A09B8D /* osmesa_context.c */, + 5B5444D81F0BC72800A09B8D /* osmesa_context.h */, + 5B5444DD1F0BC72800A09B8D /* vulkan.c */, + 7CCA8A3E1B1A8672003926E3 /* main.mm */, + 7C73309C1999832400988833 /* glfw_config.h */, + 7CE1AA7517E154F600D079FE /* nsgl_context.m */, + 7C7330A01999832400988833 /* nsgl_context.h */, + 7CE1AA8B17E16F2900D079FE /* glfw3.h */, + 7CE1AA6717E154F600D079FE /* cocoa_init.m */, + 7CE1AA6917E154F600D079FE /* cocoa_monitor.m */, + 7CE1AA6A17E154F600D079FE /* cocoa_platform.h */, + 7CE1AA6C17E154F600D079FE /* cocoa_window.m */, + 7CE1AA6E17E154F600D079FE /* context.c */, + 7CE1AA7017E154F600D079FE /* init.c */, + 7CE1AA7117E154F600D079FE /* input.c */, + 7CE1AA7217E154F600D079FE /* internal.h */, + 7CE1AA7417E154F600D079FE /* monitor.c */, + 7CE1AA7817E154F600D079FE /* window.c */, + 7C17EE5112BAD553007B72A6 /* stb_image.c */, + 7C83FEC915730D2B007D5B80 /* stb_vorbis.c */, + ); + name = "Other Sources"; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + D56BBAB52465D8E50020D5F1 /* cerberus.icns */, + 7CD5046C165B1A60009581D7 /* external */, + 7CD5046D165B1A60009581D7 /* internal */, + 7CACF8E612B5D1AF002E52F2 /* data */, + 8D1107310486CEB800E47090 /* CerberusGame-Info.plist */, + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, + ); + name = Resources; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5BD341461F2F293200608B7B /* libcurl.a */, + 7C8AF372199985960016C22B /* CoreVideo.framework */, + 7CDF25451602B81600B598F3 /* IOKit.framework */, + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, + 7C8DB52E12AF2C210090FC6E /* OpenGL.framework */, + 7CACF7FB12B5BBD4002E52F2 /* OpenAL.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8D1107260486CEB800E47090 /* CerberusGame */ = { + isa = PBXNativeTarget; + buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "CerberusGame" */; + buildPhases = ( + 8D1107290486CEB800E47090 /* Resources */, + 8D11072C0486CEB800E47090 /* Sources */, + 8D11072E0486CEB800E47090 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = CerberusGame; + productInstallPath = "$(HOME)/Applications"; + productName = CerberusGame; + productReference = 8D1107320486CEB800E47090 /* CerberusGame.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1110; + }; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "CerberusGame" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 1; + knownRegions = ( + Base, + en, + fr, + ja, + de, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* CerberusGame */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D1107260486CEB800E47090 /* CerberusGame */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D1107290486CEB800E47090 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, + 7CACF8E812B5D1AF002E52F2 /* data in Resources */, + 7CD5046E165B1A60009581D7 /* external in Resources */, + 5B9A66EA1F2F246600EF062C /* include in Resources */, + 7CD5046F165B1A60009581D7 /* internal in Resources */, + D56BBAB62465D8E50020D5F1 /* cerberus.icns in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D11072C0486CEB800E47090 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5B5444E51F0BC72800A09B8D /* osmesa_context.c in Sources */, + 5B5444E41F0BC72800A09B8D /* egl_context.c in Sources */, + 5B5444E31F0BC72800A09B8D /* cocoa_time.c in Sources */, + 7C17EE5212BAD553007B72A6 /* stb_image.c in Sources */, + 7C83FECA15730D2B007D5B80 /* stb_vorbis.c in Sources */, + 5B5444F01F0BC88300A09B8D /* posix_thread.c in Sources */, + 7CCA8A3F1B1A8672003926E3 /* main.mm in Sources */, + 7CE1AA7B17E154F600D079FE /* cocoa_init.m in Sources */, + 7CE1AA7D17E154F600D079FE /* cocoa_monitor.m in Sources */, + 7CE1AA7F17E154F600D079FE /* cocoa_window.m in Sources */, + 7CE1AA8017E154F600D079FE /* context.c in Sources */, + 7CE1AA8217E154F600D079FE /* init.c in Sources */, + 7CE1AA8317E154F600D079FE /* input.c in Sources */, + 5B5444E81F0BC72800A09B8D /* vulkan.c in Sources */, + 7CE1AA8517E154F600D079FE /* monitor.c in Sources */, + 7CE1AA8617E154F600D079FE /* nsgl_context.m in Sources */, + 7CE1AA8817E154F600D079FE /* window.c in Sources */, + 5B5444E21F0BC72800A09B8D /* cocoa_joystick.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + D56E880E2465D45F0048BE3E /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + C01FCF4B08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = CerberusGame_Prefix.pch; + GCC_VERSION = ""; + HEADER_SEARCH_PATHS = ( + ../glfw3/include, + ../openal/include, + ../stb, + ); + INFOPLIST_FILE = "CerberusGame-Info.plist"; + INSTALL_PATH = "$(HOME)/Applications"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + OTHER_CFLAGS = "-Wno-logical-op-parentheses"; + PRODUCT_BUNDLE_IDENTIFIER = "com.yourcompany.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = CerberusGame; + SDKROOT = macosx; + }; + name = Debug; + }; + C01FCF4C08A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = CerberusGame_Prefix.pch; + GCC_VERSION = ""; + HEADER_SEARCH_PATHS = ( + ../glfw3/include, + ../openal/include, + ../stb, + ); + INFOPLIST_FILE = "CerberusGame-Info.plist"; + INSTALL_PATH = "$(HOME)/Applications"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + OTHER_CFLAGS = "-Wno-logical-op-parentheses"; + PRODUCT_BUNDLE_IDENTIFIER = "com.yourcompany.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = CerberusGame; + SDKROOT = macosx; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_VERSION = com.apple.compilers.llvmgcc42; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + ../glfw/include, + ../glfw/lib, + ../openal/include, + ../glfw/lib/cocoa, + ../stb, + ); + ONLY_ACTIVE_ARCH = YES; + PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO; + SDKROOT = ""; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_VERSION = com.apple.compilers.llvmgcc42; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + ../glfw/include, + ../glfw/lib, + ../openal/include, + ../glfw/lib/cocoa, + ../stb, + ); + PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO; + SDKROOT = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "CerberusGame" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4B08A954540054247B /* Debug */, + C01FCF4C08A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "CerberusGame" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/targets/glfw3/template/xcode/CerberusGame.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/targets/glfw3/template/xcode/CerberusGame.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/targets/glfw3/template/xcode/CerberusGame.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/targets/glfw3/template/xcode/CerberusGame.xcodeproj/project.xcworkspace/xcuserdata/michaelhartlef.xcuserdatad/UserInterfaceState.xcuserstate b/targets/glfw3/template/xcode/CerberusGame.xcodeproj/project.xcworkspace/xcuserdata/michaelhartlef.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 00000000..9a574403 Binary files /dev/null and b/targets/glfw3/template/xcode/CerberusGame.xcodeproj/project.xcworkspace/xcuserdata/michaelhartlef.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/targets/glfw3/template/xcode/CerberusGame.xcodeproj/xcuserdata/michaelhartlef.xcuserdatad/xcschemes/xcschememanagement.plist b/targets/glfw3/template/xcode/CerberusGame.xcodeproj/xcuserdata/michaelhartlef.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..82461bdb --- /dev/null +++ b/targets/glfw3/template/xcode/CerberusGame.xcodeproj/xcuserdata/michaelhartlef.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,19 @@ + + + + + SchemeUserState + + CerberusGame.xcscheme + + orderHint + 0 + + CerberusGame.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/targets/glfw3/template/xcode/cerberus.icns b/targets/glfw3/template/xcode/cerberus.icns new file mode 100644 index 00000000..0964744f Binary files /dev/null and b/targets/glfw3/template/xcode/cerberus.icns differ diff --git a/targets/glfw3/template/xcode/English.lproj/InfoPlist.strings b/targets/glfw3/template/xcode/en.lproj/InfoPlist.strings similarity index 100% rename from targets/glfw3/template/xcode/English.lproj/InfoPlist.strings rename to targets/glfw3/template/xcode/en.lproj/InfoPlist.strings diff --git a/targets/html5/template/CerberusGame.html b/targets/html5/template/CerberusGame.html index daf14e2a..1426c505 100644 --- a/targets/html5/template/CerberusGame.html +++ b/targets/html5/template/CerberusGame.html @@ -2,6 +2,7 @@ +%%HTML5_APP_TITLE%%