summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/CMakeLists.txt395
-rw-r--r--utils/bspatch/LICENSE23
-rw-r--r--utils/bspatch/Makefile17
-rw-r--r--utils/bspatch/bspatch.c218
-rw-r--r--utils/bspatch/bspatch.h19
-rw-r--r--utils/bspatch/main.c34
-rw-r--r--utils/bzip2/LICENSE42
-rw-r--r--utils/bzip2/Makefile15
-rw-r--r--utils/bzip2/blocksort.c1094
-rw-r--r--utils/bzip2/bzlib.c1572
-rw-r--r--utils/bzip2/bzlib.h282
-rw-r--r--utils/bzip2/bzlib_private.h512
-rw-r--r--utils/bzip2/compress.c672
-rw-r--r--utils/bzip2/crctable.c104
-rw-r--r--utils/bzip2/decompress.c646
-rw-r--r--utils/bzip2/huffman.c205
-rw-r--r--utils/bzip2/randtable.c84
-rw-r--r--utils/chinachippatcher/Makefile17
-rw-r--r--utils/chinachippatcher/chinachip.c258
-rw-r--r--utils/chinachippatcher/chinachip.h52
-rw-r--r--utils/chinachippatcher/main.c55
-rwxr-xr-xutils/cmake/QtTest.cmake134
-rwxr-xr-xutils/cmake/QtTestAddTests.cmake102
-rw-r--r--utils/cmake/deploy.cmake219
-rw-r--r--utils/cmake/download.cmake47
-rw-r--r--utils/cmake/gitversion.cmake58
-rwxr-xr-xutils/common/deploy-themeeditor.py62
-rwxr-xr-xutils/common/deploy.py677
-rwxr-xr-xutils/common/gitscraper.py17
-rwxr-xr-xutils/common/tarball-rbutil.py (renamed from utils/common/deploy-rbutil.py)87
-rw-r--r--utils/e200rpatcher/Makefile56
-rw-r--r--utils/e200rpatcher/README48
-rw-r--r--utils/e200rpatcher/e200rpatcher.c241
-rw-r--r--utils/e200rpatcher/e200rpatcher.manifest13
-rw-r--r--utils/e200rpatcher/e200rpatcher.rc1
-rw-r--r--utils/ibassoboot/jni/Android.mk14
-rw-r--r--utils/ibassoboot/jni/chooser.bmpbin0 -> 230454 bytes
-rw-r--r--utils/ibassoboot/jni/ibassodualboot.c771
-rw-r--r--utils/ibassoboot/jni/qdbmp.c798
-rw-r--r--utils/ibassoboot/jni/qdbmp.h133
-rw-r--r--utils/ibassoboot/jni/rbmissing.bmpbin0 -> 230454 bytes
-rw-r--r--utils/ibassoboot/jni/usb.bmpbin0 -> 230454 bytes
-rw-r--r--utils/ipodpatcher/Makefile53
-rw-r--r--utils/ipodpatcher/arc4.c108
-rw-r--r--utils/ipodpatcher/arc4.h47
-rw-r--r--utils/ipodpatcher/fat32format.c530
-rw-r--r--utils/ipodpatcher/ipodio-posix.c410
-rw-r--r--utils/ipodpatcher/ipodio-win32-scsi.c147
-rw-r--r--utils/ipodpatcher/ipodio-win32.c227
-rw-r--r--utils/ipodpatcher/ipodio.h115
-rw-r--r--utils/ipodpatcher/ipodpatcher-aupd.c398
-rw-r--r--utils/ipodpatcher/ipodpatcher.c1995
-rw-r--r--utils/ipodpatcher/ipodpatcher.h84
-rw-r--r--utils/ipodpatcher/ipodpatcher.manifest13
-rw-r--r--utils/ipodpatcher/ipodpatcher.rc1
-rw-r--r--utils/ipodpatcher/main.c622
-rw-r--r--utils/ipodpatcher/parttypes.h109
-rw-r--r--utils/jztool/Makefile47
-rw-r--r--utils/jztool/README.md135
-rw-r--r--utils/jztool/include/jztool.h202
-rw-r--r--utils/jztool/jztool.c212
-rw-r--r--utils/jztool/src/buffer.c134
-rw-r--r--utils/jztool/src/context.c177
-rw-r--r--utils/jztool/src/device_info.c109
-rw-r--r--utils/jztool/src/identify_file.c170
-rw-r--r--utils/jztool/src/jztool_private.h44
-rw-r--r--utils/jztool/src/ucl_unpack.c128
-rw-r--r--utils/jztool/src/usb.c291
-rw-r--r--utils/jztool/src/x1000.c257
-rw-r--r--utils/libtools.make183
-rw-r--r--utils/mkamsboot/.gitignore2
-rw-r--r--utils/mkamsboot/Makefile31
-rw-r--r--utils/mkamsboot/README67
-rw-r--r--utils/mkamsboot/dualboot.c152
-rw-r--r--utils/mkamsboot/dualboot.h12
-rw-r--r--utils/mkamsboot/dualboot/.gitignore3
-rw-r--r--utils/mkamsboot/dualboot/Makefile61
-rw-r--r--utils/mkamsboot/dualboot/bin2c.c140
-rw-r--r--utils/mkamsboot/dualboot/dualboot.S307
-rw-r--r--utils/mkamsboot/dualboot/nrv2e_d8.S198
-rw-r--r--utils/mkamsboot/main.c174
-rw-r--r--utils/mkamsboot/md5.c246
-rw-r--r--utils/mkamsboot/md5.h25
-rw-r--r--utils/mkamsboot/mkamsboot.c595
-rw-r--r--utils/mkamsboot/mkamsboot.h195
-rw-r--r--utils/mkimxboot/Makefile46
-rw-r--r--utils/mkimxboot/dualboot.c293
-rw-r--r--utils/mkimxboot/dualboot.h8
-rw-r--r--utils/mkimxboot/dualboot/Makefile48
-rw-r--r--utils/mkimxboot/dualboot/bin2c.c140
-rw-r--r--utils/mkimxboot/dualboot/config.h26
-rw-r--r--utils/mkimxboot/dualboot/dualboot.c323
-rw-r--r--utils/mkimxboot/dualboot/dualboot.lds17
-rw-r--r--utils/mkimxboot/main.c289
-rw-r--r--utils/mkimxboot/md5.c246
-rw-r--r--utils/mkimxboot/md5.h25
-rw-r--r--utils/mkimxboot/mkimxboot.c1123
-rw-r--r--utils/mkimxboot/mkimxboot.h116
-rw-r--r--utils/mkmpioboot/Makefile23
-rw-r--r--utils/mkmpioboot/main.c55
-rw-r--r--utils/mkmpioboot/mkmpioboot.c243
-rw-r--r--utils/mkmpioboot/mkmpioboot.h46
-rw-r--r--utils/mknwzboot/Makefile52
-rw-r--r--utils/mknwzboot/install_script.sh157
-rw-r--r--utils/mknwzboot/main.c126
-rw-r--r--utils/mknwzboot/mknwzboot.c294
-rw-r--r--utils/mknwzboot/mknwzboot.h42
-rw-r--r--utils/mknwzboot/uninstall_script.sh122
-rw-r--r--utils/mkrk27boot/Makefile39
-rw-r--r--utils/mkrk27boot/ata-sim.c122
-rw-r--r--utils/mkrk27boot/autoconf.h37
-rw-r--r--utils/mkrk27boot/main.c55
-rw-r--r--utils/mkrk27boot/mkrk27boot.c281
-rw-r--r--utils/mkrk27boot/mkrk27boot.h36
-rw-r--r--utils/mks5lboot/.gitignore5
-rw-r--r--utils/mks5lboot/Makefile43
-rw-r--r--utils/mks5lboot/README228
-rw-r--r--utils/mks5lboot/dualboot.c664
-rw-r--r--utils/mks5lboot/dualboot.h4
-rw-r--r--utils/mks5lboot/dualboot/.gitignore3
-rw-r--r--utils/mks5lboot/dualboot/Makefile97
-rw-r--r--utils/mks5lboot/dualboot/autoconf.h74
-rw-r--r--utils/mks5lboot/dualboot/bin2c.c140
-rw-r--r--utils/mks5lboot/dualboot/dualboot.c287
-rw-r--r--utils/mks5lboot/dualboot/dualboot.lds59
-rw-r--r--utils/mks5lboot/dualboot/init.S43
-rw-r--r--utils/mks5lboot/ipoddfu.c1061
-rw-r--r--utils/mks5lboot/main.c296
-rw-r--r--utils/mks5lboot/mkdfu.c318
-rw-r--r--utils/mks5lboot/mks5lboot.h129
-rw-r--r--utils/mktccboot/Makefile28
-rw-r--r--utils/mktccboot/README35
-rw-r--r--utils/mktccboot/main.c133
-rw-r--r--utils/mktccboot/mktccboot.c176
-rw-r--r--utils/mktccboot/mktccboot.h50
-rw-r--r--utils/mkzenboot/Makefile30
-rw-r--r--utils/mkzenboot/dualboot.c56
-rw-r--r--utils/mkzenboot/dualboot.h6
-rw-r--r--utils/mkzenboot/dualboot/Makefile51
-rw-r--r--utils/mkzenboot/dualboot/bin2c.c140
-rw-r--r--utils/mkzenboot/dualboot/config.h22
-rw-r--r--utils/mkzenboot/dualboot/dualboot.c136
-rw-r--r--utils/mkzenboot/dualboot/dualboot.lds32
-rw-r--r--utils/mkzenboot/main.c123
-rw-r--r--utils/mkzenboot/md5.c246
-rw-r--r--utils/mkzenboot/md5.h25
-rw-r--r--utils/mkzenboot/mkzenboot.c697
-rw-r--r--utils/mkzenboot/mkzenboot.h86
-rw-r--r--utils/mkzenboot/utils.c896
-rw-r--r--utils/mkzenboot/utils.h53
-rw-r--r--utils/rbutilqt/CMakeLists.txt437
-rw-r--r--utils/rbutilqt/INSTALL54
-rw-r--r--utils/rbutilqt/Info.plist24
-rw-r--r--utils/rbutilqt/Makefile.libs79
-rw-r--r--utils/rbutilqt/RockboxUtility.desktop12
-rw-r--r--utils/rbutilqt/aboutbox.ui198
-rw-r--r--utils/rbutilqt/base/archiveutil.cpp30
-rw-r--r--utils/rbutilqt/base/archiveutil.h41
-rw-r--r--utils/rbutilqt/base/autodetection.cpp378
-rw-r--r--utils/rbutilqt/base/autodetection.h71
-rw-r--r--utils/rbutilqt/base/bootloaderinstallams.cpp201
-rw-r--r--utils/rbutilqt/base/bootloaderinstallams.h42
-rw-r--r--utils/rbutilqt/base/bootloaderinstallbase.cpp305
-rw-r--r--utils/rbutilqt/base/bootloaderinstallbase.h115
-rw-r--r--utils/rbutilqt/base/bootloaderinstallbspatch.cpp178
-rw-r--r--utils/rbutilqt/base/bootloaderinstallbspatch.h47
-rw-r--r--utils/rbutilqt/base/bootloaderinstallchinachip.cpp133
-rw-r--r--utils/rbutilqt/base/bootloaderinstallchinachip.h41
-rw-r--r--utils/rbutilqt/base/bootloaderinstallfile.cpp159
-rw-r--r--utils/rbutilqt/base/bootloaderinstallfile.h47
-rw-r--r--utils/rbutilqt/base/bootloaderinstallhelper.cpp160
-rw-r--r--utils/rbutilqt/base/bootloaderinstallhelper.h37
-rw-r--r--utils/rbutilqt/base/bootloaderinstallhex.cpp271
-rw-r--r--utils/rbutilqt/base/bootloaderinstallhex.h53
-rw-r--r--utils/rbutilqt/base/bootloaderinstallimx.cpp192
-rw-r--r--utils/rbutilqt/base/bootloaderinstallimx.h47
-rw-r--r--utils/rbutilqt/base/bootloaderinstallipod.cpp284
-rw-r--r--utils/rbutilqt/base/bootloaderinstallipod.h51
-rw-r--r--utils/rbutilqt/base/bootloaderinstallmi4.cpp162
-rw-r--r--utils/rbutilqt/base/bootloaderinstallmi4.h47
-rw-r--r--utils/rbutilqt/base/bootloaderinstallmpio.cpp143
-rw-r--r--utils/rbutilqt/base/bootloaderinstallmpio.h43
-rw-r--r--utils/rbutilqt/base/bootloaderinstalls5l.cpp437
-rw-r--r--utils/rbutilqt/base/bootloaderinstalls5l.h71
-rw-r--r--utils/rbutilqt/base/bootloaderinstallsansa.cpp291
-rw-r--r--utils/rbutilqt/base/bootloaderinstallsansa.h51
-rw-r--r--utils/rbutilqt/base/bootloaderinstalltcc.cpp165
-rw-r--r--utils/rbutilqt/base/bootloaderinstalltcc.h44
-rw-r--r--utils/rbutilqt/base/encoderbase.cpp86
-rw-r--r--utils/rbutilqt/base/encoderbase.h63
-rw-r--r--utils/rbutilqt/base/encoderexe.cpp78
-rw-r--r--utils/rbutilqt/base/encoderexe.h53
-rw-r--r--utils/rbutilqt/base/encoderlame.cpp312
-rw-r--r--utils/rbutilqt/base/encoderlame.h72
-rw-r--r--utils/rbutilqt/base/encoderrbspeex.cpp119
-rw-r--r--utils/rbutilqt/base/encoderrbspeex.h61
-rw-r--r--utils/rbutilqt/base/encttssettings.cpp70
-rw-r--r--utils/rbutilqt/base/encttssettings.h127
-rw-r--r--utils/rbutilqt/base/httpget.cpp279
-rw-r--r--utils/rbutilqt/base/httpget.h115
-rw-r--r--utils/rbutilqt/base/mspackutil.cpp164
-rw-r--r--utils/rbutilqt/base/mspackutil.h47
-rw-r--r--utils/rbutilqt/base/playerbuildinfo.cpp372
-rw-r--r--utils/rbutilqt/base/playerbuildinfo.h121
-rw-r--r--utils/rbutilqt/base/progressloglevels.h29
-rw-r--r--utils/rbutilqt/base/rbsettings.cpp206
-rw-r--r--utils/rbutilqt/base/rbsettings.h104
-rw-r--r--utils/rbutilqt/base/rockboxinfo.cpp89
-rw-r--r--utils/rbutilqt/base/rockboxinfo.h54
-rw-r--r--utils/rbutilqt/base/system.cpp520
-rw-r--r--utils/rbutilqt/base/system.h53
-rw-r--r--utils/rbutilqt/base/talkfile.cpp305
-rw-r--r--utils/rbutilqt/base/talkfile.h83
-rw-r--r--utils/rbutilqt/base/talkgenerator.cpp337
-rw-r--r--utils/rbutilqt/base/talkgenerator.h91
-rw-r--r--utils/rbutilqt/base/ttsbase.cpp122
-rw-r--r--utils/rbutilqt/base/ttsbase.h70
-rw-r--r--utils/rbutilqt/base/ttscarbon.cpp443
-rw-r--r--utils/rbutilqt/base/ttscarbon.h73
-rw-r--r--utils/rbutilqt/base/ttsespeak.h42
-rw-r--r--utils/rbutilqt/base/ttsespeakng.h41
-rw-r--r--utils/rbutilqt/base/ttsexes.cpp127
-rw-r--r--utils/rbutilqt/base/ttsexes.h61
-rw-r--r--utils/rbutilqt/base/ttsfestival.cpp420
-rw-r--r--utils/rbutilqt/base/ttsfestival.h72
-rw-r--r--utils/rbutilqt/base/ttsflite.h43
-rw-r--r--utils/rbutilqt/base/ttsmimic.h41
-rw-r--r--utils/rbutilqt/base/ttsmssp.h43
-rw-r--r--utils/rbutilqt/base/ttssapi.cpp274
-rw-r--r--utils/rbutilqt/base/ttssapi.h77
-rw-r--r--utils/rbutilqt/base/ttssapi4.h43
-rw-r--r--utils/rbutilqt/base/ttsswift.h40
-rw-r--r--utils/rbutilqt/base/uninstall.cpp132
-rw-r--r--utils/rbutilqt/base/uninstall.h63
-rw-r--r--utils/rbutilqt/base/utils.cpp1064
-rw-r--r--utils/rbutilqt/base/utils.h64
-rw-r--r--utils/rbutilqt/base/voicefile.cpp362
-rw-r--r--utils/rbutilqt/base/voicefile.h77
-rw-r--r--utils/rbutilqt/base/zipinstaller.cpp207
-rw-r--r--utils/rbutilqt/base/zipinstaller.h87
-rw-r--r--utils/rbutilqt/base/ziputil.cpp303
-rw-r--r--utils/rbutilqt/base/ziputil.h49
-rw-r--r--utils/rbutilqt/changelog.txt50
-rw-r--r--utils/rbutilqt/configure.cpp984
-rw-r--r--utils/rbutilqt/configure.h79
-rw-r--r--utils/rbutilqt/configurefrm.ui572
-rw-r--r--utils/rbutilqt/createvoicefrm.ui217
-rw-r--r--utils/rbutilqt/createvoicewindow.cpp144
-rw-r--r--utils/rbutilqt/createvoicewindow.h56
-rw-r--r--utils/rbutilqt/dmgbuild.cfg17
-rw-r--r--utils/rbutilqt/encttscfggui.cpp311
-rw-r--r--utils/rbutilqt/encttscfggui.h69
-rw-r--r--utils/rbutilqt/gui/backupdialog.cpp151
-rw-r--r--utils/rbutilqt/gui/backupdialog.h48
-rw-r--r--utils/rbutilqt/gui/backupdialogfrm.ui145
-rw-r--r--utils/rbutilqt/gui/changelog.cpp78
-rw-r--r--utils/rbutilqt/gui/changelog.h40
-rw-r--r--utils/rbutilqt/gui/changelogfrm.ui60
-rw-r--r--utils/rbutilqt/gui/comboboxviewdelegate.cpp56
-rw-r--r--utils/rbutilqt/gui/comboboxviewdelegate.h30
-rw-r--r--utils/rbutilqt/gui/infowidget.cpp104
-rw-r--r--utils/rbutilqt/gui/infowidget.h41
-rw-r--r--utils/rbutilqt/gui/infowidgetfrm.ui43
-rw-r--r--utils/rbutilqt/gui/selectiveinstallwidget.cpp677
-rw-r--r--utils/rbutilqt/gui/selectiveinstallwidget.h73
-rw-r--r--utils/rbutilqt/gui/selectiveinstallwidgetfrm.ui316
-rw-r--r--utils/rbutilqt/icons/audio-input-microphone.svg501
-rw-r--r--utils/rbutilqt/icons/audio-volume-high.svg645
-rw-r--r--utils/rbutilqt/icons/dialog-error.svg330
-rw-r--r--utils/rbutilqt/icons/dialog-information.svg1159
-rw-r--r--utils/rbutilqt/icons/dialog-warning.svg373
-rw-r--r--utils/rbutilqt/icons/document-save.svg619
-rw-r--r--utils/rbutilqt/icons/edit-clear.svg416
-rw-r--r--utils/rbutilqt/icons/edit-find.svg750
-rw-r--r--utils/rbutilqt/icons/go-next.svg192
-rw-r--r--utils/rbutilqt/icons/input-gaming.svg530
-rw-r--r--utils/rbutilqt/icons/media-eject.svg450
-rw-r--r--utils/rbutilqt/icons/multimedia-player.svg693
-rw-r--r--utils/rbutilqt/icons/network-idle.svg1370
-rw-r--r--utils/rbutilqt/icons/package-x-generic.svg485
-rw-r--r--utils/rbutilqt/icons/players/archosfmrecorder-small.pngbin0 -> 7028 bytes
-rw-r--r--utils/rbutilqt/icons/players/archosondiofm-small.pngbin0 -> 4902 bytes
-rw-r--r--utils/rbutilqt/icons/players/archosondiosp-small.pngbin0 -> 4896 bytes
-rw-r--r--utils/rbutilqt/icons/players/archosplayer-small.pngbin0 -> 4760 bytes
-rw-r--r--utils/rbutilqt/icons/players/archosrecorder-small.pngbin0 -> 5252 bytes
-rw-r--r--utils/rbutilqt/icons/players/archosrecorderv2-small.pngbin0 -> 7028 bytes
-rw-r--r--utils/rbutilqt/icons/players/cowond2-small.pngbin0 -> 2944 bytes
-rw-r--r--utils/rbutilqt/icons/players/fonts-small.pngbin0 -> 4908 bytes
-rw-r--r--utils/rbutilqt/icons/players/gigabeatfx-small.pngbin0 -> 2264 bytes
-rw-r--r--utils/rbutilqt/icons/players/gigabeats-small.pngbin0 -> 3388 bytes
-rw-r--r--utils/rbutilqt/icons/players/gogearhdd1630-small.pngbin0 -> 2567 bytes
-rw-r--r--utils/rbutilqt/icons/players/gogearhdd6330-small.pngbin0 -> 2226 bytes
-rw-r--r--utils/rbutilqt/icons/players/gogearsa9200-small.pngbin0 -> 2181 bytes
-rw-r--r--utils/rbutilqt/icons/players/hifimanhm60x-small.pngbin0 -> 4605 bytes
-rw-r--r--utils/rbutilqt/icons/players/hifimanhm801-small.pngbin0 -> 7125 bytes
-rw-r--r--utils/rbutilqt/icons/players/iaudiom3-small.pngbin0 -> 2261 bytes
-rw-r--r--utils/rbutilqt/icons/players/iaudiom5-small.pngbin0 -> 2843 bytes
-rw-r--r--utils/rbutilqt/icons/players/iaudiox5-small.pngbin0 -> 2845 bytes
-rw-r--r--utils/rbutilqt/icons/players/ipod1g2g-small.pngbin0 -> 5243 bytes
-rw-r--r--utils/rbutilqt/icons/players/ipod3g-small.pngbin0 -> 3377 bytes
-rw-r--r--utils/rbutilqt/icons/players/ipod4g-small.pngbin0 -> 2581 bytes
-rw-r--r--utils/rbutilqt/icons/players/ipod6g-small.pngbin0 -> 2833 bytes
-rw-r--r--utils/rbutilqt/icons/players/ipodcolor-small.pngbin0 -> 2520 bytes
-rw-r--r--utils/rbutilqt/icons/players/ipodmini1g-small.pngbin0 -> 2316 bytes
-rw-r--r--utils/rbutilqt/icons/players/ipodnano1g-small.pngbin0 -> 2190 bytes
-rw-r--r--utils/rbutilqt/icons/players/ipodnano2g-small.pngbin0 -> 2270 bytes
-rw-r--r--utils/rbutilqt/icons/players/ipodvideo-small.pngbin0 -> 2771 bytes
-rw-r--r--utils/rbutilqt/icons/players/iriverh10-small.pngbin0 -> 3182 bytes
-rw-r--r--utils/rbutilqt/icons/players/iriverh100-small.pngbin0 -> 3606 bytes
-rw-r--r--utils/rbutilqt/icons/players/iriverh10_5gb-small.pngbin0 -> 2631 bytes
-rw-r--r--utils/rbutilqt/icons/players/iriverh300-small.pngbin0 -> 3180 bytes
-rw-r--r--utils/rbutilqt/icons/players/mpiohd200-small.pngbin0 -> 16883 bytes
-rw-r--r--utils/rbutilqt/icons/players/mpiohd300-small.pngbin0 -> 14701 bytes
-rw-r--r--utils/rbutilqt/icons/players/mrobe100-small.pngbin0 -> 1987 bytes
-rw-r--r--utils/rbutilqt/icons/players/mrobe500-small.pngbin0 -> 3075 bytes
-rw-r--r--utils/rbutilqt/icons/players/samsungyh820-small.pngbin0 -> 3225 bytes
-rw-r--r--utils/rbutilqt/icons/players/samsungyh920-small.pngbin0 -> 3358 bytes
-rw-r--r--utils/rbutilqt/icons/players/samsungyh925-small.pngbin0 -> 3447 bytes
-rw-r--r--utils/rbutilqt/icons/players/samsungypr0-small.pngbin0 -> 3038 bytes
-rw-r--r--utils/rbutilqt/icons/players/sansac200-small.pngbin0 -> 3625 bytes
-rw-r--r--utils/rbutilqt/icons/players/sansaclip-small.pngbin0 -> 5843 bytes
-rw-r--r--utils/rbutilqt/icons/players/sansaclipplus-small.pngbin0 -> 4542 bytes
-rw-r--r--utils/rbutilqt/icons/players/sansaclipzip-small.pngbin0 -> 7640 bytes
-rw-r--r--utils/rbutilqt/icons/players/sansaconnect-small.pngbin0 -> 6603 bytes
-rw-r--r--utils/rbutilqt/icons/players/sansae200-small.pngbin0 -> 3901 bytes
-rw-r--r--utils/rbutilqt/icons/players/sansafuze-small.pngbin0 -> 4937 bytes
-rw-r--r--utils/rbutilqt/icons/players/sansafuzeplus-small.pngbin0 -> 6753 bytes
-rw-r--r--utils/rbutilqt/icons/players/source-small.pngbin0 -> 4908 bytes
-rw-r--r--utils/rbutilqt/icons/players/vibe500-small.pngbin0 -> 2891 bytes
-rw-r--r--utils/rbutilqt/icons/players/vx747-small.pngbin0 -> 2732 bytes
-rw-r--r--utils/rbutilqt/icons/players/vx777-small.pngbin0 -> 2445 bytes
-rw-r--r--utils/rbutilqt/icons/preferences-desktop-font.svg243
-rw-r--r--utils/rbutilqt/icons/preferences-desktop-locale.svg878
-rw-r--r--utils/rbutilqt/icons/preferences-desktop-theme.svg882
-rw-r--r--utils/rbutilqt/icons/preferences-system.svg398
-rw-r--r--utils/rbutilqt/icons/process-stop.svg336
-rw-r--r--utils/rbutilqt/icons/rbutilqt.icnsbin0 -> 180474 bytes
-rw-r--r--utils/rbutilqt/icons/rockbox.icobin0 -> 100082 bytes
-rw-r--r--utils/rbutilqt/icons/system-installer.svg497
-rw-r--r--utils/rbutilqt/icons/system-search.svg313
-rw-r--r--utils/rbutilqt/icons/user-trash-full.svg728
-rw-r--r--utils/rbutilqt/icons/view-refresh.svg393
-rw-r--r--utils/rbutilqt/icons/wizard.jpgbin0 -> 16221 bytes
-rw-r--r--utils/rbutilqt/installtalkfrm.ui246
-rw-r--r--utils/rbutilqt/installtalkwindow.cpp188
-rw-r--r--utils/rbutilqt/installtalkwindow.h56
-rw-r--r--utils/rbutilqt/irivertools/h100sums.h23
-rw-r--r--utils/rbutilqt/irivertools/h120sums.h23
-rw-r--r--utils/rbutilqt/irivertools/h300sums.h19
-rwxr-xr-xutils/rbutilqt/irivertools/mksums.pl69
-rw-r--r--utils/rbutilqt/lame/lame.h1243
-rw-r--r--utils/rbutilqt/lang/rbutil_cs.ts4130
-rw-r--r--utils/rbutilqt/lang/rbutil_de.ts3876
-rw-r--r--utils/rbutilqt/lang/rbutil_fi.ts3652
-rw-r--r--utils/rbutilqt/lang/rbutil_fr.ts4071
-rw-r--r--utils/rbutilqt/lang/rbutil_gr.ts3958
-rw-r--r--utils/rbutilqt/lang/rbutil_he.ts4005
-rw-r--r--utils/rbutilqt/lang/rbutil_it.ts3946
-rw-r--r--utils/rbutilqt/lang/rbutil_ja.ts4004
-rw-r--r--utils/rbutilqt/lang/rbutil_nl.ts4063
-rw-r--r--utils/rbutilqt/lang/rbutil_pl.ts4066
-rw-r--r--utils/rbutilqt/lang/rbutil_pt.ts3956
-rw-r--r--utils/rbutilqt/lang/rbutil_pt_BR.ts3267
-rw-r--r--utils/rbutilqt/lang/rbutil_ru.ts3315
-rw-r--r--utils/rbutilqt/lang/rbutil_tr.ts4993
-rw-r--r--utils/rbutilqt/lang/rbutil_zh_CN.ts3647
-rw-r--r--utils/rbutilqt/lang/rbutil_zh_TW.ts3909
-rw-r--r--utils/rbutilqt/lang/rbutilqt-lang.qrc19
-rwxr-xr-xutils/rbutilqt/langstats.py194
-rw-r--r--utils/rbutilqt/logger/LICENSE.LGPL504
-rw-r--r--utils/rbutilqt/logger/README.ROCKBOX7
-rw-r--r--utils/rbutilqt/logger/include/AbstractAppender.h49
-rw-r--r--utils/rbutilqt/logger/include/AbstractStringAppender.h46
-rw-r--r--utils/rbutilqt/logger/include/ConsoleAppender.h36
-rw-r--r--utils/rbutilqt/logger/include/CuteLogger_global.h16
-rw-r--r--utils/rbutilqt/logger/include/FileAppender.h49
-rw-r--r--utils/rbutilqt/logger/include/Logger.h238
-rw-r--r--utils/rbutilqt/logger/include/OutputDebugAppender.h29
-rw-r--r--utils/rbutilqt/logger/logger.pri22
-rw-r--r--utils/rbutilqt/logger/src/AbstractAppender.cpp147
-rw-r--r--utils/rbutilqt/logger/src/AbstractStringAppender.cpp460
-rw-r--r--utils/rbutilqt/logger/src/ConsoleAppender.cpp64
-rw-r--r--utils/rbutilqt/logger/src/FileAppender.cpp116
-rw-r--r--utils/rbutilqt/logger/src/Logger.cpp1108
-rw-r--r--utils/rbutilqt/logger/src/OutputDebugAppender.cpp43
-rw-r--r--utils/rbutilqt/main.cpp117
-rw-r--r--utils/rbutilqt/mspack/COPYING.LIB504
-rw-r--r--utils/rbutilqt/mspack/README.ROCKBOX6
-rw-r--r--utils/rbutilqt/mspack/cab.h140
-rw-r--r--utils/rbutilqt/mspack/cabc.c24
-rw-r--r--utils/rbutilqt/mspack/cabd.c1508
-rw-r--r--utils/rbutilqt/mspack/chm.h122
-rw-r--r--utils/rbutilqt/mspack/chmc.c24
-rw-r--r--utils/rbutilqt/mspack/chmd.c1377
-rw-r--r--utils/rbutilqt/mspack/des.h15
-rw-r--r--utils/rbutilqt/mspack/hlp.h33
-rw-r--r--utils/rbutilqt/mspack/hlpc.c24
-rw-r--r--utils/rbutilqt/mspack/hlpd.c24
-rw-r--r--utils/rbutilqt/mspack/kwaj.h118
-rw-r--r--utils/rbutilqt/mspack/kwajc.c24
-rw-r--r--utils/rbutilqt/mspack/kwajd.c566
-rw-r--r--utils/rbutilqt/mspack/lit.h35
-rw-r--r--utils/rbutilqt/mspack/litc.c24
-rw-r--r--utils/rbutilqt/mspack/litd.c24
-rw-r--r--utils/rbutilqt/mspack/lzss.h66
-rw-r--r--utils/rbutilqt/mspack/lzssd.c93
-rw-r--r--utils/rbutilqt/mspack/lzx.h221
-rw-r--r--utils/rbutilqt/mspack/lzxc.c18
-rw-r--r--utils/rbutilqt/mspack/lzxd.c905
-rw-r--r--utils/rbutilqt/mspack/mspack.h2385
-rw-r--r--utils/rbutilqt/mspack/mszip.h126
-rw-r--r--utils/rbutilqt/mspack/mszipc.c18
-rw-r--r--utils/rbutilqt/mspack/mszipd.c515
-rw-r--r--utils/rbutilqt/mspack/qtm.h128
-rw-r--r--utils/rbutilqt/mspack/qtmd.c490
-rw-r--r--utils/rbutilqt/mspack/readbits.h207
-rw-r--r--utils/rbutilqt/mspack/readhuff.h172
-rw-r--r--utils/rbutilqt/mspack/sha.h15
-rw-r--r--utils/rbutilqt/mspack/system-mspack.c240
-rw-r--r--utils/rbutilqt/mspack/system-mspack.h129
-rw-r--r--utils/rbutilqt/mspack/szdd.h39
-rw-r--r--utils/rbutilqt/mspack/szddc.c24
-rw-r--r--utils/rbutilqt/mspack/szddd.c247
-rw-r--r--utils/rbutilqt/msvc/Makefile61
-rw-r--r--utils/rbutilqt/msvc/README106
-rw-r--r--utils/rbutilqt/msvc/inttypes.h305
-rw-r--r--utils/rbutilqt/msvc/stdbool.h38
-rw-r--r--utils/rbutilqt/msvc/stdint.h247
-rw-r--r--utils/rbutilqt/preview.cpp122
-rw-r--r--utils/rbutilqt/preview.h74
-rw-r--r--utils/rbutilqt/previewfrm.ui90
-rw-r--r--utils/rbutilqt/progressloggerfrm.ui101
-rw-r--r--utils/rbutilqt/progressloggergui.cpp186
-rw-r--r--utils/rbutilqt/progressloggergui.h60
-rw-r--r--utils/rbutilqt/quazip/LICENSE.LGPL458
-rw-r--r--utils/rbutilqt/quazip/README.ROCKBOX9
-rw-r--r--utils/rbutilqt/quazip/ioapi.h207
-rw-r--r--utils/rbutilqt/quazip/minizip_crypt.h135
-rw-r--r--utils/rbutilqt/quazip/qioapi.cpp363
-rw-r--r--utils/rbutilqt/quazip/quazip.cpp846
-rw-r--r--utils/rbutilqt/quazip/quazip.h611
-rw-r--r--utils/rbutilqt/quazip/quazip.pri25
-rw-r--r--utils/rbutilqt/quazip/quazip_global.h63
-rw-r--r--utils/rbutilqt/quazip/quazipfile.cpp570
-rw-r--r--utils/rbutilqt/quazip/quazipfile.h508
-rw-r--r--utils/rbutilqt/quazip/quazipfileinfo.cpp196
-rw-r--r--utils/rbutilqt/quazip/quazipfileinfo.h226
-rw-r--r--utils/rbutilqt/quazip/quazipnewinfo.cpp290
-rw-r--r--utils/rbutilqt/quazip/quazipnewinfo.h208
-rw-r--r--utils/rbutilqt/quazip/unzip.c2163
-rw-r--r--utils/rbutilqt/quazip/unzip.h461
-rw-r--r--utils/rbutilqt/quazip/zip.c2111
-rw-r--r--utils/rbutilqt/quazip/zip.h391
-rw-r--r--utils/rbutilqt/rbutil.ini1000
-rw-r--r--utils/rbutilqt/rbutilqt-win.qrc5
-rw-r--r--utils/rbutilqt/rbutilqt.cpp750
-rw-r--r--utils/rbutilqt/rbutilqt.h105
-rw-r--r--utils/rbutilqt/rbutilqt.manifest19
-rw-r--r--utils/rbutilqt/rbutilqt.qrc97
-rw-r--r--utils/rbutilqt/rbutilqt.rc34
-rw-r--r--utils/rbutilqt/rbutilqtfrm.ui649
-rw-r--r--utils/rbutilqt/sysinfo.cpp95
-rw-r--r--utils/rbutilqt/sysinfo.h50
-rw-r--r--utils/rbutilqt/sysinfofrm.ui68
-rw-r--r--utils/rbutilqt/systrace.cpp138
-rw-r--r--utils/rbutilqt/systrace.h47
-rw-r--r--utils/rbutilqt/systracefrm.ui93
-rw-r--r--utils/rbutilqt/test/stubs/Logger.h11
-rw-r--r--utils/rbutilqt/test/stubs/stubs-compareversion.cpp38
-rw-r--r--utils/rbutilqt/test/stubs/stubs-playerbuildinfo.cpp36
-rw-r--r--utils/rbutilqt/test/stubs/stubs-talkgenerator.cpp104
-rw-r--r--utils/rbutilqt/test/test-compareversion.cpp148
-rw-r--r--utils/rbutilqt/test/test-httpget.cpp552
-rw-r--r--utils/rbutilqt/test/test-playerbuildinfo.cpp267
-rw-r--r--utils/rbutilqt/test/test-rockboxinfo.cpp188
-rw-r--r--utils/rbutilqt/test/test-talkgenerator.cpp83
-rw-r--r--utils/rbutilqt/test/test-talkgenerator.qrc5
-rw-r--r--utils/rbutilqt/test/tests.pri24
-rw-r--r--utils/rbutilqt/themesinstallfrm.ui149
-rw-r--r--utils/rbutilqt/themesinstallwindow.cpp383
-rw-r--r--utils/rbutilqt/themesinstallwindow.h75
-rw-r--r--utils/rbutilqt/uninstallfrm.ui188
-rw-r--r--utils/rbutilqt/uninstallwindow.cpp100
-rw-r--r--utils/rbutilqt/uninstallwindow.h51
-rw-r--r--utils/rbutilqt/version.h46
-rw-r--r--utils/rbutilqt/zlib/zconf.h326
-rw-r--r--utils/rbutilqt/zlib/zlib.h1200
-rw-r--r--utils/sansapatcher/Makefile52
-rw-r--r--utils/sansapatcher/README36
-rw-r--r--utils/sansapatcher/main.c420
-rw-r--r--utils/sansapatcher/parttypes.h109
-rw-r--r--utils/sansapatcher/sansaio-posix.c158
-rw-r--r--utils/sansapatcher/sansaio-win32.c218
-rw-r--r--utils/sansapatcher/sansaio.h88
-rw-r--r--utils/sansapatcher/sansapatcher.c975
-rw-r--r--utils/sansapatcher/sansapatcher.h67
-rw-r--r--utils/sansapatcher/sansapatcher.manifest13
-rw-r--r--utils/sansapatcher/sansapatcher.rc1
-rw-r--r--utils/themeeditor/CMakeLists.txt150
-rw-r--r--utils/themeeditor/Info.plist2
-rw-r--r--utils/themeeditor/RockboxThemeEditor.desktop12
-rw-r--r--utils/themeeditor/dmgbuild.cfg17
-rw-r--r--utils/themeeditor/resources/rbthemeeditor.svg71
-rw-r--r--utils/themeeditor/themeeditor.pro221
-rw-r--r--utils/tools/Makefile31
-rw-r--r--utils/tools/bin2c.c174
506 files changed, 159768 insertions, 1006 deletions
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
new file mode 100644
index 0000000000..55e5b7991f
--- /dev/null
+++ b/utils/CMakeLists.txt
@@ -0,0 +1,395 @@
+#
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+#
+# All files in this archive are subject to the GNU General Public License.
+# See the file COPYING in the source tree root for full license agreement.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+cmake_minimum_required(VERSION 3.12)
+project(RockboxUtils)
+
+set (CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+if (NOT CMAKE_BUILD_TYPE)
+ message("-- CMAKE_BUILD_TYPE not set, assuming Release")
+ set(CMAKE_BUILD_TYPE Release)
+endif()
+find_program(CCACHE_PROGRAM ccache)
+if(CCACHE_PROGRAM)
+ message("-- Found ccache, enabling")
+ set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
+ set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
+endif()
+
+# Global compiler options
+if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ # Clang and AppleClang
+ if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
+ # using clang with clang-cl front end
+ elseif (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
+ # using clang with regular front end
+ add_compile_options(-Wall -Wextra)
+ endif()
+elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ add_compile_options(-Wall -Wextra)
+ add_link_options($<$<CONFIG:RELEASE>:-s>)
+endif()
+
+
+enable_testing()
+
+# Qt
+find_package(QT NAMES Qt6 Qt5 REQUIRED)
+if(QT_VERSION_MAJOR EQUAL 5)
+ find_package(Qt5 REQUIRED COMPONENTS
+ Core Widgets Svg Multimedia Network Test LinguistTools)
+else()
+ find_package(Qt6 REQUIRED COMPONENTS
+ Core Core5Compat Widgets Svg Network LinguistTools SvgWidgets
+ OPTIONAL_COMPONENTS Multimedia Test)
+endif()
+get_target_property(_moc_executable Qt${QT_VERSION_MAJOR}::moc IMPORTED_LOCATION)
+get_filename_component(QT_BINDIR "${_moc_executable}" DIRECTORY)
+message("-- Found Qt${QT_VERSION_MAJOR}: ${Qt${QT_VERSION_MAJOR}_DIR}")
+
+# If we're on Linux, try to find the used libs in the system.
+if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ # required system libs
+ find_package(PkgConfig)
+ pkg_check_modules(libusb QUIET REQUIRED IMPORTED_TARGET libusb-1.0)
+ message("-- Found libusb: ${libusb_LINK_LIBRARIES}")
+
+ # optional system libs.
+ pkg_check_modules(speex QUIET IMPORTED_TARGET speex speexdsp)
+ if (${speex_FOUND})
+ message("-- Found speex: ${speex_LINK_LIBRARIES}")
+ else()
+ message("-- Could not find system speex, using our own copy.")
+ endif()
+endif()
+
+if(APPLE)
+ find_library(FRAMEWORK_IOKIT IOKit)
+ find_library(FRAMEWORK_COREFOUNDATION CoreFoundation)
+ find_library(FRAMEWORK_CARBON Carbon)
+ find_library(FRAMEWORK_SYSTEMCONFIGURATION SystemConfiguration)
+ find_library(FRAMEWORK_CORESERVICES CoreServices)
+endif()
+
+
+add_executable(ipodpatcher-bin
+ ipodpatcher/main.c
+ ipodpatcher/ipodpatcher-aupd.c
+ )
+target_link_libraries(ipodpatcher-bin ipodpatcher)
+target_compile_definitions(ipodpatcher-bin PRIVATE VERSION="none")
+set_target_properties(ipodpatcher-bin PROPERTIES OUTPUT_NAME ipodpatcher)
+if(APPLE)
+ target_link_libraries(ipodpatcher-bin ${FRAMEWORK_IOKIT} ${FRAMEWORK_COREFOUNDATION})
+endif()
+
+add_library(ipodpatcher
+ ipodpatcher/arc4.h
+ ipodpatcher/arc4.c
+ ipodpatcher/fat32format.c
+ ipodpatcher/ipodpatcher.c
+ ipodpatcher/ipodio.h
+ ipodpatcher/ipodpatcher.h
+ ipodpatcher/parttypes.h
+ )
+if(WIN32)
+ target_sources(ipodpatcher PRIVATE
+ ipodpatcher/ipodio-win32.c
+ ipodpatcher/ipodio-win32-scsi.c
+ )
+else()
+ target_sources(ipodpatcher PRIVATE
+ ipodpatcher/ipodio-posix.c
+ )
+endif()
+target_compile_definitions(ipodpatcher PUBLIC RBUTIL _LARGEFILE64_SOURCE)
+target_include_directories(ipodpatcher PUBLIC ${CMAKE_CURRENT_LIST_DIR}/ipodpatcher)
+
+add_executable(sansapatcher-bin
+ sansapatcher/main.c
+ )
+target_link_libraries(sansapatcher-bin sansapatcher)
+target_compile_definitions(sansapatcher-bin PRIVATE VERSION="none")
+set_target_properties(sansapatcher-bin PROPERTIES OUTPUT_NAME sansapatcher)
+
+add_library(sansapatcher
+ sansapatcher/parttypes.h
+ sansapatcher/sansaio.h
+ sansapatcher/sansapatcher.c
+ sansapatcher/sansapatcher.h
+ )
+if(WIN32)
+ target_sources(sansapatcher PRIVATE
+ sansapatcher/sansaio-win32.c
+ )
+else()
+ target_sources(sansapatcher PRIVATE
+ sansapatcher/sansaio-posix.c
+ )
+endif()
+
+target_compile_definitions(sansapatcher PUBLIC RBUTIL _LARGEFILE64_SOURCE)
+target_include_directories(sansapatcher PUBLIC ${CMAKE_CURRENT_LIST_DIR}/sansapatcher)
+
+add_library(chinachippatcher
+ chinachippatcher/chinachip.c
+ chinachippatcher/chinachip.h
+ )
+target_compile_definitions(chinachippatcher PUBLIC RBUTIL _LARGEFILE64_SOURCE)
+
+add_library(mkamsboot
+ mkamsboot/dualboot.c
+ mkamsboot/dualboot.h
+ mkamsboot/md5.c
+ mkamsboot/md5.h
+ mkamsboot/mkamsboot.c
+ mkamsboot/mkamsboot.h
+ )
+
+target_compile_definitions(mkamsboot PUBLIC _LARGEFILE64_SOURCE)
+target_link_libraries(mkamsboot ucl)
+
+add_library(ucl
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/alloc.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/fake16.h
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/getbit.h
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/internal.h
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/io.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/Makefile
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/n2_99.ch
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/n2b_99.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/n2b_d.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/n2b_ds.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/n2b_to.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/n2d_99.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/n2d_d.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/n2d_ds.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/n2d_to.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/n2e_99.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/n2e_d.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/n2e_ds.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/n2e_to.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/ucl_conf.h
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/ucl_crc.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/ucl_dll.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/ucl_init.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/ucl_mchw.ch
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/ucl_ptr.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/ucl_ptr.h
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/ucl_str.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/ucl_swd.ch
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/ucl_util.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/src/ucl_util.h
+ )
+
+target_include_directories(ucl PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../tools/ucl/include)
+
+add_library(rbspeex
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/rbspeex/rbspeex.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/rbspeex/rbspeex.h
+ )
+target_compile_definitions(rbspeex PRIVATE HAVE_CONFIG_H ROCKBOX_VOICE_ENCODER STATIC)
+target_include_directories(rbspeex PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../tools/rbspeex)
+
+
+if (${speex_FOUND})
+ target_link_libraries(rbspeex PUBLIC PkgConfig::speex)
+else()
+ target_sources(rbspeex PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/bits.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/cb_search.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/exc_10_16_table.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/exc_10_32_table.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/exc_20_32_table.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/exc_5_256_table.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/exc_5_64_table.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/exc_8_128_table.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/filters.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/gain_table.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/gain_table_lbr.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/hexc_10_32_table.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/hexc_table.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/high_lsp_tables.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/lsp.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/lsp_tables_nb.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/ltp.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/modes.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/modes_wb.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/nb_celp.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/quant_lsp.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/sb_celp.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/speex.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/speex_callbacks.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/lpc.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/vbr.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/vq.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/window.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex/resample.c
+ )
+ target_include_directories(rbspeex PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../lib/rbcodec/codecs/libspeex)
+endif()
+
+add_library(mkimxboot
+ mkimxboot/dualboot.c
+ mkimxboot/md5.c
+ mkimxboot/md5.h
+ mkimxboot/mkimxboot.c
+ mkimxboot/mkimxboot.h
+ )
+target_include_directories(mkimxboot PUBLIC ${CMAKE_CURRENT_LIST_DIR}/mkimxboot)
+target_link_libraries(mkimxboot sbtools)
+
+add_library(sbtools
+ imxtools/sbtools/crc.c
+ imxtools/sbtools/crypto.c
+ imxtools/sbtools/crypto.h
+ imxtools/sbtools/elf.c
+ imxtools/sbtools/elf.h
+ imxtools/sbtools/misc.c
+ imxtools/sbtools/misc.h
+ imxtools/sbtools/sb.c
+ imxtools/sbtools/sb.h
+ )
+
+target_include_directories(sbtools PUBLIC ${CMAKE_CURRENT_LIST_DIR}/imxtools/sbtools)
+target_link_libraries(sbtools PUBLIC rbtomcrypt)
+
+add_library(mkmpioboot
+ mkmpioboot/mkmpioboot.c
+ mkmpioboot/mkmpioboot.h
+ )
+target_include_directories(mkmpioboot PUBLIC ${CMAKE_CURRENT_LIST_DIR}/mkmpioboot)
+
+add_library(mktccboot
+ mktccboot/mktccboot.c
+ mktccboot/mktccboot.h
+ )
+target_include_directories(mktccboot PUBLIC ${CMAKE_CURRENT_LIST_DIR}/mktccboot)
+target_include_directories(mktccboot PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../tools)
+target_link_libraries(mktccboot PUBLIC telechips)
+
+add_library(mks5lboot
+ mks5lboot/dualboot.c
+ mks5lboot/dualboot.h
+ mks5lboot/ipoddfu.c
+ mks5lboot/mkdfu.c
+ mks5lboot/mks5lboot.h
+ )
+target_include_directories(mks5lboot PUBLIC ${CMAKE_CURRENT_LIST_DIR}/mks5lboot)
+
+add_library(bspatch
+ bspatch/bspatch.c
+ bspatch/bspatch.h
+ )
+target_include_directories(bspatch PUBLIC ${CMAKE_CURRENT_LIST_DIR}/bspatch)
+target_link_libraries(bspatch bz2)
+
+add_library(voicefont
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/voicefont.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/voicefont.h
+ )
+target_include_directories(voicefont PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../tools)
+target_compile_definitions(voicefont PUBLIC RBUTIL)
+
+add_library(telechips
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/telechips.c
+ ${CMAKE_CURRENT_LIST_DIR}/../tools/telechips.h
+ )
+target_include_directories(telechips PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../tools)
+
+find_library(LIBBZ2 bz2)
+if(${LIBBZ2} STREQUAL "LIBBZ2-NOTFOUND")
+ message("-- bz2 not found, building our own")
+ add_library(bz2
+ bzip2/blocksort.c
+ bzip2/bzlib.c
+ bzip2/bzlib.h
+ bzip2/bzlib_private.h
+ bzip2/compress.c
+ bzip2/crctable.c
+ bzip2/decompress.c
+ bzip2/huffman.c
+ bzip2/randtable.c
+ )
+ target_include_directories(bz2 PUBLIC ${CMAKE_CURRENT_LIST_DIR}/bzip2)
+else()
+ message("-- Found libbz2: ${LIBBZ2}")
+endif()
+
+add_library(rbtomcrypt
+ tomcrypt/src/ciphers/aes/aes.c
+ tomcrypt/src/ciphers/aes/aes_tab.c
+ tomcrypt/src/misc/crypt/crypt_argchk.c
+ tomcrypt/src/misc/crypt/crypt_register_cipher.c
+ tomcrypt/src/misc/crypt/crypt_cipher_is_valid.c
+ tomcrypt/src/misc/crypt/crypt_cipher_descriptor.c
+ tomcrypt/src/misc/zeromem.c
+ tomcrypt/src/misc/compare_testvector.c
+ tomcrypt/src/modes/cbc/cbc_start.c
+ tomcrypt/src/modes/cbc/cbc_decrypt.c
+ tomcrypt/src/modes/cbc/cbc_encrypt.c
+ tomcrypt/src/hashes/sha1.c
+ tomcrypt/src/headers/tomcrypt_argchk.h
+ tomcrypt/src/headers/tomcrypt_cfg.h
+ tomcrypt/src/headers/tomcrypt_cipher.h
+ tomcrypt/src/headers/tomcrypt_custom.h
+ tomcrypt/src/headers/tomcrypt.h
+ tomcrypt/src/headers/tomcrypt_hash.h
+ tomcrypt/src/headers/tomcrypt_mac.h
+ tomcrypt/src/headers/tomcrypt_macros.h
+ tomcrypt/src/headers/tomcrypt_math.h
+ tomcrypt/src/headers/tomcrypt_misc.h
+ tomcrypt/src/headers/tomcrypt_pkcs.h
+ tomcrypt/src/headers/tomcrypt_pk.h
+ tomcrypt/src/headers/tomcrypt_private.h
+ tomcrypt/src/headers/tomcrypt_prng.h
+ )
+target_include_directories(rbtomcrypt PUBLIC ${CMAKE_CURRENT_LIST_DIR}/tomcrypt/src/headers)
+
+add_library(skin_parser
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/skin_parser/skin_buffer.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/skin_parser/skin_buffer.h
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/skin_parser/skin_debug.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/skin_parser/skin_debug.h
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/skin_parser/skin_parser.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/skin_parser/skin_parser.h
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/skin_parser/skin_scan.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/skin_parser/skin_scan.h
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/skin_parser/symbols.h
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/skin_parser/tag_table.c
+ ${CMAKE_CURRENT_LIST_DIR}/../lib/skin_parser/tag_table.h
+ )
+target_include_directories(skin_parser PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../lib/skin_parser)
+target_compile_definitions(skin_parser PUBLIC __PCTOOL__)
+
+# target will always be build. File is only updated when contents change.
+add_custom_target(gitversion.h
+ COMMENT "Updating gitversion.h"
+ COMMAND ${CMAKE_COMMAND}
+ -DOUTFILE=${CMAKE_CURRENT_BINARY_DIR}/gitversion/gitversion.h
+ -P ${CMAKE_CURRENT_LIST_DIR}/cmake/gitversion.cmake
+ BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/gitversion/gitversion.h)
+
+# link to get git version header.
+add_library(gitversion INTERFACE)
+
+add_dependencies(gitversion gitversion.h)
+target_include_directories(gitversion INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/gitversion)
+
+include(${CMAKE_CURRENT_LIST_DIR}/cmake/deploy.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/cmake/QtTest.cmake)
+add_subdirectory(rbutilqt)
+add_subdirectory(themeeditor)
+
diff --git a/utils/bspatch/LICENSE b/utils/bspatch/LICENSE
new file mode 100644
index 0000000000..c82090b3eb
--- /dev/null
+++ b/utils/bspatch/LICENSE
@@ -0,0 +1,23 @@
+ Copyright 2003-2005 Colin Percival
+ All rights reserved
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted providing that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
diff --git a/utils/bspatch/Makefile b/utils/bspatch/Makefile
new file mode 100644
index 0000000000..8f287a5ebb
--- /dev/null
+++ b/utils/bspatch/Makefile
@@ -0,0 +1,17 @@
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+# $Id$
+#
+
+LIBSOURCES := bspatch.c
+
+SOURCES := main.c
+
+OUTPUT := bspatch
+EXTRADEPS := libbz2.a
+
+include ../libtools.make
diff --git a/utils/bspatch/bspatch.c b/utils/bspatch/bspatch.c
new file mode 100644
index 0000000000..d1d7a5aa7a
--- /dev/null
+++ b/utils/bspatch/bspatch.c
@@ -0,0 +1,218 @@
+/*-
+ * Copyright 2003-2005 Colin Percival
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted providing that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef WIN32
+#include <io.h>
+#else
+#include <stdarg.h>
+#include <sys/types.h>
+#endif
+#include "../bzip2/bzlib.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+
+#define errx err
+void err(int exitcode, const char * fmt, ...)
+{
+ va_list valist;
+ va_start(valist, fmt);
+ vprintf(fmt, valist);
+ va_end(valist);
+ exit(exitcode);
+}
+
+static long offtin(u_char *buf)
+{
+ long y;
+
+ y = buf[7] & 0x7F;
+ y = y * 256;y += buf[6];
+ y = y * 256;y += buf[5];
+ y = y * 256;y += buf[4];
+ y = y * 256;y += buf[3];
+ y = y * 256;y += buf[2];
+ y = y * 256;y += buf[1];
+ y = y * 256;y += buf[0];
+
+ if (buf[7] & 0x80) y = -y;
+
+ return y;
+}
+
+int apply_bspatch(const char *infile, const char *outfile, const char *patchfile)
+{
+ FILE * f, *cpf, *dpf, *epf;
+ BZFILE * cpfbz2, *dpfbz2, *epfbz2;
+ int cbz2err, dbz2err, ebz2err;
+ FILE * fs;
+ long oldsize, newsize;
+ long bzctrllen, bzdatalen;
+ u_char header[32], buf[8];
+ u_char *pold, *pnew;
+ long oldpos, newpos;
+ long ctrl[3];
+ long lenread;
+ long i;
+
+ /* Open patch file */
+ if ((f = fopen(patchfile, "r")) == NULL)
+ err(1, "fopen(%s)", patchfile);
+
+ /*
+ File format:
+ 0 8 "BSDIFF40"
+ 8 8 X
+ 16 8 Y
+ 24 8 sizeof(newfile)
+ 32 X bzip2(control block)
+ 32+X Y bzip2(diff block)
+ 32+X+Y ??? bzip2(extra block)
+ with control block a set of triples (x,y,z) meaning "add x bytes
+ from oldfile to x bytes from the diff block; copy y bytes from the
+ extra block; seek forwards in oldfile by z bytes".
+ */
+
+ /* Read header */
+ if (fread(header, 1, 32, f) < 32) {
+ if (feof(f))
+ errx(1, "Corrupt patch\n");
+ err(1, "fread(%s)", patchfile);
+ }
+
+ /* Check for appropriate magic */
+ if (memcmp(header, "BSDIFF40", 8) != 0)
+ errx(1, "Corrupt patch\n");
+
+ /* Read lengths from header */
+ bzctrllen = offtin(header + 8);
+ bzdatalen = offtin(header + 16);
+ newsize = offtin(header + 24);
+ if ((bzctrllen < 0) || (bzdatalen < 0) || (newsize < 0))
+ errx(1, "Corrupt patch\n");
+
+ /* Close patch file and re-open it via libbzip2 at the right places */
+ if (fclose(f))
+ err(1, "fclose(%s)", patchfile);
+ if ((cpf = fopen(patchfile, "rb")) == NULL)
+ err(1, "fopen(%s)", patchfile);
+ if (fseek(cpf, 32, SEEK_SET))
+ err(1, "fseeko(%s, %lld)", patchfile,
+ (long long)32);
+ if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
+ errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err);
+ if ((dpf = fopen(patchfile, "rb")) == NULL)
+ err(1, "fopen(%s)", patchfile);
+ if (fseek(dpf, 32 + bzctrllen, SEEK_SET))
+ err(1, "fseeko(%s, %lld)", patchfile,
+ (long long)(32 + bzctrllen));
+ if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
+ errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err);
+ if ((epf = fopen(patchfile, "rb")) == NULL)
+ err(1, "fopen(%s)", patchfile);
+ if (fseek(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
+ err(1, "fseeko(%s, %lld)", patchfile,
+ (long long)(32 + bzctrllen + bzdatalen));
+ if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
+ errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err);
+
+ fs = fopen(infile, "rb");
+ if (fs == NULL)err(1, "Open failed :%s", infile);
+ if (fseek(fs, 0, SEEK_END) != 0)err(1, "Seek failed :%s", infile);
+ oldsize = ftell(fs);
+ pold = (u_char *)malloc(oldsize + 1);
+ if (pold == NULL) err(1, "Malloc failed :%s", infile);
+ fseek(fs, 0, SEEK_SET);
+ if (fread(pold, 1, oldsize, fs) == -1) err(1, "Read failed :%s", infile);
+ if (fclose(fs) == -1) err(1, "Close failed :%s", infile);
+
+ pnew = malloc(newsize + 1);
+ if (pnew == NULL)err(1, NULL);
+
+ oldpos = 0;newpos = 0;
+ while (newpos < newsize) {
+ /* Read control data */
+ for (i = 0;i <= 2;i++) {
+ lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
+ if ((lenread < 8) || ((cbz2err != BZ_OK) &&
+ (cbz2err != BZ_STREAM_END)))
+ errx(1, "Corrupt patch\n");
+ ctrl[i] = offtin(buf);
+ };
+
+ /* Sanity-check */
+ if (newpos + ctrl[0] > newsize)
+ errx(1, "Corrupt patch\n");
+
+ /* Read diff string */
+ lenread = BZ2_bzRead(&dbz2err, dpfbz2, pnew + newpos, ctrl[0]);
+ if ((lenread < ctrl[0]) ||
+ ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
+ errx(1, "Corrupt patch\n");
+
+ /* Add pold data to diff string */
+ for (i = 0;i < ctrl[0];i++)
+ if ((oldpos + i >= 0) && (oldpos + i < oldsize))
+ pnew[newpos + i] += pold[oldpos + i];
+
+ /* Adjust pointers */
+ newpos += ctrl[0];
+ oldpos += ctrl[0];
+
+ /* Sanity-check */
+ if (newpos + ctrl[1] > newsize)
+ errx(1, "Corrupt patch\n");
+
+ /* Read extra string */
+ lenread = BZ2_bzRead(&ebz2err, epfbz2, pnew + newpos, ctrl[1]);
+ if ((lenread < ctrl[1]) ||
+ ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
+ errx(1, "Corrupt patch\n");
+
+ /* Adjust pointers */
+ newpos += ctrl[1];
+ oldpos += ctrl[2];
+ };
+
+ /* Clean up the bzip2 reads */
+ BZ2_bzReadClose(&cbz2err, cpfbz2);
+ BZ2_bzReadClose(&dbz2err, dpfbz2);
+ BZ2_bzReadClose(&ebz2err, epfbz2);
+ if (fclose(cpf) || fclose(dpf) || fclose(epf))
+ err(1, "fclose(%s)", patchfile);
+
+ /* Write the pnew file */
+ fs = fopen(outfile, "wb");
+ if (fs == NULL)err(1, "Create failed :%s", outfile);
+ if (fwrite(pnew, 1, newsize, fs) == -1)err(1, "Write failed :%s", outfile);
+ if (fclose(fs) == -1)err(1, "Close failed :%s", outfile);
+
+ free(pnew);
+ free(pold);
+
+ return 0;
+}
diff --git a/utils/bspatch/bspatch.h b/utils/bspatch/bspatch.h
new file mode 100644
index 0000000000..46edd5db0c
--- /dev/null
+++ b/utils/bspatch/bspatch.h
@@ -0,0 +1,19 @@
+/*
+ * Simple wrapper for the bspatch entry point.
+ */
+
+#ifndef _BSPATCH_H
+#define _BSPATCH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int apply_bspatch(const char *infile, const char *outfile, const char *patchfile);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _BSPATCH_H */
diff --git a/utils/bspatch/main.c b/utils/bspatch/main.c
new file mode 100644
index 0000000000..e130457256
--- /dev/null
+++ b/utils/bspatch/main.c
@@ -0,0 +1,34 @@
+/*-
+ * Copyright 2003-2005 Colin Percival
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted providing that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "bspatch.c"
+
+int main(int argc, char * argv[])
+{
+ if (argc != 4) errx(1, "usage: %s oldfile newfile patchfile\n", argv[0]);
+
+ apply_bspatch(argv[1], argv[2], argv[3]);
+}
diff --git a/utils/bzip2/LICENSE b/utils/bzip2/LICENSE
new file mode 100644
index 0000000000..cc614178cf
--- /dev/null
+++ b/utils/bzip2/LICENSE
@@ -0,0 +1,42 @@
+
+--------------------------------------------------------------------------
+
+This program, "bzip2", the associated library "libbzip2", and all
+documentation, are copyright (C) 1996-2010 Julian R Seward. All
+rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. 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.
+
+3. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+
+4. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Julian Seward, jseward@bzip.org
+bzip2/libbzip2 version 1.0.6 of 6 September 2010
+
+--------------------------------------------------------------------------
diff --git a/utils/bzip2/Makefile b/utils/bzip2/Makefile
new file mode 100644
index 0000000000..6dc59ed025
--- /dev/null
+++ b/utils/bzip2/Makefile
@@ -0,0 +1,15 @@
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+# $Id$
+#
+
+LIBSOURCES := blocksort.c compress.c decompress.c randtable.c \
+ bzlib.c crctable.c huffman.c
+
+OUTPUT := bz2
+
+include ../libtools.make
diff --git a/utils/bzip2/blocksort.c b/utils/bzip2/blocksort.c
new file mode 100644
index 0000000000..d0d662cd4e
--- /dev/null
+++ b/utils/bzip2/blocksort.c
@@ -0,0 +1,1094 @@
+
+/*-------------------------------------------------------------*/
+/*--- Block sorting machinery ---*/
+/*--- blocksort.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.6 of 6 September 2010
+ Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*---------------------------------------------*/
+/*--- Fallback O(N log(N)^2) sorting ---*/
+/*--- algorithm, for repetitive blocks ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+__inline__
+void fallbackSimpleSort ( UInt32* fmap,
+ UInt32* eclass,
+ Int32 lo,
+ Int32 hi )
+{
+ Int32 i, j, tmp;
+ UInt32 ec_tmp;
+
+ if (lo == hi) return;
+
+ if (hi - lo > 3) {
+ for ( i = hi-4; i >= lo; i-- ) {
+ tmp = fmap[i];
+ ec_tmp = eclass[tmp];
+ for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 )
+ fmap[j-4] = fmap[j];
+ fmap[j-4] = tmp;
+ }
+ }
+
+ for ( i = hi-1; i >= lo; i-- ) {
+ tmp = fmap[i];
+ ec_tmp = eclass[tmp];
+ for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ )
+ fmap[j-1] = fmap[j];
+ fmap[j-1] = tmp;
+ }
+}
+
+
+/*---------------------------------------------*/
+#define fswap(zz1, zz2) \
+ { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
+
+#define fvswap(zzp1, zzp2, zzn) \
+{ \
+ Int32 yyp1 = (zzp1); \
+ Int32 yyp2 = (zzp2); \
+ Int32 yyn = (zzn); \
+ while (yyn > 0) { \
+ fswap(fmap[yyp1], fmap[yyp2]); \
+ yyp1++; yyp2++; yyn--; \
+ } \
+}
+
+
+#define fmin(a,b) ((a) < (b)) ? (a) : (b)
+
+#define fpush(lz,hz) { stackLo[sp] = lz; \
+ stackHi[sp] = hz; \
+ sp++; }
+
+#define fpop(lz,hz) { sp--; \
+ lz = stackLo[sp]; \
+ hz = stackHi[sp]; }
+
+#define FALLBACK_QSORT_SMALL_THRESH 10
+#define FALLBACK_QSORT_STACK_SIZE 100
+
+
+static
+void fallbackQSort3 ( UInt32* fmap,
+ UInt32* eclass,
+ Int32 loSt,
+ Int32 hiSt )
+{
+ Int32 unLo, unHi, ltLo, gtHi, n, m;
+ Int32 sp, lo, hi;
+ UInt32 med, r, r3;
+ Int32 stackLo[FALLBACK_QSORT_STACK_SIZE];
+ Int32 stackHi[FALLBACK_QSORT_STACK_SIZE];
+
+ r = 0;
+
+ sp = 0;
+ fpush ( loSt, hiSt );
+
+ while (sp > 0) {
+
+ AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 );
+
+ fpop ( lo, hi );
+ if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) {
+ fallbackSimpleSort ( fmap, eclass, lo, hi );
+ continue;
+ }
+
+ /* Random partitioning. Median of 3 sometimes fails to
+ avoid bad cases. Median of 9 seems to help but
+ looks rather expensive. This too seems to work but
+ is cheaper. Guidance for the magic constants
+ 7621 and 32768 is taken from Sedgewick's algorithms
+ book, chapter 35.
+ */
+ r = ((r * 7621) + 1) % 32768;
+ r3 = r % 3;
+ if (r3 == 0) med = eclass[fmap[lo]]; else
+ if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else
+ med = eclass[fmap[hi]];
+
+ unLo = ltLo = lo;
+ unHi = gtHi = hi;
+
+ while (1) {
+ while (1) {
+ if (unLo > unHi) break;
+ n = (Int32)eclass[fmap[unLo]] - (Int32)med;
+ if (n == 0) {
+ fswap(fmap[unLo], fmap[ltLo]);
+ ltLo++; unLo++;
+ continue;
+ };
+ if (n > 0) break;
+ unLo++;
+ }
+ while (1) {
+ if (unLo > unHi) break;
+ n = (Int32)eclass[fmap[unHi]] - (Int32)med;
+ if (n == 0) {
+ fswap(fmap[unHi], fmap[gtHi]);
+ gtHi--; unHi--;
+ continue;
+ };
+ if (n < 0) break;
+ unHi--;
+ }
+ if (unLo > unHi) break;
+ fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--;
+ }
+
+ AssertD ( unHi == unLo-1, "fallbackQSort3(2)" );
+
+ if (gtHi < ltLo) continue;
+
+ n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n);
+ m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m);
+
+ n = lo + unLo - ltLo - 1;
+ m = hi - (gtHi - unHi) + 1;
+
+ if (n - lo > hi - m) {
+ fpush ( lo, n );
+ fpush ( m, hi );
+ } else {
+ fpush ( m, hi );
+ fpush ( lo, n );
+ }
+ }
+}
+
+#undef fmin
+#undef fpush
+#undef fpop
+#undef fswap
+#undef fvswap
+#undef FALLBACK_QSORT_SMALL_THRESH
+#undef FALLBACK_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+ nblock > 0
+ eclass exists for [0 .. nblock-1]
+ ((UChar*)eclass) [0 .. nblock-1] holds block
+ ptr exists for [0 .. nblock-1]
+
+ Post:
+ ((UChar*)eclass) [0 .. nblock-1] holds block
+ All other areas of eclass destroyed
+ fmap [0 .. nblock-1] holds sorted order
+ bhtab [ 0 .. 2+(nblock/32) ] destroyed
+*/
+
+#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31))
+#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31))
+#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31)))
+#define WORD_BH(zz) bhtab[(zz) >> 5]
+#define UNALIGNED_BH(zz) ((zz) & 0x01f)
+
+static
+void fallbackSort ( UInt32* fmap,
+ UInt32* eclass,
+ UInt32* bhtab,
+ Int32 nblock,
+ Int32 verb )
+{
+ Int32 ftab[257];
+ Int32 ftabCopy[256];
+ Int32 H, i, j, k, l, r, cc, cc1;
+ Int32 nNotDone;
+ Int32 nBhtab;
+ UChar* eclass8 = (UChar*)eclass;
+
+ /*--
+ Initial 1-char radix sort to generate
+ initial fmap and initial BH bits.
+ --*/
+ if (verb >= 4)
+ VPrintf0 ( " bucket sorting ...\n" );
+ for (i = 0; i < 257; i++) ftab[i] = 0;
+ for (i = 0; i < nblock; i++) ftab[eclass8[i]]++;
+ for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i];
+ for (i = 1; i < 257; i++) ftab[i] += ftab[i-1];
+
+ for (i = 0; i < nblock; i++) {
+ j = eclass8[i];
+ k = ftab[j] - 1;
+ ftab[j] = k;
+ fmap[k] = i;
+ }
+
+ nBhtab = 2 + (nblock / 32);
+ for (i = 0; i < nBhtab; i++) bhtab[i] = 0;
+ for (i = 0; i < 256; i++) SET_BH(ftab[i]);
+
+ /*--
+ Inductively refine the buckets. Kind-of an
+ "exponential radix sort" (!), inspired by the
+ Manber-Myers suffix array construction algorithm.
+ --*/
+
+ /*-- set sentinel bits for block-end detection --*/
+ for (i = 0; i < 32; i++) {
+ SET_BH(nblock + 2*i);
+ CLEAR_BH(nblock + 2*i + 1);
+ }
+
+ /*-- the log(N) loop --*/
+ H = 1;
+ while (1) {
+
+ if (verb >= 4)
+ VPrintf1 ( " depth %6d has ", H );
+
+ j = 0;
+ for (i = 0; i < nblock; i++) {
+ if (ISSET_BH(i)) j = i;
+ k = fmap[i] - H; if (k < 0) k += nblock;
+ eclass[k] = j;
+ }
+
+ nNotDone = 0;
+ r = -1;
+ while (1) {
+
+ /*-- find the next non-singleton bucket --*/
+ k = r + 1;
+ while (ISSET_BH(k) && UNALIGNED_BH(k)) k++;
+ if (ISSET_BH(k)) {
+ while (WORD_BH(k) == 0xffffffff) k += 32;
+ while (ISSET_BH(k)) k++;
+ }
+ l = k - 1;
+ if (l >= nblock) break;
+ while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++;
+ if (!ISSET_BH(k)) {
+ while (WORD_BH(k) == 0x00000000) k += 32;
+ while (!ISSET_BH(k)) k++;
+ }
+ r = k - 1;
+ if (r >= nblock) break;
+
+ /*-- now [l, r] bracket current bucket --*/
+ if (r > l) {
+ nNotDone += (r - l + 1);
+ fallbackQSort3 ( fmap, eclass, l, r );
+
+ /*-- scan bucket and generate header bits-- */
+ cc = -1;
+ for (i = l; i <= r; i++) {
+ cc1 = eclass[fmap[i]];
+ if (cc != cc1) { SET_BH(i); cc = cc1; };
+ }
+ }
+ }
+
+ if (verb >= 4)
+ VPrintf1 ( "%6d unresolved strings\n", nNotDone );
+
+ H *= 2;
+ if (H > nblock || nNotDone == 0) break;
+ }
+
+ /*--
+ Reconstruct the original block in
+ eclass8 [0 .. nblock-1], since the
+ previous phase destroyed it.
+ --*/
+ if (verb >= 4)
+ VPrintf0 ( " reconstructing block ...\n" );
+ j = 0;
+ for (i = 0; i < nblock; i++) {
+ while (ftabCopy[j] == 0) j++;
+ ftabCopy[j]--;
+ eclass8[fmap[i]] = (UChar)j;
+ }
+ AssertH ( j < 256, 1005 );
+}
+
+#undef SET_BH
+#undef CLEAR_BH
+#undef ISSET_BH
+#undef WORD_BH
+#undef UNALIGNED_BH
+
+
+/*---------------------------------------------*/
+/*--- The main, O(N^2 log(N)) sorting ---*/
+/*--- algorithm. Faster for "normal" ---*/
+/*--- non-repetitive blocks. ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+__inline__
+Bool mainGtU ( UInt32 i1,
+ UInt32 i2,
+ UChar* block,
+ UInt16* quadrant,
+ UInt32 nblock,
+ Int32* budget )
+{
+ Int32 k;
+ UChar c1, c2;
+ UInt16 s1, s2;
+
+ AssertD ( i1 != i2, "mainGtU" );
+ /* 1 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 2 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 3 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 4 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 5 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 6 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 7 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 8 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 9 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 10 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 11 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+ /* 12 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ i1++; i2++;
+
+ k = nblock + 8;
+
+ do {
+ /* 1 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 2 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 3 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 4 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 5 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 6 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 7 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+ /* 8 */
+ c1 = block[i1]; c2 = block[i2];
+ if (c1 != c2) return (c1 > c2);
+ s1 = quadrant[i1]; s2 = quadrant[i2];
+ if (s1 != s2) return (s1 > s2);
+ i1++; i2++;
+
+ if (i1 >= nblock) i1 -= nblock;
+ if (i2 >= nblock) i2 -= nblock;
+
+ k -= 8;
+ (*budget)--;
+ }
+ while (k >= 0);
+
+ return False;
+}
+
+
+/*---------------------------------------------*/
+/*--
+ Knuth's increments seem to work better
+ than Incerpi-Sedgewick here. Possibly
+ because the number of elems to sort is
+ usually small, typically <= 20.
+--*/
+static
+Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280,
+ 9841, 29524, 88573, 265720,
+ 797161, 2391484 };
+
+static
+void mainSimpleSort ( UInt32* ptr,
+ UChar* block,
+ UInt16* quadrant,
+ Int32 nblock,
+ Int32 lo,
+ Int32 hi,
+ Int32 d,
+ Int32* budget )
+{
+ Int32 i, j, h, bigN, hp;
+ UInt32 v;
+
+ bigN = hi - lo + 1;
+ if (bigN < 2) return;
+
+ hp = 0;
+ while (incs[hp] < bigN) hp++;
+ hp--;
+
+ for (; hp >= 0; hp--) {
+ h = incs[hp];
+
+ i = lo + h;
+ while (True) {
+
+ /*-- copy 1 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while ( mainGtU (
+ ptr[j-h]+d, v+d, block, quadrant, nblock, budget
+ ) ) {
+ ptr[j] = ptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) break;
+ }
+ ptr[j] = v;
+ i++;
+
+ /*-- copy 2 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while ( mainGtU (
+ ptr[j-h]+d, v+d, block, quadrant, nblock, budget
+ ) ) {
+ ptr[j] = ptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) break;
+ }
+ ptr[j] = v;
+ i++;
+
+ /*-- copy 3 --*/
+ if (i > hi) break;
+ v = ptr[i];
+ j = i;
+ while ( mainGtU (
+ ptr[j-h]+d, v+d, block, quadrant, nblock, budget
+ ) ) {
+ ptr[j] = ptr[j-h];
+ j = j - h;
+ if (j <= (lo + h - 1)) break;
+ }
+ ptr[j] = v;
+ i++;
+
+ if (*budget < 0) return;
+ }
+ }
+}
+
+
+/*---------------------------------------------*/
+/*--
+ The following is an implementation of
+ an elegant 3-way quicksort for strings,
+ described in a paper "Fast Algorithms for
+ Sorting and Searching Strings", by Robert
+ Sedgewick and Jon L. Bentley.
+--*/
+
+#define mswap(zz1, zz2) \
+ { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
+
+#define mvswap(zzp1, zzp2, zzn) \
+{ \
+ Int32 yyp1 = (zzp1); \
+ Int32 yyp2 = (zzp2); \
+ Int32 yyn = (zzn); \
+ while (yyn > 0) { \
+ mswap(ptr[yyp1], ptr[yyp2]); \
+ yyp1++; yyp2++; yyn--; \
+ } \
+}
+
+static
+__inline__
+UChar mmed3 ( UChar a, UChar b, UChar c )
+{
+ UChar t;
+ if (a > b) { t = a; a = b; b = t; };
+ if (b > c) {
+ b = c;
+ if (a > b) b = a;
+ }
+ return b;
+}
+
+#define mmin(a,b) ((a) < (b)) ? (a) : (b)
+
+#define mpush(lz,hz,dz) { stackLo[sp] = lz; \
+ stackHi[sp] = hz; \
+ stackD [sp] = dz; \
+ sp++; }
+
+#define mpop(lz,hz,dz) { sp--; \
+ lz = stackLo[sp]; \
+ hz = stackHi[sp]; \
+ dz = stackD [sp]; }
+
+
+#define mnextsize(az) (nextHi[az]-nextLo[az])
+
+#define mnextswap(az,bz) \
+ { Int32 tz; \
+ tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \
+ tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \
+ tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; }
+
+
+#define MAIN_QSORT_SMALL_THRESH 20
+#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT)
+#define MAIN_QSORT_STACK_SIZE 100
+
+static
+void mainQSort3 ( UInt32* ptr,
+ UChar* block,
+ UInt16* quadrant,
+ Int32 nblock,
+ Int32 loSt,
+ Int32 hiSt,
+ Int32 dSt,
+ Int32* budget )
+{
+ Int32 unLo, unHi, ltLo, gtHi, n, m, med;
+ Int32 sp, lo, hi, d;
+
+ Int32 stackLo[MAIN_QSORT_STACK_SIZE];
+ Int32 stackHi[MAIN_QSORT_STACK_SIZE];
+ Int32 stackD [MAIN_QSORT_STACK_SIZE];
+
+ Int32 nextLo[3];
+ Int32 nextHi[3];
+ Int32 nextD [3];
+
+ sp = 0;
+ mpush ( loSt, hiSt, dSt );
+
+ while (sp > 0) {
+
+ AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 );
+
+ mpop ( lo, hi, d );
+ if (hi - lo < MAIN_QSORT_SMALL_THRESH ||
+ d > MAIN_QSORT_DEPTH_THRESH) {
+ mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget );
+ if (*budget < 0) return;
+ continue;
+ }
+
+ med = (Int32)
+ mmed3 ( block[ptr[ lo ]+d],
+ block[ptr[ hi ]+d],
+ block[ptr[ (lo+hi)>>1 ]+d] );
+
+ unLo = ltLo = lo;
+ unHi = gtHi = hi;
+
+ while (True) {
+ while (True) {
+ if (unLo > unHi) break;
+ n = ((Int32)block[ptr[unLo]+d]) - med;
+ if (n == 0) {
+ mswap(ptr[unLo], ptr[ltLo]);
+ ltLo++; unLo++; continue;
+ };
+ if (n > 0) break;
+ unLo++;
+ }
+ while (True) {
+ if (unLo > unHi) break;
+ n = ((Int32)block[ptr[unHi]+d]) - med;
+ if (n == 0) {
+ mswap(ptr[unHi], ptr[gtHi]);
+ gtHi--; unHi--; continue;
+ };
+ if (n < 0) break;
+ unHi--;
+ }
+ if (unLo > unHi) break;
+ mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--;
+ }
+
+ AssertD ( unHi == unLo-1, "mainQSort3(2)" );
+
+ if (gtHi < ltLo) {
+ mpush(lo, hi, d+1 );
+ continue;
+ }
+
+ n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n);
+ m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m);
+
+ n = lo + unLo - ltLo - 1;
+ m = hi - (gtHi - unHi) + 1;
+
+ nextLo[0] = lo; nextHi[0] = n; nextD[0] = d;
+ nextLo[1] = m; nextHi[1] = hi; nextD[1] = d;
+ nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1;
+
+ if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
+ if (mnextsize(1) < mnextsize(2)) mnextswap(1,2);
+ if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
+
+ AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" );
+ AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" );
+
+ mpush (nextLo[0], nextHi[0], nextD[0]);
+ mpush (nextLo[1], nextHi[1], nextD[1]);
+ mpush (nextLo[2], nextHi[2], nextD[2]);
+ }
+}
+
+#undef mswap
+#undef mvswap
+#undef mpush
+#undef mpop
+#undef mmin
+#undef mnextsize
+#undef mnextswap
+#undef MAIN_QSORT_SMALL_THRESH
+#undef MAIN_QSORT_DEPTH_THRESH
+#undef MAIN_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+ nblock > N_OVERSHOOT
+ block32 exists for [0 .. nblock-1 +N_OVERSHOOT]
+ ((UChar*)block32) [0 .. nblock-1] holds block
+ ptr exists for [0 .. nblock-1]
+
+ Post:
+ ((UChar*)block32) [0 .. nblock-1] holds block
+ All other areas of block32 destroyed
+ ftab [0 .. 65536 ] destroyed
+ ptr [0 .. nblock-1] holds sorted order
+ if (*budget < 0), sorting was abandoned
+*/
+
+#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8])
+#define SETMASK (1 << 21)
+#define CLEARMASK (~(SETMASK))
+
+static
+void mainSort ( UInt32* ptr,
+ UChar* block,
+ UInt16* quadrant,
+ UInt32* ftab,
+ Int32 nblock,
+ Int32 verb,
+ Int32* budget )
+{
+ Int32 i, j, k, ss, sb;
+ Int32 runningOrder[256];
+ Bool bigDone[256];
+ Int32 copyStart[256];
+ Int32 copyEnd [256];
+ UChar c1;
+ Int32 numQSorted;
+ UInt16 s;
+ if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" );
+
+ /*-- set up the 2-byte frequency table --*/
+ for (i = 65536; i >= 0; i--) ftab[i] = 0;
+
+ j = block[0] << 8;
+ i = nblock-1;
+ for (; i >= 3; i -= 4) {
+ quadrant[i] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i]) << 8);
+ ftab[j]++;
+ quadrant[i-1] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i-1]) << 8);
+ ftab[j]++;
+ quadrant[i-2] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i-2]) << 8);
+ ftab[j]++;
+ quadrant[i-3] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i-3]) << 8);
+ ftab[j]++;
+ }
+ for (; i >= 0; i--) {
+ quadrant[i] = 0;
+ j = (j >> 8) | ( ((UInt16)block[i]) << 8);
+ ftab[j]++;
+ }
+
+ /*-- (emphasises close relationship of block & quadrant) --*/
+ for (i = 0; i < BZ_N_OVERSHOOT; i++) {
+ block [nblock+i] = block[i];
+ quadrant[nblock+i] = 0;
+ }
+
+ if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" );
+
+ /*-- Complete the initial radix sort --*/
+ for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1];
+
+ s = block[0] << 8;
+ i = nblock-1;
+ for (; i >= 3; i -= 4) {
+ s = (s >> 8) | (block[i] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i;
+ s = (s >> 8) | (block[i-1] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i-1;
+ s = (s >> 8) | (block[i-2] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i-2;
+ s = (s >> 8) | (block[i-3] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i-3;
+ }
+ for (; i >= 0; i--) {
+ s = (s >> 8) | (block[i] << 8);
+ j = ftab[s] -1;
+ ftab[s] = j;
+ ptr[j] = i;
+ }
+
+ /*--
+ Now ftab contains the first loc of every small bucket.
+ Calculate the running order, from smallest to largest
+ big bucket.
+ --*/
+ for (i = 0; i <= 255; i++) {
+ bigDone [i] = False;
+ runningOrder[i] = i;
+ }
+
+ {
+ Int32 vv;
+ Int32 h = 1;
+ do h = 3 * h + 1; while (h <= 256);
+ do {
+ h = h / 3;
+ for (i = h; i <= 255; i++) {
+ vv = runningOrder[i];
+ j = i;
+ while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) {
+ runningOrder[j] = runningOrder[j-h];
+ j = j - h;
+ if (j <= (h - 1)) goto zero;
+ }
+ zero:
+ runningOrder[j] = vv;
+ }
+ } while (h != 1);
+ }
+
+ /*--
+ The main sorting loop.
+ --*/
+
+ numQSorted = 0;
+
+ for (i = 0; i <= 255; i++) {
+
+ /*--
+ Process big buckets, starting with the least full.
+ Basically this is a 3-step process in which we call
+ mainQSort3 to sort the small buckets [ss, j], but
+ also make a big effort to avoid the calls if we can.
+ --*/
+ ss = runningOrder[i];
+
+ /*--
+ Step 1:
+ Complete the big bucket [ss] by quicksorting
+ any unsorted small buckets [ss, j], for j != ss.
+ Hopefully previous pointer-scanning phases have already
+ completed many of the small buckets [ss, j], so
+ we don't have to sort them at all.
+ --*/
+ for (j = 0; j <= 255; j++) {
+ if (j != ss) {
+ sb = (ss << 8) + j;
+ if ( ! (ftab[sb] & SETMASK) ) {
+ Int32 lo = ftab[sb] & CLEARMASK;
+ Int32 hi = (ftab[sb+1] & CLEARMASK) - 1;
+ if (hi > lo) {
+ if (verb >= 4)
+ VPrintf4 ( " qsort [0x%x, 0x%x] "
+ "done %d this %d\n",
+ ss, j, numQSorted, hi - lo + 1 );
+ mainQSort3 (
+ ptr, block, quadrant, nblock,
+ lo, hi, BZ_N_RADIX, budget
+ );
+ numQSorted += (hi - lo + 1);
+ if (*budget < 0) return;
+ }
+ }
+ ftab[sb] |= SETMASK;
+ }
+ }
+
+ AssertH ( !bigDone[ss], 1006 );
+
+ /*--
+ Step 2:
+ Now scan this big bucket [ss] so as to synthesise the
+ sorted order for small buckets [t, ss] for all t,
+ including, magically, the bucket [ss,ss] too.
+ This will avoid doing Real Work in subsequent Step 1's.
+ --*/
+ {
+ for (j = 0; j <= 255; j++) {
+ copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK;
+ copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1;
+ }
+ for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) {
+ k = ptr[j]-1; if (k < 0) k += nblock;
+ c1 = block[k];
+ if (!bigDone[c1])
+ ptr[ copyStart[c1]++ ] = k;
+ }
+ for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) {
+ k = ptr[j]-1; if (k < 0) k += nblock;
+ c1 = block[k];
+ if (!bigDone[c1])
+ ptr[ copyEnd[c1]-- ] = k;
+ }
+ }
+
+ AssertH ( (copyStart[ss]-1 == copyEnd[ss])
+ ||
+ /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1.
+ Necessity for this case is demonstrated by compressing
+ a sequence of approximately 48.5 million of character
+ 251; 1.0.0/1.0.1 will then die here. */
+ (copyStart[ss] == 0 && copyEnd[ss] == nblock-1),
+ 1007 )
+
+ for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK;
+
+ /*--
+ Step 3:
+ The [ss] big bucket is now done. Record this fact,
+ and update the quadrant descriptors. Remember to
+ update quadrants in the overshoot area too, if
+ necessary. The "if (i < 255)" test merely skips
+ this updating for the last bucket processed, since
+ updating for the last bucket is pointless.
+
+ The quadrant array provides a way to incrementally
+ cache sort orderings, as they appear, so as to
+ make subsequent comparisons in fullGtU() complete
+ faster. For repetitive blocks this makes a big
+ difference (but not big enough to be able to avoid
+ the fallback sorting mechanism, exponential radix sort).
+
+ The precise meaning is: at all times:
+
+ for 0 <= i < nblock and 0 <= j <= nblock
+
+ if block[i] != block[j],
+
+ then the relative values of quadrant[i] and
+ quadrant[j] are meaningless.
+
+ else {
+ if quadrant[i] < quadrant[j]
+ then the string starting at i lexicographically
+ precedes the string starting at j
+
+ else if quadrant[i] > quadrant[j]
+ then the string starting at j lexicographically
+ precedes the string starting at i
+
+ else
+ the relative ordering of the strings starting
+ at i and j has not yet been determined.
+ }
+ --*/
+ bigDone[ss] = True;
+
+ if (i < 255) {
+ Int32 bbStart = ftab[ss << 8] & CLEARMASK;
+ Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;
+ Int32 shifts = 0;
+
+ while ((bbSize >> shifts) > 65534) shifts++;
+
+ for (j = bbSize-1; j >= 0; j--) {
+ Int32 a2update = ptr[bbStart + j];
+ UInt16 qVal = (UInt16)(j >> shifts);
+ quadrant[a2update] = qVal;
+ if (a2update < BZ_N_OVERSHOOT)
+ quadrant[a2update + nblock] = qVal;
+ }
+ AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 );
+ }
+
+ }
+
+ if (verb >= 4)
+ VPrintf3 ( " %d pointers, %d sorted, %d scanned\n",
+ nblock, numQSorted, nblock - numQSorted );
+}
+
+#undef BIGFREQ
+#undef SETMASK
+#undef CLEARMASK
+
+
+/*---------------------------------------------*/
+/* Pre:
+ nblock > 0
+ arr2 exists for [0 .. nblock-1 +N_OVERSHOOT]
+ ((UChar*)arr2) [0 .. nblock-1] holds block
+ arr1 exists for [0 .. nblock-1]
+
+ Post:
+ ((UChar*)arr2) [0 .. nblock-1] holds block
+ All other areas of block destroyed
+ ftab [ 0 .. 65536 ] destroyed
+ arr1 [0 .. nblock-1] holds sorted order
+*/
+void BZ2_blockSort ( EState* s )
+{
+ UInt32* ptr = s->ptr;
+ UChar* block = s->block;
+ UInt32* ftab = s->ftab;
+ Int32 nblock = s->nblock;
+ Int32 verb = s->verbosity;
+ Int32 wfact = s->workFactor;
+ UInt16* quadrant;
+ Int32 budget;
+ Int32 budgetInit;
+ Int32 i;
+
+ if (nblock < 10000) {
+ fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
+ } else {
+ /* Calculate the location for quadrant, remembering to get
+ the alignment right. Assumes that &(block[0]) is at least
+ 2-byte aligned -- this should be ok since block is really
+ the first section of arr2.
+ */
+ i = nblock+BZ_N_OVERSHOOT;
+ if (i & 1) i++;
+ quadrant = (UInt16*)(&(block[i]));
+
+ /* (wfact-1) / 3 puts the default-factor-30
+ transition point at very roughly the same place as
+ with v0.1 and v0.9.0.
+ Not that it particularly matters any more, since the
+ resulting compressed stream is now the same regardless
+ of whether or not we use the main sort or fallback sort.
+ */
+ if (wfact < 1 ) wfact = 1;
+ if (wfact > 100) wfact = 100;
+ budgetInit = nblock * ((wfact-1) / 3);
+ budget = budgetInit;
+
+ mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget );
+ if (verb >= 3)
+ VPrintf3 ( " %d work, %d block, ratio %5.2f\n",
+ budgetInit - budget,
+ nblock,
+ (float)(budgetInit - budget) /
+ (float)(nblock==0 ? 1 : nblock) );
+ if (budget < 0) {
+ if (verb >= 2)
+ VPrintf0 ( " too repetitive; using fallback"
+ " sorting algorithm\n" );
+ fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
+ }
+ }
+
+ s->origPtr = -1;
+ for (i = 0; i < s->nblock; i++)
+ if (ptr[i] == 0)
+ { s->origPtr = i; break; };
+
+ AssertH( s->origPtr != -1, 1003 );
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end blocksort.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/utils/bzip2/bzlib.c b/utils/bzip2/bzlib.c
new file mode 100644
index 0000000000..6e78e19407
--- /dev/null
+++ b/utils/bzip2/bzlib.c
@@ -0,0 +1,1572 @@
+
+/*-------------------------------------------------------------*/
+/*--- Library top-level functions. ---*/
+/*--- bzlib.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.6 of 6 September 2010
+ Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+/* CHANGES
+ 0.9.0 -- original version.
+ 0.9.0a/b -- no changes in this file.
+ 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress().
+ fixed bzWrite/bzRead to ignore zero-length requests.
+ fixed bzread to correctly handle read requests after EOF.
+ wrong parameter order in call to bzDecompressInit in
+ bzBuffToBuffDecompress. Fixed.
+*/
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+/*--- Compression stuff ---*/
+/*---------------------------------------------------*/
+
+
+/*---------------------------------------------------*/
+#ifndef BZ_NO_STDIO
+void BZ2_bz__AssertH__fail ( int errcode )
+{
+ fprintf(stderr,
+ "\n\nbzip2/libbzip2: internal error number %d.\n"
+ "This is a bug in bzip2/libbzip2, %s.\n"
+ "Please report it to me at: jseward@bzip.org. If this happened\n"
+ "when you were using some program which uses libbzip2 as a\n"
+ "component, you should also report this bug to the author(s)\n"
+ "of that program. Please make an effort to report this bug;\n"
+ "timely and accurate bug reports eventually lead to higher\n"
+ "quality software. Thanks. Julian Seward, 10 December 2007.\n\n",
+ errcode,
+ BZ2_bzlibVersion()
+ );
+
+ if (errcode == 1007) {
+ fprintf(stderr,
+ "\n*** A special note about internal error number 1007 ***\n"
+ "\n"
+ "Experience suggests that a common cause of i.e. 1007\n"
+ "is unreliable memory or other hardware. The 1007 assertion\n"
+ "just happens to cross-check the results of huge numbers of\n"
+ "memory reads/writes, and so acts (unintendedly) as a stress\n"
+ "test of your memory system.\n"
+ "\n"
+ "I suggest the following: try compressing the file again,\n"
+ "possibly monitoring progress in detail with the -vv flag.\n"
+ "\n"
+ "* If the error cannot be reproduced, and/or happens at different\n"
+ " points in compression, you may have a flaky memory system.\n"
+ " Try a memory-test program. I have used Memtest86\n"
+ " (www.memtest86.com). At the time of writing it is free (GPLd).\n"
+ " Memtest86 tests memory much more thorougly than your BIOSs\n"
+ " power-on test, and may find failures that the BIOS doesn't.\n"
+ "\n"
+ "* If the error can be repeatably reproduced, this is a bug in\n"
+ " bzip2, and I would very much like to hear about it. Please\n"
+ " let me know, and, ideally, save a copy of the file causing the\n"
+ " problem -- without which I will be unable to investigate it.\n"
+ "\n"
+ );
+ }
+
+ exit(3);
+}
+#endif
+
+
+/*---------------------------------------------------*/
+static
+int bz_config_ok ( void )
+{
+ if (sizeof(int) != 4) return 0;
+ if (sizeof(short) != 2) return 0;
+ if (sizeof(char) != 1) return 0;
+ return 1;
+}
+
+
+/*---------------------------------------------------*/
+static
+void* default_bzalloc ( void* opaque, Int32 items, Int32 size )
+{
+ void* v = malloc ( items * size );
+ return v;
+}
+
+static
+void default_bzfree ( void* opaque, void* addr )
+{
+ if (addr != NULL) free ( addr );
+}
+
+
+/*---------------------------------------------------*/
+static
+void prepare_new_block ( EState* s )
+{
+ Int32 i;
+ s->nblock = 0;
+ s->numZ = 0;
+ s->state_out_pos = 0;
+ BZ_INITIALISE_CRC ( s->blockCRC );
+ for (i = 0; i < 256; i++) s->inUse[i] = False;
+ s->blockNo++;
+}
+
+
+/*---------------------------------------------------*/
+static
+void init_RL ( EState* s )
+{
+ s->state_in_ch = 256;
+ s->state_in_len = 0;
+}
+
+
+static
+Bool isempty_RL ( EState* s )
+{
+ if (s->state_in_ch < 256 && s->state_in_len > 0)
+ return False; else
+ return True;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompressInit)
+ ( bz_stream* strm,
+ int blockSize100k,
+ int verbosity,
+ int workFactor )
+{
+ Int32 n;
+ EState* s;
+
+ if (!bz_config_ok()) return BZ_CONFIG_ERROR;
+
+ if (strm == NULL ||
+ blockSize100k < 1 || blockSize100k > 9 ||
+ workFactor < 0 || workFactor > 250)
+ return BZ_PARAM_ERROR;
+
+ if (workFactor == 0) workFactor = 30;
+ if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
+ if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
+
+ s = BZALLOC( sizeof(EState) );
+ if (s == NULL) return BZ_MEM_ERROR;
+ s->strm = strm;
+
+ s->arr1 = NULL;
+ s->arr2 = NULL;
+ s->ftab = NULL;
+
+ n = 100000 * blockSize100k;
+ s->arr1 = BZALLOC( n * sizeof(UInt32) );
+ s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) );
+ s->ftab = BZALLOC( 65537 * sizeof(UInt32) );
+
+ if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) {
+ if (s->arr1 != NULL) BZFREE(s->arr1);
+ if (s->arr2 != NULL) BZFREE(s->arr2);
+ if (s->ftab != NULL) BZFREE(s->ftab);
+ if (s != NULL) BZFREE(s);
+ return BZ_MEM_ERROR;
+ }
+
+ s->blockNo = 0;
+ s->state = BZ_S_INPUT;
+ s->mode = BZ_M_RUNNING;
+ s->combinedCRC = 0;
+ s->blockSize100k = blockSize100k;
+ s->nblockMAX = 100000 * blockSize100k - 19;
+ s->verbosity = verbosity;
+ s->workFactor = workFactor;
+
+ s->block = (UChar*)s->arr2;
+ s->mtfv = (UInt16*)s->arr1;
+ s->zbits = NULL;
+ s->ptr = (UInt32*)s->arr1;
+
+ strm->state = s;
+ strm->total_in_lo32 = 0;
+ strm->total_in_hi32 = 0;
+ strm->total_out_lo32 = 0;
+ strm->total_out_hi32 = 0;
+ init_RL ( s );
+ prepare_new_block ( s );
+ return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+static
+void add_pair_to_block ( EState* s )
+{
+ Int32 i;
+ UChar ch = (UChar)(s->state_in_ch);
+ for (i = 0; i < s->state_in_len; i++) {
+ BZ_UPDATE_CRC( s->blockCRC, ch );
+ }
+ s->inUse[s->state_in_ch] = True;
+ switch (s->state_in_len) {
+ case 1:
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ break;
+ case 2:
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ break;
+ case 3:
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ break;
+ default:
+ s->inUse[s->state_in_len-4] = True;
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ s->block[s->nblock] = (UChar)ch; s->nblock++;
+ s->block[s->nblock] = ((UChar)(s->state_in_len-4));
+ s->nblock++;
+ break;
+ }
+}
+
+
+/*---------------------------------------------------*/
+static
+void flush_RL ( EState* s )
+{
+ if (s->state_in_ch < 256) add_pair_to_block ( s );
+ init_RL ( s );
+}
+
+
+/*---------------------------------------------------*/
+#define ADD_CHAR_TO_BLOCK(zs,zchh0) \
+{ \
+ UInt32 zchh = (UInt32)(zchh0); \
+ /*-- fast track the common case --*/ \
+ if (zchh != zs->state_in_ch && \
+ zs->state_in_len == 1) { \
+ UChar ch = (UChar)(zs->state_in_ch); \
+ BZ_UPDATE_CRC( zs->blockCRC, ch ); \
+ zs->inUse[zs->state_in_ch] = True; \
+ zs->block[zs->nblock] = (UChar)ch; \
+ zs->nblock++; \
+ zs->state_in_ch = zchh; \
+ } \
+ else \
+ /*-- general, uncommon cases --*/ \
+ if (zchh != zs->state_in_ch || \
+ zs->state_in_len == 255) { \
+ if (zs->state_in_ch < 256) \
+ add_pair_to_block ( zs ); \
+ zs->state_in_ch = zchh; \
+ zs->state_in_len = 1; \
+ } else { \
+ zs->state_in_len++; \
+ } \
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool copy_input_until_stop ( EState* s )
+{
+ Bool progress_in = False;
+
+ if (s->mode == BZ_M_RUNNING) {
+
+ /*-- fast track the common case --*/
+ while (True) {
+ /*-- block full? --*/
+ if (s->nblock >= s->nblockMAX) break;
+ /*-- no input? --*/
+ if (s->strm->avail_in == 0) break;
+ progress_in = True;
+ ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) );
+ s->strm->next_in++;
+ s->strm->avail_in--;
+ s->strm->total_in_lo32++;
+ if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
+ }
+
+ } else {
+
+ /*-- general, uncommon case --*/
+ while (True) {
+ /*-- block full? --*/
+ if (s->nblock >= s->nblockMAX) break;
+ /*-- no input? --*/
+ if (s->strm->avail_in == 0) break;
+ /*-- flush/finish end? --*/
+ if (s->avail_in_expect == 0) break;
+ progress_in = True;
+ ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) );
+ s->strm->next_in++;
+ s->strm->avail_in--;
+ s->strm->total_in_lo32++;
+ if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
+ s->avail_in_expect--;
+ }
+ }
+ return progress_in;
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool copy_output_until_stop ( EState* s )
+{
+ Bool progress_out = False;
+
+ while (True) {
+
+ /*-- no output space? --*/
+ if (s->strm->avail_out == 0) break;
+
+ /*-- block done? --*/
+ if (s->state_out_pos >= s->numZ) break;
+
+ progress_out = True;
+ *(s->strm->next_out) = s->zbits[s->state_out_pos];
+ s->state_out_pos++;
+ s->strm->avail_out--;
+ s->strm->next_out++;
+ s->strm->total_out_lo32++;
+ if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+ }
+
+ return progress_out;
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool handle_compress ( bz_stream* strm )
+{
+ Bool progress_in = False;
+ Bool progress_out = False;
+ EState* s = strm->state;
+
+ while (True) {
+
+ if (s->state == BZ_S_OUTPUT) {
+ progress_out |= copy_output_until_stop ( s );
+ if (s->state_out_pos < s->numZ) break;
+ if (s->mode == BZ_M_FINISHING &&
+ s->avail_in_expect == 0 &&
+ isempty_RL(s)) break;
+ prepare_new_block ( s );
+ s->state = BZ_S_INPUT;
+ if (s->mode == BZ_M_FLUSHING &&
+ s->avail_in_expect == 0 &&
+ isempty_RL(s)) break;
+ }
+
+ if (s->state == BZ_S_INPUT) {
+ progress_in |= copy_input_until_stop ( s );
+ if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
+ flush_RL ( s );
+ BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) );
+ s->state = BZ_S_OUTPUT;
+ }
+ else
+ if (s->nblock >= s->nblockMAX) {
+ BZ2_compressBlock ( s, False );
+ s->state = BZ_S_OUTPUT;
+ }
+ else
+ if (s->strm->avail_in == 0) {
+ break;
+ }
+ }
+
+ }
+
+ return progress_in || progress_out;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action )
+{
+ Bool progress;
+ EState* s;
+ if (strm == NULL) return BZ_PARAM_ERROR;
+ s = strm->state;
+ if (s == NULL) return BZ_PARAM_ERROR;
+ if (s->strm != strm) return BZ_PARAM_ERROR;
+
+ preswitch:
+ switch (s->mode) {
+
+ case BZ_M_IDLE:
+ return BZ_SEQUENCE_ERROR;
+
+ case BZ_M_RUNNING:
+ if (action == BZ_RUN) {
+ progress = handle_compress ( strm );
+ return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;
+ }
+ else
+ if (action == BZ_FLUSH) {
+ s->avail_in_expect = strm->avail_in;
+ s->mode = BZ_M_FLUSHING;
+ goto preswitch;
+ }
+ else
+ if (action == BZ_FINISH) {
+ s->avail_in_expect = strm->avail_in;
+ s->mode = BZ_M_FINISHING;
+ goto preswitch;
+ }
+ else
+ return BZ_PARAM_ERROR;
+
+ case BZ_M_FLUSHING:
+ if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR;
+ if (s->avail_in_expect != s->strm->avail_in)
+ return BZ_SEQUENCE_ERROR;
+ progress = handle_compress ( strm );
+ if (s->avail_in_expect > 0 || !isempty_RL(s) ||
+ s->state_out_pos < s->numZ) return BZ_FLUSH_OK;
+ s->mode = BZ_M_RUNNING;
+ return BZ_RUN_OK;
+
+ case BZ_M_FINISHING:
+ if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR;
+ if (s->avail_in_expect != s->strm->avail_in)
+ return BZ_SEQUENCE_ERROR;
+ progress = handle_compress ( strm );
+ if (!progress) return BZ_SEQUENCE_ERROR;
+ if (s->avail_in_expect > 0 || !isempty_RL(s) ||
+ s->state_out_pos < s->numZ) return BZ_FINISH_OK;
+ s->mode = BZ_M_IDLE;
+ return BZ_STREAM_END;
+ }
+ return BZ_OK; /*--not reached--*/
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm )
+{
+ EState* s;
+ if (strm == NULL) return BZ_PARAM_ERROR;
+ s = strm->state;
+ if (s == NULL) return BZ_PARAM_ERROR;
+ if (s->strm != strm) return BZ_PARAM_ERROR;
+
+ if (s->arr1 != NULL) BZFREE(s->arr1);
+ if (s->arr2 != NULL) BZFREE(s->arr2);
+ if (s->ftab != NULL) BZFREE(s->ftab);
+ BZFREE(strm->state);
+
+ strm->state = NULL;
+
+ return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+/*--- Decompression stuff ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompressInit)
+ ( bz_stream* strm,
+ int verbosity,
+ int small )
+{
+ DState* s;
+
+ if (!bz_config_ok()) return BZ_CONFIG_ERROR;
+
+ if (strm == NULL) return BZ_PARAM_ERROR;
+ if (small != 0 && small != 1) return BZ_PARAM_ERROR;
+ if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
+
+ if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
+ if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
+
+ s = BZALLOC( sizeof(DState) );
+ if (s == NULL) return BZ_MEM_ERROR;
+ s->strm = strm;
+ strm->state = s;
+ s->state = BZ_X_MAGIC_1;
+ s->bsLive = 0;
+ s->bsBuff = 0;
+ s->calculatedCombinedCRC = 0;
+ strm->total_in_lo32 = 0;
+ strm->total_in_hi32 = 0;
+ strm->total_out_lo32 = 0;
+ strm->total_out_hi32 = 0;
+ s->smallDecompress = (Bool)small;
+ s->ll4 = NULL;
+ s->ll16 = NULL;
+ s->tt = NULL;
+ s->currBlockNo = 0;
+ s->verbosity = verbosity;
+
+ return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+/* Return True iff data corruption is discovered.
+ Returns False if there is no problem.
+*/
+static
+Bool unRLE_obuf_to_output_FAST ( DState* s )
+{
+ UChar k1;
+
+ if (s->blockRandomised) {
+
+ while (True) {
+ /* try to finish existing run */
+ while (True) {
+ if (s->strm->avail_out == 0) return False;
+ if (s->state_out_len == 0) break;
+ *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+ BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+ s->state_out_len--;
+ s->strm->next_out++;
+ s->strm->avail_out--;
+ s->strm->total_out_lo32++;
+ if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+ }
+
+ /* can a new run be started? */
+ if (s->nblock_used == s->save_nblock+1) return False;
+
+ /* Only caused by corrupt data stream? */
+ if (s->nblock_used > s->save_nblock+1)
+ return True;
+
+ s->state_out_len = 1;
+ s->state_out_ch = s->k0;
+ BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ s->state_out_len = 2;
+ BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ s->state_out_len = 3;
+ BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ s->state_out_len = ((Int32)k1) + 4;
+ BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK;
+ s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
+ }
+
+ } else {
+
+ /* restore */
+ UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC;
+ UChar c_state_out_ch = s->state_out_ch;
+ Int32 c_state_out_len = s->state_out_len;
+ Int32 c_nblock_used = s->nblock_used;
+ Int32 c_k0 = s->k0;
+ UInt32* c_tt = s->tt;
+ UInt32 c_tPos = s->tPos;
+ char* cs_next_out = s->strm->next_out;
+ unsigned int cs_avail_out = s->strm->avail_out;
+ Int32 ro_blockSize100k = s->blockSize100k;
+ /* end restore */
+
+ UInt32 avail_out_INIT = cs_avail_out;
+ Int32 s_save_nblockPP = s->save_nblock+1;
+ unsigned int total_out_lo32_old;
+
+ while (True) {
+
+ /* try to finish existing run */
+ if (c_state_out_len > 0) {
+ while (True) {
+ if (cs_avail_out == 0) goto return_notr;
+ if (c_state_out_len == 1) break;
+ *( (UChar*)(cs_next_out) ) = c_state_out_ch;
+ BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
+ c_state_out_len--;
+ cs_next_out++;
+ cs_avail_out--;
+ }
+ s_state_out_len_eq_one:
+ {
+ if (cs_avail_out == 0) {
+ c_state_out_len = 1; goto return_notr;
+ };
+ *( (UChar*)(cs_next_out) ) = c_state_out_ch;
+ BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
+ cs_next_out++;
+ cs_avail_out--;
+ }
+ }
+ /* Only caused by corrupt data stream? */
+ if (c_nblock_used > s_save_nblockPP)
+ return True;
+
+ /* can a new run be started? */
+ if (c_nblock_used == s_save_nblockPP) {
+ c_state_out_len = 0; goto return_notr;
+ };
+ c_state_out_ch = c_k0;
+ BZ_GET_FAST_C(k1); c_nblock_used++;
+ if (k1 != c_k0) {
+ c_k0 = k1; goto s_state_out_len_eq_one;
+ };
+ if (c_nblock_used == s_save_nblockPP)
+ goto s_state_out_len_eq_one;
+
+ c_state_out_len = 2;
+ BZ_GET_FAST_C(k1); c_nblock_used++;
+ if (c_nblock_used == s_save_nblockPP) continue;
+ if (k1 != c_k0) { c_k0 = k1; continue; };
+
+ c_state_out_len = 3;
+ BZ_GET_FAST_C(k1); c_nblock_used++;
+ if (c_nblock_used == s_save_nblockPP) continue;
+ if (k1 != c_k0) { c_k0 = k1; continue; };
+
+ BZ_GET_FAST_C(k1); c_nblock_used++;
+ c_state_out_len = ((Int32)k1) + 4;
+ BZ_GET_FAST_C(c_k0); c_nblock_used++;
+ }
+
+ return_notr:
+ total_out_lo32_old = s->strm->total_out_lo32;
+ s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
+ if (s->strm->total_out_lo32 < total_out_lo32_old)
+ s->strm->total_out_hi32++;
+
+ /* save */
+ s->calculatedBlockCRC = c_calculatedBlockCRC;
+ s->state_out_ch = c_state_out_ch;
+ s->state_out_len = c_state_out_len;
+ s->nblock_used = c_nblock_used;
+ s->k0 = c_k0;
+ s->tt = c_tt;
+ s->tPos = c_tPos;
+ s->strm->next_out = cs_next_out;
+ s->strm->avail_out = cs_avail_out;
+ /* end save */
+ }
+ return False;
+}
+
+
+
+/*---------------------------------------------------*/
+__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab )
+{
+ Int32 nb, na, mid;
+ nb = 0;
+ na = 256;
+ do {
+ mid = (nb + na) >> 1;
+ if (indx >= cftab[mid]) nb = mid; else na = mid;
+ }
+ while (na - nb != 1);
+ return nb;
+}
+
+
+/*---------------------------------------------------*/
+/* Return True iff data corruption is discovered.
+ Returns False if there is no problem.
+*/
+static
+Bool unRLE_obuf_to_output_SMALL ( DState* s )
+{
+ UChar k1;
+
+ if (s->blockRandomised) {
+
+ while (True) {
+ /* try to finish existing run */
+ while (True) {
+ if (s->strm->avail_out == 0) return False;
+ if (s->state_out_len == 0) break;
+ *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+ BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+ s->state_out_len--;
+ s->strm->next_out++;
+ s->strm->avail_out--;
+ s->strm->total_out_lo32++;
+ if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+ }
+
+ /* can a new run be started? */
+ if (s->nblock_used == s->save_nblock+1) return False;
+
+ /* Only caused by corrupt data stream? */
+ if (s->nblock_used > s->save_nblock+1)
+ return True;
+
+ s->state_out_len = 1;
+ s->state_out_ch = s->k0;
+ BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ s->state_out_len = 2;
+ BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ s->state_out_len = 3;
+ BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
+ k1 ^= BZ_RAND_MASK; s->nblock_used++;
+ s->state_out_len = ((Int32)k1) + 4;
+ BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK;
+ s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
+ }
+
+ } else {
+
+ while (True) {
+ /* try to finish existing run */
+ while (True) {
+ if (s->strm->avail_out == 0) return False;
+ if (s->state_out_len == 0) break;
+ *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+ BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+ s->state_out_len--;
+ s->strm->next_out++;
+ s->strm->avail_out--;
+ s->strm->total_out_lo32++;
+ if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+ }
+
+ /* can a new run be started? */
+ if (s->nblock_used == s->save_nblock+1) return False;
+
+ /* Only caused by corrupt data stream? */
+ if (s->nblock_used > s->save_nblock+1)
+ return True;
+
+ s->state_out_len = 1;
+ s->state_out_ch = s->k0;
+ BZ_GET_SMALL(k1); s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ s->state_out_len = 2;
+ BZ_GET_SMALL(k1); s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ s->state_out_len = 3;
+ BZ_GET_SMALL(k1); s->nblock_used++;
+ if (s->nblock_used == s->save_nblock+1) continue;
+ if (k1 != s->k0) { s->k0 = k1; continue; };
+
+ BZ_GET_SMALL(k1); s->nblock_used++;
+ s->state_out_len = ((Int32)k1) + 4;
+ BZ_GET_SMALL(s->k0); s->nblock_used++;
+ }
+
+ }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
+{
+ Bool corrupt;
+ DState* s;
+ if (strm == NULL) return BZ_PARAM_ERROR;
+ s = strm->state;
+ if (s == NULL) return BZ_PARAM_ERROR;
+ if (s->strm != strm) return BZ_PARAM_ERROR;
+
+ while (True) {
+ if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
+ if (s->state == BZ_X_OUTPUT) {
+ if (s->smallDecompress)
+ corrupt = unRLE_obuf_to_output_SMALL ( s ); else
+ corrupt = unRLE_obuf_to_output_FAST ( s );
+ if (corrupt) return BZ_DATA_ERROR;
+ if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
+ BZ_FINALISE_CRC ( s->calculatedBlockCRC );
+ if (s->verbosity >= 3)
+ VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC,
+ s->calculatedBlockCRC );
+ if (s->verbosity >= 2) VPrintf0 ( "]" );
+ if (s->calculatedBlockCRC != s->storedBlockCRC)
+ return BZ_DATA_ERROR;
+ s->calculatedCombinedCRC
+ = (s->calculatedCombinedCRC << 1) |
+ (s->calculatedCombinedCRC >> 31);
+ s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
+ s->state = BZ_X_BLKHDR_1;
+ } else {
+ return BZ_OK;
+ }
+ }
+ if (s->state >= BZ_X_MAGIC_1) {
+ Int32 r = BZ2_decompress ( s );
+ if (r == BZ_STREAM_END) {
+ if (s->verbosity >= 3)
+ VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x",
+ s->storedCombinedCRC, s->calculatedCombinedCRC );
+ if (s->calculatedCombinedCRC != s->storedCombinedCRC)
+ return BZ_DATA_ERROR;
+ return r;
+ }
+ if (s->state != BZ_X_OUTPUT) return r;
+ }
+ }
+
+ AssertH ( 0, 6001 );
+
+ return 0; /*NOTREACHED*/
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm )
+{
+ DState* s;
+ if (strm == NULL) return BZ_PARAM_ERROR;
+ s = strm->state;
+ if (s == NULL) return BZ_PARAM_ERROR;
+ if (s->strm != strm) return BZ_PARAM_ERROR;
+
+ if (s->tt != NULL) BZFREE(s->tt);
+ if (s->ll16 != NULL) BZFREE(s->ll16);
+ if (s->ll4 != NULL) BZFREE(s->ll4);
+
+ BZFREE(strm->state);
+ strm->state = NULL;
+
+ return BZ_OK;
+}
+
+
+#ifndef BZ_NO_STDIO
+/*---------------------------------------------------*/
+/*--- File I/O stuff ---*/
+/*---------------------------------------------------*/
+
+#define BZ_SETERR(eee) \
+{ \
+ if (bzerror != NULL) *bzerror = eee; \
+ if (bzf != NULL) bzf->lastErr = eee; \
+}
+
+typedef
+ struct {
+ FILE* handle;
+ Char buf[BZ_MAX_UNUSED];
+ Int32 bufN;
+ Bool writing;
+ bz_stream strm;
+ Int32 lastErr;
+ Bool initialisedOk;
+ }
+ bzFile;
+
+
+/*---------------------------------------------*/
+static Bool myfeof ( FILE* f )
+{
+ Int32 c = fgetc ( f );
+ if (c == EOF) return True;
+ ungetc ( c, f );
+ return False;
+}
+
+
+/*---------------------------------------------------*/
+BZFILE* BZ_API(BZ2_bzWriteOpen)
+ ( int* bzerror,
+ FILE* f,
+ int blockSize100k,
+ int verbosity,
+ int workFactor )
+{
+ Int32 ret;
+ bzFile* bzf = NULL;
+
+ BZ_SETERR(BZ_OK);
+
+ if (f == NULL ||
+ (blockSize100k < 1 || blockSize100k > 9) ||
+ (workFactor < 0 || workFactor > 250) ||
+ (verbosity < 0 || verbosity > 4))
+ { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
+
+ if (ferror(f))
+ { BZ_SETERR(BZ_IO_ERROR); return NULL; };
+
+ bzf = malloc ( sizeof(bzFile) );
+ if (bzf == NULL)
+ { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
+
+ BZ_SETERR(BZ_OK);
+ bzf->initialisedOk = False;
+ bzf->bufN = 0;
+ bzf->handle = f;
+ bzf->writing = True;
+ bzf->strm.bzalloc = NULL;
+ bzf->strm.bzfree = NULL;
+ bzf->strm.opaque = NULL;
+
+ if (workFactor == 0) workFactor = 30;
+ ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k,
+ verbosity, workFactor );
+ if (ret != BZ_OK)
+ { BZ_SETERR(ret); free(bzf); return NULL; };
+
+ bzf->strm.avail_in = 0;
+ bzf->initialisedOk = True;
+ return bzf;
+}
+
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzWrite)
+ ( int* bzerror,
+ BZFILE* b,
+ void* buf,
+ int len )
+{
+ Int32 n, n2, ret;
+ bzFile* bzf = (bzFile*)b;
+
+ BZ_SETERR(BZ_OK);
+ if (bzf == NULL || buf == NULL || len < 0)
+ { BZ_SETERR(BZ_PARAM_ERROR); return; };
+ if (!(bzf->writing))
+ { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+ if (ferror(bzf->handle))
+ { BZ_SETERR(BZ_IO_ERROR); return; };
+
+ if (len == 0)
+ { BZ_SETERR(BZ_OK); return; };
+
+ bzf->strm.avail_in = len;
+ bzf->strm.next_in = buf;
+
+ while (True) {
+ bzf->strm.avail_out = BZ_MAX_UNUSED;
+ bzf->strm.next_out = bzf->buf;
+ ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN );
+ if (ret != BZ_RUN_OK)
+ { BZ_SETERR(ret); return; };
+
+ if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
+ n = BZ_MAX_UNUSED - bzf->strm.avail_out;
+ n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
+ n, bzf->handle );
+ if (n != n2 || ferror(bzf->handle))
+ { BZ_SETERR(BZ_IO_ERROR); return; };
+ }
+
+ if (bzf->strm.avail_in == 0)
+ { BZ_SETERR(BZ_OK); return; };
+ }
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzWriteClose)
+ ( int* bzerror,
+ BZFILE* b,
+ int abandon,
+ unsigned int* nbytes_in,
+ unsigned int* nbytes_out )
+{
+ BZ2_bzWriteClose64 ( bzerror, b, abandon,
+ nbytes_in, NULL, nbytes_out, NULL );
+}
+
+
+void BZ_API(BZ2_bzWriteClose64)
+ ( int* bzerror,
+ BZFILE* b,
+ int abandon,
+ unsigned int* nbytes_in_lo32,
+ unsigned int* nbytes_in_hi32,
+ unsigned int* nbytes_out_lo32,
+ unsigned int* nbytes_out_hi32 )
+{
+ Int32 n, n2, ret;
+ bzFile* bzf = (bzFile*)b;
+
+ if (bzf == NULL)
+ { BZ_SETERR(BZ_OK); return; };
+ if (!(bzf->writing))
+ { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+ if (ferror(bzf->handle))
+ { BZ_SETERR(BZ_IO_ERROR); return; };
+
+ if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0;
+ if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0;
+ if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0;
+ if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0;
+
+ if ((!abandon) && bzf->lastErr == BZ_OK) {
+ while (True) {
+ bzf->strm.avail_out = BZ_MAX_UNUSED;
+ bzf->strm.next_out = bzf->buf;
+ ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH );
+ if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
+ { BZ_SETERR(ret); return; };
+
+ if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
+ n = BZ_MAX_UNUSED - bzf->strm.avail_out;
+ n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
+ n, bzf->handle );
+ if (n != n2 || ferror(bzf->handle))
+ { BZ_SETERR(BZ_IO_ERROR); return; };
+ }
+
+ if (ret == BZ_STREAM_END) break;
+ }
+ }
+
+ if ( !abandon && !ferror ( bzf->handle ) ) {
+ fflush ( bzf->handle );
+ if (ferror(bzf->handle))
+ { BZ_SETERR(BZ_IO_ERROR); return; };
+ }
+
+ if (nbytes_in_lo32 != NULL)
+ *nbytes_in_lo32 = bzf->strm.total_in_lo32;
+ if (nbytes_in_hi32 != NULL)
+ *nbytes_in_hi32 = bzf->strm.total_in_hi32;
+ if (nbytes_out_lo32 != NULL)
+ *nbytes_out_lo32 = bzf->strm.total_out_lo32;
+ if (nbytes_out_hi32 != NULL)
+ *nbytes_out_hi32 = bzf->strm.total_out_hi32;
+
+ BZ_SETERR(BZ_OK);
+ BZ2_bzCompressEnd ( &(bzf->strm) );
+ free ( bzf );
+}
+
+
+/*---------------------------------------------------*/
+BZFILE* BZ_API(BZ2_bzReadOpen)
+ ( int* bzerror,
+ FILE* f,
+ int verbosity,
+ int small,
+ void* unused,
+ int nUnused )
+{
+ bzFile* bzf = NULL;
+ int ret;
+
+ BZ_SETERR(BZ_OK);
+
+ if (f == NULL ||
+ (small != 0 && small != 1) ||
+ (verbosity < 0 || verbosity > 4) ||
+ (unused == NULL && nUnused != 0) ||
+ (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
+ { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
+
+ if (ferror(f))
+ { BZ_SETERR(BZ_IO_ERROR); return NULL; };
+
+ bzf = malloc ( sizeof(bzFile) );
+ if (bzf == NULL)
+ { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
+
+ BZ_SETERR(BZ_OK);
+
+ bzf->initialisedOk = False;
+ bzf->handle = f;
+ bzf->bufN = 0;
+ bzf->writing = False;
+ bzf->strm.bzalloc = NULL;
+ bzf->strm.bzfree = NULL;
+ bzf->strm.opaque = NULL;
+
+ while (nUnused > 0) {
+ bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++;
+ unused = ((void*)( 1 + ((UChar*)(unused)) ));
+ nUnused--;
+ }
+
+ ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small );
+ if (ret != BZ_OK)
+ { BZ_SETERR(ret); free(bzf); return NULL; };
+
+ bzf->strm.avail_in = bzf->bufN;
+ bzf->strm.next_in = bzf->buf;
+
+ bzf->initialisedOk = True;
+ return bzf;
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b )
+{
+ bzFile* bzf = (bzFile*)b;
+
+ BZ_SETERR(BZ_OK);
+ if (bzf == NULL)
+ { BZ_SETERR(BZ_OK); return; };
+
+ if (bzf->writing)
+ { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+
+ if (bzf->initialisedOk)
+ (void)BZ2_bzDecompressEnd ( &(bzf->strm) );
+ free ( bzf );
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzRead)
+ ( int* bzerror,
+ BZFILE* b,
+ void* buf,
+ int len )
+{
+ Int32 n, ret;
+ bzFile* bzf = (bzFile*)b;
+
+ BZ_SETERR(BZ_OK);
+
+ if (bzf == NULL || buf == NULL || len < 0)
+ { BZ_SETERR(BZ_PARAM_ERROR); return 0; };
+
+ if (bzf->writing)
+ { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; };
+
+ if (len == 0)
+ { BZ_SETERR(BZ_OK); return 0; };
+
+ bzf->strm.avail_out = len;
+ bzf->strm.next_out = buf;
+
+ while (True) {
+
+ if (ferror(bzf->handle))
+ { BZ_SETERR(BZ_IO_ERROR); return 0; };
+
+ if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) {
+ n = fread ( bzf->buf, sizeof(UChar),
+ BZ_MAX_UNUSED, bzf->handle );
+ if (ferror(bzf->handle))
+ { BZ_SETERR(BZ_IO_ERROR); return 0; };
+ bzf->bufN = n;
+ bzf->strm.avail_in = bzf->bufN;
+ bzf->strm.next_in = bzf->buf;
+ }
+
+ ret = BZ2_bzDecompress ( &(bzf->strm) );
+
+ if (ret != BZ_OK && ret != BZ_STREAM_END)
+ { BZ_SETERR(ret); return 0; };
+
+ if (ret == BZ_OK && myfeof(bzf->handle) &&
+ bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0)
+ { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; };
+
+ if (ret == BZ_STREAM_END)
+ { BZ_SETERR(BZ_STREAM_END);
+ return len - bzf->strm.avail_out; };
+ if (bzf->strm.avail_out == 0)
+ { BZ_SETERR(BZ_OK); return len; };
+
+ }
+
+ return 0; /*not reached*/
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzReadGetUnused)
+ ( int* bzerror,
+ BZFILE* b,
+ void** unused,
+ int* nUnused )
+{
+ bzFile* bzf = (bzFile*)b;
+ if (bzf == NULL)
+ { BZ_SETERR(BZ_PARAM_ERROR); return; };
+ if (bzf->lastErr != BZ_STREAM_END)
+ { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+ if (unused == NULL || nUnused == NULL)
+ { BZ_SETERR(BZ_PARAM_ERROR); return; };
+
+ BZ_SETERR(BZ_OK);
+ *nUnused = bzf->strm.avail_in;
+ *unused = bzf->strm.next_in;
+}
+#endif
+
+
+/*---------------------------------------------------*/
+/*--- Misc convenience stuff ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzBuffToBuffCompress)
+ ( char* dest,
+ unsigned int* destLen,
+ char* source,
+ unsigned int sourceLen,
+ int blockSize100k,
+ int verbosity,
+ int workFactor )
+{
+ bz_stream strm;
+ int ret;
+
+ if (dest == NULL || destLen == NULL ||
+ source == NULL ||
+ blockSize100k < 1 || blockSize100k > 9 ||
+ verbosity < 0 || verbosity > 4 ||
+ workFactor < 0 || workFactor > 250)
+ return BZ_PARAM_ERROR;
+
+ if (workFactor == 0) workFactor = 30;
+ strm.bzalloc = NULL;
+ strm.bzfree = NULL;
+ strm.opaque = NULL;
+ ret = BZ2_bzCompressInit ( &strm, blockSize100k,
+ verbosity, workFactor );
+ if (ret != BZ_OK) return ret;
+
+ strm.next_in = source;
+ strm.next_out = dest;
+ strm.avail_in = sourceLen;
+ strm.avail_out = *destLen;
+
+ ret = BZ2_bzCompress ( &strm, BZ_FINISH );
+ if (ret == BZ_FINISH_OK) goto output_overflow;
+ if (ret != BZ_STREAM_END) goto errhandler;
+
+ /* normal termination */
+ *destLen -= strm.avail_out;
+ BZ2_bzCompressEnd ( &strm );
+ return BZ_OK;
+
+ output_overflow:
+ BZ2_bzCompressEnd ( &strm );
+ return BZ_OUTBUFF_FULL;
+
+ errhandler:
+ BZ2_bzCompressEnd ( &strm );
+ return ret;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzBuffToBuffDecompress)
+ ( char* dest,
+ unsigned int* destLen,
+ char* source,
+ unsigned int sourceLen,
+ int small,
+ int verbosity )
+{
+ bz_stream strm;
+ int ret;
+
+ if (dest == NULL || destLen == NULL ||
+ source == NULL ||
+ (small != 0 && small != 1) ||
+ verbosity < 0 || verbosity > 4)
+ return BZ_PARAM_ERROR;
+
+ strm.bzalloc = NULL;
+ strm.bzfree = NULL;
+ strm.opaque = NULL;
+ ret = BZ2_bzDecompressInit ( &strm, verbosity, small );
+ if (ret != BZ_OK) return ret;
+
+ strm.next_in = source;
+ strm.next_out = dest;
+ strm.avail_in = sourceLen;
+ strm.avail_out = *destLen;
+
+ ret = BZ2_bzDecompress ( &strm );
+ if (ret == BZ_OK) goto output_overflow_or_eof;
+ if (ret != BZ_STREAM_END) goto errhandler;
+
+ /* normal termination */
+ *destLen -= strm.avail_out;
+ BZ2_bzDecompressEnd ( &strm );
+ return BZ_OK;
+
+ output_overflow_or_eof:
+ if (strm.avail_out > 0) {
+ BZ2_bzDecompressEnd ( &strm );
+ return BZ_UNEXPECTED_EOF;
+ } else {
+ BZ2_bzDecompressEnd ( &strm );
+ return BZ_OUTBUFF_FULL;
+ };
+
+ errhandler:
+ BZ2_bzDecompressEnd ( &strm );
+ return ret;
+}
+
+
+/*---------------------------------------------------*/
+/*--
+ Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
+ to support better zlib compatibility.
+ This code is not _officially_ part of libbzip2 (yet);
+ I haven't tested it, documented it, or considered the
+ threading-safeness of it.
+ If this code breaks, please contact both Yoshioka and me.
+--*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+/*--
+ return version like "0.9.5d, 4-Sept-1999".
+--*/
+const char * BZ_API(BZ2_bzlibVersion)(void)
+{
+ return BZ_VERSION;
+}
+
+
+#ifndef BZ_NO_STDIO
+/*---------------------------------------------------*/
+
+#if defined(_WIN32) || defined(OS2) || defined(MSDOS)
+# include <fcntl.h>
+# include <io.h>
+# define SET_BINARY_MODE(file) _setmode(_fileno(file),O_BINARY)
+#else
+# define SET_BINARY_MODE(file)
+#endif
+static
+BZFILE * bzopen_or_bzdopen
+ ( const char *path, /* no use when bzdopen */
+ int fd, /* no use when bzdopen */
+ const char *mode,
+ int open_mode) /* bzopen: 0, bzdopen:1 */
+{
+ int bzerr;
+ char unused[BZ_MAX_UNUSED];
+ int blockSize100k = 9;
+ int writing = 0;
+ char mode2[10] = "";
+ FILE *fp = NULL;
+ BZFILE *bzfp = NULL;
+ int verbosity = 0;
+ int workFactor = 30;
+ int smallMode = 0;
+ int nUnused = 0;
+
+ if (mode == NULL) return NULL;
+ while (*mode) {
+ switch (*mode) {
+ case 'r':
+ writing = 0; break;
+ case 'w':
+ writing = 1; break;
+ case 's':
+ smallMode = 1; break;
+ default:
+ if (isdigit((int)(*mode))) {
+ blockSize100k = *mode-BZ_HDR_0;
+ }
+ }
+ mode++;
+ }
+ strcat(mode2, writing ? "w" : "r" );
+ strcat(mode2,"b"); /* binary mode */
+
+ if (open_mode==0) {
+ if (path==NULL || strcmp(path,"")==0) {
+ fp = (writing ? stdout : stdin);
+ SET_BINARY_MODE(fp);
+ } else {
+ fp = fopen(path,mode2);
+ }
+ } else {
+#ifdef BZ_STRICT_ANSI
+ fp = NULL;
+#else
+ fp = _fdopen(fd,mode2);
+#endif
+ }
+ if (fp == NULL) return NULL;
+
+ if (writing) {
+ /* Guard against total chaos and anarchy -- JRS */
+ if (blockSize100k < 1) blockSize100k = 1;
+ if (blockSize100k > 9) blockSize100k = 9;
+ bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k,
+ verbosity,workFactor);
+ } else {
+ bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode,
+ unused,nUnused);
+ }
+ if (bzfp == NULL) {
+ if (fp != stdin && fp != stdout) fclose(fp);
+ return NULL;
+ }
+ return bzfp;
+}
+
+
+/*---------------------------------------------------*/
+/*--
+ open file for read or write.
+ ex) bzopen("file","w9")
+ case path="" or NULL => use stdin or stdout.
+--*/
+BZFILE * BZ_API(BZ2_bzopen)
+ ( const char *path,
+ const char *mode )
+{
+ return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0);
+}
+
+
+/*---------------------------------------------------*/
+BZFILE * BZ_API(BZ2_bzdopen)
+ ( int fd,
+ const char *mode )
+{
+ return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1);
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len )
+{
+ int bzerr, nread;
+ if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0;
+ nread = BZ2_bzRead(&bzerr,b,buf,len);
+ if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) {
+ return nread;
+ } else {
+ return -1;
+ }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len )
+{
+ int bzerr;
+
+ BZ2_bzWrite(&bzerr,b,buf,len);
+ if(bzerr == BZ_OK){
+ return len;
+ }else{
+ return -1;
+ }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzflush) (BZFILE *b)
+{
+ /* do nothing now... */
+ return 0;
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzclose) (BZFILE* b)
+{
+ int bzerr;
+ FILE *fp;
+
+ if (b==NULL) {return;}
+ fp = ((bzFile *)b)->handle;
+ if(((bzFile*)b)->writing){
+ BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
+ if(bzerr != BZ_OK){
+ BZ2_bzWriteClose(NULL,b,1,NULL,NULL);
+ }
+ }else{
+ BZ2_bzReadClose(&bzerr,b);
+ }
+ if(fp!=stdin && fp!=stdout){
+ fclose(fp);
+ }
+}
+
+
+/*---------------------------------------------------*/
+/*--
+ return last error code
+--*/
+static const char *bzerrorstrings[] = {
+ "OK"
+ ,"SEQUENCE_ERROR"
+ ,"PARAM_ERROR"
+ ,"MEM_ERROR"
+ ,"DATA_ERROR"
+ ,"DATA_ERROR_MAGIC"
+ ,"IO_ERROR"
+ ,"UNEXPECTED_EOF"
+ ,"OUTBUFF_FULL"
+ ,"CONFIG_ERROR"
+ ,"???" /* for future */
+ ,"???" /* for future */
+ ,"???" /* for future */
+ ,"???" /* for future */
+ ,"???" /* for future */
+ ,"???" /* for future */
+};
+
+
+const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum)
+{
+ int err = ((bzFile *)b)->lastErr;
+
+ if(err>0) err = 0;
+ *errnum = err;
+ return bzerrorstrings[err*-1];
+}
+#endif
+
+
+/*-------------------------------------------------------------*/
+/*--- end bzlib.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/utils/bzip2/bzlib.h b/utils/bzip2/bzlib.h
new file mode 100644
index 0000000000..8277123da8
--- /dev/null
+++ b/utils/bzip2/bzlib.h
@@ -0,0 +1,282 @@
+
+/*-------------------------------------------------------------*/
+/*--- Public header file for the library. ---*/
+/*--- bzlib.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.6 of 6 September 2010
+ Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+#ifndef _BZLIB_H
+#define _BZLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BZ_RUN 0
+#define BZ_FLUSH 1
+#define BZ_FINISH 2
+
+#define BZ_OK 0
+#define BZ_RUN_OK 1
+#define BZ_FLUSH_OK 2
+#define BZ_FINISH_OK 3
+#define BZ_STREAM_END 4
+#define BZ_SEQUENCE_ERROR (-1)
+#define BZ_PARAM_ERROR (-2)
+#define BZ_MEM_ERROR (-3)
+#define BZ_DATA_ERROR (-4)
+#define BZ_DATA_ERROR_MAGIC (-5)
+#define BZ_IO_ERROR (-6)
+#define BZ_UNEXPECTED_EOF (-7)
+#define BZ_OUTBUFF_FULL (-8)
+#define BZ_CONFIG_ERROR (-9)
+
+typedef
+ struct {
+ char *next_in;
+ unsigned int avail_in;
+ unsigned int total_in_lo32;
+ unsigned int total_in_hi32;
+
+ char *next_out;
+ unsigned int avail_out;
+ unsigned int total_out_lo32;
+ unsigned int total_out_hi32;
+
+ void *state;
+
+ void *(*bzalloc)(void *,int,int);
+ void (*bzfree)(void *,void *);
+ void *opaque;
+ }
+ bz_stream;
+
+
+#ifndef BZ_IMPORT
+#define BZ_EXPORT
+#endif
+
+#ifndef BZ_NO_STDIO
+/* Need a definitition for FILE */
+#include <stdio.h>
+#endif
+
+#ifdef _WIN32
+# include <windows.h>
+# ifdef small
+ /* windows.h define small to char */
+# undef small
+# endif
+# ifdef BZ_EXPORT
+# define BZ_API(func) WINAPI func
+# define BZ_EXTERN extern
+# else
+ /* import windows dll dynamically */
+# define BZ_API(func) (WINAPI * func)
+# define BZ_EXTERN
+# endif
+#else
+# define BZ_API(func) func
+# define BZ_EXTERN extern
+#endif
+
+
+/*-- Core (low-level) library functions --*/
+
+BZ_EXTERN int BZ_API(BZ2_bzCompressInit) (
+ bz_stream* strm,
+ int blockSize100k,
+ int verbosity,
+ int workFactor
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompress) (
+ bz_stream* strm,
+ int action
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) (
+ bz_stream* strm
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) (
+ bz_stream *strm,
+ int verbosity,
+ int small
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompress) (
+ bz_stream* strm
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) (
+ bz_stream *strm
+ );
+
+
+
+/*-- High(er) level library functions --*/
+
+#ifndef BZ_NO_STDIO
+#define BZ_MAX_UNUSED 5000
+
+typedef void BZFILE;
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) (
+ int* bzerror,
+ FILE* f,
+ int verbosity,
+ int small,
+ void* unused,
+ int nUnused
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadClose) (
+ int* bzerror,
+ BZFILE* b
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) (
+ int* bzerror,
+ BZFILE* b,
+ void** unused,
+ int* nUnused
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzRead) (
+ int* bzerror,
+ BZFILE* b,
+ void* buf,
+ int len
+ );
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) (
+ int* bzerror,
+ FILE* f,
+ int blockSize100k,
+ int verbosity,
+ int workFactor
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzWrite) (
+ int* bzerror,
+ BZFILE* b,
+ void* buf,
+ int len
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose) (
+ int* bzerror,
+ BZFILE* b,
+ int abandon,
+ unsigned int* nbytes_in,
+ unsigned int* nbytes_out
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) (
+ int* bzerror,
+ BZFILE* b,
+ int abandon,
+ unsigned int* nbytes_in_lo32,
+ unsigned int* nbytes_in_hi32,
+ unsigned int* nbytes_out_lo32,
+ unsigned int* nbytes_out_hi32
+ );
+#endif
+
+
+/*-- Utility functions --*/
+
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) (
+ char* dest,
+ unsigned int* destLen,
+ char* source,
+ unsigned int sourceLen,
+ int blockSize100k,
+ int verbosity,
+ int workFactor
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) (
+ char* dest,
+ unsigned int* destLen,
+ char* source,
+ unsigned int sourceLen,
+ int small,
+ int verbosity
+ );
+
+
+/*--
+ Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
+ to support better zlib compatibility.
+ This code is not _officially_ part of libbzip2 (yet);
+ I haven't tested it, documented it, or considered the
+ threading-safeness of it.
+ If this code breaks, please contact both Yoshioka and me.
+--*/
+
+BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
+ void
+ );
+
+#ifndef BZ_NO_STDIO
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
+ const char *path,
+ const char *mode
+ );
+
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
+ int fd,
+ const char *mode
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzread) (
+ BZFILE* b,
+ void* buf,
+ int len
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzwrite) (
+ BZFILE* b,
+ void* buf,
+ int len
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzflush) (
+ BZFILE* b
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzclose) (
+ BZFILE* b
+ );
+
+BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
+ BZFILE *b,
+ int *errnum
+ );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*-------------------------------------------------------------*/
+/*--- end bzlib.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/utils/bzip2/bzlib_private.h b/utils/bzip2/bzlib_private.h
new file mode 100644
index 0000000000..d2b1a97ccb
--- /dev/null
+++ b/utils/bzip2/bzlib_private.h
@@ -0,0 +1,512 @@
+
+/*-------------------------------------------------------------*/
+/*--- Private header file for the library. ---*/
+/*--- bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.6 of 6 September 2010
+ Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+#ifndef _BZLIB_PRIVATE_H
+#define _BZLIB_PRIVATE_H
+
+#include <stdlib.h>
+
+#ifndef BZ_NO_STDIO
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#endif
+
+#include "bzlib.h"
+
+
+
+/*-- General stuff. --*/
+
+#define BZ_VERSION "1.0.6, 6-Sept-2010"
+
+typedef char Char;
+typedef unsigned char Bool;
+typedef unsigned char UChar;
+typedef int Int32;
+typedef unsigned int UInt32;
+typedef short Int16;
+typedef unsigned short UInt16;
+
+#define True ((Bool)1)
+#define False ((Bool)0)
+
+#ifndef __GNUC__
+#define __inline__ /* */
+#endif
+
+#ifndef BZ_NO_STDIO
+
+extern void BZ2_bz__AssertH__fail ( int errcode );
+#define AssertH(cond,errcode) \
+ { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); }
+
+#if BZ_DEBUG
+#define AssertD(cond,msg) \
+ { if (!(cond)) { \
+ fprintf ( stderr, \
+ "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\
+ exit(1); \
+ }}
+#else
+#define AssertD(cond,msg) /* */
+#endif
+
+#define VPrintf0(zf) \
+ fprintf(stderr,zf)
+#define VPrintf1(zf,za1) \
+ fprintf(stderr,zf,za1)
+#define VPrintf2(zf,za1,za2) \
+ fprintf(stderr,zf,za1,za2)
+#define VPrintf3(zf,za1,za2,za3) \
+ fprintf(stderr,zf,za1,za2,za3)
+#define VPrintf4(zf,za1,za2,za3,za4) \
+ fprintf(stderr,zf,za1,za2,za3,za4)
+#define VPrintf5(zf,za1,za2,za3,za4,za5) \
+ fprintf(stderr,zf,za1,za2,za3,za4,za5)
+
+#else
+
+extern void bz_internal_error ( int errcode );
+#define AssertH(cond,errcode) \
+ { if (!(cond)) bz_internal_error ( errcode ); }
+#define AssertD(cond,msg) do { } while (0)
+#define VPrintf0(zf) do { } while (0)
+#define VPrintf1(zf,za1) do { } while (0)
+#define VPrintf2(zf,za1,za2) do { } while (0)
+#define VPrintf3(zf,za1,za2,za3) do { } while (0)
+#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0)
+#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0)
+
+#endif
+
+
+#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1)
+#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp))
+
+
+/*-- Header bytes. --*/
+
+#define BZ_HDR_B 0x42 /* 'B' */
+#define BZ_HDR_Z 0x5a /* 'Z' */
+#define BZ_HDR_h 0x68 /* 'h' */
+#define BZ_HDR_0 0x30 /* '0' */
+
+/*-- Constants for the back end. --*/
+
+#define BZ_MAX_ALPHA_SIZE 258
+#define BZ_MAX_CODE_LEN 23
+
+#define BZ_RUNA 0
+#define BZ_RUNB 1
+
+#define BZ_N_GROUPS 6
+#define BZ_G_SIZE 50
+#define BZ_N_ITERS 4
+
+#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
+
+
+
+/*-- Stuff for randomising repetitive blocks. --*/
+
+extern Int32 BZ2_rNums[512];
+
+#define BZ_RAND_DECLS \
+ Int32 rNToGo; \
+ Int32 rTPos \
+
+#define BZ_RAND_INIT_MASK \
+ s->rNToGo = 0; \
+ s->rTPos = 0 \
+
+#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0)
+
+#define BZ_RAND_UPD_MASK \
+ if (s->rNToGo == 0) { \
+ s->rNToGo = BZ2_rNums[s->rTPos]; \
+ s->rTPos++; \
+ if (s->rTPos == 512) s->rTPos = 0; \
+ } \
+ s->rNToGo--;
+
+
+
+/*-- Stuff for doing CRCs. --*/
+
+extern UInt32 BZ2_crc32Table[256];
+
+#define BZ_INITIALISE_CRC(crcVar) \
+{ \
+ crcVar = 0xffffffffL; \
+}
+
+#define BZ_FINALISE_CRC(crcVar) \
+{ \
+ crcVar = ~(crcVar); \
+}
+
+#define BZ_UPDATE_CRC(crcVar,cha) \
+{ \
+ crcVar = (crcVar << 8) ^ \
+ BZ2_crc32Table[(crcVar >> 24) ^ \
+ ((UChar)cha)]; \
+}
+
+
+
+/*-- States and modes for compression. --*/
+
+#define BZ_M_IDLE 1
+#define BZ_M_RUNNING 2
+#define BZ_M_FLUSHING 3
+#define BZ_M_FINISHING 4
+
+#define BZ_S_OUTPUT 1
+#define BZ_S_INPUT 2
+
+#define BZ_N_RADIX 2
+#define BZ_N_QSORT 12
+#define BZ_N_SHELL 18
+#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
+
+
+
+
+/*-- Structure holding all the compression-side stuff. --*/
+
+typedef
+ struct {
+ /* pointer back to the struct bz_stream */
+ bz_stream* strm;
+
+ /* mode this stream is in, and whether inputting */
+ /* or outputting data */
+ Int32 mode;
+ Int32 state;
+
+ /* remembers avail_in when flush/finish requested */
+ UInt32 avail_in_expect;
+
+ /* for doing the block sorting */
+ UInt32* arr1;
+ UInt32* arr2;
+ UInt32* ftab;
+ Int32 origPtr;
+
+ /* aliases for arr1 and arr2 */
+ UInt32* ptr;
+ UChar* block;
+ UInt16* mtfv;
+ UChar* zbits;
+
+ /* for deciding when to use the fallback sorting algorithm */
+ Int32 workFactor;
+
+ /* run-length-encoding of the input */
+ UInt32 state_in_ch;
+ Int32 state_in_len;
+ BZ_RAND_DECLS;
+
+ /* input and output limits and current posns */
+ Int32 nblock;
+ Int32 nblockMAX;
+ Int32 numZ;
+ Int32 state_out_pos;
+
+ /* map of bytes used in block */
+ Int32 nInUse;
+ Bool inUse[256];
+ UChar unseqToSeq[256];
+
+ /* the buffer for bit stream creation */
+ UInt32 bsBuff;
+ Int32 bsLive;
+
+ /* block and combined CRCs */
+ UInt32 blockCRC;
+ UInt32 combinedCRC;
+
+ /* misc administratium */
+ Int32 verbosity;
+ Int32 blockNo;
+ Int32 blockSize100k;
+
+ /* stuff for coding the MTF values */
+ Int32 nMTF;
+ Int32 mtfFreq [BZ_MAX_ALPHA_SIZE];
+ UChar selector [BZ_MAX_SELECTORS];
+ UChar selectorMtf[BZ_MAX_SELECTORS];
+
+ UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ /* second dimension: only 3 needed; 4 makes index calculations faster */
+ UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4];
+
+ }
+ EState;
+
+
+
+/*-- externs for compression. --*/
+
+extern void
+BZ2_blockSort ( EState* );
+
+extern void
+BZ2_compressBlock ( EState*, Bool );
+
+extern void
+BZ2_bsInitWrite ( EState* );
+
+extern void
+BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 );
+
+extern void
+BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 );
+
+
+
+/*-- states for decompression. --*/
+
+#define BZ_X_IDLE 1
+#define BZ_X_OUTPUT 2
+
+#define BZ_X_MAGIC_1 10
+#define BZ_X_MAGIC_2 11
+#define BZ_X_MAGIC_3 12
+#define BZ_X_MAGIC_4 13
+#define BZ_X_BLKHDR_1 14
+#define BZ_X_BLKHDR_2 15
+#define BZ_X_BLKHDR_3 16
+#define BZ_X_BLKHDR_4 17
+#define BZ_X_BLKHDR_5 18
+#define BZ_X_BLKHDR_6 19
+#define BZ_X_BCRC_1 20
+#define BZ_X_BCRC_2 21
+#define BZ_X_BCRC_3 22
+#define BZ_X_BCRC_4 23
+#define BZ_X_RANDBIT 24
+#define BZ_X_ORIGPTR_1 25
+#define BZ_X_ORIGPTR_2 26
+#define BZ_X_ORIGPTR_3 27
+#define BZ_X_MAPPING_1 28
+#define BZ_X_MAPPING_2 29
+#define BZ_X_SELECTOR_1 30
+#define BZ_X_SELECTOR_2 31
+#define BZ_X_SELECTOR_3 32
+#define BZ_X_CODING_1 33
+#define BZ_X_CODING_2 34
+#define BZ_X_CODING_3 35
+#define BZ_X_MTF_1 36
+#define BZ_X_MTF_2 37
+#define BZ_X_MTF_3 38
+#define BZ_X_MTF_4 39
+#define BZ_X_MTF_5 40
+#define BZ_X_MTF_6 41
+#define BZ_X_ENDHDR_2 42
+#define BZ_X_ENDHDR_3 43
+#define BZ_X_ENDHDR_4 44
+#define BZ_X_ENDHDR_5 45
+#define BZ_X_ENDHDR_6 46
+#define BZ_X_CCRC_1 47
+#define BZ_X_CCRC_2 48
+#define BZ_X_CCRC_3 49
+#define BZ_X_CCRC_4 50
+
+
+
+/*-- Constants for the fast MTF decoder. --*/
+
+#define MTFA_SIZE 4096
+#define MTFL_SIZE 16
+
+
+
+/*-- Structure holding all the decompression-side stuff. --*/
+
+typedef
+ struct {
+ /* pointer back to the struct bz_stream */
+ bz_stream* strm;
+
+ /* state indicator for this stream */
+ Int32 state;
+
+ /* for doing the final run-length decoding */
+ UChar state_out_ch;
+ Int32 state_out_len;
+ Bool blockRandomised;
+ BZ_RAND_DECLS;
+
+ /* the buffer for bit stream reading */
+ UInt32 bsBuff;
+ Int32 bsLive;
+
+ /* misc administratium */
+ Int32 blockSize100k;
+ Bool smallDecompress;
+ Int32 currBlockNo;
+ Int32 verbosity;
+
+ /* for undoing the Burrows-Wheeler transform */
+ Int32 origPtr;
+ UInt32 tPos;
+ Int32 k0;
+ Int32 unzftab[256];
+ Int32 nblock_used;
+ Int32 cftab[257];
+ Int32 cftabCopy[257];
+
+ /* for undoing the Burrows-Wheeler transform (FAST) */
+ UInt32 *tt;
+
+ /* for undoing the Burrows-Wheeler transform (SMALL) */
+ UInt16 *ll16;
+ UChar *ll4;
+
+ /* stored and calculated CRCs */
+ UInt32 storedBlockCRC;
+ UInt32 storedCombinedCRC;
+ UInt32 calculatedBlockCRC;
+ UInt32 calculatedCombinedCRC;
+
+ /* map of bytes used in block */
+ Int32 nInUse;
+ Bool inUse[256];
+ Bool inUse16[16];
+ UChar seqToUnseq[256];
+
+ /* for decoding the MTF values */
+ UChar mtfa [MTFA_SIZE];
+ Int32 mtfbase[256 / MTFL_SIZE];
+ UChar selector [BZ_MAX_SELECTORS];
+ UChar selectorMtf[BZ_MAX_SELECTORS];
+ UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+
+ Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ Int32 minLens[BZ_N_GROUPS];
+
+ /* save area for scalars in the main decompress code */
+ Int32 save_i;
+ Int32 save_j;
+ Int32 save_t;
+ Int32 save_alphaSize;
+ Int32 save_nGroups;
+ Int32 save_nSelectors;
+ Int32 save_EOB;
+ Int32 save_groupNo;
+ Int32 save_groupPos;
+ Int32 save_nextSym;
+ Int32 save_nblockMAX;
+ Int32 save_nblock;
+ Int32 save_es;
+ Int32 save_N;
+ Int32 save_curr;
+ Int32 save_zt;
+ Int32 save_zn;
+ Int32 save_zvec;
+ Int32 save_zj;
+ Int32 save_gSel;
+ Int32 save_gMinlen;
+ Int32* save_gLimit;
+ Int32* save_gBase;
+ Int32* save_gPerm;
+
+ }
+ DState;
+
+
+
+/*-- Macros for decompression. --*/
+
+#define BZ_GET_FAST(cccc) \
+ /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+ if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
+ s->tPos = s->tt[s->tPos]; \
+ cccc = (UChar)(s->tPos & 0xff); \
+ s->tPos >>= 8;
+
+#define BZ_GET_FAST_C(cccc) \
+ /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+ if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \
+ c_tPos = c_tt[c_tPos]; \
+ cccc = (UChar)(c_tPos & 0xff); \
+ c_tPos >>= 8;
+
+#define SET_LL4(i,n) \
+ { if (((i) & 0x1) == 0) \
+ s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \
+ s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \
+ }
+
+#define GET_LL4(i) \
+ ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF)
+
+#define SET_LL(i,n) \
+ { s->ll16[i] = (UInt16)(n & 0x0000ffff); \
+ SET_LL4(i, n >> 16); \
+ }
+
+#define GET_LL(i) \
+ (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16))
+
+#define BZ_GET_SMALL(cccc) \
+ /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+ if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
+ cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \
+ s->tPos = GET_LL(s->tPos);
+
+
+/*-- externs for decompression. --*/
+
+extern Int32
+BZ2_indexIntoF ( Int32, Int32* );
+
+extern Int32
+BZ2_decompress ( DState* );
+
+extern void
+BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*,
+ Int32, Int32, Int32 );
+
+
+#endif
+
+
+/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/
+
+#ifdef BZ_NO_STDIO
+#ifndef NULL
+#define NULL 0
+#endif
+#endif
+
+#ifndef WIN32
+#define _fdopen fdopen
+#endif
+
+/*-------------------------------------------------------------*/
+/*--- end bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/utils/bzip2/compress.c b/utils/bzip2/compress.c
new file mode 100644
index 0000000000..caf7696011
--- /dev/null
+++ b/utils/bzip2/compress.c
@@ -0,0 +1,672 @@
+
+/*-------------------------------------------------------------*/
+/*--- Compression machinery (not incl block sorting) ---*/
+/*--- compress.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.6 of 6 September 2010
+ Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+/* CHANGES
+ 0.9.0 -- original version.
+ 0.9.0a/b -- no changes in this file.
+ 0.9.0c -- changed setting of nGroups in sendMTFValues()
+ so as to do a bit better on small files
+*/
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+/*--- Bit stream I/O ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+void BZ2_bsInitWrite ( EState* s )
+{
+ s->bsLive = 0;
+ s->bsBuff = 0;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsFinishWrite ( EState* s )
+{
+ while (s->bsLive > 0) {
+ s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24);
+ s->numZ++;
+ s->bsBuff <<= 8;
+ s->bsLive -= 8;
+ }
+}
+
+
+/*---------------------------------------------------*/
+#define bsNEEDW(nz) \
+{ \
+ while (s->bsLive >= 8) { \
+ s->zbits[s->numZ] \
+ = (UChar)(s->bsBuff >> 24); \
+ s->numZ++; \
+ s->bsBuff <<= 8; \
+ s->bsLive -= 8; \
+ } \
+}
+
+
+/*---------------------------------------------------*/
+static
+__inline__
+void bsW ( EState* s, Int32 n, UInt32 v )
+{
+ bsNEEDW ( n );
+ s->bsBuff |= (v << (32 - s->bsLive - n));
+ s->bsLive += n;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutUInt32 ( EState* s, UInt32 u )
+{
+ bsW ( s, 8, (u >> 24) & 0xffL );
+ bsW ( s, 8, (u >> 16) & 0xffL );
+ bsW ( s, 8, (u >> 8) & 0xffL );
+ bsW ( s, 8, u & 0xffL );
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutUChar ( EState* s, UChar c )
+{
+ bsW( s, 8, (UInt32)c );
+}
+
+
+/*---------------------------------------------------*/
+/*--- The back end proper ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+static
+void makeMaps_e ( EState* s )
+{
+ Int32 i;
+ s->nInUse = 0;
+ for (i = 0; i < 256; i++)
+ if (s->inUse[i]) {
+ s->unseqToSeq[i] = s->nInUse;
+ s->nInUse++;
+ }
+}
+
+
+/*---------------------------------------------------*/
+static
+void generateMTFValues ( EState* s )
+{
+ UChar yy[256];
+ Int32 i, j;
+ Int32 zPend;
+ Int32 wr;
+ Int32 EOB;
+
+ /*
+ After sorting (eg, here),
+ s->arr1 [ 0 .. s->nblock-1 ] holds sorted order,
+ and
+ ((UChar*)s->arr2) [ 0 .. s->nblock-1 ]
+ holds the original block data.
+
+ The first thing to do is generate the MTF values,
+ and put them in
+ ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ].
+ Because there are strictly fewer or equal MTF values
+ than block values, ptr values in this area are overwritten
+ with MTF values only when they are no longer needed.
+
+ The final compressed bitstream is generated into the
+ area starting at
+ (UChar*) (&((UChar*)s->arr2)[s->nblock])
+
+ These storage aliases are set up in bzCompressInit(),
+ except for the last one, which is arranged in
+ compressBlock().
+ */
+ UInt32* ptr = s->ptr;
+ UChar* block = s->block;
+ UInt16* mtfv = s->mtfv;
+
+ makeMaps_e ( s );
+ EOB = s->nInUse+1;
+
+ for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0;
+
+ wr = 0;
+ zPend = 0;
+ for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i;
+
+ for (i = 0; i < s->nblock; i++) {
+ UChar ll_i;
+ AssertD ( wr <= i, "generateMTFValues(1)" );
+ j = ptr[i]-1; if (j < 0) j += s->nblock;
+ ll_i = s->unseqToSeq[block[j]];
+ AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" );
+
+ if (yy[0] == ll_i) {
+ zPend++;
+ } else {
+
+ if (zPend > 0) {
+ zPend--;
+ while (True) {
+ if (zPend & 1) {
+ mtfv[wr] = BZ_RUNB; wr++;
+ s->mtfFreq[BZ_RUNB]++;
+ } else {
+ mtfv[wr] = BZ_RUNA; wr++;
+ s->mtfFreq[BZ_RUNA]++;
+ }
+ if (zPend < 2) break;
+ zPend = (zPend - 2) / 2;
+ };
+ zPend = 0;
+ }
+ {
+ register UChar rtmp;
+ register UChar* ryy_j;
+ register UChar rll_i;
+ rtmp = yy[1];
+ yy[1] = yy[0];
+ ryy_j = &(yy[1]);
+ rll_i = ll_i;
+ while ( rll_i != rtmp ) {
+ register UChar rtmp2;
+ ryy_j++;
+ rtmp2 = rtmp;
+ rtmp = *ryy_j;
+ *ryy_j = rtmp2;
+ };
+ yy[0] = rtmp;
+ j = ryy_j - &(yy[0]);
+ mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++;
+ }
+
+ }
+ }
+
+ if (zPend > 0) {
+ zPend--;
+ while (True) {
+ if (zPend & 1) {
+ mtfv[wr] = BZ_RUNB; wr++;
+ s->mtfFreq[BZ_RUNB]++;
+ } else {
+ mtfv[wr] = BZ_RUNA; wr++;
+ s->mtfFreq[BZ_RUNA]++;
+ }
+ if (zPend < 2) break;
+ zPend = (zPend - 2) / 2;
+ };
+ zPend = 0;
+ }
+
+ mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++;
+
+ s->nMTF = wr;
+}
+
+
+/*---------------------------------------------------*/
+#define BZ_LESSER_ICOST 0
+#define BZ_GREATER_ICOST 15
+
+static
+void sendMTFValues ( EState* s )
+{
+ Int32 v, t, i, j, gs, ge, totc, bt, bc, iter;
+ Int32 nSelectors, alphaSize, minLen, maxLen, selCtr;
+ Int32 nGroups, nBytes;
+
+ /*--
+ UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ is a global since the decoder also needs it.
+
+ Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+ are also globals only used in this proc.
+ Made global to keep stack frame size small.
+ --*/
+
+
+ UInt16 cost[BZ_N_GROUPS];
+ Int32 fave[BZ_N_GROUPS];
+
+ UInt16* mtfv = s->mtfv;
+
+ if (s->verbosity >= 3)
+ VPrintf3( " %d in block, %d after MTF & 1-2 coding, "
+ "%d+2 syms in use\n",
+ s->nblock, s->nMTF, s->nInUse );
+
+ alphaSize = s->nInUse+2;
+ for (t = 0; t < BZ_N_GROUPS; t++)
+ for (v = 0; v < alphaSize; v++)
+ s->len[t][v] = BZ_GREATER_ICOST;
+
+ /*--- Decide how many coding tables to use ---*/
+ AssertH ( s->nMTF > 0, 3001 );
+ if (s->nMTF < 200) nGroups = 2; else
+ if (s->nMTF < 600) nGroups = 3; else
+ if (s->nMTF < 1200) nGroups = 4; else
+ if (s->nMTF < 2400) nGroups = 5; else
+ nGroups = 6;
+
+ /*--- Generate an initial set of coding tables ---*/
+ {
+ Int32 nPart, remF, tFreq, aFreq;
+
+ nPart = nGroups;
+ remF = s->nMTF;
+ gs = 0;
+ while (nPart > 0) {
+ tFreq = remF / nPart;
+ ge = gs-1;
+ aFreq = 0;
+ while (aFreq < tFreq && ge < alphaSize-1) {
+ ge++;
+ aFreq += s->mtfFreq[ge];
+ }
+
+ if (ge > gs
+ && nPart != nGroups && nPart != 1
+ && ((nGroups-nPart) % 2 == 1)) {
+ aFreq -= s->mtfFreq[ge];
+ ge--;
+ }
+
+ if (s->verbosity >= 3)
+ VPrintf5( " initial group %d, [%d .. %d], "
+ "has %d syms (%4.1f%%)\n",
+ nPart, gs, ge, aFreq,
+ (100.0 * (float)aFreq) / (float)(s->nMTF) );
+
+ for (v = 0; v < alphaSize; v++)
+ if (v >= gs && v <= ge)
+ s->len[nPart-1][v] = BZ_LESSER_ICOST; else
+ s->len[nPart-1][v] = BZ_GREATER_ICOST;
+
+ nPart--;
+ gs = ge+1;
+ remF -= aFreq;
+ }
+ }
+
+ /*---
+ Iterate up to BZ_N_ITERS times to improve the tables.
+ ---*/
+ for (iter = 0; iter < BZ_N_ITERS; iter++) {
+
+ for (t = 0; t < nGroups; t++) fave[t] = 0;
+
+ for (t = 0; t < nGroups; t++)
+ for (v = 0; v < alphaSize; v++)
+ s->rfreq[t][v] = 0;
+
+ /*---
+ Set up an auxiliary length table which is used to fast-track
+ the common case (nGroups == 6).
+ ---*/
+ if (nGroups == 6) {
+ for (v = 0; v < alphaSize; v++) {
+ s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
+ s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
+ s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
+ }
+ }
+
+ nSelectors = 0;
+ totc = 0;
+ gs = 0;
+ while (True) {
+
+ /*--- Set group start & end marks. --*/
+ if (gs >= s->nMTF) break;
+ ge = gs + BZ_G_SIZE - 1;
+ if (ge >= s->nMTF) ge = s->nMTF-1;
+
+ /*--
+ Calculate the cost of this group as coded
+ by each of the coding tables.
+ --*/
+ for (t = 0; t < nGroups; t++) cost[t] = 0;
+
+ if (nGroups == 6 && 50 == ge-gs+1) {
+ /*--- fast track the common case ---*/
+ register UInt32 cost01, cost23, cost45;
+ register UInt16 icv;
+ cost01 = cost23 = cost45 = 0;
+
+# define BZ_ITER(nn) \
+ icv = mtfv[gs+(nn)]; \
+ cost01 += s->len_pack[icv][0]; \
+ cost23 += s->len_pack[icv][1]; \
+ cost45 += s->len_pack[icv][2]; \
+
+ BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4);
+ BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9);
+ BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
+ BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
+ BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
+ BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
+ BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
+ BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
+ BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
+ BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
+
+# undef BZ_ITER
+
+ cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
+ cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
+ cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
+
+ } else {
+ /*--- slow version which correctly handles all situations ---*/
+ for (i = gs; i <= ge; i++) {
+ UInt16 icv = mtfv[i];
+ for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv];
+ }
+ }
+
+ /*--
+ Find the coding table which is best for this group,
+ and record its identity in the selector table.
+ --*/
+ bc = 999999999; bt = -1;
+ for (t = 0; t < nGroups; t++)
+ if (cost[t] < bc) { bc = cost[t]; bt = t; };
+ totc += bc;
+ fave[bt]++;
+ s->selector[nSelectors] = bt;
+ nSelectors++;
+
+ /*--
+ Increment the symbol frequencies for the selected table.
+ --*/
+ if (nGroups == 6 && 50 == ge-gs+1) {
+ /*--- fast track the common case ---*/
+
+# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++
+
+ BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4);
+ BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9);
+ BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
+ BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
+ BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
+ BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
+ BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
+ BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
+ BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
+ BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
+
+# undef BZ_ITUR
+
+ } else {
+ /*--- slow version which correctly handles all situations ---*/
+ for (i = gs; i <= ge; i++)
+ s->rfreq[bt][ mtfv[i] ]++;
+ }
+
+ gs = ge+1;
+ }
+ if (s->verbosity >= 3) {
+ VPrintf2 ( " pass %d: size is %d, grp uses are ",
+ iter+1, totc/8 );
+ for (t = 0; t < nGroups; t++)
+ VPrintf1 ( "%d ", fave[t] );
+ VPrintf0 ( "\n" );
+ }
+
+ /*--
+ Recompute the tables based on the accumulated frequencies.
+ --*/
+ /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See
+ comment in huffman.c for details. */
+ for (t = 0; t < nGroups; t++)
+ BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]),
+ alphaSize, 17 /*20*/ );
+ }
+
+
+ AssertH( nGroups < 8, 3002 );
+ AssertH( nSelectors < 32768 &&
+ nSelectors <= (2 + (900000 / BZ_G_SIZE)),
+ 3003 );
+
+
+ /*--- Compute MTF values for the selectors. ---*/
+ {
+ UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
+ for (i = 0; i < nGroups; i++) pos[i] = i;
+ for (i = 0; i < nSelectors; i++) {
+ ll_i = s->selector[i];
+ j = 0;
+ tmp = pos[j];
+ while ( ll_i != tmp ) {
+ j++;
+ tmp2 = tmp;
+ tmp = pos[j];
+ pos[j] = tmp2;
+ };
+ pos[0] = tmp;
+ s->selectorMtf[i] = j;
+ }
+ };
+
+ /*--- Assign actual codes for the tables. --*/
+ for (t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (i = 0; i < alphaSize; i++) {
+ if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+ if (s->len[t][i] < minLen) minLen = s->len[t][i];
+ }
+ AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
+ AssertH ( !(minLen < 1), 3005 );
+ BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]),
+ minLen, maxLen, alphaSize );
+ }
+
+ /*--- Transmit the mapping table. ---*/
+ {
+ Bool inUse16[16];
+ for (i = 0; i < 16; i++) {
+ inUse16[i] = False;
+ for (j = 0; j < 16; j++)
+ if (s->inUse[i * 16 + j]) inUse16[i] = True;
+ }
+
+ nBytes = s->numZ;
+ for (i = 0; i < 16; i++)
+ if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0);
+
+ for (i = 0; i < 16; i++)
+ if (inUse16[i])
+ for (j = 0; j < 16; j++) {
+ if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0);
+ }
+
+ if (s->verbosity >= 3)
+ VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes );
+ }
+
+ /*--- Now the selectors. ---*/
+ nBytes = s->numZ;
+ bsW ( s, 3, nGroups );
+ bsW ( s, 15, nSelectors );
+ for (i = 0; i < nSelectors; i++) {
+ for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1);
+ bsW(s,1,0);
+ }
+ if (s->verbosity >= 3)
+ VPrintf1( "selectors %d, ", s->numZ-nBytes );
+
+ /*--- Now the coding tables. ---*/
+ nBytes = s->numZ;
+
+ for (t = 0; t < nGroups; t++) {
+ Int32 curr = s->len[t][0];
+ bsW ( s, 5, curr );
+ for (i = 0; i < alphaSize; i++) {
+ while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ };
+ while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ };
+ bsW ( s, 1, 0 );
+ }
+ }
+
+ if (s->verbosity >= 3)
+ VPrintf1 ( "code lengths %d, ", s->numZ-nBytes );
+
+ /*--- And finally, the block data proper ---*/
+ nBytes = s->numZ;
+ selCtr = 0;
+ gs = 0;
+ while (True) {
+ if (gs >= s->nMTF) break;
+ ge = gs + BZ_G_SIZE - 1;
+ if (ge >= s->nMTF) ge = s->nMTF-1;
+ AssertH ( s->selector[selCtr] < nGroups, 3006 );
+
+ if (nGroups == 6 && 50 == ge-gs+1) {
+ /*--- fast track the common case ---*/
+ UInt16 mtfv_i;
+ UChar* s_len_sel_selCtr
+ = &(s->len[s->selector[selCtr]][0]);
+ Int32* s_code_sel_selCtr
+ = &(s->code[s->selector[selCtr]][0]);
+
+# define BZ_ITAH(nn) \
+ mtfv_i = mtfv[gs+(nn)]; \
+ bsW ( s, \
+ s_len_sel_selCtr[mtfv_i], \
+ s_code_sel_selCtr[mtfv_i] )
+
+ BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4);
+ BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9);
+ BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
+ BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
+ BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
+ BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
+ BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
+ BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
+ BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
+ BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
+
+# undef BZ_ITAH
+
+ } else {
+ /*--- slow version which correctly handles all situations ---*/
+ for (i = gs; i <= ge; i++) {
+ bsW ( s,
+ s->len [s->selector[selCtr]] [mtfv[i]],
+ s->code [s->selector[selCtr]] [mtfv[i]] );
+ }
+ }
+
+
+ gs = ge+1;
+ selCtr++;
+ }
+ AssertH( selCtr == nSelectors, 3007 );
+
+ if (s->verbosity >= 3)
+ VPrintf1( "codes %d\n", s->numZ-nBytes );
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_compressBlock ( EState* s, Bool is_last_block )
+{
+ if (s->nblock > 0) {
+
+ BZ_FINALISE_CRC ( s->blockCRC );
+ s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
+ s->combinedCRC ^= s->blockCRC;
+ if (s->blockNo > 1) s->numZ = 0;
+
+ if (s->verbosity >= 2)
+ VPrintf4( " block %d: crc = 0x%08x, "
+ "combined CRC = 0x%08x, size = %d\n",
+ s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
+
+ BZ2_blockSort ( s );
+ }
+
+ s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]);
+
+ /*-- If this is the first block, create the stream header. --*/
+ if (s->blockNo == 1) {
+ BZ2_bsInitWrite ( s );
+ bsPutUChar ( s, BZ_HDR_B );
+ bsPutUChar ( s, BZ_HDR_Z );
+ bsPutUChar ( s, BZ_HDR_h );
+ bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) );
+ }
+
+ if (s->nblock > 0) {
+
+ bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 );
+ bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 );
+ bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 );
+
+ /*-- Now the block's CRC, so it is in a known place. --*/
+ bsPutUInt32 ( s, s->blockCRC );
+
+ /*--
+ Now a single bit indicating (non-)randomisation.
+ As of version 0.9.5, we use a better sorting algorithm
+ which makes randomisation unnecessary. So always set
+ the randomised bit to 'no'. Of course, the decoder
+ still needs to be able to handle randomised blocks
+ so as to maintain backwards compatibility with
+ older versions of bzip2.
+ --*/
+ bsW(s,1,0);
+
+ bsW ( s, 24, s->origPtr );
+ generateMTFValues ( s );
+ sendMTFValues ( s );
+ }
+
+
+ /*-- If this is the last block, add the stream trailer. --*/
+ if (is_last_block) {
+
+ bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 );
+ bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 );
+ bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
+ bsPutUInt32 ( s, s->combinedCRC );
+ if (s->verbosity >= 2)
+ VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC );
+ bsFinishWrite ( s );
+ }
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end compress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/utils/bzip2/crctable.c b/utils/bzip2/crctable.c
new file mode 100644
index 0000000000..1fea7e946c
--- /dev/null
+++ b/utils/bzip2/crctable.c
@@ -0,0 +1,104 @@
+
+/*-------------------------------------------------------------*/
+/*--- Table for doing CRCs ---*/
+/*--- crctable.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.6 of 6 September 2010
+ Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*--
+ I think this is an implementation of the AUTODIN-II,
+ Ethernet & FDDI 32-bit CRC standard. Vaguely derived
+ from code by Rob Warnock, in Section 51 of the
+ comp.compression FAQ.
+--*/
+
+UInt32 BZ2_crc32Table[256] = {
+
+ /*-- Ugly, innit? --*/
+
+ 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
+ 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
+ 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
+ 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
+ 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
+ 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
+ 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
+ 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
+ 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
+ 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
+ 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
+ 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
+ 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
+ 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
+ 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
+ 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
+ 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
+ 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
+ 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
+ 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
+ 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
+ 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
+ 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
+ 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
+ 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
+ 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
+ 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
+ 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
+ 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
+ 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
+ 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
+ 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
+ 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
+ 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
+ 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
+ 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
+ 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
+ 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
+ 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
+ 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
+ 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
+ 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
+ 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
+ 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
+ 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
+ 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
+ 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
+ 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
+ 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
+ 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
+ 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
+ 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
+ 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
+ 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
+ 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
+ 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
+ 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
+ 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
+ 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
+ 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
+ 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
+ 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
+ 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
+ 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
+};
+
+
+/*-------------------------------------------------------------*/
+/*--- end crctable.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/utils/bzip2/decompress.c b/utils/bzip2/decompress.c
new file mode 100644
index 0000000000..311f5668f9
--- /dev/null
+++ b/utils/bzip2/decompress.c
@@ -0,0 +1,646 @@
+
+/*-------------------------------------------------------------*/
+/*--- Decompression machinery ---*/
+/*--- decompress.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.6 of 6 September 2010
+ Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+static
+void makeMaps_d ( DState* s )
+{
+ Int32 i;
+ s->nInUse = 0;
+ for (i = 0; i < 256; i++)
+ if (s->inUse[i]) {
+ s->seqToUnseq[s->nInUse] = i;
+ s->nInUse++;
+ }
+}
+
+
+/*---------------------------------------------------*/
+#define RETURN(rrr) \
+ { retVal = rrr; goto save_state_and_return; };
+
+#define GET_BITS(lll,vvv,nnn) \
+ case lll: s->state = lll; \
+ while (True) { \
+ if (s->bsLive >= nnn) { \
+ UInt32 v; \
+ v = (s->bsBuff >> \
+ (s->bsLive-nnn)) & ((1 << nnn)-1); \
+ s->bsLive -= nnn; \
+ vvv = v; \
+ break; \
+ } \
+ if (s->strm->avail_in == 0) RETURN(BZ_OK); \
+ s->bsBuff \
+ = (s->bsBuff << 8) | \
+ ((UInt32) \
+ (*((UChar*)(s->strm->next_in)))); \
+ s->bsLive += 8; \
+ s->strm->next_in++; \
+ s->strm->avail_in--; \
+ s->strm->total_in_lo32++; \
+ if (s->strm->total_in_lo32 == 0) \
+ s->strm->total_in_hi32++; \
+ }
+
+#define GET_UCHAR(lll,uuu) \
+ GET_BITS(lll,uuu,8)
+
+#define GET_BIT(lll,uuu) \
+ GET_BITS(lll,uuu,1)
+
+/*---------------------------------------------------*/
+#define GET_MTF_VAL(label1,label2,lval) \
+{ \
+ if (groupPos == 0) { \
+ groupNo++; \
+ if (groupNo >= nSelectors) \
+ RETURN(BZ_DATA_ERROR); \
+ groupPos = BZ_G_SIZE; \
+ gSel = s->selector[groupNo]; \
+ gMinlen = s->minLens[gSel]; \
+ gLimit = &(s->limit[gSel][0]); \
+ gPerm = &(s->perm[gSel][0]); \
+ gBase = &(s->base[gSel][0]); \
+ } \
+ groupPos--; \
+ zn = gMinlen; \
+ GET_BITS(label1, zvec, zn); \
+ while (1) { \
+ if (zn > 20 /* the longest code */) \
+ RETURN(BZ_DATA_ERROR); \
+ if (zvec <= gLimit[zn]) break; \
+ zn++; \
+ GET_BIT(label2, zj); \
+ zvec = (zvec << 1) | zj; \
+ }; \
+ if (zvec - gBase[zn] < 0 \
+ || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \
+ RETURN(BZ_DATA_ERROR); \
+ lval = gPerm[zvec - gBase[zn]]; \
+}
+
+
+/*---------------------------------------------------*/
+Int32 BZ2_decompress ( DState* s )
+{
+ UChar uc;
+ Int32 retVal;
+ Int32 minLen, maxLen;
+ bz_stream* strm = s->strm;
+
+ /* stuff that needs to be saved/restored */
+ Int32 i;
+ Int32 j;
+ Int32 t;
+ Int32 alphaSize;
+ Int32 nGroups;
+ Int32 nSelectors;
+ Int32 EOB;
+ Int32 groupNo;
+ Int32 groupPos;
+ Int32 nextSym;
+ Int32 nblockMAX;
+ Int32 nblock;
+ Int32 es;
+ Int32 N;
+ Int32 curr;
+ Int32 zt;
+ Int32 zn;
+ Int32 zvec;
+ Int32 zj;
+ Int32 gSel;
+ Int32 gMinlen;
+ Int32* gLimit;
+ Int32* gBase;
+ Int32* gPerm;
+
+ if (s->state == BZ_X_MAGIC_1) {
+ /*initialise the save area*/
+ s->save_i = 0;
+ s->save_j = 0;
+ s->save_t = 0;
+ s->save_alphaSize = 0;
+ s->save_nGroups = 0;
+ s->save_nSelectors = 0;
+ s->save_EOB = 0;
+ s->save_groupNo = 0;
+ s->save_groupPos = 0;
+ s->save_nextSym = 0;
+ s->save_nblockMAX = 0;
+ s->save_nblock = 0;
+ s->save_es = 0;
+ s->save_N = 0;
+ s->save_curr = 0;
+ s->save_zt = 0;
+ s->save_zn = 0;
+ s->save_zvec = 0;
+ s->save_zj = 0;
+ s->save_gSel = 0;
+ s->save_gMinlen = 0;
+ s->save_gLimit = NULL;
+ s->save_gBase = NULL;
+ s->save_gPerm = NULL;
+ }
+
+ /*restore from the save area*/
+ i = s->save_i;
+ j = s->save_j;
+ t = s->save_t;
+ alphaSize = s->save_alphaSize;
+ nGroups = s->save_nGroups;
+ nSelectors = s->save_nSelectors;
+ EOB = s->save_EOB;
+ groupNo = s->save_groupNo;
+ groupPos = s->save_groupPos;
+ nextSym = s->save_nextSym;
+ nblockMAX = s->save_nblockMAX;
+ nblock = s->save_nblock;
+ es = s->save_es;
+ N = s->save_N;
+ curr = s->save_curr;
+ zt = s->save_zt;
+ zn = s->save_zn;
+ zvec = s->save_zvec;
+ zj = s->save_zj;
+ gSel = s->save_gSel;
+ gMinlen = s->save_gMinlen;
+ gLimit = s->save_gLimit;
+ gBase = s->save_gBase;
+ gPerm = s->save_gPerm;
+
+ retVal = BZ_OK;
+
+ switch (s->state) {
+
+ GET_UCHAR(BZ_X_MAGIC_1, uc);
+ if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC);
+
+ GET_UCHAR(BZ_X_MAGIC_2, uc);
+ if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC);
+
+ GET_UCHAR(BZ_X_MAGIC_3, uc)
+ if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC);
+
+ GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
+ if (s->blockSize100k < (BZ_HDR_0 + 1) ||
+ s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC);
+ s->blockSize100k -= BZ_HDR_0;
+
+ if (s->smallDecompress) {
+ s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
+ s->ll4 = BZALLOC(
+ ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar)
+ );
+ if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
+ } else {
+ s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
+ if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
+ }
+
+ GET_UCHAR(BZ_X_BLKHDR_1, uc);
+
+ if (uc == 0x17) goto endhdr_2;
+ if (uc != 0x31) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_2, uc);
+ if (uc != 0x41) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_3, uc);
+ if (uc != 0x59) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_4, uc);
+ if (uc != 0x26) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_5, uc);
+ if (uc != 0x53) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_BLKHDR_6, uc);
+ if (uc != 0x59) RETURN(BZ_DATA_ERROR);
+
+ s->currBlockNo++;
+ if (s->verbosity >= 2)
+ VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo );
+
+ s->storedBlockCRC = 0;
+ GET_UCHAR(BZ_X_BCRC_1, uc);
+ s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_BCRC_2, uc);
+ s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_BCRC_3, uc);
+ s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_BCRC_4, uc);
+ s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+
+ GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
+
+ s->origPtr = 0;
+ GET_UCHAR(BZ_X_ORIGPTR_1, uc);
+ s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+ GET_UCHAR(BZ_X_ORIGPTR_2, uc);
+ s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+ GET_UCHAR(BZ_X_ORIGPTR_3, uc);
+ s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+
+ if (s->origPtr < 0)
+ RETURN(BZ_DATA_ERROR);
+ if (s->origPtr > 10 + 100000*s->blockSize100k)
+ RETURN(BZ_DATA_ERROR);
+
+ /*--- Receive the mapping table ---*/
+ for (i = 0; i < 16; i++) {
+ GET_BIT(BZ_X_MAPPING_1, uc);
+ if (uc == 1)
+ s->inUse16[i] = True; else
+ s->inUse16[i] = False;
+ }
+
+ for (i = 0; i < 256; i++) s->inUse[i] = False;
+
+ for (i = 0; i < 16; i++)
+ if (s->inUse16[i])
+ for (j = 0; j < 16; j++) {
+ GET_BIT(BZ_X_MAPPING_2, uc);
+ if (uc == 1) s->inUse[i * 16 + j] = True;
+ }
+ makeMaps_d ( s );
+ if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
+ alphaSize = s->nInUse+2;
+
+ /*--- Now the selectors ---*/
+ GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
+ if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR);
+ GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
+ if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
+ for (i = 0; i < nSelectors; i++) {
+ j = 0;
+ while (True) {
+ GET_BIT(BZ_X_SELECTOR_3, uc);
+ if (uc == 0) break;
+ j++;
+ if (j >= nGroups) RETURN(BZ_DATA_ERROR);
+ }
+ s->selectorMtf[i] = j;
+ }
+
+ /*--- Undo the MTF values for the selectors. ---*/
+ {
+ UChar pos[BZ_N_GROUPS], tmp, v;
+ for (v = 0; v < nGroups; v++) pos[v] = v;
+
+ for (i = 0; i < nSelectors; i++) {
+ v = s->selectorMtf[i];
+ tmp = pos[v];
+ while (v > 0) { pos[v] = pos[v-1]; v--; }
+ pos[0] = tmp;
+ s->selector[i] = tmp;
+ }
+ }
+
+ /*--- Now the coding tables ---*/
+ for (t = 0; t < nGroups; t++) {
+ GET_BITS(BZ_X_CODING_1, curr, 5);
+ for (i = 0; i < alphaSize; i++) {
+ while (True) {
+ if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
+ GET_BIT(BZ_X_CODING_2, uc);
+ if (uc == 0) break;
+ GET_BIT(BZ_X_CODING_3, uc);
+ if (uc == 0) curr++; else curr--;
+ }
+ s->len[t][i] = curr;
+ }
+ }
+
+ /*--- Create the Huffman decoding tables ---*/
+ for (t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (i = 0; i < alphaSize; i++) {
+ if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+ if (s->len[t][i] < minLen) minLen = s->len[t][i];
+ }
+ BZ2_hbCreateDecodeTables (
+ &(s->limit[t][0]),
+ &(s->base[t][0]),
+ &(s->perm[t][0]),
+ &(s->len[t][0]),
+ minLen, maxLen, alphaSize
+ );
+ s->minLens[t] = minLen;
+ }
+
+ /*--- Now the MTF values ---*/
+
+ EOB = s->nInUse+1;
+ nblockMAX = 100000 * s->blockSize100k;
+ groupNo = -1;
+ groupPos = 0;
+
+ for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
+
+ /*-- MTF init --*/
+ {
+ Int32 ii, jj, kk;
+ kk = MTFA_SIZE-1;
+ for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
+ for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
+ s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
+ kk--;
+ }
+ s->mtfbase[ii] = kk + 1;
+ }
+ }
+ /*-- end MTF init --*/
+
+ nblock = 0;
+ GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
+
+ while (True) {
+
+ if (nextSym == EOB) break;
+
+ if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
+
+ es = -1;
+ N = 1;
+ do {
+ /* Check that N doesn't get too big, so that es doesn't
+ go negative. The maximum value that can be
+ RUNA/RUNB encoded is equal to the block size (post
+ the initial RLE), viz, 900k, so bounding N at 2
+ million should guard against overflow without
+ rejecting any legitimate inputs. */
+ if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR);
+ if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
+ if (nextSym == BZ_RUNB) es = es + (1+1) * N;
+ N = N * 2;
+ GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
+ }
+ while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
+
+ es++;
+ uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
+ s->unzftab[uc] += es;
+
+ if (s->smallDecompress)
+ while (es > 0) {
+ if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+ s->ll16[nblock] = (UInt16)uc;
+ nblock++;
+ es--;
+ }
+ else
+ while (es > 0) {
+ if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+ s->tt[nblock] = (UInt32)uc;
+ nblock++;
+ es--;
+ };
+
+ continue;
+
+ } else {
+
+ if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+
+ /*-- uc = MTF ( nextSym-1 ) --*/
+ {
+ Int32 ii, jj, kk, pp, lno, off;
+ UInt32 nn;
+ nn = (UInt32)(nextSym - 1);
+
+ if (nn < MTFL_SIZE) {
+ /* avoid general-case expense */
+ pp = s->mtfbase[0];
+ uc = s->mtfa[pp+nn];
+ while (nn > 3) {
+ Int32 z = pp+nn;
+ s->mtfa[(z) ] = s->mtfa[(z)-1];
+ s->mtfa[(z)-1] = s->mtfa[(z)-2];
+ s->mtfa[(z)-2] = s->mtfa[(z)-3];
+ s->mtfa[(z)-3] = s->mtfa[(z)-4];
+ nn -= 4;
+ }
+ while (nn > 0) {
+ s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--;
+ };
+ s->mtfa[pp] = uc;
+ } else {
+ /* general case */
+ lno = nn / MTFL_SIZE;
+ off = nn % MTFL_SIZE;
+ pp = s->mtfbase[lno] + off;
+ uc = s->mtfa[pp];
+ while (pp > s->mtfbase[lno]) {
+ s->mtfa[pp] = s->mtfa[pp-1]; pp--;
+ };
+ s->mtfbase[lno]++;
+ while (lno > 0) {
+ s->mtfbase[lno]--;
+ s->mtfa[s->mtfbase[lno]]
+ = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
+ lno--;
+ }
+ s->mtfbase[0]--;
+ s->mtfa[s->mtfbase[0]] = uc;
+ if (s->mtfbase[0] == 0) {
+ kk = MTFA_SIZE-1;
+ for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
+ for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
+ s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
+ kk--;
+ }
+ s->mtfbase[ii] = kk + 1;
+ }
+ }
+ }
+ }
+ /*-- end uc = MTF ( nextSym-1 ) --*/
+
+ s->unzftab[s->seqToUnseq[uc]]++;
+ if (s->smallDecompress)
+ s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
+ s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]);
+ nblock++;
+
+ GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
+ continue;
+ }
+ }
+
+ /* Now we know what nblock is, we can do a better sanity
+ check on s->origPtr.
+ */
+ if (s->origPtr < 0 || s->origPtr >= nblock)
+ RETURN(BZ_DATA_ERROR);
+
+ /*-- Set up cftab to facilitate generation of T^(-1) --*/
+ /* Check: unzftab entries in range. */
+ for (i = 0; i <= 255; i++) {
+ if (s->unzftab[i] < 0 || s->unzftab[i] > nblock)
+ RETURN(BZ_DATA_ERROR);
+ }
+ /* Actually generate cftab. */
+ s->cftab[0] = 0;
+ for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
+ for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
+ /* Check: cftab entries in range. */
+ for (i = 0; i <= 256; i++) {
+ if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
+ /* s->cftab[i] can legitimately be == nblock */
+ RETURN(BZ_DATA_ERROR);
+ }
+ }
+ /* Check: cftab entries non-descending. */
+ for (i = 1; i <= 256; i++) {
+ if (s->cftab[i-1] > s->cftab[i]) {
+ RETURN(BZ_DATA_ERROR);
+ }
+ }
+
+ s->state_out_len = 0;
+ s->state_out_ch = 0;
+ BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
+ s->state = BZ_X_OUTPUT;
+ if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
+
+ if (s->smallDecompress) {
+
+ /*-- Make a copy of cftab, used in generation of T --*/
+ for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
+
+ /*-- compute the T vector --*/
+ for (i = 0; i < nblock; i++) {
+ uc = (UChar)(s->ll16[i]);
+ SET_LL(i, s->cftabCopy[uc]);
+ s->cftabCopy[uc]++;
+ }
+
+ /*-- Compute T^(-1) by pointer reversal on T --*/
+ i = s->origPtr;
+ j = GET_LL(i);
+ do {
+ Int32 tmp = GET_LL(j);
+ SET_LL(j, i);
+ i = j;
+ j = tmp;
+ }
+ while (i != s->origPtr);
+
+ s->tPos = s->origPtr;
+ s->nblock_used = 0;
+ if (s->blockRandomised) {
+ BZ_RAND_INIT_MASK;
+ BZ_GET_SMALL(s->k0); s->nblock_used++;
+ BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
+ } else {
+ BZ_GET_SMALL(s->k0); s->nblock_used++;
+ }
+
+ } else {
+
+ /*-- compute the T^(-1) vector --*/
+ for (i = 0; i < nblock; i++) {
+ uc = (UChar)(s->tt[i] & 0xff);
+ s->tt[s->cftab[uc]] |= (i << 8);
+ s->cftab[uc]++;
+ }
+
+ s->tPos = s->tt[s->origPtr] >> 8;
+ s->nblock_used = 0;
+ if (s->blockRandomised) {
+ BZ_RAND_INIT_MASK;
+ BZ_GET_FAST(s->k0); s->nblock_used++;
+ BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
+ } else {
+ BZ_GET_FAST(s->k0); s->nblock_used++;
+ }
+
+ }
+
+ RETURN(BZ_OK);
+
+
+
+ endhdr_2:
+
+ GET_UCHAR(BZ_X_ENDHDR_2, uc);
+ if (uc != 0x72) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_ENDHDR_3, uc);
+ if (uc != 0x45) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_ENDHDR_4, uc);
+ if (uc != 0x38) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_ENDHDR_5, uc);
+ if (uc != 0x50) RETURN(BZ_DATA_ERROR);
+ GET_UCHAR(BZ_X_ENDHDR_6, uc);
+ if (uc != 0x90) RETURN(BZ_DATA_ERROR);
+
+ s->storedCombinedCRC = 0;
+ GET_UCHAR(BZ_X_CCRC_1, uc);
+ s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_CCRC_2, uc);
+ s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_CCRC_3, uc);
+ s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+ GET_UCHAR(BZ_X_CCRC_4, uc);
+ s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+
+ s->state = BZ_X_IDLE;
+ RETURN(BZ_STREAM_END);
+
+ default: AssertH ( False, 4001 );
+ }
+
+ AssertH ( False, 4002 );
+
+ save_state_and_return:
+
+ s->save_i = i;
+ s->save_j = j;
+ s->save_t = t;
+ s->save_alphaSize = alphaSize;
+ s->save_nGroups = nGroups;
+ s->save_nSelectors = nSelectors;
+ s->save_EOB = EOB;
+ s->save_groupNo = groupNo;
+ s->save_groupPos = groupPos;
+ s->save_nextSym = nextSym;
+ s->save_nblockMAX = nblockMAX;
+ s->save_nblock = nblock;
+ s->save_es = es;
+ s->save_N = N;
+ s->save_curr = curr;
+ s->save_zt = zt;
+ s->save_zn = zn;
+ s->save_zvec = zvec;
+ s->save_zj = zj;
+ s->save_gSel = gSel;
+ s->save_gMinlen = gMinlen;
+ s->save_gLimit = gLimit;
+ s->save_gBase = gBase;
+ s->save_gPerm = gPerm;
+
+ return retVal;
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end decompress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/utils/bzip2/huffman.c b/utils/bzip2/huffman.c
new file mode 100644
index 0000000000..2283fdbc5a
--- /dev/null
+++ b/utils/bzip2/huffman.c
@@ -0,0 +1,205 @@
+
+/*-------------------------------------------------------------*/
+/*--- Huffman coding low-level stuff ---*/
+/*--- huffman.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.6 of 6 September 2010
+ Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*---------------------------------------------------*/
+#define WEIGHTOF(zz0) ((zz0) & 0xffffff00)
+#define DEPTHOF(zz1) ((zz1) & 0x000000ff)
+#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
+
+#define ADDWEIGHTS(zw1,zw2) \
+ (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \
+ (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
+
+#define UPHEAP(z) \
+{ \
+ Int32 zz, tmp; \
+ zz = z; tmp = heap[zz]; \
+ while (weight[tmp] < weight[heap[zz >> 1]]) { \
+ heap[zz] = heap[zz >> 1]; \
+ zz >>= 1; \
+ } \
+ heap[zz] = tmp; \
+}
+
+#define DOWNHEAP(z) \
+{ \
+ Int32 zz, yy, tmp; \
+ zz = z; tmp = heap[zz]; \
+ while (True) { \
+ yy = zz << 1; \
+ if (yy > nHeap) break; \
+ if (yy < nHeap && \
+ weight[heap[yy+1]] < weight[heap[yy]]) \
+ yy++; \
+ if (weight[tmp] < weight[heap[yy]]) break; \
+ heap[zz] = heap[yy]; \
+ zz = yy; \
+ } \
+ heap[zz] = tmp; \
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbMakeCodeLengths ( UChar *len,
+ Int32 *freq,
+ Int32 alphaSize,
+ Int32 maxLen )
+{
+ /*--
+ Nodes and heap entries run from 1. Entry 0
+ for both the heap and nodes is a sentinel.
+ --*/
+ Int32 nNodes, nHeap, n1, n2, i, j, k;
+ Bool tooLong;
+
+ Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ];
+ Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ];
+ Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ];
+
+ for (i = 0; i < alphaSize; i++)
+ weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+
+ while (True) {
+
+ nNodes = alphaSize;
+ nHeap = 0;
+
+ heap[0] = 0;
+ weight[0] = 0;
+ parent[0] = -2;
+
+ for (i = 1; i <= alphaSize; i++) {
+ parent[i] = -1;
+ nHeap++;
+ heap[nHeap] = i;
+ UPHEAP(nHeap);
+ }
+
+ AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 );
+
+ while (nHeap > 1) {
+ n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
+ n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
+ nNodes++;
+ parent[n1] = parent[n2] = nNodes;
+ weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
+ parent[nNodes] = -1;
+ nHeap++;
+ heap[nHeap] = nNodes;
+ UPHEAP(nHeap);
+ }
+
+ AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 );
+
+ tooLong = False;
+ for (i = 1; i <= alphaSize; i++) {
+ j = 0;
+ k = i;
+ while (parent[k] >= 0) { k = parent[k]; j++; }
+ len[i-1] = j;
+ if (j > maxLen) tooLong = True;
+ }
+
+ if (! tooLong) break;
+
+ /* 17 Oct 04: keep-going condition for the following loop used
+ to be 'i < alphaSize', which missed the last element,
+ theoretically leading to the possibility of the compressor
+ looping. However, this count-scaling step is only needed if
+ one of the generated Huffman code words is longer than
+ maxLen, which up to and including version 1.0.2 was 20 bits,
+ which is extremely unlikely. In version 1.0.3 maxLen was
+ changed to 17 bits, which has minimal effect on compression
+ ratio, but does mean this scaling step is used from time to
+ time, enough to verify that it works.
+
+ This means that bzip2-1.0.3 and later will only produce
+ Huffman codes with a maximum length of 17 bits. However, in
+ order to preserve backwards compatibility with bitstreams
+ produced by versions pre-1.0.3, the decompressor must still
+ handle lengths of up to 20. */
+
+ for (i = 1; i <= alphaSize; i++) {
+ j = weight[i] >> 8;
+ j = 1 + (j / 2);
+ weight[i] = j << 8;
+ }
+ }
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbAssignCodes ( Int32 *code,
+ UChar *length,
+ Int32 minLen,
+ Int32 maxLen,
+ Int32 alphaSize )
+{
+ Int32 n, vec, i;
+
+ vec = 0;
+ for (n = minLen; n <= maxLen; n++) {
+ for (i = 0; i < alphaSize; i++)
+ if (length[i] == n) { code[i] = vec; vec++; };
+ vec <<= 1;
+ }
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbCreateDecodeTables ( Int32 *limit,
+ Int32 *base,
+ Int32 *perm,
+ UChar *length,
+ Int32 minLen,
+ Int32 maxLen,
+ Int32 alphaSize )
+{
+ Int32 pp, i, j, vec;
+
+ pp = 0;
+ for (i = minLen; i <= maxLen; i++)
+ for (j = 0; j < alphaSize; j++)
+ if (length[j] == i) { perm[pp] = j; pp++; };
+
+ for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0;
+ for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
+
+ for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1];
+
+ for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0;
+ vec = 0;
+
+ for (i = minLen; i <= maxLen; i++) {
+ vec += (base[i+1] - base[i]);
+ limit[i] = vec-1;
+ vec <<= 1;
+ }
+ for (i = minLen + 1; i <= maxLen; i++)
+ base[i] = ((limit[i-1] + 1) << 1) - base[i];
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end huffman.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/utils/bzip2/randtable.c b/utils/bzip2/randtable.c
new file mode 100644
index 0000000000..6d62459906
--- /dev/null
+++ b/utils/bzip2/randtable.c
@@ -0,0 +1,84 @@
+
+/*-------------------------------------------------------------*/
+/*--- Table for randomising repetitive blocks ---*/
+/*--- randtable.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.6 of 6 September 2010
+ Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
+
+ Please read the WARNING, DISCLAIMER and PATENTS sections in the
+ README file.
+
+ This program is released under the terms of the license contained
+ in the file LICENSE.
+ ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------*/
+Int32 BZ2_rNums[512] = {
+ 619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
+ 985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
+ 733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
+ 419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
+ 878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
+ 862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
+ 150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
+ 170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
+ 73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
+ 909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
+ 641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
+ 161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
+ 382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
+ 98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
+ 227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
+ 469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
+ 184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
+ 715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
+ 951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
+ 652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
+ 645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
+ 609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
+ 653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
+ 411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
+ 170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
+ 857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
+ 669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
+ 944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
+ 344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
+ 897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
+ 433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
+ 686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
+ 946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
+ 978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
+ 680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
+ 707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
+ 297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
+ 134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
+ 343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
+ 140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
+ 170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
+ 369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
+ 804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
+ 896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
+ 661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
+ 768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
+ 61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
+ 372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
+ 780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
+ 920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
+ 645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
+ 936, 638
+};
+
+
+/*-------------------------------------------------------------*/
+/*--- end randtable.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/utils/chinachippatcher/Makefile b/utils/chinachippatcher/Makefile
new file mode 100644
index 0000000000..c8defcb5c4
--- /dev/null
+++ b/utils/chinachippatcher/Makefile
@@ -0,0 +1,17 @@
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+# $Id$
+#
+CFLAGS += -g -Wall
+
+OUTPUT = chinachippatcher
+
+LIBSOURCES = chinachip.c
+SOURCES = main.c
+
+include ../libtools.make
+
diff --git a/utils/chinachippatcher/chinachip.c b/utils/chinachippatcher/chinachip.c
new file mode 100644
index 0000000000..79b5acad66
--- /dev/null
+++ b/utils/chinachippatcher/chinachip.c
@@ -0,0 +1,258 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2009 by Maurus Cuelenaere
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+#include "chinachip.h"
+
+/* From http://www.rockbox.org/wiki/ChinaChip */
+struct header
+{
+ uint32_t signature; /* WADF */
+ uint32_t unk;
+ int8_t timestamp[12]; /* 200805081100 */
+ uint32_t size;
+ uint32_t checksum;
+ uint32_t unk2;
+ int8_t identifier[32]; /* Chinachip PMP firmware V1.0 */
+} __attribute__ ((packed));
+
+static inline void int2le(unsigned char* addr, unsigned int val)
+{
+ addr[0] = val & 0xff;
+ addr[1] = (val >> 8) & 0xff;
+ addr[2] = (val >> 16) & 0xff;
+ addr[3] = (val >> 24) & 0xff;
+}
+
+static inline unsigned int le2int(unsigned char* buf)
+{
+ return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+}
+
+static long int filesize(FILE* fd)
+{
+ long int len;
+ fseek(fd, 0, SEEK_END);
+ len = ftell(fd);
+ fseek(fd, 0, SEEK_SET);
+ return len;
+}
+
+#define FCLOSE(fd) fclose(fd); fd = NULL;
+#define CCPMPBIN_HEADER_SIZE (sizeof(uint32_t)*2 + sizeof(uint8_t) + 9)
+#define TOTAL_SIZE (fsize + CCPMPBIN_HEADER_SIZE + bsize)
+enum cc_error chinachip_patch(const char* firmware, const char* bootloader,
+ const char* output, const char* ccpmp_backup)
+{
+ char header_time[13];
+ time_t cur_time;
+ struct tm* time_info;
+ unsigned char* buf = NULL;
+ FILE *fd = NULL, *bd = NULL, *od = NULL;
+ unsigned int ccpmp_size = 0, i, fsize, bsize;
+ signed int checksum = 0, ccpmp_pos;
+ int result = E_OK;
+
+ fd = fopen(firmware, "rb");
+ if(!fd)
+ {
+ fprintf(stderr, "[ERR] Can't open file %s!\n", firmware);
+ result = E_OPEN_FIRMWARE;
+ goto err;
+ }
+ bd = fopen(bootloader, "rb");
+ if(!bd)
+ {
+ fprintf(stderr, "[ERR] Can't open file %s!\n", bootloader);
+ result = E_OPEN_BOOTLOADER;
+ goto err;
+ }
+
+ bsize = filesize(bd);
+ fprintf(stderr, "[INFO] Bootloader size is %d bytes\n", bsize);
+ FCLOSE(bd);
+
+ fsize = filesize(fd);
+ fprintf(stderr, "[INFO] Firmware size is %d bytes\n", fsize);
+
+ buf = malloc(TOTAL_SIZE);
+ if(buf == NULL)
+ {
+ fprintf(stderr, "[ERR] Can't allocate %d bytes!\n", fsize);
+ result = E_MEMALLOC;
+ goto err;
+ }
+ memset(buf, 0, TOTAL_SIZE);
+
+ fprintf(stderr, "[INFO] Reading %s into memory...\n", firmware);
+ if(fread(buf, fsize, 1, fd) != 1)
+ {
+ fprintf(stderr, "[ERR] Can't read file %s to memory!\n", firmware);
+ result = E_LOAD_FIRMWARE;
+ goto err;
+ }
+ FCLOSE(fd);
+
+ if(memcmp(buf, "WADF", 4))
+ {
+ fprintf(stderr, "[ERR] File %s isn't a valid ChinaChip firmware!\n", firmware);
+ result = E_INVALID_FILE;
+ goto err;
+ }
+
+ ccpmp_pos = -1, i = 0x40;
+ do
+ {
+ int filenamesize = le2int(&buf[i]);
+ i += sizeof(uint32_t);
+
+ if(!strncmp((char*) &buf[i], "ccpmp.bin", 9))
+ {
+ ccpmp_pos = i;
+ ccpmp_size = le2int(&buf[i + sizeof(uint8_t) + filenamesize]);
+ }
+ else
+ i += filenamesize + le2int(&buf[i + sizeof(uint8_t) + filenamesize])
+ + sizeof(uint32_t) + sizeof(uint8_t);
+ } while(ccpmp_pos < 0 && i < fsize);
+
+ if(i >= fsize)
+ {
+ fprintf(stderr, "[ERR] Couldn't find ccpmp.bin in %s!\n", firmware);
+ result = E_NO_CCPMP;
+ goto err;
+ }
+ fprintf(stderr, "[INFO] Found ccpmp.bin at %d bytes\n", ccpmp_pos);
+
+ if(ccpmp_backup)
+ {
+ int ccpmp_data_pos = ccpmp_pos + 9;
+ bd = fopen(ccpmp_backup, "wb");
+ if(!bd)
+ {
+ fprintf(stderr, "[ERR] Can't open file %s!\n", ccpmp_backup);
+ result = E_OPEN_BACKUP;
+ goto err;
+ }
+
+ fprintf(stderr, "[INFO] Writing %d bytes to %s...\n", ccpmp_size, ccpmp_backup);
+ if(fwrite(&buf[ccpmp_data_pos], ccpmp_size, 1, bd) != 1)
+ {
+ fprintf(stderr, "[ERR] Can't write to file %s!\n", ccpmp_backup);
+ result = E_WRITE_BACKUP;
+ goto err;
+ }
+ FCLOSE(bd);
+ }
+
+ fprintf(stderr, "[INFO] Renaming it to ccpmp.old...\n");
+ buf[ccpmp_pos + 6] = 'o';
+ buf[ccpmp_pos + 7] = 'l';
+ buf[ccpmp_pos + 8] = 'd';
+
+ bd = fopen(bootloader, "rb");
+ if(!bd)
+ {
+ fprintf(stderr, "[ERR] Can't open file %s!\n", bootloader);
+ result = E_OPEN_BOOTLOADER;
+ goto err;
+ }
+
+ /* Also include path size */
+ ccpmp_pos -= sizeof(uint32_t);
+
+ fprintf(stderr, "[INFO] Making place for ccpmp.bin...\n");
+ memmove(&buf[ccpmp_pos + bsize + CCPMPBIN_HEADER_SIZE],
+ &buf[ccpmp_pos], fsize - ccpmp_pos);
+
+ fprintf(stderr, "[INFO] Reading %s into memory...\n", bootloader);
+ if(fread(&buf[ccpmp_pos + CCPMPBIN_HEADER_SIZE],
+ bsize, 1, bd) != 1)
+ {
+ fprintf(stderr, "[ERR] Can't read file %s to memory!\n", bootloader);
+ result = E_LOAD_BOOTLOADER;
+ goto err;
+ }
+ FCLOSE(bd);
+
+ fprintf(stderr, "[INFO] Adding header to %s...\n", bootloader);
+ int2le(&buf[ccpmp_pos ], 9); /* Pathname Size */
+ memcpy(&buf[ccpmp_pos + 4 ], "ccpmp.bin", 9); /* Pathname */
+ memset(&buf[ccpmp_pos + 4 + 9 ], 0x20, sizeof(uint8_t)); /* File Type */
+ int2le(&buf[ccpmp_pos + 4 + 9 + 1], bsize); /* File Size */
+
+ time(&cur_time);
+ time_info = localtime(&cur_time);
+ if(time_info == NULL)
+ {
+ fprintf(stderr, "[ERR] Can't obtain current time!\n");
+ result = E_GET_TIME;
+ goto err;
+ }
+
+ snprintf(header_time, 13, "%04d%02d%02d%02d%02d", time_info->tm_year + 1900,
+ time_info->tm_mon,
+ time_info->tm_mday,
+ time_info->tm_hour,
+ time_info->tm_min);
+
+ fprintf(stderr, "[INFO] Computing checksum...\n");
+ for(i = sizeof(struct header); i < TOTAL_SIZE; i+=4)
+ checksum += le2int(&buf[i]);
+
+ fprintf(stderr, "[INFO] Updating main header...\n");
+ memcpy(&buf[offsetof(struct header, timestamp)], header_time, 12);
+ int2le(&buf[offsetof(struct header, size) ], TOTAL_SIZE);
+ int2le(&buf[offsetof(struct header, checksum) ], checksum);
+
+ od = fopen(output, "wb");
+ if(!od)
+ {
+ fprintf(stderr, "[ERR] Can't open file %s!\n", output);
+ result = E_OPEN_OUTFILE;
+ goto err;
+ }
+
+ fprintf(stderr, "[INFO] Writing output to %s...\n", output);
+ if(fwrite(buf, TOTAL_SIZE, 1, od) != 1)
+ {
+ fprintf(stderr, "[ERR] Can't write to file %s!\n", output);
+ result = E_WRITE_OUTFILE;
+ goto err;
+ }
+
+err:
+ if(buf)
+ free(buf);
+ if(fd)
+ fclose(fd);
+ if(bd)
+ fclose(bd);
+ if(od)
+ fclose(od);
+
+ return result;
+}
+
diff --git a/utils/chinachippatcher/chinachip.h b/utils/chinachippatcher/chinachip.h
new file mode 100644
index 0000000000..b92066bb8b
--- /dev/null
+++ b/utils/chinachippatcher/chinachip.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2009 by Maurus Cuelenaere
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_CHINACHIP_H_
+#define __INCLUDE_CHINACHIP_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum cc_error {
+ E_OK,
+ E_OPEN_FIRMWARE,
+ E_OPEN_BOOTLOADER,
+ E_MEMALLOC,
+ E_LOAD_FIRMWARE,
+ E_INVALID_FILE,
+ E_NO_CCPMP,
+ E_OPEN_BACKUP,
+ E_WRITE_BACKUP,
+ E_LOAD_BOOTLOADER,
+ E_GET_TIME,
+ E_OPEN_OUTFILE,
+ E_WRITE_OUTFILE,
+};
+
+enum cc_error chinachip_patch(const char* firmware, const char* bootloader,
+ const char* output, const char* ccpmp_backup);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_CHINACHIP_H_ */
diff --git a/utils/chinachippatcher/main.c b/utils/chinachippatcher/main.c
new file mode 100644
index 0000000000..e7779774c9
--- /dev/null
+++ b/utils/chinachippatcher/main.c
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2009 by Maurus Cuelenaere
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <stdio.h>
+#include <stdarg.h>
+#include "chinachip.h"
+
+#ifndef VERSION /* allow setting version from outside for svn builds */
+#define VERSION "0.1"
+#endif
+#define PRINT(fmt, ...) fprintf(stderr, fmt"\n", ##__VA_ARGS__)
+
+void usage(char* name)
+{
+ PRINT("Usage:");
+ PRINT(" %s <firmware> <bootloader> <firmware_output> [backup]", name);
+ PRINT("\nExample:");
+ PRINT(" %s VX747.HXF bootloader.bin output.HXF ccpmp.bak", name);
+ PRINT(" This will copy ccpmp.bin in VX747.HXF as ccpmp.old and replace it\n"
+ " with bootloader.bin, the output will get written to output.HXF.\n"
+ " The old ccpmp.bin will get written to ccpmp.bak.\n");
+}
+
+int main(int argc, char* argv[])
+{
+ PRINT("ChinaChipPatcher v" VERSION " - (C) Maurus Cuelenaere 2009");
+ PRINT("This is free software; see the source for copying conditions. There is NO");
+ PRINT("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
+
+ if(argc < 4)
+ {
+ usage(argv[0]);
+ return 1;
+ }
+
+ return chinachip_patch(argv[1], argv[2], argv[3], argc > 4 ? argv[4] : NULL);
+}
+
diff --git a/utils/cmake/QtTest.cmake b/utils/cmake/QtTest.cmake
new file mode 100755
index 0000000000..4214c7ddc3
--- /dev/null
+++ b/utils/cmake/QtTest.cmake
@@ -0,0 +1,134 @@
+# Copyright 2020 Olivier Croquette <ocroquette@free.fr>
+#
+# 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.
+#
+# v1.2
+#
+# Latest version is available from GitHub:
+# https://github.com/ocroquette/cmake-qtest-discovery
+
+#[=======================================================================[.rst:
+QtTest
+----------
+
+This module defines functions to help use the Qt Test infrastructure.
+The main function is :command:`qtest_discover_tests`.
+
+.. command:: qtest_discover_tests
+
+ Automatically add tests with CTest by querying the compiled test executable
+ for available tests::
+
+ qtest_discover_tests(target
+ [WORKING_DIRECTORY dir]
+ [TEST_PREFIX prefix]
+ [TEST_SUFFIX suffix]
+ [PROPERTIES name1 value1...]
+ [DISCOVERY_TIMEOUT seconds])
+
+ ``qtest_discover_tests`` sets up a post-build command on the test executable
+ that generates the list of tests by parsing the output from running the test
+ with the ``-datatags`` argument. This ensures that the full list of
+ tests, including instantiations of parameterized tests, is obtained. Since
+ test discovery occurs at build time, it is not necessary to re-run CMake when
+ the list of tests changes.
+
+ The options are:
+
+ ``target``
+ Specifies the Google Test executable, which must be a known CMake
+ executable target. CMake will substitute the location of the built
+ executable when running the test.
+
+ ``WORKING_DIRECTORY dir``
+ Specifies the directory in which to run the discovered test cases. If this
+ option is not provided, the current binary directory is used.
+
+ ``TEST_PREFIX prefix``
+ Specifies a ``prefix`` to be prepended to the name of each discovered test
+ case.
+
+ ``TEST_SUFFIX suffix``
+ Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
+ every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
+ be specified.
+
+ ``PROPERTIES name1 value1...``
+ Specifies additional properties to be set on all tests discovered by this
+ invocation of ``qtest_discover_tests``. You can specify a timeout for the
+ test execution by setting the TIMEOUT property here, as supported by ctest.
+
+ ``DISCOVERY_TIMEOUT sec``
+ Specifies how long (in seconds) CMake will wait for the test to enumerate
+ available tests. If the test takes longer than this, discovery (and your
+ build) will fail. Most test executables will enumerate their tests very
+ quickly, but under some exceptional circumstances, a test may require a
+ longer timeout. The default is 5. See also the ``TIMEOUT`` option of
+ :command:`execute_process`.
+
+#]=======================================================================]
+
+function(qtest_discover_tests TARGET)
+if(NOT CMAKE_CROSSCOMPILING)
+ cmake_parse_arguments(
+ ""
+ ""
+ "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;DISCOVERY_TIMEOUT"
+ "PROPERTIES"
+ ${ARGN}
+ )
+
+ if(NOT _WORKING_DIRECTORY)
+ set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+ endif()
+ if(NOT _DISCOVERY_TIMEOUT)
+ set(_DISCOVERY_TIMEOUT 5)
+ endif()
+
+ set(ctest_file_base "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}")
+ set(ctest_include_file "${ctest_file_base}_tests.cmake")
+ add_custom_command(TARGET ${TARGET}
+ POST_BUILD
+ COMMAND "${CMAKE_COMMAND}"
+ -D "\"TEST_EXECUTABLE:FILEPATH=$<TARGET_FILE:${TARGET}>\""
+ -D "\"CTEST_FILE:FILEPATH=${ctest_include_file}\""
+ -D "\"TEST_PROPERTIES=${_PROPERTIES}\""
+ -D "\"TEST_DISCOVERY_TIMEOUT=${_DISCOVERY_TIMEOUT}\""
+ -D "\"TEST_PREFIX=${_TEST_PREFIX}\""
+ -D "\"TEST_SUFFIX=${_TEST_SUFFIX}\""
+ -D "\"TEST_WORKING_DIR=${_WORKING_DIRECTORY}\""
+ -P "\"${_QTTEST_DISCOVER_TESTS_SCRIPT}\""
+ BYPRODUCTS "${ctest_include_file}"
+ )
+
+ set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES
+ "${ctest_include_file}"
+ )
+else()
+ message("-- Cross compiling, discovering unit tests disabled.")
+endif()
+endfunction()
+
+
+###############################################################################
+
+set(_QTTEST_DISCOVER_TESTS_SCRIPT
+ ${CMAKE_CURRENT_LIST_DIR}/QtTestAddTests.cmake
+)
diff --git a/utils/cmake/QtTestAddTests.cmake b/utils/cmake/QtTestAddTests.cmake
new file mode 100755
index 0000000000..1a8db46783
--- /dev/null
+++ b/utils/cmake/QtTestAddTests.cmake
@@ -0,0 +1,102 @@
+# Copyright 2020 Olivier Croquette <ocroquette@free.fr>
+#
+# 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.
+#
+# This script is run as POST_BUILD step, added by QtTest.cmake. See there
+# for more information.
+#
+# v1.2
+#
+# Latest version is available from GitHub:
+# https://github.com/ocroquette/cmake-qtest-discovery
+
+get_filename_component(working_dir ${TEST_EXECUTABLE} DIRECTORY)
+
+execute_process(
+ COMMAND "${TEST_EXECUTABLE}" -datatags
+ WORKING_DIR ${working_dir}
+ OUTPUT_VARIABLE output_variable
+ TIMEOUT ${TEST_DISCOVERY_TIMEOUT}
+ ERROR_VARIABLE error_variable
+ RESULT_VARIABLE result_variable
+)
+
+if(NOT "${result_variable}" EQUAL 0)
+ string(REPLACE "\n" "\n " output "${output}")
+ message(FATAL_ERROR
+ "Error running test executable.\n"
+ " Path: '${TEST_EXECUTABLE}'\n"
+ " Result: ${result_variable}\n"
+ " Output:\n"
+ " ${output_variable}\n"
+ " Error:\n"
+ " ${error_variable}\n"
+ )
+endif()
+
+macro(get_and_escape_parameters)
+ set(test_class ${CMAKE_MATCH_1})
+ set(test_method ${CMAKE_MATCH_2})
+ set(test_dataset ${CMAKE_MATCH_3})
+
+ # Test class and method should be safe, but the dataset name might
+ # contain problematic characters
+ set(test_dataset_escaped "${test_dataset}")
+ string(REPLACE "\\" "\\\\" test_dataset_escaped "${test_dataset_escaped}")
+ string(REPLACE "\"" "\\\"" test_dataset_escaped "${test_dataset_escaped}")
+endmacro()
+
+set(ctest_script_content)
+string(REPLACE "\n" ";" output_lines "${output_variable}")
+foreach(line ${output_lines})
+ set(generated_name)
+ if(line MATCHES "^([^ ]*) ([^ ]*) (.*)$")
+ # Line contains a data set name, like in:
+ # test_qttestdemo myParameterizedTest data set name 1
+ # test_qttestdemo myParameterizedTest data set name 2
+ get_and_escape_parameters()
+ set(generated_name "${TEST_PREFIX}${test_class}.${test_method}:${test_dataset_escaped}${TEST_SUFFIX}")
+ string(APPEND ctest_script_content "add_test(\"${generated_name}\" \"${TEST_EXECUTABLE}\" \"${test_method}:${test_dataset_escaped}\")\n")
+ elseif(line MATCHES "^([^ ]*) ([^ ]*)$")
+ # Line doesn't contain a data set name, like in:
+ # test_qttestdemo myFirstTest
+ # test_qttestdemo mySecondTest
+ get_and_escape_parameters()
+ set(generated_name "${TEST_PREFIX}${test_class}.${test_method}${TEST_SUFFIX}")
+ string(APPEND ctest_script_content "add_test(\"${generated_name}\" \"${TEST_EXECUTABLE}\" \"${test_method}\")\n")
+ endif()
+ if(generated_name)
+ # Make ctest aware of tests skipped with QSKIP()
+ # SKIP : test_qttestdemo::mySkippedTest() Example of skipped test
+ string(APPEND ctest_script_content
+ "set_tests_properties(\"${generated_name}\" PROPERTIES SKIP_REGULAR_EXPRESSION \"SKIP : \")\n"
+ )
+ # Set other properties
+ string(APPEND ctest_script_content
+ "set_tests_properties(\"${generated_name}\" PROPERTIES WORKING_DIRECTORY \"${TEST_WORKING_DIR}\")\n"
+ )
+ string(REPLACE ";" " " external_properties "${TEST_PROPERTIES}")
+ string(APPEND ctest_script_content
+ "set_tests_properties(\"${generated_name}\" PROPERTIES ${external_properties})\n"
+ )
+ endif()
+endforeach()
+
+file(WRITE "${CTEST_FILE}" "${ctest_script_content}")
diff --git a/utils/cmake/deploy.cmake b/utils/cmake/deploy.cmake
new file mode 100644
index 0000000000..252aba0636
--- /dev/null
+++ b/utils/cmake/deploy.cmake
@@ -0,0 +1,219 @@
+#
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+#
+# All files in this archive are subject to the GNU General Public License.
+# See the file COPYING in the source tree root for full license agreement.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+
+# include this file to
+# - get a new target "deploy"
+# - get a function "deploy_qt()" which will add a deploy target that creates a
+# zip / AppImage / dmg and depends on "deploy".
+
+if(NOT have_deploy)
+ add_custom_target(deploy)
+ set(have_deploy ON)
+endif()
+
+# Linux: Build AppImage
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ set(LINUXDEPLOY ${CMAKE_BINARY_DIR}/linuxdeploy-x86_64.AppImage)
+ set(LINUXDEPLOYQT ${CMAKE_BINARY_DIR}/linuxdeploy-plugin-qt-x86_64.AppImage)
+ add_custom_command(
+ COMMENT "Downloading linuxdeploy"
+ OUTPUT ${LINUXDEPLOY}
+ ${LINUXDEPLOYQT}
+ COMMAND ${CMAKE_COMMAND}
+ -DOUTDIR=${CMAKE_BINARY_DIR}
+ -DURL=https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
+ -P ${CMAKE_CURRENT_LIST_DIR}/download.cmake
+ COMMAND ${CMAKE_COMMAND}
+ -DOUTDIR=${CMAKE_BINARY_DIR}
+ -DURL=https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
+ -P ${CMAKE_CURRENT_LIST_DIR}/download.cmake
+ )
+ # intermediate target needed to be able to get back to the actual file dependency.
+ add_custom_target(linuxdeploy DEPENDS ${LINUXDEPLOY})
+
+ function(deploy_qt)
+ cmake_parse_arguments(deploy ""
+ "TARGET;DESKTOPFILE;ICONFILE;QTBINDIR;DMGBUILDCFG"
+ "EXECUTABLES"
+ ${ARGN})
+ if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
+ message(WARNING "Deploying a Debug build.")
+ endif()
+
+ add_custom_target(deploy_${deploy_TARGET}
+ DEPENDS ${CMAKE_BINARY_DIR}/${deploy_TARGET}.AppImage)
+
+ # need extra rules so we can use generator expressions
+ # (using get_target_property() doesn't know neede values during generation)
+ set(_deploy_deps "")
+ foreach(_deploy_exe_tgt ${deploy_EXECUTABLES})
+ add_custom_command(
+ OUTPUT ${CMAKE_BINARY_DIR}/${_deploy_exe_tgt}.appimage.stamp
+ COMMENT "Copying ${_deploy_exe_tgt} to AppImage"
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/AppImage-${deploy_TARGET}/usr/bin
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${_deploy_exe_tgt}>
+ ${CMAKE_BINARY_DIR}/AppImage-${deploy_TARGET}/usr/bin
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${_deploy_exe_tgt}.appimage.stamp
+ DEPENDS ${_deploy_exe_tgt}
+ )
+ add_custom_target(deploy_${deploy_TARGET}_${_deploy_exe_tgt}
+ DEPENDS ${CMAKE_BINARY_DIR}/${_deploy_exe_tgt}.appimage.stamp)
+
+ set(_deploy_deps "${_deploy_deps};deploy_${deploy_TARGET}_${_deploy_exe_tgt}")
+ endforeach()
+
+ add_custom_command(
+ OUTPUT ${CMAKE_BINARY_DIR}/${deploy_TARGET}.AppImage
+ COMMENT "Creating AppImage ${deploy_TARGET}"
+ COMMAND OUTPUT=${CMAKE_BINARY_DIR}/${deploy_TARGET}.AppImage
+ ${LINUXDEPLOY}
+ --plugin qt
+ --icon-file=${deploy_ICONFILE}
+ --desktop-file=${deploy_DESKTOPFILE}
+ --executable=$<TARGET_FILE:${deploy_TARGET}>
+ --appdir=${CMAKE_BINARY_DIR}/AppImage-${deploy_TARGET}
+ --output=appimage
+ --verbosity=2
+ DEPENDS ${deploy_TARGET} ${_deploy_deps} linuxdeploy
+ )
+ add_dependencies(deploy deploy_${deploy_TARGET})
+ endfunction()
+endif()
+
+# MacOS: Build dmg
+if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ function(deploy_qt)
+ cmake_parse_arguments(deploy ""
+ "TARGET;DESKTOPFILE;ICONFILE;QTBINDIR;DMGBUILDCFG"
+ "EXECUTABLES"
+ ${ARGN})
+ if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
+ message(WARNING "Deploying a Debug build.")
+ endif()
+ set(DMGBUILD ${CMAKE_BINARY_DIR}/venv/bin/python3 -m dmgbuild)
+ set(DMGBUILD_STAMP ${CMAKE_BINARY_DIR}/dmgbuild.stamp)
+ find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${QTBINDIR}")
+
+ # need extra rules so we can use generator expressions
+ # (using get_target_property() doesn't know neede values during generation)
+ set(_deploy_deps "")
+ foreach(_deploy_exe_tgt ${deploy_EXECUTABLES})
+ add_custom_command(
+ OUTPUT ${CMAKE_BINARY_DIR}/${_deploy_exe_tgt}.app.stamp
+ COMMENT "Copying ${_deploy_exe_tgt} to App"
+ COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_BUNDLE_CONTENT_DIR:${deploy_TARGET}>/bin
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${_deploy_exe_tgt}>
+ $<TARGET_BUNDLE_CONTENT_DIR:${deploy_TARGET}>/bin
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${_deploy_exe_tgt}.app.stamp
+ DEPENDS ${_deploy_exe_tgt}
+ )
+ add_custom_target(deploy_${deploy_TARGET}_${_deploy_exe_tgt}
+ DEPENDS ${CMAKE_BINARY_DIR}/${_deploy_exe_tgt}.app.stamp)
+
+ set(_deploy_deps "${_deploy_deps};deploy_${deploy_TARGET}_${_deploy_exe_tgt}")
+ endforeach()
+
+ add_custom_command(
+ COMMENT "Setting up dmgbuild virtualenv"
+ OUTPUT ${DMGBUILD_STAMP}
+ COMMAND python3 -m venv ${CMAKE_BINARY_DIR}/venv
+ COMMAND ${CMAKE_BINARY_DIR}/venv/bin/python -m pip install -q dmgbuild
+ )
+
+ add_custom_command(
+ # TODO: find a better way to figure the app bundle name.
+ OUTPUT ${CMAKE_BINARY_DIR}/${deploy_TARGET}.dmg
+ COMMENT "Running macdeployqt and creating dmg ${deploy_TARGET}"
+ COMMAND ${MACDEPLOYQT_EXECUTABLE} ${deploy_TARGET}.app
+ COMMAND ${DMGBUILD} -s ${deploy_DMGBUILDCFG}
+ -Dappbundle=${deploy_TARGET}.app
+ ${deploy_TARGET} ${CMAKE_BINARY_DIR}/${deploy_TARGET}.dmg
+ DEPENDS ${deploy_TARGET}
+ ${DMGBUILD_STAMP}
+ ${_deploy_deps}
+ )
+ add_custom_target(deploy_${deploy_TARGET}
+ DEPENDS ${CMAKE_BINARY_DIR}/${deploy_TARGET}.dmg)
+ add_dependencies(deploy deploy_${deploy_TARGET})
+ endfunction()
+endif()
+
+# Windows. Copy to dist folder, run windeployqt on the binary, compress to zip.
+if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+ function(deploy_qt)
+ cmake_parse_arguments(deploy ""
+ "TARGET;DESKTOPFILE;ICONFILE;QTBINDIR;DMGBUILDCFG"
+ "EXECUTABLES"
+ ${ARGN})
+ if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
+ message(WARNING "Deploying a Debug build.")
+ endif()
+ find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${QTBINDIR}")
+ set(deploydir ${CMAKE_BINARY_DIR}/deploy-${deploy_TARGET})
+ if(WINDEPLOYQT_EXECUTABLE)
+ add_custom_command(
+ COMMENT "Creating deploy folder and running windeployqt"
+ OUTPUT ${deploydir}/${deploy_TARGET}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${deploydir}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${deploy_TARGET}> ${deploydir}
+ COMMAND ${WINDEPLOYQT_EXECUTABLE}
+ # on MinGW, release is mistaken as debug for Qt less than 5.14.
+ # For later versions the opposite is true: adding --debug or
+ # --release will fail with "platform plugin not found."
+ $<IF:$<VERSION_LESS:${Qt${QT_VERSION_MAJOR}Core_VERSION},5.14.0>,$<IF:$<CONFIG:Debug>,--debug,--release>,>
+ ${deploydir}/$<TARGET_FILE_NAME:${deploy_TARGET}>
+ DEPENDS ${deploy_TARGET}
+ )
+ else()
+ add_custom_command(
+ COMMENT "Creating deploy folder"
+ OUTPUT ${deploydir}/${deploy_TARGET}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${deploydir}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${deploy_TARGET}> ${deploydir}
+ DEPENDS ${deploy_TARGET}
+ )
+ endif()
+ # need extra rules so we can use generator expressions
+ # (using get_target_property() doesn't know neede values during generation)
+ set(_deploy_deps "")
+ foreach(_deploy_exe_tgt ${deploy_EXECUTABLES})
+ add_custom_command(
+ OUTPUT ${CMAKE_BINARY_DIR}/${_deploy_exe_tgt}.app.stamp
+ COMMENT "Copying ${_deploy_exe_tgt} to deploy folder"
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${deploydir}
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${_deploy_exe_tgt}> ${deploydir}
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${_deploy_exe_tgt}.app.stamp
+ DEPENDS ${_deploy_exe_tgt}
+ )
+ add_custom_target(deploy_${deploy_TARGET}_${_deploy_exe_tgt}
+ DEPENDS ${CMAKE_BINARY_DIR}/${_deploy_exe_tgt}.app.stamp)
+
+ set(_deploy_deps "${_deploy_deps};deploy_${deploy_TARGET}_${_deploy_exe_tgt}")
+ endforeach()
+ add_custom_command(
+ COMMENT "Compressing to zip"
+ OUTPUT ${CMAKE_BINARY_DIR}/${deploy_TARGET}.zip
+ WORKING_DIRECTORY ${deploydir}
+ COMMAND ${CMAKE_COMMAND} -E tar c ${CMAKE_BINARY_DIR}/${deploy_TARGET}.zip
+ --format=zip .
+ DEPENDS ${deploydir}/${deploy_TARGET} ${_deploy_deps}
+ )
+
+ add_custom_target(deploy_${deploy_TARGET}
+ DEPENDS ${CMAKE_BINARY_DIR}/${deploy_TARGET}.zip)
+ add_dependencies(deploy deploy_${deploy_TARGET})
+ endfunction()
+endif()
+
diff --git a/utils/cmake/download.cmake b/utils/cmake/download.cmake
new file mode 100644
index 0000000000..bd3df4d83d
--- /dev/null
+++ b/utils/cmake/download.cmake
@@ -0,0 +1,47 @@
+#
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+#
+# All files in this archive are subject to the GNU General Public License.
+# See the file COPYING in the source tree root for full license agreement.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+
+# This is a separate cmake script, to be invoked as
+# cmake -P -DURL=<url-to-download> -DOUTDIR=<output-folder>
+# Downloads the file and store it in OUTDIR, using the file basename as output
+# filename.
+# The downloaded file gets its executable flag set.
+
+function(gettempdir basedir tmpdir)
+ # Create a random filename in current directory.
+ # Result stored in tmpdir.
+ string(RANDOM LENGTH 24 _tmp)
+ while(EXISTS "${basedir}/${_tmp}.tmp")
+ string(RANDOM LENGTH 24 _tmp)
+ endwhile()
+ set("${tmpdir}" "${basedir}/${_tmp}.tmp" PARENT_SCOPE)
+endfunction()
+
+get_filename_component(fname "${URL}" NAME)
+
+if(EXISTS "${OUTDIR}/${fname}")
+ message("-- Found ${fname}")
+else()
+ message("-- Downloading ${URL} ...")
+ gettempdir(${OUTDIR} tmp)
+
+ # cmake CHOWN is 3.19+, thus download to a temporary folder, then copy.
+ file(DOWNLOAD "${URL}" "${tmp}/${fname}")
+ file(COPY "${tmp}/${fname}" DESTINATION "${OUTDIR}"
+ FILE_PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ)
+ file(REMOVE_RECURSE "${tmp}")
+endif()
+
+
diff --git a/utils/cmake/gitversion.cmake b/utils/cmake/gitversion.cmake
new file mode 100644
index 0000000000..b13dfc0a0f
--- /dev/null
+++ b/utils/cmake/gitversion.cmake
@@ -0,0 +1,58 @@
+#
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+#
+# All files in this archive are subject to the GNU General Public License.
+# See the file COPYING in the source tree root for full license agreement.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+
+find_package(Git QUIET)
+
+execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --verify --short=10 HEAD
+ OUTPUT_VARIABLE GIT_HASH
+ ERROR_QUIET)
+
+# Check whether we got any revision (which isn't
+# always the case, e.g. when someone downloaded a zip
+# file from Github instead of a checkout)
+if ("${GIT_HASH}" STREQUAL "")
+ set(GIT_HASH "N/A")
+else()
+ execute_process(
+ COMMAND git diff --quiet --exit-code
+ RESULT_VARIABLE GIT_DIFF_EXITCODE)
+
+ string(STRIP "${GIT_HASH}" GIT_HASH)
+ if (${GIT_DIFF_EXITCODE})
+ set(GIT_DIFF "M")
+ endif()
+endif()
+
+string(TIMESTAMP TODAY "%y%m%d")
+set(VERSION "
+#ifndef GITVERSION
+#define GITVERSION \"${GIT_HASH}${GIT_DIFF}-${TODAY}\"
+#define GITHASH \"${GIT_HASH}${GIT_DIFF}\"
+#define BUILDDATE \"${TODAY}\"
+#endif
+")
+
+if(EXISTS ${OUTFILE})
+ file(READ "${OUTFILE}" _version)
+else()
+ set(_version "")
+endif()
+
+if (NOT "${VERSION}" STREQUAL "${_version}")
+ file(WRITE "${OUTFILE}" "${VERSION}")
+endif()
+
+message("-- Revision: ${GIT_HASH}${GIT_DIFF}")
+
diff --git a/utils/common/deploy-themeeditor.py b/utils/common/deploy-themeeditor.py
deleted file mode 100755
index a85317a426..0000000000
--- a/utils/common/deploy-themeeditor.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/usr/bin/python
-# __________ __ ___.
-# Open \______ \ ____ ____ | | _\_ |__ _______ ___
-# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
-# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
-# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
-# \/ \/ \/ \/ \/
-# $Id$
-#
-# Copyright (c) 2010 Dominik Riebeling
-#
-# All files in this archive are subject to the GNU General Public License.
-# See the file COPYING in the source tree root for full license agreement.
-#
-# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
-# KIND, either express or implied.
-#
-
-import deploy
-
-deploy.program = "rbthemeeditor"
-deploy.project = "utils/themeeditor/themeeditor.pro"
-deploy.svnserver = "svn://svn.rockbox.org/rockbox/"
-deploy.svnpaths = \
- ["utils/themeeditor/",
- "lib/skin_parser/",
- "docs/COPYING"]
-deploy.useupx = False
-deploy.bundlecopy = {
- "resources/windowicon.icns" : "Contents/Resources/",
- "Info.plist" : "Contents/"
-}
-deploy.progexe = {
- "win32" : "release/rbthemeeditor.exe",
- "darwin" : "rbthemeeditor.app",
- "linux2" : "rbthemeeditor",
- "linux" : "rbthemeeditor"
-}
-deploy.regreplace = {}
-# OS X 10.6 defaults to gcc 4.2. Building universal binaries that are
-# compatible with 10.4 requires using gcc-4.0.
-deploy.qmakespec = {
- "win32" : "",
- "darwin" : "macx-g++40",
- "linux2" : "",
- "linux" : ""
-}
-deploy.make = {
- "win32" : "mingw32-make",
- "darwin" : "make",
- "linux2" : "make",
- "linux" : "make"
-}
-
-# all files of the program. Will get put into an archive after building
-# (zip on w32, tar.bz2 on Linux). Does not apply on Mac which uses dmg.
-# progexe will get added automatically.
-deploy.programfiles = list()
-deploy.nsisscript = "utils/themeeditor/themeeditor.nsi"
-
-deploy.deploy()
-
diff --git a/utils/common/deploy.py b/utils/common/deploy.py
deleted file mode 100755
index 04eef0b7d5..0000000000
--- a/utils/common/deploy.py
+++ /dev/null
@@ -1,677 +0,0 @@
-#!/usr/bin/python
-# __________ __ ___.
-# Open \______ \ ____ ____ | | _\_ |__ _______ ___
-# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
-# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
-# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
-# \/ \/ \/ \/ \/
-# $Id$
-#
-# Copyright (c) 2009 Dominik Riebeling
-#
-# All files in this archive are subject to the GNU General Public License.
-# See the file COPYING in the source tree root for full license agreement.
-#
-# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
-# KIND, either express or implied.
-#
-#
-# Automate building releases for deployment.
-# Run from any folder to build
-# - trunk
-# - any tag (using the -t option)
-# - any local folder (using the -p option)
-# Will build a binary archive (tar.bz2 / zip) and source archive.
-# The source archive won't be built for local builds. Trunk and
-# tag builds will retrieve the sources directly from svn and build
-# below the systems temporary folder.
-#
-# If the required Qt installation isn't in PATH use --qmake option.
-# Tested on Linux and MinGW / W32
-#
-# requires upx.exe in PATH on Windows.
-#
-
-import re
-import os
-import sys
-import tarfile
-import zipfile
-import shutil
-import subprocess
-import getopt
-import time
-import hashlib
-import tempfile
-from datetime import datetime
-import multiprocessing
-import gitscraper
-
-CPUS = multiprocessing.cpu_count()
-print("Info: %s cores found." % CPUS)
-
-# == Global stuff ==
-# DLL files to ignore when searching for required DLL files.
-SYSTEMDLLS = [
- 'advapi32.dll',
- 'comdlg32.dll',
- 'crypt32.dll',
- 'd3d9.dll',
- 'dwmapi.dll',
- 'dxva2.dll',
- 'evr.dll',
- 'gdi32.dll',
- 'imm32.dll',
- 'imm32.dll',
- 'iphlpapi.dll',
- 'kernel32.dll',
- 'mf.dll',
- 'mfplat.dll',
- 'msvcrt.dll',
- 'msvcrt.dll',
- 'netapi32.dll',
- 'ole32.dll',
- 'oleaut32.dll',
- 'setupapi.dll',
- 'shell32.dll',
- 'user32.dll',
- 'userenv.dll',
- 'uxtheme.dll',
- 'version.dll',
- 'winmm.dll',
- 'winspool.drv',
- 'ws2_32.dll',
- 'wtsapi32.dll'
- ]
-
-gitrepo = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
-
-
-# == Functions ==
-def usage(myself):
- print("Usage: %s [options]" % myself)
- print(" -q, --qmake=<qmake> path to qmake")
- print(" -p, --project=<pro> path to .pro file for building with local tree")
- print(" -t, --tag=<tag> use specified tag from svn")
- print(" -a, --add=<file> add file to build folder before building")
- print(" -s, --source-only only create source archive")
- print(" -b, --binary-only only create binary archive")
- if nsisscript != "":
- print(" -n, --makensis=<file> path to makensis for building Windows setup program.")
- if sys.platform != "darwin":
- print(" -d, --dynamic link dynamically instead of static")
- if sys.platform != "win32":
- print(" -x, --cross= prefix to cross compile for win32")
- print(" -k, --keep-temp keep temporary folder on build failure")
- print(" -h, --help this help")
- print(" If neither a project file nor tag is specified trunk will get downloaded")
- print(" from svn.")
-
-
-def which(executable):
- path = os.environ.get("PATH", "").split(os.pathsep)
- for p in path:
- fullpath = p + "/" + executable
- if os.path.exists(fullpath):
- return fullpath
- print("which: could not find " + executable)
- return ""
-
-
-def getsources(treehash, filelist, dest):
- '''Get the files listed in filelist from svnsrv and put it at dest.'''
- gitscraper.scrape_files(gitrepo, treehash, filelist, dest)
- return 0
-
-
-def getfolderrev(svnsrv):
- '''Get the most recent revision for svnsrv'''
- client = pysvn.Client()
- entries = client.info2(svnsrv, recurse=False)
- return entries[0][1].rev.number
-
-
-def findversion(versionfile):
- '''figure most recent program version from version.h,
- returns version string.'''
- h = open(versionfile, "r")
- c = h.read()
- h.close()
- version = dict()
- for v in ['MAJOR', 'MINOR', 'MICRO']:
- r = re.compile("#define +VERSION_" + v + " +([0-9a-z]+)")
- m = re.search(r, c)
- version[v] = m.group(1)
- return "%s.%s.%s" % (version['MAJOR'], version['MINOR'], version['MICRO'])
-
-
-def findqt(cross=""):
- '''Search for Qt4 installation. Return path to qmake.'''
- print("Searching for Qt")
- bins = [cross + "qmake", cross + "qmake-qt4"]
- for binary in bins:
- try:
- q = which(binary)
- if len(q) > 0:
- result = checkqt(q)
- if not result == "":
- return result
- except:
- print(sys.exc_info()[1])
-
- return ""
-
-
-def checkqt(qmakebin):
- '''Check if given path to qmake exists and is a suitable version.'''
- result = ""
- # check if binary exists
- if not os.path.exists(qmakebin):
- print("Specified qmake path does not exist!")
- return result
- # check version
- output = subprocess.Popen(
- [qmakebin, "-version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- cmdout = output.communicate()
- # don't check the qmake return code here, Qt3 doesn't return 0 on -version.
- for ou in cmdout:
- r = re.compile(b'Qt[^0-9]+([0-9\.]+[a-z]*)')
- m = re.search(r, ou)
- if m is not None:
- print("Qt found: %s" % m.group(1).decode())
- s = re.compile(b'[45]\..*')
- n = re.search(s, m.group(1))
- if n is not None:
- result = qmakebin
- return result
-
-
-def qmake(qmake, projfile, platform=sys.platform, wd=".", static=True, cross=""):
- print("Running qmake in %s..." % wd)
- command = [qmake, "-config", "release", "-config", "noccache"]
- if static == True:
- command.extend(["-config", "-static"])
- # special spec required?
- if len(qmakespec[platform]) > 0:
- command.extend(["-spec", qmakespec[platform]])
- # cross compiling prefix set?
- if len(cross) > 0:
- command.extend(["-config", "cross"])
- command.append(projfile)
- output = subprocess.Popen(command, stdout=subprocess.PIPE, cwd=wd)
- output.communicate()
- if not output.returncode == 0:
- print("qmake returned an error!")
- return -1
- return 0
-
-
-def build(wd=".", platform=sys.platform, cross=""):
- # make
- print("Building ...")
- # use the current platforms make here, cross compiling uses the native make.
- command = [make[sys.platform]]
- if CPUS > 1:
- command.append("-j")
- command.append(str(CPUS))
- output = subprocess.Popen(command, stdout=subprocess.PIPE, cwd=wd)
- while True:
- c = output.stdout.readline()
- sys.stdout.write(".")
- sys.stdout.flush()
- if not output.poll() == None:
- sys.stdout.write("\n")
- sys.stdout.flush()
- if not output.returncode == 0:
- print("Build failed!")
- return -1
- break
- if platform != "darwin":
- # strip. OS X handles this via macdeployqt.
- print("Stripping binary.")
- output = subprocess.Popen([cross + "strip", progexe[platform]], \
- stdout=subprocess.PIPE, cwd=wd)
- output.communicate()
- if not output.returncode == 0:
- print("Stripping failed!")
- return -1
- return 0
-
-
-def upxfile(wd=".", platform=sys.platform):
- # run upx on binary
- print("UPX'ing binary ...")
- output = subprocess.Popen(["upx", progexe[platform]], \
- stdout=subprocess.PIPE, cwd=wd)
- output.communicate()
- if not output.returncode == 0:
- print("UPX'ing failed!")
- return -1
- return 0
-
-
-def runnsis(versionstring, nsis, script, srcfolder):
- # run script through nsis to create installer.
- print("Running NSIS ...")
-
- # Assume the generated installer gets placed in the same folder the nsi
- # script lives in. This seems to be a valid assumption unless the nsi
- # script specifies a path. NSIS expects files relative to source folder so
- # copy progexe. Additional files are injected into the nsis script.
-
- # FIXME: instead of copying binaries around copy the NSI file and inject
- # the correct paths.
- # Only win32 supported as target platform so hard coded.
- b = srcfolder + "/" + os.path.dirname(script) + "/" \
- + os.path.dirname(progexe["win32"])
- if not os.path.exists(b):
- os.mkdir(b)
- shutil.copy(srcfolder + "/" + progexe["win32"], b)
- output = subprocess.Popen([nsis, srcfolder + "/" + script], \
- stdout=subprocess.PIPE)
- output.communicate()
- if not output.returncode == 0:
- print("NSIS failed!")
- return -1
- setupfile = program + "-" + versionstring + "-setup.exe"
- # find output filename in nsis script file
- nsissetup = ""
- for line in open(srcfolder + "/" + script):
- if re.match(r'^[^;]*OutFile\s+', line) != None:
- nsissetup = re.sub(r'^[^;]*OutFile\s+"(.+)"', r'\1', line).rstrip()
- if nsissetup == "":
- print("Could not retrieve output file name!")
- return -1
- shutil.copy(srcfolder + "/" + os.path.dirname(script) + "/" + nsissetup, \
- setupfile)
- return 0
-
-
-def nsisfileinject(nsis, outscript, filelist):
- '''Inject files in filelist into NSIS script file after the File line
- containing the main binary. This assumes that the main binary is present
- in the NSIS script and that all additiona files (dlls etc) to get placed
- into $INSTDIR.'''
- output = open(outscript, "w")
- for line in open(nsis, "r"):
- output.write(line)
- # inject files after the progexe binary.
- # Match the basename only to avoid path mismatches.
- if re.match(r'^\s*File\s*.*' + os.path.basename(progexe["win32"]),
- line, re.IGNORECASE):
- for f in filelist:
- injection = " File /oname=$INSTDIR\\" + os.path.basename(f) \
- + " " + os.path.normcase(f) + "\n"
- output.write(injection)
- output.write(" ; end of injected files\n")
- output.close()
-
-
-def finddlls(program, extrapaths=[], cross=""):
- '''Check program for required DLLs. Find all required DLLs except ignored
- ones and return a list of DLL filenames (including path).'''
- # ask objdump about dependencies.
- output = subprocess.Popen([cross + "objdump", "-x", program], \
- stdout=subprocess.PIPE)
- cmdout = output.communicate()
-
- # create list of used DLLs. Store as lower case as W32 is case-insensitive.
- dlls = []
- for line in cmdout[0].decode().split('\n'):
- if re.match(r'\s*DLL Name', line) != None:
- dll = re.sub(r'^\s*DLL Name:\s+([a-zA-Z_\-0-9\.\+]+).*$', r'\1', line)
- dlls.append(dll.lower())
-
- # find DLLs in extrapaths and PATH environment variable.
- dllpaths = []
- for file in dlls:
- if file in SYSTEMDLLS:
- print("System DLL: " + file)
- continue
- dllpath = ""
- for path in extrapaths:
- if os.path.exists(path + "/" + file):
- dllpath = re.sub(r"\\", r"/", path + "/" + file)
- print(file + ": found at " + dllpath)
- dllpaths.append(dllpath)
- break
- if dllpath == "":
- try:
- dllpath = re.sub(r"\\", r"/", which(file))
- print(file + ": found at " + dllpath)
- dllpaths.append(dllpath)
- except:
- print("MISSING DLL: " + file)
- return dllpaths
-
-
-def zipball(programfiles, versionstring, buildfolder, platform=sys.platform):
- '''package created binary'''
- print("Creating binary zipball.")
- archivebase = program + "-" + versionstring
- outfolder = buildfolder + "/" + archivebase
- archivename = archivebase + ".zip"
- # create output folder
- os.mkdir(outfolder)
- # move program files to output folder
- for f in programfiles:
- if re.match(r'^(/|[a-zA-Z]:)', f) != None:
- shutil.copy(f, outfolder)
- else:
- shutil.copy(buildfolder + "/" + f, outfolder)
- # create zipball from output folder
- zf = zipfile.ZipFile(archivename, mode='w', compression=zipfile.ZIP_DEFLATED)
- for root, dirs, files in os.walk(outfolder):
- for name in files:
- physname = os.path.normpath(os.path.join(root, name))
- filename = os.path.relpath(physname, buildfolder)
- zf.write(physname, filename)
- zf.close()
- # remove output folder
- shutil.rmtree(outfolder)
- return archivename
-
-
-def tarball(programfiles, versionstring, buildfolder):
- '''package created binary'''
- print("Creating binary tarball.")
- archivebase = program + "-" + versionstring
- outfolder = buildfolder + "/" + archivebase
- archivename = archivebase + ".tar.bz2"
- # create output folder
- os.mkdir(outfolder)
- # move program files to output folder
- for f in programfiles:
- shutil.copy(buildfolder + "/" + f, outfolder)
- # create tarball from output folder
- tf = tarfile.open(archivename, mode='w:bz2')
- tf.add(outfolder, archivebase)
- tf.close()
- # remove output folder
- shutil.rmtree(outfolder)
- return archivename
-
-
-def macdeploy(versionstring, buildfolder, platform=sys.platform):
- '''package created binary to dmg'''
- dmgfile = program + "-" + versionstring + ".dmg"
- appbundle = buildfolder + "/" + progexe[platform]
-
- # workaround to Qt issues when building out-of-tree. Copy files into bundle.
- sourcebase = buildfolder + re.sub('[^/]+.pro$', '', project) + "/"
- print(sourcebase)
- for src in bundlecopy:
- shutil.copy(sourcebase + src, appbundle + "/" + bundlecopy[src])
- # end of Qt workaround
-
- output = subprocess.Popen(["macdeployqt", progexe[platform], "-dmg"], \
- stdout=subprocess.PIPE, cwd=buildfolder)
- output.communicate()
- if not output.returncode == 0:
- print("macdeployqt failed!")
- return -1
- # copy dmg to output folder
- shutil.copy(buildfolder + "/" + program + ".dmg", dmgfile)
- return dmgfile
-
-
-def filehashes(filename):
- '''Calculate md5 and sha1 hashes for a given file.'''
- if not os.path.exists(filename):
- return ["", ""]
- m = hashlib.md5()
- s = hashlib.sha1()
- f = open(filename, 'rb')
- while True:
- d = f.read(65536)
- if d == b"":
- break
- m.update(d)
- s.update(d)
- return [m.hexdigest(), s.hexdigest()]
-
-
-def filestats(filename):
- if not os.path.exists(filename):
- return
- st = os.stat(filename)
- print("%s\n%s" % (filename, "-" * len(filename)))
- print("Size: %i bytes" % st.st_size)
- h = filehashes(filename)
- print("md5sum: %s" % h[0])
- print("sha1sum: %s" % h[1])
- print("%s\n" % ("-" * len(filename)))
-
-
-def tempclean(workfolder, nopro):
- if nopro == True:
- print("Cleaning up working folder %s" % workfolder)
- shutil.rmtree(workfolder)
- else:
- print("Project file specified or cleanup disabled!")
- print("Temporary files kept at %s" % workfolder)
-
-
-def deploy():
- startup = time.time()
-
- try:
- opts, args = getopt.getopt(
- sys.argv[1:], "q:p:t:a:n:sbdkx:i:h",
- ["qmake=", "project=", "tag=", "add=", "makensis=", "source-only",
- "binary-only", "dynamic", "keep-temp", "cross=", "buildid=", "help"])
- except getopt.GetoptError as err:
- print(str(err))
- usage(sys.argv[0])
- sys.exit(1)
- qt = ""
- proj = ""
- svnbase = svnserver + "trunk/"
- tag = ""
- addfiles = []
- cleanup = True
- binary = True
- source = True
- keeptemp = False
- makensis = ""
- cross = ""
- buildid = None
- platform = sys.platform
- treehash = gitscraper.get_refs(gitrepo)['refs/remotes/origin/HEAD']
- if sys.platform != "darwin":
- static = True
- else:
- static = False
- for o, a in opts:
- if o in ("-q", "--qmake"):
- qt = a
- if o in ("-p", "--project"):
- proj = a
- cleanup = False
- if o in ("-a", "--add"):
- addfiles.append(a)
- if o in ("-n", "--makensis"):
- makensis = a
- if o in ("-s", "--source-only"):
- binary = False
- if o in ("-b", "--binary-only"):
- source = False
- if o in ("-d", "--dynamic") and sys.platform != "darwin":
- static = False
- if o in ("-k", "--keep-temp"):
- keeptemp = True
- if o in ("-t", "--tree"):
- treehash = a
- if o in ("-x", "--cross") and sys.platform != "win32":
- cross = a
- platform = "win32"
- if o in ("-i", "--buildid"):
- buildid = a
- if o in ("-h", "--help"):
- usage(sys.argv[0])
- sys.exit(0)
-
- if source == False and binary == False:
- print("Building build neither source nor binary means nothing to do. Exiting.")
- sys.exit(1)
-
- print("Building " + progexe[platform] + " for " + platform)
- # search for qmake
- if qt == "":
- qm = findqt(cross)
- else:
- qm = checkqt(qt)
- if qm == "":
- print("ERROR: No suitable Qt installation found.")
- sys.exit(1)
-
- # create working folder. Use current directory if -p option used.
- if proj == "":
- w = tempfile.mkdtemp()
- # make sure the path doesn't contain backslashes to prevent issues
- # later when running on windows.
- workfolder = re.sub(r'\\', '/', w)
- revision = gitscraper.describe_treehash(gitrepo, treehash)
- # try to find a version number from describe output.
- # WARNING: this is broken and just a temporary workaround!
- v = re.findall(b'([\d\.a-f]+)', revision)
- if v:
- if v[-1].decode().find('.') >= 0:
- revision = "v" + v[-1].decode()
- else:
- revision = v[-1].decode()
- if buildid == None:
- versionextra = ""
- else:
- versionextra = "-" + buildid
- sourcefolder = workfolder + "/" + program + "-" + str(revision) + versionextra + "/"
- archivename = program + "-" + str(revision) + versionextra + "-src.tar.bz2"
- ver = str(revision)
- os.mkdir(sourcefolder)
- print("Version: %s" % revision)
- else:
- workfolder = "."
- sourcefolder = "."
- archivename = ""
- # check if project file explicitly given. If yes, don't get sources from svn
- if proj == "":
- proj = sourcefolder + project
- # get sources and pack source tarball
- if getsources(treehash, svnpaths, sourcefolder) != 0:
- tempclean(workfolder, cleanup and not keeptemp)
- sys.exit(1)
-
- # replace version strings.
- print("Updating version information in sources")
- for f in regreplace:
- infile = open(sourcefolder + "/" + f, "r")
- incontents = infile.readlines()
- infile.close()
-
- outfile = open(sourcefolder + "/" + f, "w")
- for line in incontents:
- newline = line
- for r in regreplace[f]:
- # replacements made on the replacement string:
- # %REVISION% is replaced with the revision number
- replacement = re.sub("%REVISION%", str(revision), r[1])
- newline = re.sub(r[0], replacement, newline)
- # %BUILD% is replaced with buildid as passed on the command line
- if buildid != None:
- replacement = re.sub("%BUILDID%", "-" + str(buildid), replacement)
- else:
- replacement = re.sub("%BUILDID%", "", replacement)
- newline = re.sub(r[0], replacement, newline)
- outfile.write(newline)
- outfile.close()
-
- if source == True:
- print("Creating source tarball %s\n" % archivename)
- tf = tarfile.open(archivename, mode='w:bz2')
- tf.add(sourcefolder, os.path.basename(re.subn('/$', '', sourcefolder)[0]))
- tf.close()
- if binary == False:
- shutil.rmtree(workfolder)
- sys.exit(0)
- else:
- # figure version from sources. Need to take path to project file into account.
- versionfile = re.subn('[\w\.]+$', "version.h", proj)[0]
- ver = findversion(versionfile) + "-dev" + datetime.now().strftime('%Y%m%d%H%M%S')
- # append buildid if any.
- if buildid != None:
- ver += "-" + buildid
-
- # check project file
- if not os.path.exists(proj):
- print("ERROR: path to project file wrong.")
- sys.exit(1)
-
- # copy specified (--add) files to working folder
- for f in addfiles:
- shutil.copy(f, sourcefolder)
- buildstart = time.time()
- header = "Building %s %s" % (program, ver)
- print(header)
- print(len(header) * "=")
-
- # build it.
- if not qmake(qm, proj, platform, sourcefolder, static, cross) == 0:
- tempclean(workfolder, cleanup and not keeptemp)
- sys.exit(1)
- if not build(sourcefolder, platform, cross) == 0:
- tempclean(workfolder, cleanup and not keeptemp)
- sys.exit(1)
- buildtime = time.time() - buildstart
- progfiles = programfiles
- progfiles.append(progexe[platform])
- if platform == "win32":
- if useupx == True:
- if not upxfile(sourcefolder, platform) == 0:
- tempclean(workfolder, cleanup and not keeptemp)
- sys.exit(1)
- dllfiles = finddlls(sourcefolder + "/" + progexe[platform], \
- [os.path.dirname(qm)], cross)
- if len(dllfiles) > 0:
- progfiles.extend(dllfiles)
- archive = zipball(progfiles, ver, sourcefolder, platform)
- # only when running native right now.
- if nsisscript != "" and makensis != "":
- nsisfileinject(sourcefolder + "/" + nsisscript, sourcefolder \
- + "/" + nsisscript + ".tmp", dllfiles)
- runnsis(ver, makensis, nsisscript + ".tmp", sourcefolder)
- elif platform == "darwin":
- archive = macdeploy(ver, sourcefolder, platform)
- else:
- if platform in ['linux', 'linux2']:
- for p in progfiles:
- prog = sourcefolder + "/" + p
- output = subprocess.Popen(
- ["file", prog], stdout=subprocess.PIPE)
- res = output.communicate()
- if re.findall("ELF 64-bit", res[0]):
- ver += "-64bit"
- break
-
- archive = tarball(progfiles, ver, sourcefolder)
-
- # remove temporary files
- tempclean(workfolder, cleanup)
-
- # display summary
- headline = "Build Summary for %s" % program
- print("\n%s\n%s" % (headline, "=" * len(headline)))
- if archivename != "":
- filestats(archivename)
- filestats(archive)
- duration = time.time() - startup
- durmins = (int)(duration / 60)
- dursecs = (int)(duration % 60)
- buildmins = (int)(buildtime / 60)
- buildsecs = (int)(buildtime % 60)
- print("Overall time %smin %ssec, building took %smin %ssec." % \
- (durmins, dursecs, buildmins, buildsecs))
-
-
-if __name__ == "__main__":
- print("You cannot run this module directly!")
- print("Set required environment and call deploy().")
diff --git a/utils/common/gitscraper.py b/utils/common/gitscraper.py
index 5b3b316115..8d162155d9 100755
--- a/utils/common/gitscraper.py
+++ b/utils/common/gitscraper.py
@@ -142,6 +142,23 @@ def get_object(repo, blob, destfile):
return True
+def parse_rev(repo, hash):
+ '''Retrieve output of git rev-parse for a given hash.
+ @param repo Path to repository root.
+ @param hash Hash identifying the tree / commit to describe.
+ @return Description string.
+ '''
+ output = subprocess.Popen(
+ ["git", "rev-parse", "--verify", "--short=10", hash],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=repo)
+ cmdout = output.communicate()
+ if len(cmdout[1]) > 0:
+ print("An error occured!\n")
+ print(cmdout[1])
+ return ""
+ return cmdout[0].decode().rstrip()
+
+
def describe_treehash(repo, treehash):
'''Retrieve output of git-describe for a given hash.
@param repo Path to repository root.
diff --git a/utils/common/deploy-rbutil.py b/utils/common/tarball-rbutil.py
index 0c98575843..ccc413ca59 100755
--- a/utils/common/deploy-rbutil.py
+++ b/utils/common/tarball-rbutil.py
@@ -1,13 +1,12 @@
-#!/usr/bin/python
+#!/usr/bin/python3
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
-# $Id$
#
-# Copyright (c) 2010 Dominik Riebeling
+# Copyright (c) 2022 Dominik Riebeling
#
# All files in this archive are subject to the GNU General Public License.
# See the file COPYING in the source tree root for full license agreement.
@@ -16,13 +15,44 @@
# KIND, either express or implied.
#
-import deploy
+import os
+import sys
+import gitscraper
-deploy.program = "RockboxUtility"
-deploy.project = "rbutil/rbutilqt/rbutilqt.pro"
-deploy.svnserver = "svn://svn.rockbox.org/rockbox/"
-deploy.svnpaths = \
- ["rbutil/",
+if len(sys.argv) < 2:
+ print("Usage: %s <version|hash>" % sys.argv[0])
+ sys.exit()
+
+repository = os.path.abspath(
+ os.path.join(os.path.dirname(os.path.abspath(__file__)), "../.."))
+
+if '.' in sys.argv[1]:
+ version = sys.argv[1]
+ basename = f"RockboxUtility-v{version}-src"
+ ref = f"refs/tags/rbutil_{version}"
+ refs = gitscraper.get_refs(repository)
+ if ref in refs:
+ tree = refs[ref]
+ else:
+ print("Could not find hash for version!")
+ sys.exit()
+else:
+ tree = gitscraper.parse_rev(repository, sys.argv[1])
+ basename = f"RockboxUtility-{tree}"
+
+filelist = ["utils/rbutilqt",
+ "utils/ipodpatcher",
+ "utils/sansapatcher",
+ "utils/mkamsboot",
+ "utils/chinachippatcher",
+ "utils/mks5lboot",
+ "utils/mkmpioboot",
+ "utils/mkimxboot",
+ "utils/mktccboot",
+ "utils/bspatch",
+ "utils/bzip2",
+ "utils/cmake",
+ "utils/CMakeLists.txt",
"tools/ucl",
"tools/rbspeex",
"utils/imxtools",
@@ -48,41 +78,8 @@ deploy.svnpaths = \
"tools/voicefont.h",
"tools/wavtrim.c",
"tools/sapi_voice.vbs"]
-deploy.useupx = False
-deploy.bundlecopy = {
- "icons/rbutilqt.icns" : "Contents/Resources/",
- "Info.plist" : "Contents/"
-}
-deploy.progexe = {
- "win32" : "release/RockboxUtility.exe",
- "darwin" : "RockboxUtility.app",
- "linux2" : "RockboxUtility",
- "linux" : "RockboxUtility"
-}
-deploy.regreplace = {
- "rbutil/rbutilqt/version.h" : [["\$Rev\$", "%REVISION%"],
- ["(^#define BUILDID).*", "\\1 \"%BUILDID%\""]],
- "rbutil/rbutilqt/Info.plist" : [["\$Rev\$", "%REVISION%"]],
-}
-# OS X 10.6 defaults to gcc 4.2. Building universal binaries that are
-# compatible with 10.4 requires using gcc-4.0.
-deploy.qmakespec = {
- "win32" : "",
- "darwin" : "macx-g++40",
- "linux2" : "",
- "linux" : ""
-}
-deploy.make = {
- "win32" : "mingw32-make",
- "darwin" : "make",
- "linux2" : "make",
- "linux" : "make"
-}
-# all files of the program. Will get put into an archive after building
-# (zip on w32, tar.bz2 on Linux). Does not apply on Mac which uses dmg.
-# progexe will get added automatically.
-deploy.programfiles = list()
-deploy.nsisscript = ""
+print(f"Getting git revision {tree}")
+gitscraper.archive_files(repository, tree, filelist, basename, archive="tbz")
-deploy.deploy()
+print(f"Created {basename}.tar.bz2.")
diff --git a/utils/e200rpatcher/Makefile b/utils/e200rpatcher/Makefile
new file mode 100644
index 0000000000..dfe5c1e037
--- /dev/null
+++ b/utils/e200rpatcher/Makefile
@@ -0,0 +1,56 @@
+CFLAGS=-Wall -W
+
+ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
+OUTPUT=e200rpatcher.exe
+CROSS=
+CFLAGS+=-mno-cygwin
+else
+OUTPUT=e200rpatcher
+CROSS=i586-mingw32msvc-
+endif
+
+LIBS = -lusb
+WINLIBS = -I libusb-win32-device-bin-0.1.12.1/include libusb-win32-device-bin-0.1.12.1/lib/dynamic/libusb_dyn.c
+
+NATIVECC = gcc
+CC = $(CROSS)gcc
+WINDRES = $(CROSS)windres
+
+all: $(OUTPUT)
+
+e200rpatcher: e200rpatcher.c bootimg.c
+ gcc $(CFLAGS) $(LIBS) -o e200rpatcher e200rpatcher.c bootimg.c
+ strip e200rpatcher
+
+e200rpatcher.exe: e200rpatcher.c bootimg.c e200rpatcher-rc.o
+ $(CC) $(CFLAGS) $(WINLIBS) -o e200rpatcher.exe e200rpatcher.c bootimg.c e200rpatcher-rc.o
+ $(CROSS)strip e200rpatcher.exe
+
+e200rpatcher-rc.o: e200rpatcher.rc e200rpatcher.manifest
+ $(WINDRES) -i e200rpatcher.rc -o e200rpatcher-rc.o
+
+e200rpatcher-mac: e200rpatcher-i386 e200rpatcher-ppc
+ lipo -create e200rpatcher-ppc e200rpatcher-i386 -output e200rpatcher-mac
+
+e200rpatcher.dmg: e200rpatcher-mac
+ mkdir -p e200rpatcher-dmg
+ cp -p e200rpatcher-mac e200rpatcher-dmg
+ hdiutil create -srcfolder e200rpatcher-dmg e200rpatcher.dmg
+
+e200rpatcher-i386: e200rpatcher.c bootimg.c usb.h libusb-i386.a
+ gcc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -framework iokit -framework coreservices -arch i386 $(CFLAGS) -o e200rpatcher-i386 e200rpatcher.c bootimg.c -I. libusb-i386.a
+ strip e200rpatcher-i386
+
+e200rpatcher-ppc: e200rpatcher.c bootimg.c usb.h libusb-ppc.a
+ gcc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -framework iokit -framework coreservices -arch ppc $(CFLAGS) -o e200rpatcher-ppc e200rpatcher.c bootimg.c -I. libusb-ppc.a
+ strip e200rpatcher-ppc
+
+bin2c: ../tools/bin2c.c
+ $(NATIVECC) $(CFLAGS) -o bin2c ../tools/bin2c.c
+
+bootimg.c: bootloader.bin bin2c
+ ./bin2c bootloader.bin bootimg
+
+clean:
+ rm -f e200rpatcher.exe e200rpatcher-mac e200rpatcher-i386 e200rpatcher-ppc e200rpatcher bin2c bootimg.c bootimg.h *~ e200rpatcher.dmg
+ rm -rf e200rpatcher-dmg
diff --git a/utils/e200rpatcher/README b/utils/e200rpatcher/README
new file mode 100644
index 0000000000..1942b3aa7a
--- /dev/null
+++ b/utils/e200rpatcher/README
@@ -0,0 +1,48 @@
+INTRODUCTION
+
+e200rpatcher is a tool for uploading and executing an application to
+an E200R in manufacturing mode. It is intended to be used to upload
+the patching application to allow Rockbox installs.
+
+e200rpatcher requires libusb (v0.1.2 has been tested successfully) for
+cross-platform USB access. No-one has yet successfully installed
+e200rpatcher on Windows, but it works on Linux and Mac OS X (and
+should be fine on other Unix-like systems that libusb supports).
+
+GENERAL BUILD INSTRUCTIONS
+
+A pre-requisite for compiling e200rpatcher is a file called
+"bootloader.bin" - this is the output of running an "I" (installer)
+build for the E200R target.
+
+In the Rockbox source directory, do:
+
+mkdir build-e200rbootbin
+cd build-e200rbootbin
+../tools/configure
+[Select E200R, then I for installer]
+make
+
+This should give you a bootloader/bootloader/bin file which you should
+copy to the e200rpatcher source directory.
+
+BUILDING ON LINUX
+
+The Makefile expects libusb (and the headers) to be installed on your
+system and will link dynamically. Just type "make".
+
+BUILDING ON A MAC
+
+To build the mac version (target e200rpatcher-mac in the Makefile)
+requires three files from libusb to be copied to the current
+directory:
+
+usb.h (copied from your libusb build directory)
+libusb-i386.a (copied and renamed from .libs/libusb.a in an i386 build)
+libusb-ppc.a (copied and renamed from .libs/libusb.a in a PPC build)
+
+To build the required libusb.a files, just run ./configure && make for
+libusb. If anyone knows how to cross-compile a static libusb.a please
+make the information known - this is currently done by compiling
+natively on the appropriate hardware.
+
diff --git a/utils/e200rpatcher/e200rpatcher.c b/utils/e200rpatcher/e200rpatcher.c
new file mode 100644
index 0000000000..be09370997
--- /dev/null
+++ b/utils/e200rpatcher/e200rpatcher.c
@@ -0,0 +1,241 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2007 Dave Chapman
+ *
+ * USB code based on ifp-line - http://ifp-driver.sourceforge.net
+ *
+ * ifp-line is (C) Pavel Kriz, Jun Yamishiro and Joe Roback and
+ * licensed under the GPL (v2)
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <usb.h>
+#include <string.h>
+#include "stdbool.h"
+
+#include "bootimg.h"
+
+#define VERSION "0.2"
+
+/* USB IDs for Manufacturing Mode */
+#define E200R_VENDORID 0x0781
+#define E200R_PRODUCTID 0x0720
+
+#define E200R_BULK_TO 1
+#define TOUT 5000
+#define MAX_TRANSFER 64 /* Number of bytes to send in one write */
+
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+static void put_int32le(uint32_t x, char* p)
+{
+ p[0] = x & 0xff;
+ p[1] = (x >> 8) & 0xff;
+ p[2] = (x >> 16) & 0xff;
+ p[3] = (x >> 24) & 0xff;
+}
+
+int upload_app(usb_dev_handle* dh)
+{
+ char buf[4];
+ int err;
+ int tosend;
+ char* p = (char*)bootimg;
+ int bytesleft = LEN_bootimg;
+
+ /* Write the data length */
+
+ put_int32le(LEN_bootimg, buf);
+
+ err = usb_bulk_write(dh, E200R_BULK_TO, buf, 4, TOUT);
+
+ if (err < 0)
+ {
+ fprintf(stderr,"[ERR] Error writing data length\n");
+ fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
+ return -1;
+ }
+
+ /* Now send the data, MAX_TRANSFER bytes at a time. */
+
+ while (bytesleft > 0)
+ {
+ tosend = MAX(MAX_TRANSFER, bytesleft);
+
+ err = usb_bulk_write(dh, E200R_BULK_TO, p, tosend, TOUT);
+
+ if (err < 0)
+ {
+ fprintf(stderr,"[ERR] Error writing data\n");
+ fprintf(stderr,"[ERR] Bulk write error (%d, %s)\n", err, strerror(-err));
+ return -1;
+ }
+
+ p += tosend;
+ bytesleft -= tosend;
+ }
+
+ return 0;
+}
+
+
+/* The main function */
+
+void do_patching(void)
+{
+ struct usb_bus *busses;
+ struct usb_bus *bus;
+ struct usb_device *tmp_dev;
+ struct usb_device *dev = NULL;
+ usb_dev_handle *dh;
+ int err;
+
+ fprintf(stderr,"[INFO] Searching for E200R\n");
+
+ usb_init();
+
+ if(usb_find_busses() < 0) {
+ fprintf(stderr, "[ERR] Could not find any USB busses.\n");
+ return;
+ }
+
+ if (usb_find_devices() < 0) {
+ fprintf(stderr, "[ERR] USB devices not found(nor hubs!).\n");
+ return;
+ }
+
+ /* C calling convention, it's not nice to use global stuff */
+ busses = usb_get_busses();
+
+ for (bus = busses; bus; bus = bus->next) {
+ for (tmp_dev = bus->devices; tmp_dev; tmp_dev = tmp_dev->next) {
+ if (tmp_dev->descriptor.idVendor == E200R_VENDORID &&
+ tmp_dev->descriptor.idProduct == E200R_PRODUCTID ) {
+
+ dev = tmp_dev;
+ goto found;
+
+ }
+ }
+ }
+
+ if (dev == NULL) {
+ fprintf(stderr, "[ERR] E200R device not found.\n");
+ fprintf(stderr, "[ERR] Ensure your E200R is in manufacturing mode and run e200rpatcher again.\n");
+ return;
+ }
+
+found:
+ if ( (dh = usb_open(dev)) == NULL) {
+ fprintf(stderr,"[ERR] Unable to open E200R device.\n");
+ return;
+ }
+
+ err = usb_set_configuration(dh, 1);
+
+ if (err < 0) {
+ fprintf(stderr, "[ERR] usb_set_configuration failed (%d)\n", err);
+ usb_close(dh);
+ return;
+ }
+
+ /* "must be called" written in the libusb documentation */
+ err = usb_claim_interface(dh, dev->config->interface->altsetting->bInterfaceNumber);
+ if (err < 0) {
+ fprintf(stderr, "[ERR] Unable to claim interface (%d)\n", err);
+ usb_close(dh);
+ return;
+ }
+
+ fprintf(stderr,"[INFO] Found E200R, uploading patching application.\n");
+
+ /* Now we can transfer the application to the device. */
+
+ if (upload_app(dh) < 0)
+ {
+ fprintf(stderr,"[ERR] Upload of application failed.\n");
+ }
+ else
+ {
+ fprintf(stderr,"[INFO] Patching application uploaded successfully!\n");
+ }
+
+ /* release claimed interface */
+ usb_release_interface(dh, dev->config->interface->altsetting->bInterfaceNumber);
+
+ usb_close(dh);
+}
+void print_usage(void)
+{
+ fprintf(stderr,"Usage: e200rpatcher [options]\n");
+ fprintf(stderr,"Options:\n");
+ fprintf(stderr," -s, --silent\t\tDont display instructions\n");
+}
+
+int main(int argc, char* argv[])
+{
+ char input[4];
+ int silent = 0;
+ int i;
+
+ /* check args */
+ if ((argc > 1) && ((strcmp(argv[1],"-h")==0) || (strcmp(argv[1],"--help")==0))) {
+ print_usage();
+ return 1;
+ }
+ for (i=1;i<argc;i++)
+ {
+ if (!strcmp(argv[i], "--silent") || !strcmp(argv[i], "-s"))
+ silent = 1;
+ }
+
+ printf("e200rpatcher v" VERSION " - (C) 2007 Jonathan Gordon & Dave Chapman\n");
+ printf("This is free software; see the source for copying conditions. There is NO\n");
+ printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
+
+ if (!silent)
+ {
+ printf("Attach your E200R in \"manufacturing mode\" as follows:\n");
+ printf(" 1) Power-off your E200R\n");
+ printf(" 2) Turn ON the lock/hold switch\n");
+ printf(" 3) Press and hold the SELECT button and whilst it is held down,\n");
+ printf(" attach your E200R to your computer via USB\n");
+ printf(" 4) After attaching to USB, keep the SELECT button held for 10 seconds.\n");
+ printf("\n");
+ printf("NOTE: If your E200R starts in the normal Sansa firmware, you have\n");
+ printf(" failed to enter manufacturing mode and should try again at step 1).\n\n");
+
+ printf("[INFO] Press Enter to continue:");
+ fgets(input, 4, stdin);
+ }
+ do_patching();
+
+ if (!silent)
+ {
+ printf("[INFO] Press ENTER to exit: ");
+ fgets(input, 4, stdin);
+ }
+
+ return 0;
+}
diff --git a/utils/e200rpatcher/e200rpatcher.manifest b/utils/e200rpatcher/e200rpatcher.manifest
new file mode 100644
index 0000000000..ec0c49df33
--- /dev/null
+++ b/utils/e200rpatcher/e200rpatcher.manifest
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="e200rpatcher.exe" type="win32"/>
+
+ <!-- Identify the application security requirements. -->
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="requireAdministrator"/>
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+</assembly>
diff --git a/utils/e200rpatcher/e200rpatcher.rc b/utils/e200rpatcher/e200rpatcher.rc
new file mode 100644
index 0000000000..4d80442d44
--- /dev/null
+++ b/utils/e200rpatcher/e200rpatcher.rc
@@ -0,0 +1 @@
+1 24 MOVEABLE PURE "e200rpatcher.manifest"
diff --git a/utils/ibassoboot/jni/Android.mk b/utils/ibassoboot/jni/Android.mk
new file mode 100644
index 0000000000..9cd667c5b9
--- /dev/null
+++ b/utils/ibassoboot/jni/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := MangoPlayer
+LOCAL_SRC_FILES := ibassodualboot.c qdbmp.c
+
+TARGET_ARCH=arm
+TARGET_PLATFORM=android-14
+TARGET_ARCH_ABI=armeabi
+
+#LOCAL_CFLAGS := -DDEBUG
+#LOCAL_LDLIBS := -llog
+
+include $(BUILD_EXECUTABLE)
diff --git a/utils/ibassoboot/jni/chooser.bmp b/utils/ibassoboot/jni/chooser.bmp
new file mode 100644
index 0000000000..3e6742d600
--- /dev/null
+++ b/utils/ibassoboot/jni/chooser.bmp
Binary files differ
diff --git a/utils/ibassoboot/jni/ibassodualboot.c b/utils/ibassoboot/jni/ibassodualboot.c
new file mode 100644
index 0000000000..0458ff1b71
--- /dev/null
+++ b/utils/ibassoboot/jni/ibassodualboot.c
@@ -0,0 +1,771 @@
+/***************************************************************************
+ * __________ __ ___
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * Copyright (C) 2014 by Ilia Sergachev: Initial Rockbox port to iBasso DX50
+ * Copyright (C) 2014 by Mario Basister: iBasso DX90 port
+ * Copyright (C) 2014 by Simon Rothen: Initial Rockbox repository submission, additional features
+ * Copyright (C) 2014 by Udo Schl├Ąpfer: Code clean up, additional features
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/fb.h>
+#include <linux/input.h>
+#include <sys/mman.h>
+#include <sys/poll.h>
+#include <sys/reboot.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+
+#include "qdbmp.h"
+
+
+/*- Android logcat ------------------------------------------------------------------------------*/
+
+
+#ifdef DEBUG
+#include <android/log.h>
+
+
+static const char log_tag[] = "Rockbox Boot";
+
+
+void debugf(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ __android_log_vprint(ANDROID_LOG_DEBUG, log_tag, fmt, ap);
+ va_end(ap);
+}
+
+
+void ldebugf(const char* file, int line, const char *fmt, ...)
+{
+ va_list ap;
+ /* 13: 5 literal chars and 8 chars for the line number. */
+ char buf[strlen(file) + strlen(fmt) + 13];
+ snprintf(buf, sizeof(buf), "%s (%d): %s", file, line, fmt);
+ va_start(ap, fmt);
+ __android_log_vprint(ANDROID_LOG_DEBUG, log_tag, buf, ap);
+ va_end(ap);
+}
+
+
+void debug_trace(const char* function)
+{
+ static const char trace_tag[] = "TRACE: ";
+ char msg[strlen(trace_tag) + strlen(function) + 1];
+ snprintf(msg, sizeof(msg), "%s%s", trace_tag, function);
+ __android_log_write(ANDROID_LOG_DEBUG, log_tag, msg);
+}
+
+
+#define DEBUGF debugf
+#define TRACE debug_trace(__func__)
+#else
+#define DEBUGF(...)
+#define TRACE
+#endif /* DEBUG */
+
+
+/*- Vold monitor --------------------------------------------------------------------------------*/
+
+
+/*
+ Without this socket iBasso Vold will not start.
+ iBasso Vold uses this to send status messages about storage devices.
+*/
+static const char VOLD_MONITOR_SOCKET_NAME[] = "UNIX_domain";
+static int _vold_monitor_socket_fd = -1;
+
+
+static void vold_monitor_open_socket(void)
+{
+ TRACE;
+
+ unlink(VOLD_MONITOR_SOCKET_NAME);
+
+ _vold_monitor_socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+
+ if(_vold_monitor_socket_fd < 0)
+ {
+ _vold_monitor_socket_fd = -1;
+ return;
+ }
+
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, VOLD_MONITOR_SOCKET_NAME, sizeof(addr.sun_path) - 1);
+
+ if(bind(_vold_monitor_socket_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
+ {
+ close(_vold_monitor_socket_fd);
+ unlink(VOLD_MONITOR_SOCKET_NAME);
+ _vold_monitor_socket_fd = -1;
+ return;
+ }
+
+ if(listen(_vold_monitor_socket_fd, 1) < 0)
+ {
+ close(_vold_monitor_socket_fd);
+ unlink(VOLD_MONITOR_SOCKET_NAME);
+ _vold_monitor_socket_fd = -1;
+ return;
+ }
+}
+
+
+/*
+ bionic does not have pthread_cancel.
+ 0: Vold monitor thread stopped/ending.
+ 1: Vold monitor thread started/running.
+*/
+static volatile sig_atomic_t _vold_monitor_active = 0;
+
+
+/* true: sdcard not mounted. */
+static bool _sdcard_not_mounted = true;
+
+
+/* Mutex for sdcard mounted flag. */
+static pthread_mutex_t _sdcard_mount_mtx = PTHREAD_MUTEX_INITIALIZER;
+
+
+/* Signal condition for sdcard mounted flag. */
+static pthread_cond_t _sdcard_mount_cond = PTHREAD_COND_INITIALIZER;
+
+
+static void* vold_monitor_run(void* nothing)
+{
+ _vold_monitor_active = 1;
+
+ (void) nothing;
+
+ DEBUGF("DEBUG %s: Thread start.", __func__);
+
+ vold_monitor_open_socket();
+ if(_vold_monitor_socket_fd < 0)
+ {
+ DEBUGF("ERROR %s: Thread end: No socket.", __func__);
+
+ _vold_monitor_active = 0;
+ return 0;
+ }
+
+ struct pollfd fds[1];
+ fds[0].fd = _vold_monitor_socket_fd;
+ fds[0].events = POLLIN;
+
+ while(_vold_monitor_active == 1)
+ {
+ poll(fds, 1, 10);
+ if(! (fds[0].revents & POLLIN))
+ {
+ continue;
+ }
+
+ int socket_fd = accept(_vold_monitor_socket_fd, NULL, NULL);
+
+ if(socket_fd < 0)
+ {
+ DEBUGF("ERROR %s: accept failed.", __func__);
+
+ continue;
+ }
+
+ while(true)
+ {
+ char msg[1024];
+ memset(msg, 0, sizeof(msg));
+ int length = read(socket_fd, msg, sizeof(msg));
+
+ if(length <= 0)
+ {
+ close(socket_fd);
+ break;
+ }
+
+ DEBUGF("DEBUG %s: msg: %s", __func__, msg);
+
+ if(strcmp(msg, "Volume flash /mnt/sdcard state changed from 3 (Checking) to 4 (Mounted)") == 0)
+ {
+ pthread_mutex_lock(&_sdcard_mount_mtx);
+ _sdcard_not_mounted = false;
+ pthread_cond_signal(&_sdcard_mount_cond);
+ pthread_mutex_unlock(&_sdcard_mount_mtx);
+ }
+ }
+ }
+
+ close(_vold_monitor_socket_fd);
+ unlink(VOLD_MONITOR_SOCKET_NAME);
+ _vold_monitor_socket_fd = -1;
+
+ DEBUGF("DEBUG %s: Thread end.", __func__);
+
+ _vold_monitor_active = 0;
+ return 0;
+}
+
+
+/* Vold monitor thread. */
+static pthread_t _vold_monitor_thread;
+
+
+static void vold_monitor_start(void)
+{
+ TRACE;
+
+ if(_vold_monitor_active == 0)
+ {
+ pthread_create(&_vold_monitor_thread, NULL, vold_monitor_run, NULL);
+ }
+}
+
+
+static void vold_monitor_stop(void)
+{
+ TRACE;
+
+ if(_vold_monitor_active == 1)
+ {
+ _vold_monitor_active = 0;
+ int ret = pthread_join(_vold_monitor_thread, NULL);
+ DEBUGF("DEBUG %s: Thread joined: ret: %d.", __func__, ret);
+ }
+}
+
+
+/*- Input handler -------------------------------------------------------------------------------*/
+
+
+/* Input devices monitored with poll API. */
+static struct pollfd* _fds = NULL;
+
+
+/* Number of input devices monitored with poll API. */
+static nfds_t _nfds = 0;
+
+
+/* The names of the devices in _fds. */
+static char** _device_names = NULL;
+
+
+/* Open device device_name and add it to the list of polled devices. */
+static void open_device(const char* device_name)
+{
+ int fd = open(device_name, O_RDONLY);
+ if(fd == -1)
+ {
+ DEBUGF("ERROR %s: open failed on %s.", __func__, device_name);
+ exit(-1);
+ }
+
+ struct pollfd* new_fds = realloc(_fds, sizeof(struct pollfd) * (_nfds + 1));
+ if(new_fds == NULL)
+ {
+ DEBUGF("ERROR %s: realloc for _fds failed.", __func__);
+ exit(-1);
+ }
+
+ _fds = new_fds;
+ _fds[_nfds].fd = fd;
+ _fds[_nfds].events = POLLIN;
+
+ char** new_device_names = realloc(_device_names, sizeof(char*) * (_nfds + 1));
+ if(new_device_names == NULL)
+ {
+ DEBUGF("ERROR %s: realloc for _device_names failed.", __func__);
+ exit(-1);
+ }
+
+ _device_names = new_device_names;
+ _device_names[_nfds] = strdup(device_name);
+ if(_device_names[_nfds] == NULL)
+ {
+ DEBUGF("ERROR %s: strdup failed.", __func__);
+ exit(-1);
+ }
+
+ ++_nfds;
+
+ DEBUGF("DEBUG %s: Opened device %s.", __func__, device_name);
+}
+
+
+static void button_init_device(void)
+{
+ TRACE;
+
+ if((_fds != NULL) || (_nfds != 0) || (_device_names != NULL))
+ {
+ DEBUGF("ERROR %s: Allready initialized.", __func__);
+ return;
+ }
+
+ /* The input device directory. */
+ static const char device_path[] = "/dev/input";
+
+ /* Path delimeter. */
+ static const char delimeter[] = "/";
+
+ /* Open all devices in device_path. */
+ DIR* dir = opendir(device_path);
+ if(dir == NULL)
+ {
+ DEBUGF("ERROR %s: opendir failed: errno: %d.", __func__, errno);
+ exit(errno);
+ }
+
+ char device_name[PATH_MAX];
+ strcpy(device_name, device_path);
+ strcat(device_name, delimeter);
+ char* device_name_idx = device_name + strlen(device_name);
+
+ struct dirent* dir_entry;
+ while((dir_entry = readdir(dir)))
+ {
+ if( ((dir_entry->d_name[0] == '.') && (dir_entry->d_name[1] == '\0'))
+ || ((dir_entry->d_name[0] == '.') && (dir_entry->d_name[1] == '.') && (dir_entry->d_name[2] == '\0')))
+ {
+ continue;
+ }
+
+ strcpy(device_name_idx, dir_entry->d_name);
+
+ /* Open and add device to _fds. */
+ open_device(device_name);
+ }
+
+ closedir(dir);
+
+ /* Sanity check. */
+ if(_nfds < 2)
+ {
+ DEBUGF("ERROR %s: No input devices.", __func__);
+ exit(-1);
+ }
+}
+
+
+#define EVENT_TYPE_BUTTON 1
+
+
+#define EVENT_CODE_BUTTON_PWR_LONG 117
+#define EVENT_CODE_BUTTON_REV 160
+#define EVENT_CODE_BUTTON_NEXT 162
+
+
+#define EVENT_TYPE_TOUCHSCREEN 3
+
+
+#define EVENT_CODE_TOUCHSCREEN_X 53
+
+
+enum user_choice
+{
+ CHOICE_NONE = -1,
+ CHOICE_MANGO,
+ CHOICE_ROCKBOX,
+ CHOICE_POWEROFF
+};
+
+
+static int get_user_choice(void)
+{
+ TRACE;
+
+ button_init_device();
+
+ enum user_choice choice = CHOICE_NONE;
+
+ while(choice == CHOICE_NONE)
+ {
+ /* Poll all input devices. */
+ poll(_fds, _nfds, 0);
+
+ nfds_t fds_idx = 0;
+ for( ; fds_idx < _nfds; ++fds_idx)
+ {
+ if(! (_fds[fds_idx].revents & POLLIN))
+ {
+ continue;
+ }
+
+ struct input_event event;
+ if(read(_fds[fds_idx].fd, &event, sizeof(event)) < (int) sizeof(event))
+ {
+ DEBUGF("ERROR %s: Read of input devices failed.", __func__);
+ continue;
+ }
+
+ DEBUGF("DEBUG %s: device: %s, event.type: %d, event.code: %d, event.value: %d", __func__, _device_names[fds_idx], event.type, event.code, event.value);
+
+ if(event.type == EVENT_TYPE_BUTTON)
+ {
+ switch(event.code)
+ {
+ case EVENT_CODE_BUTTON_REV:
+ {
+ choice = CHOICE_MANGO;
+ break;
+ }
+
+ case EVENT_CODE_BUTTON_NEXT:
+ {
+ choice = CHOICE_ROCKBOX;
+ break;
+ }
+
+ case EVENT_CODE_BUTTON_PWR_LONG:
+ {
+ choice = CHOICE_POWEROFF;
+ break;
+ }
+ }
+ }
+ else if((event.type == EVENT_TYPE_TOUCHSCREEN) && (event.code == EVENT_CODE_TOUCHSCREEN_X))
+ {
+ if(event.value < 160)
+ {
+ choice = CHOICE_MANGO;
+ }
+ else
+ {
+ choice = CHOICE_ROCKBOX;
+ }
+ }
+ }
+ }
+
+ if(_fds)
+ {
+ nfds_t fds_idx = 0;
+ for( ; fds_idx < _nfds; ++fds_idx)
+ {
+ close(_fds[fds_idx].fd);
+ }
+ free(_fds);
+ _fds = NULL;
+ }
+
+ if(_device_names)
+ {
+ nfds_t fds_idx = 0;
+ for( ; fds_idx < _nfds; ++fds_idx)
+ {
+ free(_device_names[fds_idx]);
+ }
+ free(_device_names);
+ _device_names = NULL;
+ }
+
+ _nfds = 0;
+
+ return choice;
+}
+
+
+/*
+ Changing bit, when hold switch is toggled.
+ Bit is off when hold switch is engaged.
+*/
+#define HOLD_SWITCH_BIT 16
+
+
+static bool check_for_hold(void)
+{
+ TRACE;
+
+ char hold_state;
+
+ FILE* f = fopen("/sys/class/axppower/holdkey", "r");
+ fscanf(f, "%c", &hold_state);
+ fclose(f);
+
+ return(! (hold_state & HOLD_SWITCH_BIT));
+}
+
+
+/*- Display -------------------------------------------------------------------------------------*/
+
+
+static void draw(const char* file)
+{
+ DEBUGF("DEBUG %s: file: %s.", __func__, file);
+
+ int dev_fd = open("/dev/graphics/fb0", O_RDWR);
+ if(dev_fd == -1)
+ {
+ DEBUGF("ERROR %s: open failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
+ exit(errno);
+ }
+
+ /* Get fixed screen information. */
+ struct fb_fix_screeninfo finfo;
+ if(ioctl(dev_fd, FBIOGET_FSCREENINFO, &finfo) < 0)
+ {
+ DEBUGF("ERROR %s: ioctl FBIOGET_FSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
+ exit(errno);
+ }
+
+ /* Get the changeable information. */
+ struct fb_var_screeninfo vinfo;
+ if(ioctl(dev_fd, FBIOGET_VSCREENINFO, &vinfo) < 0)
+ {
+ DEBUGF("ERROR %s: ioctl FBIOGET_VSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
+ exit(errno);
+ }
+
+ DEBUGF("DEBUG %s: bits_per_pixel: %u, width: %u, height: %u.", __func__, vinfo.bits_per_pixel, vinfo.width, vinfo.height);
+
+ size_t screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
+
+ /* ToDo: Is this needed? */
+ vinfo.xres = 320;
+ vinfo.xres_virtual = 320;
+ vinfo.width = 320;
+ vinfo.yres = 240;
+ vinfo.yres_virtual = 240;
+ vinfo.height = 240;
+ vinfo.xoffset = 0;
+ vinfo.yoffset = 0;
+ vinfo.sync = 0;
+ vinfo.vmode = 0;
+ vinfo.pixclock = 104377;
+ vinfo.left_margin = 20;
+ vinfo.right_margin = 50;
+ vinfo.upper_margin = 2;
+ vinfo.lower_margin = 4;
+ vinfo.hsync_len = 10;
+ vinfo.vsync_len = 2;
+ vinfo.red.offset = 11;
+ vinfo.red.length = 5;
+ vinfo.red.msb_right = 0;
+ vinfo.green.offset = 5;
+ vinfo.green.length = 6;
+ vinfo.green.msb_right = 0;
+ vinfo.blue.offset = 0;
+ vinfo.blue.length = 5;
+ vinfo.blue.msb_right = 0;
+ vinfo.transp.offset = 0;
+ vinfo.transp.length = 0;
+ vinfo.transp.msb_right = 0;
+ vinfo.nonstd = 4;
+ if(ioctl(dev_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0)
+ {
+ DEBUGF("ERROR %s: ioctl FBIOPUT_VSCREENINFO failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
+ exit(errno);
+ }
+
+ /* Map the device to memory. */
+ char* dev_fb = (char*) mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, 0);
+ if(dev_fb == MAP_FAILED)
+ {
+ DEBUGF("ERROR %s: mmap failed on /dev/graphics/fb0, errno: %d.", __func__, errno);
+ exit(errno);
+ }
+
+ BMP* bmp = BMP_ReadFile(file);
+ if(BMP_GetError() != BMP_OK )
+ {
+ DEBUGF("ERROR %s: BMP_ReadFile failed on %s: %d.", __func__, file, BMP_GetError());
+ exit(BMP_GetError());
+ }
+
+ int y = 0;
+ for( ; y < 240; ++y)
+ {
+ int x = 0;
+ for( ; x < 320; ++x)
+ {
+ long int position = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8 )
+ + (y + vinfo.yoffset) * finfo.line_length;
+ UCHAR r, g, b;
+ BMP_GetPixelRGB(bmp, x, y, &r, &g, &b);
+ unsigned short int pixel = (r >> 3) << 11 | (g >> 2) << 5 | (b >> 3);
+ *((unsigned short int*)(dev_fb + position)) = pixel;
+ }
+ }
+
+ BMP_Free(bmp);
+ munmap(dev_fb, screensize);
+ close(dev_fd);
+}
+
+
+/*-----------------------------------------------------------------------------------------------*/
+
+
+static const char ROCKBOX_BIN[] = "/mnt/sdcard/.rockbox/rockbox";
+static const char OF_PLAYER_BIN[] = "/system/bin/MangoPlayer_original";
+static const char PLAYER_FILE[] = "/data/chosen_player";
+
+
+int main(int argc, char **argv)
+{
+ TRACE;
+
+ /*
+ Create the iBasso Vold socket and monitor it.
+ Do this early to not block Vold.
+ */
+ vold_monitor_start();
+
+ int last_chosen_player = CHOICE_NONE;
+
+ FILE* f = fopen(PLAYER_FILE, "r");
+ if(f != NULL)
+ {
+ fscanf(f, "%d", &last_chosen_player);
+ fclose(f);
+ }
+
+ DEBUGF("DEBUG %s: Current player choice: %d.", __func__, last_chosen_player);
+
+ if(check_for_hold() || (last_chosen_player == CHOICE_NONE))
+ {
+ draw("/system/chooser.bmp");
+
+ enum user_choice choice = get_user_choice();
+
+ if(choice == CHOICE_POWEROFF)
+ {
+ reboot(RB_POWER_OFF);
+ while(true)
+ {
+ sleep(1);
+ }
+ }
+
+ if(choice != last_chosen_player)
+ {
+ last_chosen_player = choice;
+
+ f = fopen(PLAYER_FILE, "w");
+ fprintf(f, "%d", last_chosen_player);
+ fclose(f);
+ }
+
+ DEBUGF("DEBUG %s: New player choice: %d.", __func__, last_chosen_player);
+ }
+
+ /* true, Rockbox was started at least once. */
+ bool rockboxStarted = false;
+
+ while(true)
+ {
+ /* Excecute OF MangoPlayer or Rockbox and restart it if it crashes. */
+
+ if(last_chosen_player == CHOICE_ROCKBOX)
+ {
+ if(rockboxStarted)
+ {
+ /*
+ At this point it is assumed, that Rockbox has exited due to a USB connection
+ triggering a remount of the internal storage for mass storage access.
+ Rockbox will eventually restart, when /mnt/sdcard becomes available again.
+ */
+ draw("/system/usb.bmp");
+ }
+
+ pthread_mutex_lock(&_sdcard_mount_mtx);
+ while(_sdcard_not_mounted)
+ {
+ DEBUGF("DEBUG %s: Waiting on /mnt/sdcard/.", __func__);
+
+ pthread_cond_wait(&_sdcard_mount_cond, &_sdcard_mount_mtx);
+
+ DEBUGF("DEBUG %s: /mnt/sdcard/ available.", __func__);
+ }
+ pthread_mutex_unlock(&_sdcard_mount_mtx);
+
+ /* To be able to execute rockbox. */
+ system("mount -o remount,exec /mnt/sdcard");
+
+ /* This symlink is needed mainly to keep themes functional. */
+ system("ln -s /mnt/sdcard/.rockbox /.rockbox");
+
+ if(access(ROCKBOX_BIN, X_OK) != -1)
+ {
+ /* Start Rockbox. */
+
+ /* Rockbox has its own vold monitor. */
+ vold_monitor_stop();
+
+ DEBUGF("DEBUG %s: Excecuting %s.", __func__, ROCKBOX_BIN);
+
+ int ret_code = system(ROCKBOX_BIN);
+ rockboxStarted = true;
+
+ DEBUGF("DEBUG %s: ret_code: %d.", __func__, ret_code);
+
+ if(WIFEXITED(ret_code) && (WEXITSTATUS(ret_code) == 42))
+ {
+ /*
+ Rockbox terminated to prevent a froced shutdown due to a USB connection
+ triggering a remount of the internal storage for mass storage access.
+ */
+ _sdcard_not_mounted = true;
+ }
+ /* else Rockbox crashed ... */
+
+ vold_monitor_start();
+ }
+ else
+ {
+ /* Rockbox executable missing. Show info screen for 30 seconds. */
+ draw("/system/rbmissing.bmp");
+ sleep(30);
+
+ /* Do not block Vold, so stop after sleep. */
+ vold_monitor_stop();
+
+#ifdef DEBUG
+ system("setprop persist.sys.usb.config adb");
+ system("setprop persist.usb.debug 1");
+#endif
+
+ DEBUGF("DEBUG %s: Rockbox missing, excecuting %s.", __func__, OF_PLAYER_BIN);
+
+ /* Start OF MangoPlayer. */
+ int ret_code = system(OF_PLAYER_BIN);
+
+ DEBUGF("DEBUG %s: ret_code: %d.", __func__, ret_code);
+ }
+ }
+ else /* if(last_chosen_player == CHOICE_MANGO) */
+ {
+ vold_monitor_stop();
+
+ DEBUGF("DEBUG %s: Excecuting %s.", __func__, OF_PLAYER_BIN);
+
+ int ret_code = system(OF_PLAYER_BIN);
+
+ DEBUGF("DEBUG %s: ret_code: %d.", __func__, ret_code);
+ }
+ }
+
+ return 0;
+}
diff --git a/utils/ibassoboot/jni/qdbmp.c b/utils/ibassoboot/jni/qdbmp.c
new file mode 100644
index 0000000000..fd1337277d
--- /dev/null
+++ b/utils/ibassoboot/jni/qdbmp.c
@@ -0,0 +1,798 @@
+#include "qdbmp.h"
+#include <stdlib.h>
+#include <string.h>
+
+
+/* Bitmap header */
+typedef struct _BMP_Header
+{
+ USHORT Magic; /* Magic identifier: "BM" */
+ UINT FileSize; /* Size of the BMP file in bytes */
+ USHORT Reserved1; /* Reserved */
+ USHORT Reserved2; /* Reserved */
+ UINT DataOffset; /* Offset of image data relative to the file's start */
+ UINT HeaderSize; /* Size of the header in bytes */
+ UINT Width; /* Bitmap's width */
+ UINT Height; /* Bitmap's height */
+ USHORT Planes; /* Number of color planes in the bitmap */
+ USHORT BitsPerPixel; /* Number of bits per pixel */
+ UINT CompressionType; /* Compression type */
+ UINT ImageDataSize; /* Size of uncompressed image's data */
+ UINT HPixelsPerMeter; /* Horizontal resolution (pixels per meter) */
+ UINT VPixelsPerMeter; /* Vertical resolution (pixels per meter) */
+ UINT ColorsUsed; /* Number of color indexes in the color table that are actually used by the bitmap */
+ UINT ColorsRequired; /* Number of color indexes that are required for displaying the bitmap */
+} BMP_Header;
+
+
+/* Private data structure */
+struct _BMP
+{
+ BMP_Header Header;
+ UCHAR* Palette;
+ UCHAR* Data;
+};
+
+
+/* Holds the last error code */
+static BMP_STATUS BMP_LAST_ERROR_CODE = 0;
+
+
+/* Error description strings */
+static const char* BMP_ERROR_STRING[] =
+{
+ "",
+ "General error",
+ "Could not allocate enough memory to complete the operation",
+ "File input/output error",
+ "File not found",
+ "File is not a supported BMP variant (must be uncompressed 8, 24 or 32 BPP)",
+ "File is not a valid BMP image",
+ "An argument is invalid or out of range",
+ "The requested action is not compatible with the BMP's type"
+};
+
+
+/* Size of the palette data for 8 BPP bitmaps */
+#define BMP_PALETTE_SIZE ( 256 * 4 )
+
+
+
+/*********************************** Forward declarations **********************************/
+int ReadHeader ( BMP* bmp, FILE* f );
+int WriteHeader ( BMP* bmp, FILE* f );
+
+int ReadUINT ( UINT* x, FILE* f );
+int ReadUSHORT ( USHORT *x, FILE* f );
+
+int WriteUINT ( UINT x, FILE* f );
+int WriteUSHORT ( USHORT x, FILE* f );
+
+
+
+
+
+
+/*********************************** Public methods **********************************/
+
+
+/**************************************************************
+ Creates a blank BMP image with the specified dimensions
+ and bit depth.
+**************************************************************/
+BMP* BMP_Create( UINT width, UINT height, USHORT depth )
+{
+ BMP* bmp;
+ int bytes_per_pixel = depth >> 3;
+ UINT bytes_per_row;
+
+ if ( height <= 0 || width <= 0 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ return NULL;
+ }
+
+ if ( depth != 8 && depth != 24 && depth != 32 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED;
+ return NULL;
+ }
+
+
+ /* Allocate the bitmap data structure */
+ bmp = calloc( 1, sizeof( BMP ) );
+ if ( bmp == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
+ return NULL;
+ }
+
+
+ /* Set header' default values */
+ bmp->Header.Magic = 0x4D42;
+ bmp->Header.Reserved1 = 0;
+ bmp->Header.Reserved2 = 0;
+ bmp->Header.HeaderSize = 40;
+ bmp->Header.Planes = 1;
+ bmp->Header.CompressionType = 0;
+ bmp->Header.HPixelsPerMeter = 0;
+ bmp->Header.VPixelsPerMeter = 0;
+ bmp->Header.ColorsUsed = 0;
+ bmp->Header.ColorsRequired = 0;
+
+
+ /* Calculate the number of bytes used to store a single image row. This is always
+ rounded up to the next multiple of 4. */
+ bytes_per_row = width * bytes_per_pixel;
+ bytes_per_row += ( bytes_per_row % 4 ? 4 - bytes_per_row % 4 : 0 );
+
+
+ /* Set header's image specific values */
+ bmp->Header.Width = width;
+ bmp->Header.Height = height;
+ bmp->Header.BitsPerPixel = depth;
+ bmp->Header.ImageDataSize = bytes_per_row * height;
+ bmp->Header.FileSize = bmp->Header.ImageDataSize + 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 );
+ bmp->Header.DataOffset = 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 );
+
+
+ /* Allocate palette */
+ if ( bmp->Header.BitsPerPixel == 8 )
+ {
+ bmp->Palette = (UCHAR*) calloc( BMP_PALETTE_SIZE, sizeof( UCHAR ) );
+ if ( bmp->Palette == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
+ free( bmp );
+ return NULL;
+ }
+ }
+ else
+ {
+ bmp->Palette = NULL;
+ }
+
+
+ /* Allocate pixels */
+ bmp->Data = (UCHAR*) calloc( bmp->Header.ImageDataSize, sizeof( UCHAR ) );
+ if ( bmp->Data == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
+ free( bmp->Palette );
+ free( bmp );
+ return NULL;
+ }
+
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ return bmp;
+}
+
+
+/**************************************************************
+ Frees all the memory used by the specified BMP image.
+**************************************************************/
+void BMP_Free( BMP* bmp )
+{
+ if ( bmp == NULL )
+ {
+ return;
+ }
+
+ if ( bmp->Palette != NULL )
+ {
+ free( bmp->Palette );
+ }
+
+ if ( bmp->Data != NULL )
+ {
+ free( bmp->Data );
+ }
+
+ free( bmp );
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+}
+
+
+/**************************************************************
+ Reads the specified BMP image file.
+**************************************************************/
+BMP* BMP_ReadFile( const char* filename )
+{
+ BMP* bmp;
+ FILE* f;
+
+ if ( filename == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ return NULL;
+ }
+
+
+ /* Allocate */
+ bmp = calloc( 1, sizeof( BMP ) );
+ if ( bmp == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
+ return NULL;
+ }
+
+
+ /* Open file */
+ f = fopen( filename, "rb" );
+ if ( f == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND;
+ free( bmp );
+ return NULL;
+ }
+
+
+ /* Read header */
+ if ( ReadHeader( bmp, f ) != BMP_OK || bmp->Header.Magic != 0x4D42 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
+ fclose( f );
+ free( bmp );
+ return NULL;
+ }
+
+
+ /* Verify that the bitmap variant is supported */
+ if ( ( bmp->Header.BitsPerPixel != 32 && bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 8 )
+ || bmp->Header.CompressionType != 0 || bmp->Header.HeaderSize != 40 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED;
+ fclose( f );
+ free( bmp );
+ return NULL;
+ }
+
+
+ /* Allocate and read palette */
+ if ( bmp->Header.BitsPerPixel == 8 )
+ {
+ bmp->Palette = (UCHAR*) malloc( BMP_PALETTE_SIZE * sizeof( UCHAR ) );
+ if ( bmp->Palette == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
+ fclose( f );
+ free( bmp );
+ return NULL;
+ }
+
+ if ( fread( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE )
+ {
+ BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
+ fclose( f );
+ free( bmp->Palette );
+ free( bmp );
+ return NULL;
+ }
+ }
+ else /* Not an indexed image */
+ {
+ bmp->Palette = NULL;
+ }
+
+
+ /* Allocate memory for image data */
+ bmp->Data = (UCHAR*) malloc( bmp->Header.ImageDataSize );
+ if ( bmp->Data == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
+ fclose( f );
+ free( bmp->Palette );
+ free( bmp );
+ return NULL;
+ }
+
+
+ /* Read image data */
+ if ( fread( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize )
+ {
+ BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
+ fclose( f );
+ free( bmp->Data );
+ free( bmp->Palette );
+ free( bmp );
+ return NULL;
+ }
+
+
+ fclose( f );
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ return bmp;
+}
+
+
+/**************************************************************
+ Writes the BMP image to the specified file.
+**************************************************************/
+void BMP_WriteFile( BMP* bmp, const char* filename )
+{
+ FILE* f;
+
+ if ( filename == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ return;
+ }
+
+
+ /* Open file */
+ f = fopen( filename, "wb" );
+ if ( f == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND;
+ return;
+ }
+
+
+ /* Write header */
+ if ( WriteHeader( bmp, f ) != BMP_OK )
+ {
+ BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
+ fclose( f );
+ return;
+ }
+
+
+ /* Write palette */
+ if ( bmp->Palette )
+ {
+ if ( fwrite( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE )
+ {
+ BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
+ fclose( f );
+ return;
+ }
+ }
+
+
+ /* Write data */
+ if ( fwrite( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize )
+ {
+ BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
+ fclose( f );
+ return;
+ }
+
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+ fclose( f );
+}
+
+
+/**************************************************************
+ Returns the image's width.
+**************************************************************/
+UINT BMP_GetWidth( BMP* bmp )
+{
+ if ( bmp == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ return -1;
+ }
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ return ( bmp->Header.Width );
+}
+
+
+/**************************************************************
+ Returns the image's height.
+**************************************************************/
+UINT BMP_GetHeight( BMP* bmp )
+{
+ if ( bmp == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ return -1;
+ }
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ return ( bmp->Header.Height );
+}
+
+
+/**************************************************************
+ Returns the image's color depth (bits per pixel).
+**************************************************************/
+USHORT BMP_GetDepth( BMP* bmp )
+{
+ if ( bmp == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ return -1;
+ }
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ return ( bmp->Header.BitsPerPixel );
+}
+
+
+/**************************************************************
+ Populates the arguments with the specified pixel's RGB
+ values.
+**************************************************************/
+void BMP_GetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b )
+{
+ UCHAR* pixel;
+ UINT bytes_per_row;
+ UCHAR bytes_per_pixel;
+
+ if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ }
+ else
+ {
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ bytes_per_pixel = bmp->Header.BitsPerPixel >> 3;
+
+ /* Row's size is rounded up to the next multiple of 4 bytes */
+ bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
+
+ /* Calculate the location of the relevant pixel (rows are flipped) */
+ pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel );
+
+
+ /* In indexed color mode the pixel's value is an index within the palette */
+ if ( bmp->Header.BitsPerPixel == 8 )
+ {
+ pixel = bmp->Palette + *pixel * 4;
+ }
+
+ /* Note: colors are stored in BGR order */
+ if ( r ) *r = *( pixel + 2 );
+ if ( g ) *g = *( pixel + 1 );
+ if ( b ) *b = *( pixel + 0 );
+ }
+}
+
+
+/**************************************************************
+ Sets the specified pixel's RGB values.
+**************************************************************/
+void BMP_SetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b )
+{
+ UCHAR* pixel;
+ UINT bytes_per_row;
+ UCHAR bytes_per_pixel;
+
+ if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ }
+
+ else if ( bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 32 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
+ }
+
+ else
+ {
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ bytes_per_pixel = bmp->Header.BitsPerPixel >> 3;
+
+ /* Row's size is rounded up to the next multiple of 4 bytes */
+ bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
+
+ /* Calculate the location of the relevant pixel (rows are flipped) */
+ pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel );
+
+ /* Note: colors are stored in BGR order */
+ *( pixel + 2 ) = r;
+ *( pixel + 1 ) = g;
+ *( pixel + 0 ) = b;
+ }
+}
+
+
+/**************************************************************
+ Gets the specified pixel's color index.
+**************************************************************/
+void BMP_GetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR* val )
+{
+ UCHAR* pixel;
+ UINT bytes_per_row;
+
+ if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ }
+
+ else if ( bmp->Header.BitsPerPixel != 8 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
+ }
+
+ else
+ {
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ /* Row's size is rounded up to the next multiple of 4 bytes */
+ bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
+
+ /* Calculate the location of the relevant pixel */
+ pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x );
+
+
+ if ( val ) *val = *pixel;
+ }
+}
+
+
+/**************************************************************
+ Sets the specified pixel's color index.
+**************************************************************/
+void BMP_SetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR val )
+{
+ UCHAR* pixel;
+ UINT bytes_per_row;
+
+ if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ }
+
+ else if ( bmp->Header.BitsPerPixel != 8 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
+ }
+
+ else
+ {
+ BMP_LAST_ERROR_CODE = BMP_OK;
+
+ /* Row's size is rounded up to the next multiple of 4 bytes */
+ bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
+
+ /* Calculate the location of the relevant pixel */
+ pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x );
+
+ *pixel = val;
+ }
+}
+
+
+/**************************************************************
+ Gets the color value for the specified palette index.
+**************************************************************/
+void BMP_GetPaletteColor( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b )
+{
+ if ( bmp == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ }
+
+ else if ( bmp->Header.BitsPerPixel != 8 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
+ }
+
+ else
+ {
+ if ( r ) *r = *( bmp->Palette + index * 4 + 2 );
+ if ( g ) *g = *( bmp->Palette + index * 4 + 1 );
+ if ( b ) *b = *( bmp->Palette + index * 4 + 0 );
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+ }
+}
+
+
+/**************************************************************
+ Sets the color value for the specified palette index.
+**************************************************************/
+void BMP_SetPaletteColor( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b )
+{
+ if ( bmp == NULL )
+ {
+ BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
+ }
+
+ else if ( bmp->Header.BitsPerPixel != 8 )
+ {
+ BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
+ }
+
+ else
+ {
+ *( bmp->Palette + index * 4 + 2 ) = r;
+ *( bmp->Palette + index * 4 + 1 ) = g;
+ *( bmp->Palette + index * 4 + 0 ) = b;
+
+ BMP_LAST_ERROR_CODE = BMP_OK;
+ }
+}
+
+
+/**************************************************************
+ Returns the last error code.
+**************************************************************/
+BMP_STATUS BMP_GetError()
+{
+ return BMP_LAST_ERROR_CODE;
+}
+
+
+/**************************************************************
+ Returns a description of the last error code.
+**************************************************************/
+const char* BMP_GetErrorDescription()
+{
+ if ( BMP_LAST_ERROR_CODE > 0 && BMP_LAST_ERROR_CODE < BMP_ERROR_NUM )
+ {
+ return BMP_ERROR_STRING[ BMP_LAST_ERROR_CODE ];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+
+
+
+/*********************************** Private methods **********************************/
+
+
+/**************************************************************
+ Reads the BMP file's header into the data structure.
+ Returns BMP_OK on success.
+**************************************************************/
+int ReadHeader( BMP* bmp, FILE* f )
+{
+ if ( bmp == NULL || f == NULL )
+ {
+ return BMP_INVALID_ARGUMENT;
+ }
+
+ /* The header's fields are read one by one, and converted from the format's
+ little endian to the system's native representation. */
+ if ( !ReadUSHORT( &( bmp->Header.Magic ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.FileSize ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUSHORT( &( bmp->Header.Reserved1 ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUSHORT( &( bmp->Header.Reserved2 ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.DataOffset ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.HeaderSize ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.Width ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.Height ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUSHORT( &( bmp->Header.Planes ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUSHORT( &( bmp->Header.BitsPerPixel ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.CompressionType ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.ImageDataSize ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.HPixelsPerMeter ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.VPixelsPerMeter ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.ColorsUsed ), f ) ) return BMP_IO_ERROR;
+ if ( !ReadUINT( &( bmp->Header.ColorsRequired ), f ) ) return BMP_IO_ERROR;
+
+ return BMP_OK;
+}
+
+
+/**************************************************************
+ Writes the BMP file's header into the data structure.
+ Returns BMP_OK on success.
+**************************************************************/
+int WriteHeader( BMP* bmp, FILE* f )
+{
+ if ( bmp == NULL || f == NULL )
+ {
+ return BMP_INVALID_ARGUMENT;
+ }
+
+ /* The header's fields are written one by one, and converted to the format's
+ little endian representation. */
+ if ( !WriteUSHORT( bmp->Header.Magic, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.FileSize, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUSHORT( bmp->Header.Reserved1, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUSHORT( bmp->Header.Reserved2, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.DataOffset, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.HeaderSize, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.Width, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.Height, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUSHORT( bmp->Header.Planes, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUSHORT( bmp->Header.BitsPerPixel, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.CompressionType, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.ImageDataSize, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.HPixelsPerMeter, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.VPixelsPerMeter, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.ColorsUsed, f ) ) return BMP_IO_ERROR;
+ if ( !WriteUINT( bmp->Header.ColorsRequired, f ) ) return BMP_IO_ERROR;
+
+ return BMP_OK;
+}
+
+
+/**************************************************************
+ Reads a little-endian unsigned int from the file.
+ Returns non-zero on success.
+**************************************************************/
+int ReadUINT( UINT* x, FILE* f )
+{
+ UCHAR little[ 4 ]; /* BMPs use 32 bit ints */
+
+ if ( x == NULL || f == NULL )
+ {
+ return 0;
+ }
+
+ if ( fread( little, 4, 1, f ) != 1 )
+ {
+ return 0;
+ }
+
+ *x = ( little[ 3 ] << 24 | little[ 2 ] << 16 | little[ 1 ] << 8 | little[ 0 ] );
+
+ return 1;
+}
+
+
+/**************************************************************
+ Reads a little-endian unsigned short int from the file.
+ Returns non-zero on success.
+**************************************************************/
+int ReadUSHORT( USHORT *x, FILE* f )
+{
+ UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */
+
+ if ( x == NULL || f == NULL )
+ {
+ return 0;
+ }
+
+ if ( fread( little, 2, 1, f ) != 1 )
+ {
+ return 0;
+ }
+
+ *x = ( little[ 1 ] << 8 | little[ 0 ] );
+
+ return 1;
+}
+
+
+/**************************************************************
+ Writes a little-endian unsigned int to the file.
+ Returns non-zero on success.
+**************************************************************/
+int WriteUINT( UINT x, FILE* f )
+{
+ UCHAR little[ 4 ]; /* BMPs use 32 bit ints */
+
+ little[ 3 ] = (UCHAR)( ( x & 0xff000000 ) >> 24 );
+ little[ 2 ] = (UCHAR)( ( x & 0x00ff0000 ) >> 16 );
+ little[ 1 ] = (UCHAR)( ( x & 0x0000ff00 ) >> 8 );
+ little[ 0 ] = (UCHAR)( ( x & 0x000000ff ) >> 0 );
+
+ return ( f && fwrite( little, 4, 1, f ) == 1 );
+}
+
+
+/**************************************************************
+ Writes a little-endian unsigned short int to the file.
+ Returns non-zero on success.
+**************************************************************/
+int WriteUSHORT( USHORT x, FILE* f )
+{
+ UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */
+
+ little[ 1 ] = (UCHAR)( ( x & 0xff00 ) >> 8 );
+ little[ 0 ] = (UCHAR)( ( x & 0x00ff ) >> 0 );
+
+ return ( f && fwrite( little, 2, 1, f ) == 1 );
+}
+
diff --git a/utils/ibassoboot/jni/qdbmp.h b/utils/ibassoboot/jni/qdbmp.h
new file mode 100644
index 0000000000..d6c0e6c452
--- /dev/null
+++ b/utils/ibassoboot/jni/qdbmp.h
@@ -0,0 +1,133 @@
+#ifndef _BMP_H_
+#define _BMP_H_
+
+
+/**************************************************************
+
+ QDBMP - Quick n' Dirty BMP
+
+ v1.0.0 - 2007-04-07
+ http://qdbmp.sourceforge.net
+
+
+ The library supports the following BMP variants:
+ 1. Uncompressed 32 BPP (alpha values are ignored)
+ 2. Uncompressed 24 BPP
+ 3. Uncompressed 8 BPP (indexed color)
+
+ QDBMP is free and open source software, distributed
+ under the MIT licence.
+
+ Copyright (c) 2007 Chai Braudo (braudo@users.sourceforge.net)
+
+ 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.
+
+**************************************************************/
+
+#include <stdio.h>
+
+
+
+/* Type definitions */
+#ifndef UINT
+ #define UINT unsigned long int
+#endif
+
+#ifndef USHORT
+ #define USHORT unsigned short
+#endif
+
+#ifndef UCHAR
+ #define UCHAR unsigned char
+#endif
+
+
+/* Version */
+#define QDBMP_VERSION_MAJOR 1
+#define QDBMP_VERSION_MINOR 0
+#define QDBMP_VERSION_PATCH 1
+
+
+/* Error codes */
+typedef enum
+{
+ BMP_OK = 0, /* No error */
+ BMP_ERROR, /* General error */
+ BMP_OUT_OF_MEMORY, /* Could not allocate enough memory to complete the operation */
+ BMP_IO_ERROR, /* General input/output error */
+ BMP_FILE_NOT_FOUND, /* File not found */
+ BMP_FILE_NOT_SUPPORTED, /* File is not a supported BMP variant */
+ BMP_FILE_INVALID, /* File is not a BMP image or is an invalid BMP */
+ BMP_INVALID_ARGUMENT, /* An argument is invalid or out of range */
+ BMP_TYPE_MISMATCH, /* The requested action is not compatible with the BMP's type */
+ BMP_ERROR_NUM
+} BMP_STATUS;
+
+
+/* Bitmap image */
+typedef struct _BMP BMP;
+
+
+
+
+/*********************************** Public methods **********************************/
+
+
+/* Construction/destruction */
+BMP* BMP_Create ( UINT width, UINT height, USHORT depth );
+void BMP_Free ( BMP* bmp );
+
+
+/* I/O */
+BMP* BMP_ReadFile ( const char* filename );
+void BMP_WriteFile ( BMP* bmp, const char* filename );
+
+
+/* Meta info */
+UINT BMP_GetWidth ( BMP* bmp );
+UINT BMP_GetHeight ( BMP* bmp );
+USHORT BMP_GetDepth ( BMP* bmp );
+
+
+/* Pixel access */
+void BMP_GetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b );
+void BMP_SetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b );
+void BMP_GetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR* val );
+void BMP_SetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR val );
+
+
+/* Palette handling */
+void BMP_GetPaletteColor ( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b );
+void BMP_SetPaletteColor ( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b );
+
+
+/* Error handling */
+BMP_STATUS BMP_GetError ();
+const char* BMP_GetErrorDescription ();
+
+
+/* Useful macro that may be used after each BMP operation to check for an error */
+#define BMP_CHECK_ERROR( output_file, return_value ) \
+ if ( BMP_GetError() != BMP_OK ) \
+ { \
+ fprintf( ( output_file ), "BMP error: %s\n", BMP_GetErrorDescription() ); \
+ return( return_value ); \
+ } \
+
+#endif
diff --git a/utils/ibassoboot/jni/rbmissing.bmp b/utils/ibassoboot/jni/rbmissing.bmp
new file mode 100644
index 0000000000..1e97066d8c
--- /dev/null
+++ b/utils/ibassoboot/jni/rbmissing.bmp
Binary files differ
diff --git a/utils/ibassoboot/jni/usb.bmp b/utils/ibassoboot/jni/usb.bmp
new file mode 100644
index 0000000000..c462de2236
--- /dev/null
+++ b/utils/ibassoboot/jni/usb.bmp
Binary files differ
diff --git a/utils/ipodpatcher/Makefile b/utils/ipodpatcher/Makefile
new file mode 100644
index 0000000000..4254995d22
--- /dev/null
+++ b/utils/ipodpatcher/Makefile
@@ -0,0 +1,53 @@
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+# $Id$
+#
+
+CFLAGS += -Wall -W
+
+# Build with "make BOOTOBJS=1" to build with embedded bootloaders and the
+# --install option and interactive mode. You need the full set of Rockbox
+# bootloaders in this directory - download them from
+# http://download.rockbox.org/bootloader/ipod/bootloaders.zip
+
+# Releases of ipodpatcher are created with "make RELEASE=1". This
+# enables BOOTOBJS and uses the VERSION string defined in main.c
+ifdef RELEASE
+CFLAGS += -DRELEASE
+BOOTOBJS=1
+endif
+
+ifdef BOOTOBJS
+BOOTSRC = ipod1g2g.c ipod3g.c ipod4g.c ipodcolor.c ipodmini1g.c \
+ ipodmini2g.c ipodnano1g.c ipodvideo.c ipodnano2g.c
+CFLAGS += -DWITH_BOOTOBJS
+endif
+
+# additional frameworks to link on on OS X
+LDOPTS_OSX = -framework CoreFoundation -framework IOKit
+
+LIBSOURCES = ipodpatcher.c fat32format.c arc4.c \
+ ipodio-posix.c ipodio-win32-scsi.c ipodio-win32.c
+SOURCES = main.c $(BOOTSRC)
+ipodpatcher: SOURCES+= ipodio-posix.c
+
+OUTPUT = ipodpatcher
+include ../libtools.make
+
+ipodpatcher.exe: $(OBJDIR)ipodpatcher-rc.o
+$(OBJDIR)ipodpatcher-rc.o: ipodpatcher.rc ipodpatcher.manifest
+ @echo WINDRES $(notdir $<)
+ $(SILENT)$(CROSS)$(WINDRES) -i $< -o $@
+
+%.c: bootloader-%.ipod $(BIN2C)
+ @echo BIN2C $<
+ $(SILENT)$(BIN2C) -i $< $*
+
+%.c: bootloader-%.ipodx $(BIN2C)
+ @echo BIN2C $<
+ $(SILENT)$(BIN2C) -i $< $*
+
diff --git a/utils/ipodpatcher/arc4.c b/utils/ipodpatcher/arc4.c
new file mode 100644
index 0000000000..75b1862b89
--- /dev/null
+++ b/utils/ipodpatcher/arc4.c
@@ -0,0 +1,108 @@
+/*
+ * arc4.c
+ * Release $Name: MATRIXSSL_1_8_3_OPEN $
+ *
+ * ARC4 stream cipher implementation
+ */
+/*
+ * Copyright (c) PeerSec Networks, 2002-2007. All Rights Reserved.
+ * The latest version of this code is available at http://www.matrixssl.org
+ *
+ * This software is open source; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This General Public License does NOT permit incorporating this software
+ * into proprietary programs. If you are unable to comply with the GPL, a
+ * commercial license for this software may be purchased from PeerSec Networks
+ * at http://www.peersec.com
+ *
+ * This program is distributed in WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/******************************************************************************/
+
+#include "arc4.h"
+
+/*
+ Some accounts, such as O'Reilly's Secure Programming Cookbook say that no
+ more than 2^30 bytes should be processed without rekeying, so we
+ enforce that limit here. FYI, this is equal to 1GB of data transferred.
+*/
+#define ARC4_MAX_BYTES 0x40000000
+
+/******************************************************************************/
+/*
+ SSL_RSA_WITH_RC4_* cipher callbacks
+ */
+void matrixArc4Init(struct rc4_key_t *ctx, unsigned char *key, int32_t keylen)
+{
+ unsigned char index1, index2, tmp, *state;
+ int16_t counter;
+
+ ctx->byteCount = 0;
+ state = &ctx->state[0];
+
+ for (counter = 0; counter < 256; counter++) {
+ state[counter] = (unsigned char)counter;
+ }
+ ctx->x = 0;
+ ctx->y = 0;
+ index1 = 0;
+ index2 = 0;
+
+ for (counter = 0; counter < 256; counter++) {
+ index2 = (key[index1] + state[counter] + index2) & 0xff;
+
+ tmp = state[counter];
+ state[counter] = state[index2];
+ state[index2] = tmp;
+
+ index1 = (index1 + 1) % keylen;
+ }
+}
+
+int32_t matrixArc4(struct rc4_key_t *ctx, unsigned char *in,
+ unsigned char *out, int32_t len)
+{
+ unsigned char x, y, *state, xorIndex, tmp;
+ int counter; /* NOTE BY DAVE CHAPMAN: This was a short in
+ the original code, which caused a segfault
+ when attempting to process data > 32767
+ bytes. */
+
+ ctx->byteCount += len;
+ if (ctx->byteCount > ARC4_MAX_BYTES) {
+ return -1;
+ }
+
+ x = ctx->x;
+ y = ctx->y;
+ state = &ctx->state[0];
+ for (counter = 0; counter < len; counter++) {
+ x = (x + 1) & 0xff;
+ y = (state[x] + y) & 0xff;
+
+ tmp = state[x];
+ state[x] = state[y];
+ state[y] = tmp;
+
+ xorIndex = (state[x] + state[y]) & 0xff;
+
+ tmp = in[counter];
+ tmp ^= state[xorIndex];
+ out[counter] = tmp;
+ }
+ ctx->x = x;
+ ctx->y = y;
+ return len;
+}
+
+/*****************************************************************************/
diff --git a/utils/ipodpatcher/arc4.h b/utils/ipodpatcher/arc4.h
new file mode 100644
index 0000000000..8bff0e2dc1
--- /dev/null
+++ b/utils/ipodpatcher/arc4.h
@@ -0,0 +1,47 @@
+/*
+ arc4.h - based on matrixssl-1-8-3-open
+
+*/
+
+/*
+ * Copyright (c) PeerSec Networks, 2002-2007. All Rights Reserved.
+ * The latest version of this code is available at http://www.matrixssl.org
+ *
+ * This software is open source; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This General Public License does NOT permit incorporating this software
+ * into proprietary programs. If you are unable to comply with the GPL, a
+ * commercial license for this software may be purchased from PeerSec Networks
+ * at http://www.peersec.com
+ *
+ * This program is distributed in WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/*****************************************************************************/
+
+#ifndef _ARC4_H
+
+#include <stdint.h>
+
+struct rc4_key_t
+{
+ unsigned char state[256];
+ uint32_t byteCount;
+ unsigned char x;
+ unsigned char y;
+};
+
+void matrixArc4Init(struct rc4_key_t *ctx, unsigned char *key, int32_t keylen);
+int32_t matrixArc4(struct rc4_key_t *ctx, unsigned char *in,
+ unsigned char *out, int32_t len);
+
+#endif
diff --git a/utils/ipodpatcher/fat32format.c b/utils/ipodpatcher/fat32format.c
new file mode 100644
index 0000000000..7ee8021cbf
--- /dev/null
+++ b/utils/ipodpatcher/fat32format.c
@@ -0,0 +1,530 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ *
+ * FAT32 formatting functions. Based on:
+ *
+ * Fat32 formatter version 1.03
+ * (c) Tom Thornhill 2005
+ * This software is covered by the GPL.
+ * By using this tool, you agree to absolve Ridgecrop of an liabilities for
+ * lost data.
+ * Please backup any data you value before using this tool.
+ *
+ *
+ * Modified June 2007 by Dave Chapman for use in ipodpatcher
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include "ipodio.h"
+
+static inline uint16_t swap16(uint16_t value)
+{
+ return (value >> 8) | (value << 8);
+}
+
+static inline uint32_t swap32(uint32_t value)
+{
+ uint32_t hi = swap16(value >> 16);
+ uint32_t lo = swap16(value & 0xffff);
+ return (lo << 16) | hi;
+}
+
+/* The following functions are not the most efficient, but are
+ self-contained and don't require needing to know endianness of CPU
+ at compile-time.
+
+ Note that htole16/htole32 exist on some platforms, so for
+ simplicity we use different names.
+
+*/
+
+static uint16_t rb_htole16(uint16_t x)
+{
+ uint16_t test = 0x1234;
+ unsigned char* p = (unsigned char*)&test;
+
+ if (p[0]==0x12) {
+ /* Big-endian */
+ return swap16(x);
+ } else {
+ return x;
+ }
+}
+
+static uint32_t rb_htole32(uint32_t x)
+{
+ uint32_t test = 0x12345678;
+ unsigned char* p = (unsigned char*)&test;
+
+ if (p[0]==0x12) {
+ /* Big-endian */
+ return swap32(x);
+ } else {
+ return x;
+ }
+}
+
+
+/* TODO: Pass these as parameters to the various create_ functions */
+
+/* can be zero for default or 1,2,4,8,16,32 or 64 */
+static int sectors_per_cluster = 0;
+
+/* Recommended values */
+static uint32_t ReservedSectCount = 32;
+static uint32_t NumFATs = 2;
+static uint32_t BackupBootSect = 6;
+static uint32_t VolumeId=0; /* calculated before format */
+
+/* Calculated later */
+static uint32_t FatSize=0;
+static uint32_t BytesPerSect=0;
+static uint32_t SectorsPerCluster=0;
+static uint32_t TotalSectors=0;
+static uint32_t SystemAreaSize=0;
+static uint32_t UserAreaSize=0;
+static uint8_t VolId[12] = "NO NAME ";
+
+
+struct FAT_BOOTSECTOR32
+{
+ /* Common fields. */
+ uint8_t sJmpBoot[3];
+ char sOEMName[8];
+ uint16_t wBytsPerSec;
+ uint8_t bSecPerClus;
+ uint16_t wRsvdSecCnt;
+ uint8_t bNumFATs;
+ uint16_t wRootEntCnt;
+ uint16_t wTotSec16; /* if zero, use dTotSec32 instead */
+ uint8_t bMedia;
+ uint16_t wFATSz16;
+ uint16_t wSecPerTrk;
+ uint16_t wNumHeads;
+ uint32_t dHiddSec;
+ uint32_t dTotSec32;
+
+ /* Fat 32/16 only */
+ uint32_t dFATSz32;
+ uint16_t wExtFlags;
+ uint16_t wFSVer;
+ uint32_t dRootClus;
+ uint16_t wFSInfo;
+ uint16_t wBkBootSec;
+ uint8_t Reserved[12];
+ uint8_t bDrvNum;
+ uint8_t Reserved1;
+ uint8_t bBootSig; /* == 0x29 if next three fields are ok */
+ uint32_t dBS_VolID;
+ uint8_t sVolLab[11];
+ uint8_t sBS_FilSysType[8];
+} __attribute__((packed));
+
+struct FAT_FSINFO {
+ uint32_t dLeadSig; // 0x41615252
+ uint8_t sReserved1[480]; // zeros
+ uint32_t dStrucSig; // 0x61417272
+ uint32_t dFree_Count; // 0xFFFFFFFF
+ uint32_t dNxt_Free; // 0xFFFFFFFF
+ uint8_t sReserved2[12]; // zeros
+ uint32_t dTrailSig; // 0xAA550000
+} __attribute__((packed));
+
+
+/* Write "count" zero sectors, starting at sector "sector" */
+static int zero_sectors(struct ipod_t* ipod, uint64_t sector, int count)
+{
+ int n;
+
+ if (ipod_seek(ipod, sector * ipod->sector_size) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ memset(ipod->sectorbuf, 0, 128 * ipod->sector_size);
+
+ /* Write 128 sectors at a time */
+ while (count) {
+ if (count >= 128)
+ n = 128;
+ else
+ n = count;
+
+ if (ipod_write(ipod,n * ipod->sector_size) < 0) {
+ perror("[ERR] Write failed in zero_sectors\n");
+ return -1;
+ }
+
+ count -= n;
+ }
+
+ return 0;
+}
+
+
+/*
+28.2 CALCULATING THE VOLUME SERIAL NUMBER
+
+For example, say a disk was formatted on 26 Dec 95 at 9:55 PM and 41.94
+seconds. DOS takes the date and time just before it writes it to the
+disk.
+
+Low order word is calculated: Volume Serial Number is:
+ Month & Day 12/26 0c1ah
+ Sec & Hundrenths 41:94 295eh 3578:1d02
+ -----
+ 3578h
+
+High order word is calculated:
+ Hours & Minutes 21:55 1537h
+ Year 1995 07cbh
+ -----
+ 1d02h
+*/
+static uint32_t get_volume_id ( )
+{
+ /* TODO */
+#if 0
+ SYSTEMTIME s;
+ uint32_t d;
+ uint16_t lo,hi,tmp;
+
+ GetLocalTime( &s );
+
+ lo = s.wDay + ( s.wMonth << 8 );
+ tmp = (s.wMilliseconds/10) + (s.wSecond << 8 );
+ lo += tmp;
+
+ hi = s.wMinute + ( s.wHour << 8 );
+ hi += s.wYear;
+
+ d = lo + (hi << 16);
+ return(d);
+#endif
+ return(0);
+}
+
+/*
+This is the Microsoft calculation from FATGEN
+
+ uint32_t RootDirSectors = 0;
+ uint32_t TmpVal1, TmpVal2, FATSz;
+
+ TmpVal1 = DskSize - ( ReservedSecCnt + RootDirSectors);
+ TmpVal2 = (256 * SecPerClus) + NumFATs;
+ TmpVal2 = TmpVal2 / 2;
+ FATSz = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2;
+
+ return( FatSz );
+*/
+
+
+static uint32_t get_fat_size_sectors(uint32_t DskSize, uint32_t ReservedSecCnt,
+ uint32_t SecPerClus, uint32_t NumFATs,
+ uint32_t BytesPerSect)
+{
+ uint64_t Numerator, Denominator;
+ uint64_t FatElementSize = 4;
+ uint64_t FatSz;
+
+ /* This is based on
+ http://hjem.get2net.dk/rune_moeller_barnkob/filesystems/fat.html
+ I've made the obvious changes for FAT32
+ */
+
+ Numerator = FatElementSize * ( DskSize - ReservedSecCnt );
+ Denominator = ( SecPerClus * BytesPerSect ) + ( FatElementSize * NumFATs );
+ FatSz = Numerator / Denominator;
+
+ /* round up */
+ FatSz += 1;
+
+ return((uint32_t)FatSz);
+}
+
+static uint8_t get_spc(uint32_t ClusterSizeKB, uint32_t BytesPerSect)
+{
+ uint32_t spc = ( ClusterSizeKB * 1024 ) / BytesPerSect;
+ return( (uint8_t) spc );
+}
+
+static uint8_t get_sectors_per_cluster(uint32_t DiskSizeSectors,
+ uint32_t BytesPerSect)
+{
+ uint8_t ret = 0x01; /* 1 sector per cluster */
+ uint64_t DiskSizeBytes = (uint64_t)DiskSizeSectors * (uint64_t)BytesPerSect;
+ int64_t DiskSizeMB = DiskSizeBytes / ( 1024*1024 );
+
+ /* 512 MB to 8,191 MB 4 KB */
+ if ( DiskSizeMB > 512 )
+ ret = get_spc( 4, BytesPerSect ); /* ret = 0x8; */
+
+ /* 8,192 MB to 16,383 MB 8 KB */
+ if ( DiskSizeMB > 8192 )
+ ret = get_spc( 8, BytesPerSect ); /* ret = 0x10; */
+
+ /* 16,384 MB to 32,767 MB 16 KB */
+ if ( DiskSizeMB > 16384 )
+ ret = get_spc( 16, BytesPerSect ); /* ret = 0x20; */
+
+ /* Larger than 32,768 MB 32 KB */
+ if ( DiskSizeMB > 32768 )
+ ret = get_spc( 32, BytesPerSect ); /* ret = 0x40; */
+
+ return( ret );
+
+}
+
+static void create_boot_sector(unsigned char* buf,
+ struct ipod_t* ipod, int partition)
+{
+ struct FAT_BOOTSECTOR32* pFAT32BootSect = (struct FAT_BOOTSECTOR32*)buf;
+
+ /* fill out the boot sector and fs info */
+ pFAT32BootSect->sJmpBoot[0]=0xEB;
+ pFAT32BootSect->sJmpBoot[1]=0x5A;
+ pFAT32BootSect->sJmpBoot[2]=0x90;
+ memcpy(pFAT32BootSect->sOEMName, "MSWIN4.1", 8 );
+ pFAT32BootSect->wBytsPerSec = rb_htole16(BytesPerSect);
+ pFAT32BootSect->bSecPerClus = SectorsPerCluster ;
+ pFAT32BootSect->wRsvdSecCnt = rb_htole16(ReservedSectCount);
+ pFAT32BootSect->bNumFATs = NumFATs;
+ pFAT32BootSect->wRootEntCnt = rb_htole16(0);
+ pFAT32BootSect->wTotSec16 = rb_htole16(0);
+ pFAT32BootSect->bMedia = 0xF8;
+ pFAT32BootSect->wFATSz16 = rb_htole16(0);
+ pFAT32BootSect->wSecPerTrk = rb_htole16(ipod->sectors_per_track);
+ pFAT32BootSect->wNumHeads = rb_htole16(ipod->num_heads);
+ pFAT32BootSect->dHiddSec = rb_htole16(ipod->pinfo[partition].start);
+ pFAT32BootSect->dTotSec32 = rb_htole32(TotalSectors);
+ pFAT32BootSect->dFATSz32 = rb_htole32(FatSize);
+ pFAT32BootSect->wExtFlags = rb_htole16(0);
+ pFAT32BootSect->wFSVer = rb_htole16(0);
+ pFAT32BootSect->dRootClus = rb_htole32(2);
+ pFAT32BootSect->wFSInfo = rb_htole16(1);
+ pFAT32BootSect->wBkBootSec = rb_htole16(BackupBootSect);
+ pFAT32BootSect->bDrvNum = 0x80;
+ pFAT32BootSect->Reserved1 = 0;
+ pFAT32BootSect->bBootSig = 0x29;
+ pFAT32BootSect->dBS_VolID = rb_htole32(VolumeId);
+ memcpy(pFAT32BootSect->sVolLab, VolId, 11);
+ memcpy(pFAT32BootSect->sBS_FilSysType, "FAT32 ", 8 );
+
+ buf[510] = 0x55;
+ buf[511] = 0xaa;
+}
+
+static void create_fsinfo(unsigned char* buf)
+{
+ struct FAT_FSINFO* pFAT32FsInfo = (struct FAT_FSINFO*)buf;
+
+ /* FSInfo sect */
+ pFAT32FsInfo->dLeadSig = rb_htole32(0x41615252);
+ pFAT32FsInfo->dStrucSig = rb_htole32(0x61417272);
+ pFAT32FsInfo->dFree_Count = rb_htole32((uint32_t) -1);
+ pFAT32FsInfo->dNxt_Free = rb_htole32((uint32_t) -1);
+ pFAT32FsInfo->dTrailSig = rb_htole32(0xaa550000);
+ pFAT32FsInfo->dFree_Count = rb_htole32((UserAreaSize/SectorsPerCluster)-1);
+
+ /* clusters 0-1 reserved, we used cluster 2 for the root dir */
+ pFAT32FsInfo->dNxt_Free = rb_htole32(3);
+}
+
+static void create_firstfatsector(unsigned char* buf)
+{
+ uint32_t* p = (uint32_t*)buf; /* We know the buffer is aligned */
+
+ /* First FAT Sector */
+ p[0] = rb_htole32(0x0ffffff8); /* Reserved cluster 1 media id in low byte */
+ p[1] = rb_htole32(0x0fffffff); /* Reserved cluster 2 EOC */
+ p[2] = rb_htole32(0x0fffffff); /* end of cluster chain for root dir */
+}
+
+int format_partition(struct ipod_t* ipod, int partition)
+{
+ uint32_t i;
+ uint64_t qTotalSectors=0;
+ uint64_t FatNeeded;
+
+ VolumeId = get_volume_id( );
+
+ /* Only support hard disks at the moment */
+ if ( ipod->sector_size != 512 )
+ {
+ fprintf(stderr,"[ERR] Only disks with 512 bytes per sector are supported.\n");
+ return -1;
+ }
+ BytesPerSect = ipod->sector_size;
+
+ /* Checks on Disk Size */
+ qTotalSectors = ipod->pinfo[partition].size;
+
+ /* low end limit - 65536 sectors */
+ if ( qTotalSectors < 65536 )
+ {
+ /* I suspect that most FAT32 implementations would mount this
+ volume just fine, but the spec says that we shouldn't do
+ this, so we won't */
+
+ fprintf(stderr,"[ERR] This drive is too small for FAT32 - there must be at least 64K clusters\n" );
+ return -1;
+ }
+
+ if ( qTotalSectors >= 0xffffffff )
+ {
+ /* This is a more fundamental limitation on FAT32 - the total
+ sector count in the root dir is 32bit. With a bit of
+ creativity, FAT32 could be extended to handle at least 2^28
+ clusters There would need to be an extra field in the
+ FSInfo sector, and the old sector count could be set to
+ 0xffffffff. This is non standard though, the Windows FAT
+ driver FASTFAT.SYS won't understand this. Perhaps a future
+ version of FAT32 and FASTFAT will handle this. */
+
+ fprintf(stderr,"[ERR] This drive is too big for FAT32 - max 2TB supported\n");
+ }
+
+ if ( sectors_per_cluster ) {
+ SectorsPerCluster = sectors_per_cluster;
+ } else {
+ SectorsPerCluster = get_sectors_per_cluster(ipod->pinfo[partition].size,
+ BytesPerSect );
+ }
+
+ TotalSectors = (uint32_t) qTotalSectors;
+
+ FatSize = get_fat_size_sectors(TotalSectors, ReservedSectCount,
+ SectorsPerCluster, NumFATs, BytesPerSect );
+
+ UserAreaSize = TotalSectors - ReservedSectCount - (NumFATs*FatSize);
+
+ /* First zero out ReservedSect + FatSize * NumFats + SectorsPerCluster */
+ SystemAreaSize = (ReservedSectCount+(NumFATs*FatSize) + SectorsPerCluster);
+
+ /* Work out the Cluster count */
+ FatNeeded = UserAreaSize/SectorsPerCluster;
+
+ /* check for a cluster count of >2^28, since the upper 4 bits of
+ the cluster values in the FAT are reserved. */
+ if (FatNeeded > 0x0FFFFFFF) {
+ fprintf(stderr,"[ERR] This drive has more than 2^28 clusters, try to specify a larger cluster size\n" );
+ return -1;
+ }
+
+ /* Sanity check, make sure the fat is big enough.
+ Convert the cluster count into a Fat sector count, and check
+ the fat size value we calculated earlier is OK. */
+
+ FatNeeded *=4;
+ FatNeeded += (BytesPerSect-1);
+ FatNeeded /= BytesPerSect;
+
+ if ( FatNeeded > FatSize ) {
+ fprintf(stderr,"[ERR] Drive too big to format\n");
+ return -1;
+ }
+
+ /*
+ Write boot sector, fats
+ Sector 0 Boot Sector
+ Sector 1 FSInfo
+ Sector 2 More boot code - we write zeros here
+ Sector 3 unused
+ Sector 4 unused
+ Sector 5 unused
+ Sector 6 Backup boot sector
+ Sector 7 Backup FSInfo sector
+ Sector 8 Backup 'more boot code'
+ zero'd sectors upto ReservedSectCount
+ FAT1 ReservedSectCount to ReservedSectCount + FatSize
+ ...
+ FATn ReservedSectCount to ReservedSectCount + FatSize
+ RootDir - allocated to cluster2
+ */
+
+ fprintf(stderr,"[INFO] Heads - %d, sectors/track = %d\n",ipod->num_heads,ipod->sectors_per_track);
+ fprintf(stderr,"[INFO] Size : %" PRIu64 "GB %u sectors\n",
+ ((uint64_t)ipod->pinfo[partition].size * (uint64_t)ipod->sector_size) / (1000*1000*1000), TotalSectors );
+ fprintf(stderr,"[INFO] %d Bytes Per Sector, Cluster size %d bytes\n", BytesPerSect, SectorsPerCluster*BytesPerSect );
+ fprintf(stderr,"[INFO] Volume ID is %x:%x\n", VolumeId>>16, VolumeId&0xffff );
+ fprintf(stderr,"[INFO] %d Reserved Sectors, %d Sectors per FAT, %d fats\n", ReservedSectCount, FatSize, NumFATs );
+ fprintf (stderr,"[INFO] %d Total clusters\n", UserAreaSize/SectorsPerCluster );
+
+ fprintf(stderr,"[INFO] Formatting partition %d:...\n",partition);
+
+ /* Once zero_sectors has run, any data on the drive is basically lost... */
+ fprintf(stderr,"[INFO] Clearing out %d sectors for Reserved sectors, fats and root cluster...\n", SystemAreaSize );
+
+ zero_sectors(ipod, ipod->pinfo[partition].start, SystemAreaSize);
+
+ fprintf(stderr,"[INFO] Initialising reserved sectors and FATs...\n" );
+
+ /* Create the boot sector structure */
+ create_boot_sector(ipod->sectorbuf, ipod, partition);
+ create_fsinfo(ipod->sectorbuf + 512);
+
+ /* Write boot sector and fsinfo at start of partition */
+ if (ipod_seek(ipod, ipod->pinfo[partition].start * ipod->sector_size) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+ if (ipod_write(ipod,512 * 2) < 0) {
+ perror("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
+ return -1;
+ }
+
+ /* Write backup copy of boot sector and fsinfo */
+ if (ipod_seek(ipod, (ipod->pinfo[partition].start + BackupBootSect) * ipod->sector_size) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+ if (ipod_write(ipod,512 * 2) < 0) {
+ perror("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
+ return -1;
+ }
+
+ /* Create the first FAT sector */
+ create_firstfatsector(ipod->sectorbuf);
+
+ /* Write the first fat sector in the right places */
+ for ( i=0; i<NumFATs; i++ ) {
+ int SectorStart = ReservedSectCount + (i * FatSize );
+
+ if (ipod_seek(ipod, (ipod->pinfo[partition].start + SectorStart) * ipod->sector_size) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ if (ipod_write(ipod,512) < 0) {
+ perror("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
+ return -1;
+ }
+ }
+
+ fprintf(stderr,"[INFO] Format successful\n");
+
+ return 0;
+}
diff --git a/utils/ipodpatcher/ipodio-posix.c b/utils/ipodpatcher/ipodio-posix.c
new file mode 100644
index 0000000000..dc856a2e0d
--- /dev/null
+++ b/utils/ipodpatcher/ipodio-posix.c
@@ -0,0 +1,410 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006-2007 Dave Chapman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#if !defined(_WIN32) /* all non-Windows platforms are considered POSIX. */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "ipodio.h"
+
+#if defined(linux) || defined (__linux)
+#include <sys/mount.h>
+#include <linux/hdreg.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/sg.h>
+
+#define IPOD_SECTORSIZE_IOCTL BLKSSZGET
+
+static void get_geometry(struct ipod_t* ipod)
+{
+ struct hd_geometry geometry;
+
+ if (!ioctl(ipod->dh, HDIO_GETGEO, &geometry)) {
+ /* never use geometry.cylinders - it is truncated */
+ ipod->num_heads = geometry.heads;
+ ipod->sectors_per_track = geometry.sectors;
+ } else {
+ ipod->num_heads = 0;
+ ipod->sectors_per_track = 0;
+ }
+}
+
+/* Linux SCSI Inquiry code based on the documentation and example code from
+ http://www.ibm.com/developerworks/linux/library/l-scsi-api/index.html
+*/
+
+int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
+ unsigned char* buf, int bufsize)
+{
+ unsigned char cdb[6];
+ struct sg_io_hdr hdr;
+ unsigned char sense_buffer[255];
+
+ memset(&hdr, 0, sizeof(hdr));
+
+ hdr.interface_id = 'S'; /* this is the only choice we have! */
+ hdr.flags = SG_FLAG_LUN_INHIBIT; /* this would put the LUN to 2nd byte of cdb*/
+
+ /* Set xfer data */
+ hdr.dxferp = buf;
+ hdr.dxfer_len = bufsize;
+
+ /* Set sense data */
+ hdr.sbp = sense_buffer;
+ hdr.mx_sb_len = sizeof(sense_buffer);
+
+ /* Set the cdb format */
+ cdb[0] = 0x12;
+ cdb[1] = 1; /* Enable Vital Product Data (EVPD) */
+ cdb[2] = page_code & 0xff;
+ cdb[3] = 0;
+ cdb[4] = 0xff;
+ cdb[5] = 0; /* For control filed, just use 0 */
+
+ hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ hdr.cmdp = cdb;
+ hdr.cmd_len = 6;
+
+ int ret = ioctl(ipod->dh, SG_IO, &hdr);
+
+ if (ret < 0) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
+ || defined(__bsdi__) || defined(__DragonFly__)
+#include <sys/disk.h>
+#define IPOD_SECTORSIZE_IOCTL DIOCGSECTORSIZE
+
+/* TODO: Implement this function for BSD */
+static void get_geometry(struct ipod_t* ipod)
+{
+ /* Are these universal for all ipods? */
+ ipod->num_heads = 255;
+ ipod->sectors_per_track = 63;
+}
+
+int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
+ unsigned char* buf, int bufsize)
+{
+ /* TODO: Implement for BSD */
+ (void)ipod;
+ (void)page_code;
+ (void)buf;
+ (void)bufsize;
+ return -1;
+}
+
+#elif defined(__APPLE__) && defined(__MACH__)
+/* OS X IOKit includes don't like VERSION being defined! */
+#undef VERSION
+#include <sys/disk.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/scsi/SCSITaskLib.h>
+#include <IOKit/scsi/SCSICommandOperationCodes.h>
+#define IPOD_SECTORSIZE_IOCTL DKIOCGETBLOCKSIZE
+
+/* TODO: Implement this function for Mac OS X */
+static void get_geometry(struct ipod_t* ipod)
+{
+ /* Are these universal for all ipods? */
+ ipod->num_heads = 255;
+ ipod->sectors_per_track = 63;
+}
+
+int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
+ unsigned char* buf, int bufsize)
+{
+ /* OS X doesn't allow to simply send out a SCSI inquiry request but
+ * requires registering an interface handler first.
+ * Currently this is done on each inquiry request which is somewhat
+ * inefficient but the current ipodpatcher API doesn't really fit here.
+ * Based on the documentation in Apple's document
+ * "SCSI Architecture Model Device Interface Guide".
+ *
+ * WARNING: this code currently doesn't take the selected device into
+ * account. It simply looks for an Ipod on the system and uses
+ * the first match.
+ */
+ (void)ipod;
+ int result = 0;
+ /* first, create a dictionary to match the device. This is needed to get the
+ * service. */
+ CFMutableDictionaryRef match_dict;
+ match_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL);
+ if(match_dict == NULL)
+ return -1;
+
+ /* set value to match. In case of the Ipod this is "iPodUserClientDevice". */
+ CFMutableDictionaryRef sub_dict;
+ sub_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL);
+ if(sub_dict == NULL)
+ return -1;
+ CFDictionarySetValue(sub_dict, CFSTR(kIOPropertySCSITaskDeviceCategory),
+ CFSTR("iPodUserClientDevice"));
+ CFDictionarySetValue(match_dict, CFSTR(kIOPropertyMatchKey), sub_dict);
+
+ /* get an iterator for searching for the service. */
+ kern_return_t kr;
+ io_iterator_t iterator = IO_OBJECT_NULL;
+ /* get matching services from IO registry. Consumes one reference to
+ * the dictionary, so no need to release that. */
+ kr = IOServiceGetMatchingServices(kIOMasterPortDefault, match_dict, &iterator);
+
+ if(!iterator | (kr != kIOReturnSuccess))
+ return -1;
+
+ /* get interface and obtain exclusive access */
+ SInt32 score;
+ HRESULT herr;
+ kern_return_t err;
+ IOCFPlugInInterface **plugin_interface = NULL;
+ SCSITaskDeviceInterface **interface = NULL;
+ io_service_t device = IO_OBJECT_NULL;
+ device = IOIteratorNext(iterator);
+
+ err = IOCreatePlugInInterfaceForService(device, kIOSCSITaskDeviceUserClientTypeID,
+ kIOCFPlugInInterfaceID, &plugin_interface,
+ &score);
+
+ if(err != noErr) {
+ return -1;
+ }
+ /* query the plugin interface for task interface */
+ herr = (*plugin_interface)->QueryInterface(plugin_interface,
+ CFUUIDGetUUIDBytes(kIOSCSITaskDeviceInterfaceID), (LPVOID*)&interface);
+ if(herr != S_OK) {
+ IODestroyPlugInInterface(plugin_interface);
+ return -1;
+ }
+
+ err = (*interface)->ObtainExclusiveAccess(interface);
+ if(err != noErr) {
+ (*interface)->Release(interface);
+ IODestroyPlugInInterface(plugin_interface);
+ return -1;
+ }
+
+ /* do the inquiry */
+ SCSITaskInterface **task = NULL;
+
+ task = (*interface)->CreateSCSITask(interface);
+ if(task != NULL) {
+ kern_return_t err;
+ SCSITaskStatus task_status;
+ IOVirtualRange* range;
+ SCSI_Sense_Data sense_data;
+ SCSICommandDescriptorBlock cdb;
+ UInt64 transfer_count = 0;
+ memset(buf, 0, bufsize);
+ /* allocate virtual range for buffer. */
+ range = (IOVirtualRange*) malloc(sizeof(IOVirtualRange));
+ memset(&sense_data, 0, sizeof(sense_data));
+ memset(cdb, 0, sizeof(cdb));
+ /* set up range. address is buffer address, length is request size. */
+ range->address = (IOVirtualAddress)buf;
+ range->length = bufsize;
+ /* setup CDB */
+ cdb[0] = 0x12; /* inquiry */
+ cdb[1] = 1;
+ cdb[2] = page_code;
+ cdb[4] = bufsize;
+
+ /* set cdb in task */
+ err = (*task)->SetCommandDescriptorBlock(task, cdb, kSCSICDBSize_6Byte);
+ if(err != kIOReturnSuccess) {
+ result = -1;
+ goto cleanup;
+ }
+ err = (*task)->SetScatterGatherEntries(task, range, 1, bufsize,
+ kSCSIDataTransfer_FromTargetToInitiator);
+ if(err != kIOReturnSuccess) {
+ result = -1;
+ goto cleanup;
+ }
+ /* set timeout */
+ err = (*task)->SetTimeoutDuration(task, 10000);
+ if(err != kIOReturnSuccess) {
+ result = -1;
+ goto cleanup;
+ }
+
+ /* request data */
+ err = (*task)->ExecuteTaskSync(task, &sense_data, &task_status, &transfer_count);
+ if(err != kIOReturnSuccess) {
+ result = -1;
+ goto cleanup;
+ }
+ /* cleanup */
+ free(range);
+
+ /* release task interface */
+ (*task)->Release(task);
+ }
+ else {
+ result = -1;
+ }
+cleanup:
+ /* cleanup interface */
+ (*interface)->ReleaseExclusiveAccess(interface);
+ (*interface)->Release(interface);
+ IODestroyPlugInInterface(plugin_interface);
+
+ return result;
+}
+
+#else
+ #error No sector-size detection implemented for this platform
+#endif
+
+#if defined(__APPLE__) && defined(__MACH__)
+static int ipod_unmount(struct ipod_t* ipod)
+{
+ char cmd[4096];
+ int res;
+
+ sprintf(cmd, "/usr/sbin/diskutil unmount \"%ss2\"",ipod->diskname);
+ fprintf(stderr,"[INFO] ");
+ res = system(cmd);
+
+ if (res==0) {
+ return 0;
+ } else {
+ perror("Unmount failed");
+ return -1;
+ }
+}
+#endif
+
+void ipod_print_error(char* msg)
+{
+ perror(msg);
+}
+
+int ipod_open(struct ipod_t* ipod, int silent)
+{
+ ipod->dh=open(ipod->diskname,O_RDONLY);
+ if (ipod->dh < 0) {
+ if (!silent) perror(ipod->diskname);
+ if(errno == EACCES) return -2;
+ else return -1;
+ }
+
+ /* Read information about the disk */
+
+ if(ioctl(ipod->dh,IPOD_SECTORSIZE_IOCTL,&ipod->sector_size) < 0) {
+ ipod->sector_size=512;
+ if (!silent) {
+ fprintf(stderr,"[ERR] ioctl() call to get sector size failed, defaulting to %d\n"
+ ,ipod->sector_size);
+ }
+ }
+
+ get_geometry(ipod);
+
+ return 0;
+}
+
+
+int ipod_reopen_rw(struct ipod_t* ipod)
+{
+#if defined(__APPLE__) && defined(__MACH__)
+ if (ipod_unmount(ipod) < 0)
+ return -1;
+#endif
+
+ close(ipod->dh);
+ ipod->dh=open(ipod->diskname,O_RDWR);
+ if (ipod->dh < 0) {
+ perror(ipod->diskname);
+ return -1;
+ }
+ return 0;
+}
+
+int ipod_close(struct ipod_t* ipod)
+{
+ close(ipod->dh);
+ ipod->dh = -1;
+ return 0;
+}
+
+int ipod_alloc_buffer(struct ipod_t* ipod, int bufsize)
+{
+ ipod->sectorbuf = malloc(bufsize);
+ if (ipod->sectorbuf== NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+int ipod_dealloc_buffer(struct ipod_t* ipod)
+{
+ if (ipod->sectorbuf == NULL) {
+ return -1;
+ }
+ free(ipod->sectorbuf);
+ ipod->sectorbuf = NULL;
+ return 0;
+}
+
+int ipod_seek(struct ipod_t* ipod, unsigned long pos)
+{
+ off_t res;
+
+ res = lseek(ipod->dh, pos, SEEK_SET);
+
+ if (res == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+ssize_t ipod_read(struct ipod_t* ipod, int nbytes)
+{
+ if(ipod->sectorbuf == NULL) {
+ return -1;
+ }
+ return read(ipod->dh, ipod->sectorbuf, nbytes);
+}
+
+ssize_t ipod_write(struct ipod_t* ipod, int nbytes)
+{
+ if(ipod->sectorbuf == NULL) {
+ return -1;
+ }
+ return write(ipod->dh, ipod->sectorbuf, nbytes);
+}
+
+#endif
+
diff --git a/utils/ipodpatcher/ipodio-win32-scsi.c b/utils/ipodpatcher/ipodio-win32-scsi.c
new file mode 100644
index 0000000000..16460cfba3
--- /dev/null
+++ b/utils/ipodpatcher/ipodio-win32-scsi.c
@@ -0,0 +1,147 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2009 Dave Chapman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ *
+ * Based on the getCapsUsingSCSIPassThrough() function from "cddrv.cpp":
+ * - http://www.farmanager.com/svn/trunk/unicode_far/cddrv.cpp
+ *
+ * Copyright (c) 1996 Eugene Roshal
+ * Copyright (c) 2000 Far Group
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the authors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#if defined(_WIN32)
+#include <windows.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#include "ipodio.h"
+
+/* from ddk/ntddscsi.h */
+#define SCSI_IOCTL_DATA_OUT 0
+#define SCSI_IOCTL_DATA_IN 1
+#define SCSI_IOCTL_DATA_UNSPECIFIED 2
+
+#define IOCTL_SCSI_PASS_THROUGH \
+ CTL_CODE(FILE_DEVICE_CONTROLLER, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+typedef struct _SCSI_PASS_THROUGH {
+ USHORT Length;
+ UCHAR ScsiStatus;
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+ UCHAR CdbLength;
+ UCHAR SenseInfoLength;
+ UCHAR DataIn;
+ ULONG DataTransferLength;
+ ULONG TimeOutValue;
+ ULONG_PTR DataBufferOffset;
+ ULONG SenseInfoOffset;
+ UCHAR Cdb[16];
+} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
+
+typedef struct _SCSI_PASS_THROUGH_WITH_BUFFERS {
+ SCSI_PASS_THROUGH Spt;
+ ULONG Filler; /* realign buffers to double word boundary */
+ UCHAR SenseBuf[32];
+ UCHAR DataBuf[512];
+} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;
+
+int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
+ unsigned char* buf, int bufsize)
+{
+ SCSI_PASS_THROUGH_WITH_BUFFERS sptwb;
+ ULONG length;
+ DWORD returned;
+ BOOL status;
+
+ if (bufsize > 255) {
+ fprintf(stderr,"[ERR] Invalid bufsize in ipod_scsi_inquiry\n");
+ return -1;
+ }
+
+ memset(&sptwb, 0, sizeof(sptwb));
+
+ sptwb.Spt.Length = sizeof(SCSI_PASS_THROUGH);
+ sptwb.Spt.PathId = 0;
+ sptwb.Spt.TargetId = 1;
+ sptwb.Spt.Lun = 0;
+ sptwb.Spt.CdbLength = 6;
+ sptwb.Spt.SenseInfoLength = 32; /* sbuf size */;
+ sptwb.Spt.DataIn = SCSI_IOCTL_DATA_IN;
+ sptwb.Spt.DataTransferLength = bufsize;
+ sptwb.Spt.TimeOutValue = 2; /* 2 seconds */
+ sptwb.Spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuf);
+ sptwb.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, SenseBuf);
+ length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuf) +
+ sptwb.Spt.DataTransferLength;
+
+ /* Set cdb info */
+ sptwb.Spt.Cdb[0] = 0x12; /* SCSI Inquiry */
+ sptwb.Spt.Cdb[1] = 1;
+ sptwb.Spt.Cdb[2] = page_code;
+ sptwb.Spt.Cdb[3] = 0;
+ sptwb.Spt.Cdb[4] = bufsize;
+ sptwb.Spt.Cdb[5] = 0;
+
+ status = DeviceIoControl(ipod->dh,
+ IOCTL_SCSI_PASS_THROUGH,
+ &sptwb,
+ sizeof(SCSI_PASS_THROUGH),
+ &sptwb,
+ length,
+ &returned,
+ FALSE);
+
+ if (status) {
+ /* W32 sometimes returns more bytes with additional garbage.
+ * Make sure to not copy that garbage. */
+ memcpy(buf, sptwb.DataBuf,
+ (DWORD)bufsize >= returned ? returned : (DWORD)bufsize);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+#endif
+
diff --git a/utils/ipodpatcher/ipodio-win32.c b/utils/ipodpatcher/ipodio-win32.c
new file mode 100644
index 0000000000..2c52a64658
--- /dev/null
+++ b/utils/ipodpatcher/ipodio-win32.c
@@ -0,0 +1,227 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006-2007 Dave Chapman
+ *
+ * error(), lock_volume() and unlock_volume() functions and inspiration taken
+ * from:
+ * RawDisk - Direct Disk Read/Write Access for NT/2000/XP
+ * Copyright (c) 2003 Jan Kiszka
+ * http://www.stud.uni-hannover.de/user/73174/RawDisk/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#if defined(_WIN32)
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <windows.h>
+#include <stddef.h>
+#include <winioctl.h>
+
+#include "ipodio.h"
+
+static int lock_volume(HANDLE hDisk)
+{
+ DWORD dummy;
+
+ return DeviceIoControl(hDisk, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0,
+ &dummy, NULL);
+}
+
+static int unlock_volume(HANDLE hDisk)
+{
+ DWORD dummy;
+
+ return DeviceIoControl(hDisk, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0,
+ &dummy, NULL);
+}
+
+void ipod_print_error(char* msg)
+{
+ LPSTR pMsgBuf = NULL;
+
+ printf(msg);
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), pMsgBuf,
+ 0, NULL);
+ printf(pMsgBuf);
+ LocalFree(pMsgBuf);
+}
+
+int ipod_open(struct ipod_t* ipod, int silent)
+{
+ DISK_GEOMETRY_EX diskgeometry_ex;
+ DISK_GEOMETRY diskgeometry;
+ unsigned long n;
+
+ ipod->dh = CreateFileA(ipod->diskname, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL);
+
+ if (ipod->dh == INVALID_HANDLE_VALUE) {
+ if (!silent) ipod_print_error(" Error opening disk: ");
+ if(GetLastError() == ERROR_ACCESS_DENIED)
+ return -2;
+ else
+ return -1;
+ }
+
+ if (!lock_volume(ipod->dh)) {
+ if (!silent) ipod_print_error(" Error locking disk: ");
+ return -1;
+ }
+
+ /* Defaults */
+ ipod->num_heads = 0;
+ ipod->sectors_per_track = 0;
+
+ if (!DeviceIoControl(ipod->dh,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
+ NULL,
+ 0,
+ &diskgeometry_ex,
+ sizeof(diskgeometry_ex),
+ &n,
+ NULL)) {
+ if (!DeviceIoControl(ipod->dh,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL,
+ 0,
+ &diskgeometry,
+ sizeof(diskgeometry),
+ &n,
+ NULL)) {
+ if (!silent) ipod_print_error(" Error reading disk geometry: ");
+ return -1;
+ } else {
+ ipod->sector_size = diskgeometry.BytesPerSector;
+ ipod->num_heads = diskgeometry.TracksPerCylinder;
+ ipod->sectors_per_track = diskgeometry.SectorsPerTrack;
+ }
+ } else {
+ ipod->sector_size = diskgeometry_ex.Geometry.BytesPerSector;
+ ipod->num_heads = diskgeometry_ex.Geometry.TracksPerCylinder;
+ ipod->sectors_per_track = diskgeometry_ex.Geometry.SectorsPerTrack;
+ }
+
+ return 0;
+}
+
+int ipod_reopen_rw(struct ipod_t* ipod)
+{
+ /* Close existing file and re-open for writing */
+ unlock_volume(ipod->dh);
+ CloseHandle(ipod->dh);
+
+ ipod->dh = CreateFileA(ipod->diskname, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL);
+
+ if (ipod->dh == INVALID_HANDLE_VALUE) {
+ ipod_print_error(" Error opening disk: ");
+ return -1;
+ }
+
+ if (!lock_volume(ipod->dh)) {
+ ipod_print_error(" Error locking disk: ");
+ return -1;
+ }
+
+ return 0;
+}
+
+int ipod_close(struct ipod_t* ipod)
+{
+ unlock_volume(ipod->dh);
+ CloseHandle(ipod->dh);
+ ipod->dh = INVALID_HANDLE_VALUE;
+ return 0;
+}
+
+int ipod_alloc_buffer(struct ipod_t* ipod, int bufsize)
+{
+ /* The ReadFile function requires a memory buffer aligned to a multiple of
+ the disk sector size. */
+ ipod->sectorbuf = (unsigned char*)VirtualAlloc(NULL, bufsize, MEM_COMMIT, PAGE_READWRITE);
+ if (ipod->sectorbuf== NULL) {
+ ipod_print_error(" Error allocating a buffer: ");
+ return -1;
+ }
+ return 0;
+}
+
+int ipod_dealloc_buffer(struct ipod_t* ipod)
+{
+ if (ipod->sectorbuf == NULL) {
+ return -1;
+ }
+ if(!VirtualFree(ipod->sectorbuf, 0, MEM_RELEASE)) {
+ ipod_print_error(" Error releasing buffer ");
+ return -1;
+ }
+ ipod->sectorbuf = NULL;
+ return 0;
+}
+
+int ipod_seek(struct ipod_t* ipod, unsigned long pos)
+{
+ if (SetFilePointer(ipod->dh, pos, NULL, FILE_BEGIN)==0xffffffff) {
+ ipod_print_error(" Seek error ");
+ return -1;
+ }
+ return 0;
+}
+
+ssize_t ipod_read(struct ipod_t* ipod, int nbytes)
+{
+ unsigned long count;
+
+ if(ipod->sectorbuf == NULL) {
+ return -1;
+ }
+ if (!ReadFile(ipod->dh, ipod->sectorbuf, nbytes, &count, NULL)) {
+ ipod_print_error(" Error reading from disk: ");
+ return -1;
+ }
+
+ return count;
+}
+
+ssize_t ipod_write(struct ipod_t* ipod, int nbytes)
+{
+ unsigned long count;
+
+ if(ipod->sectorbuf == NULL) {
+ return -1;
+ }
+ if (!WriteFile(ipod->dh, ipod->sectorbuf, nbytes, &count, NULL)) {
+ ipod_print_error(" Error writing to disk: ");
+ return -1;
+ }
+
+ return count;
+}
+
+#endif
+
diff --git a/utils/ipodpatcher/ipodio.h b/utils/ipodpatcher/ipodio.h
new file mode 100644
index 0000000000..4f1a35dd09
--- /dev/null
+++ b/utils/ipodpatcher/ipodio.h
@@ -0,0 +1,115 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006-2007 Dave Chapman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef __IPODIO_H
+#define __IPODIO_H
+
+#include <stdint.h>
+#if !defined(_WIN32)
+#include <unistd.h>
+#elif defined(_MSC_VER)
+/* MSVC uses a different name for ssize_t */
+#define ssize_t SSIZE_T
+#endif
+
+#if defined(__WIN32__) || defined(_WIN32)
+#include <windows.h>
+#else
+#define HANDLE int
+#define O_BINARY 0
+#endif
+
+/* The maximum number of images in a firmware partition - a guess... */
+#define MAX_IMAGES 10
+
+enum firmwaretype_t {
+ FTYPE_OSOS = 0,
+ FTYPE_RSRC,
+ FTYPE_AUPD,
+ FTYPE_HIBE,
+ FTYPE_OSBK
+};
+
+struct ipod_directory_t {
+ enum firmwaretype_t ftype;
+ int id;
+ uint32_t devOffset; /* Offset of image relative to one sector into bootpart*/
+ uint32_t len;
+ uint32_t addr;
+ uint32_t entryOffset;
+ uint32_t chksum;
+ uint32_t vers;
+ uint32_t loadAddr;
+};
+
+/* A fake partition type - DOS partition tables can't include HFS partitions */
+#define PARTTYPE_HFS 0xffff
+
+struct partinfo_t {
+ uint32_t start; /* first sector (LBA) */
+ uint32_t size; /* number of sectors */
+ uint32_t type;
+};
+
+struct ipod_t {
+ unsigned char* sectorbuf;
+ HANDLE dh;
+ char diskname[4096];
+ int sector_size;
+ int sectors_per_track;
+ int num_heads;
+ struct ipod_directory_t ipod_directory[MAX_IMAGES];
+ int nimages;
+ int ososimage;
+ off_t diroffset;
+ off_t start; /* Offset in bytes of firmware partition from start of disk */
+ off_t fwoffset; /* Offset in bytes of start of firmware images from start of disk */
+ struct partinfo_t pinfo[4];
+ int modelnum;
+ char* modelname;
+ char* modelstr;
+ char* targetname;
+ int macpod;
+ char* xmlinfo; /* The XML Device Information (if available) */
+ int xmlinfo_len;
+ int ramsize; /* The amount of RAM in the ipod (if available) */
+#ifdef WITH_BOOTOBJS
+ unsigned char* bootloader;
+ int bootloader_len;
+#endif
+};
+
+void ipod_print_error(char* msg);
+int ipod_open(struct ipod_t* ipod, int silent);
+int ipod_reopen_rw(struct ipod_t* ipod);
+int ipod_close(struct ipod_t* ipod);
+int ipod_seek(struct ipod_t* ipod, unsigned long pos);
+int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
+ unsigned char* buf, int bufsize);
+ssize_t ipod_read(struct ipod_t* ipod, int nbytes);
+ssize_t ipod_write(struct ipod_t* ipod, int nbytes);
+int ipod_alloc_buffer(struct ipod_t* ipod, int bufsize);
+int ipod_dealloc_buffer(struct ipod_t* ipod);
+
+/* In fat32format.c */
+int format_partition(struct ipod_t* ipod, int partition);
+
+#endif
diff --git a/utils/ipodpatcher/ipodpatcher-aupd.c b/utils/ipodpatcher/ipodpatcher-aupd.c
new file mode 100644
index 0000000000..69b027284c
--- /dev/null
+++ b/utils/ipodpatcher/ipodpatcher-aupd.c
@@ -0,0 +1,398 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006-2007 Dave Chapman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "ipodpatcher.h"
+
+#include "arc4.h"
+
+static inline int le2int(unsigned char* buf)
+{
+ int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+
+ return res;
+}
+
+static inline void int2le(unsigned int val, unsigned char* addr)
+{
+ addr[0] = val & 0xFF;
+ addr[1] = (val >> 8) & 0xff;
+ addr[2] = (val >> 16) & 0xff;
+ addr[3] = (val >> 24) & 0xff;
+}
+
+static inline uint32_t getuint32le(unsigned char* buf)
+{
+ int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+
+ return res;
+}
+
+/* testMarker and GetSecurityBlockKey based on code from BadBlocks and
+ Kingstone, posted at http://ipodlinux.org/Flash_Decryption
+
+*/
+
+static bool testMarker(int marker)
+{
+ int mask, decrypt, temp1, temp2;
+
+ mask = (marker&0xff)|((marker&0xff)<<8)|((marker&0xff)<<16)|((marker&0xff)<<24);
+ decrypt = marker ^ mask;
+ temp1=(int)((unsigned int)decrypt>>24);
+ temp2=decrypt<<8;
+
+ if (temp1==0)
+ return false;
+
+ temp2=(int)((unsigned int)temp2>>24);
+ decrypt=decrypt<<16;
+ decrypt=(int)((unsigned int)decrypt>>24);
+
+ if ((temp1 < temp2) && (temp2 < decrypt))
+ {
+ temp1 = temp1 & 0xf;
+ temp2 = temp2 & 0xf;
+ decrypt = decrypt & 0xf;
+
+ if ((temp1 > temp2) && (temp2 > decrypt) && (decrypt != 0))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+static int GetSecurityBlockKey(unsigned char *data, unsigned char* this_key)
+{
+ int constant = 0x54c3a298;
+ int key=0;
+ int nkeys = 0;
+ int aMarker=0;
+ int pos=0;
+ int c, count;
+ int temp1;
+ static const int offset[8]={0x5,0x25,0x6f,0x69,0x15,0x4d,0x40,0x34};
+
+ for (c = 0; c < 8; c++)
+ {
+ pos = offset[c]*4;
+ aMarker = getuint32le(data + pos);
+
+ if (testMarker(aMarker))
+ {
+ if (c<7)
+ pos =(offset[c+1]*4)+4;
+ else
+ pos =(offset[0]*4)+4;
+
+ key=0;
+
+ temp1=aMarker;
+
+ for (count=0;count<2;count++){
+ int word = getuint32le(data + pos);
+ temp1 = aMarker;
+ temp1 = temp1^word;
+ temp1 = temp1^constant;
+ key = temp1;
+ pos = pos+4;
+ }
+ int r1=0x6f;
+ int r2=0;
+ int r12;
+ int r14;
+ unsigned int r_tmp;
+
+ for (count=2;count<128;count=count+2){
+ r2=getuint32le(data+count*4);
+ r12=getuint32le(data+(count*4)+4);
+ r_tmp=(unsigned int)r12>>16;
+ r14=r2 | ((int)r_tmp);
+ r2=r2&0xffff;
+ r2=r2 | r12;
+ r1=r1^r14;
+ r1=r1+r2;
+ }
+ key=key^r1;
+
+ // Invert key, little endian
+ this_key[0] = key & 0xff;
+ this_key[1] = (key >> 8) & 0xff;
+ this_key[2] = (key >> 16) & 0xff;
+ this_key[3] = (key >> 24) & 0xff;
+ nkeys++;
+ }
+ }
+ return nkeys;
+}
+
+static int find_key(struct ipod_t* ipod, int aupd, unsigned char* key)
+{
+ int n;
+
+ /* Firstly read the security block and find the RC4 key. This is
+ in the sector preceeding the AUPD image. */
+
+ if(ipod->sectorbuf == NULL) {
+ fprintf(stderr,"[ERR] Buffer not initialized.");
+ return -1;
+ }
+ fprintf(stderr, "[INFO] Reading security block at offset 0x%08x\n",ipod->ipod_directory[aupd].devOffset-ipod->sector_size);
+ if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset-ipod->sector_size) < 0) {
+ return -1;
+ }
+
+ if ((n = ipod_read(ipod, 512)) < 0) {
+ return -1;
+ }
+
+ n = GetSecurityBlockKey(ipod->sectorbuf, key);
+
+ if (n != 1)
+ {
+ fprintf(stderr, "[ERR] %d keys found in security block, can not continue\n",n);
+ return -1;
+ }
+
+ return 0;
+}
+
+int read_aupd(struct ipod_t* ipod, char* filename)
+{
+ int length;
+ int i;
+ int outfile;
+ int n;
+ int aupd;
+ struct rc4_key_t rc4;
+ unsigned char key[4];
+ unsigned long chksum=0;
+
+ if(ipod->sectorbuf == NULL) {
+ fprintf(stderr,"[ERR] Buffer not initialized.");
+ return -1;
+ }
+ aupd = 0;
+ while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
+ {
+ aupd++;
+ }
+
+ if (aupd == ipod->nimages)
+ {
+ fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
+ return -1;
+ }
+
+ length = ipod->ipod_directory[aupd].len;
+
+ fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
+
+ if (find_key(ipod, aupd, key) < 0)
+ {
+ return -1;
+ }
+
+ fprintf(stderr, "[INFO] Decrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
+
+ if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
+ return -1;
+ }
+
+ i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
+
+ if ((n = ipod_read(ipod,i)) < 0) {
+ return -1;
+ }
+
+ if (n < i) {
+ fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
+ i,n);
+ return -1;
+ }
+
+ /* Perform the decryption - this is standard (A)RC4 */
+ matrixArc4Init(&rc4, key, 4);
+ matrixArc4(&rc4, ipod->sectorbuf, ipod->sectorbuf, length);
+
+ chksum = 0;
+ for (i = 0; i < (int)length; i++) {
+ /* add 8 unsigned bits but keep a 32 bit sum */
+ chksum += ipod->sectorbuf[i];
+ }
+
+ if (chksum != ipod->ipod_directory[aupd].chksum)
+ {
+ fprintf(stderr,"[ERR] Decryption failed - checksum error\n");
+ return -1;
+ }
+ fprintf(stderr,"[INFO] Decrypted OK (checksum matches header)\n");
+
+ outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
+ if (outfile < 0) {
+ fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
+ return -1;
+ }
+
+ n = write(outfile,ipod->sectorbuf,length);
+ if (n != length) {
+ fprintf(stderr,"[ERR] Write error - %d\n",n);
+ }
+ close(outfile);
+
+ return 0;
+}
+
+int write_aupd(struct ipod_t* ipod, char* filename)
+{
+ unsigned int length;
+ int i;
+ int x;
+ int n;
+ int infile;
+ int newsize;
+ int aupd;
+ unsigned long chksum=0;
+ struct rc4_key_t rc4;
+ unsigned char key[4];
+
+ if(ipod->sectorbuf == NULL) {
+ fprintf(stderr,"[ERR] Buffer not initialized.");
+ return -1;
+ }
+ /* First check that the input file is the correct type for this ipod. */
+ infile=open(filename,O_RDONLY);
+ if (infile < 0) {
+ fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
+ return -1;
+ }
+
+ length = filesize(infile);
+ newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
+
+ fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
+ length,newsize);
+
+ if (newsize > BUFFER_SIZE) {
+ fprintf(stderr,"[ERR] Input file too big for buffer\n");
+ if (infile >= 0) close(infile);
+ return -1;
+ }
+
+ /* Find aupd image number */
+ aupd = 0;
+ while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
+ {
+ aupd++;
+ }
+
+ if (aupd == ipod->nimages)
+ {
+ fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
+ return -1;
+ }
+
+ if (length != ipod->ipod_directory[aupd].len)
+ {
+ fprintf(stderr,"[ERR] AUPD image (%d bytes) differs in size to %s (%d bytes).\n",
+ ipod->ipod_directory[aupd].len, filename, length);
+ return -1;
+ }
+
+ if (find_key(ipod, aupd, key) < 0)
+ {
+ return -1;
+ }
+
+ fprintf(stderr, "[INFO] Encrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
+
+ /* We now know we have enough space, so write it. */
+
+ fprintf(stderr,"[INFO] Reading input file...\n");
+ n = read(infile,ipod->sectorbuf,length);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Couldn't read input file\n");
+ close(infile);
+ return -1;
+ }
+ close(infile);
+
+ /* Pad the data with zeros */
+ memset(ipod->sectorbuf+length,0,newsize-length);
+
+ /* Calculate the new checksum (before we encrypt) */
+ chksum = 0;
+ for (i = 0; i < (int)length; i++) {
+ /* add 8 unsigned bits but keep a 32 bit sum */
+ chksum += ipod->sectorbuf[i];
+ }
+
+ /* Perform the encryption - this is standard (A)RC4 */
+ matrixArc4Init(&rc4, key, 4);
+ matrixArc4(&rc4, ipod->sectorbuf, ipod->sectorbuf, length);
+
+ if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ if ((n = ipod_write(ipod,newsize)) < 0) {
+ perror("[ERR] Write failed\n");
+ return -1;
+ }
+
+ if (n < newsize) {
+ fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
+ ,newsize,n);
+ return -1;
+ }
+ fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
+
+ x = ipod->diroffset % ipod->sector_size;
+
+ /* Read directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
+
+ n=ipod_read(ipod, ipod->sector_size);
+ if (n < 0) { return -1; }
+
+ /* Update checksum */
+ fprintf(stderr,"[INFO] Updating checksum to 0x%08x (was 0x%08x)\n",(unsigned int)chksum,le2int(ipod->sectorbuf + x + aupd*40 + 28));
+ int2le(chksum,ipod->sectorbuf+x+aupd*40+28);
+
+ /* Write directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
+ n=ipod_write(ipod, ipod->sector_size);
+ if (n < 0) { return -1; }
+
+ return 0;
+}
+
diff --git a/utils/ipodpatcher/ipodpatcher.c b/utils/ipodpatcher/ipodpatcher.c
new file mode 100644
index 0000000000..e7c0cc3358
--- /dev/null
+++ b/utils/ipodpatcher/ipodpatcher.c
@@ -0,0 +1,1995 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006-2007 Dave Chapman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "parttypes.h"
+#include "ipodio.h"
+#include "ipodpatcher.h"
+
+#ifdef WITH_BOOTOBJS
+#include "ipod1g2g.h"
+#include "ipod3g.h"
+#include "ipod4g.h"
+#include "ipodmini1g.h"
+#include "ipodmini2g.h"
+#include "ipodcolor.h"
+#include "ipodnano1g.h"
+#include "ipodvideo.h"
+#include "ipodnano2g.h"
+#endif
+
+int ipod_verbose = 0;
+
+
+/* The following string appears at the start of the firmware partition */
+static const char apple_stop_sign[] = "{{~~ /-----\\ "\
+ "{{~~ / \\ "\
+ "{{~~| | "\
+ "{{~~| S T O P | "\
+ "{{~~| | "\
+ "{{~~ \\ / "\
+ "{{~~ \\-----/ "\
+ "Copyright(C) 200"\
+ "1 Apple Computer"\
+ ", Inc.----------"\
+ "----------------"\
+ "----------------"\
+ "----------------"\
+ "----------------"\
+ "----------------"\
+ "---------------";
+
+/* Windows requires the buffer for disk I/O to be aligned in memory on a
+ multiple of the disk volume size - so we use a single global variable
+ and initialise it with ipod_alloc_buf()
+*/
+
+char* get_parttype(unsigned int pt)
+{
+ int i;
+ static char unknown[]="Unknown";
+
+ if (pt == PARTTYPE_HFS) {
+ return "HFS/HFS+";
+ }
+
+ i=0;
+ while (parttypes[i].name != NULL) {
+ if (parttypes[i].type == pt) {
+ return (parttypes[i].name);
+ }
+ i++;
+ }
+
+ return unknown;
+}
+
+off_t filesize(int fd) {
+ struct stat buf;
+
+ if (fstat(fd,&buf) < 0) {
+ perror("[ERR] Checking filesize of input file");
+ return -1;
+ } else {
+ return(buf.st_size);
+ }
+}
+
+/* Partition table parsing code taken from Rockbox */
+
+#define MAX_SECTOR_SIZE 2048
+#define SECTOR_SIZE 512
+
+static inline unsigned short le2ushort(unsigned char* buf)
+{
+ unsigned short res = (buf[1] << 8) | buf[0];
+
+ return res;
+}
+
+static inline int le2int(unsigned char* buf)
+{
+ int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+
+ return res;
+}
+
+static inline int be2int(unsigned char* buf)
+{
+ int32_t res = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+
+ return res;
+}
+
+static inline int getint16le(char* buf)
+{
+ int16_t res = (buf[1] << 8) | buf[0];
+
+ return res;
+}
+
+static inline void short2le(unsigned short val, unsigned char* addr)
+{
+ addr[0] = val & 0xFF;
+ addr[1] = (val >> 8) & 0xff;
+}
+
+static inline void int2le(unsigned int val, unsigned char* addr)
+{
+ addr[0] = val & 0xFF;
+ addr[1] = (val >> 8) & 0xff;
+ addr[2] = (val >> 16) & 0xff;
+ addr[3] = (val >> 24) & 0xff;
+}
+
+static inline void int2be(unsigned int val, unsigned char* addr)
+{
+ addr[0] = (val >> 24) & 0xff;
+ addr[1] = (val >> 16) & 0xff;
+ addr[2] = (val >> 8) & 0xff;
+ addr[3] = val & 0xFF;
+}
+
+
+#define BYTES2INT32(array,pos)\
+ ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
+ ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
+
+int read_partinfo(struct ipod_t* ipod, int silent)
+{
+ int i;
+ unsigned long count;
+
+ if(ipod->sectorbuf == NULL) {
+ fprintf(stderr,"[ERR] Buffer not initialized.");
+ return -1;
+ }
+
+ count = ipod_read(ipod,ipod->sector_size);
+
+ if (count <= 0) {
+ ipod_print_error(" Error reading from disk: ");
+ return -1;
+ }
+
+ memset(ipod->pinfo, 0, sizeof(ipod->pinfo));
+
+ if ((ipod->sectorbuf[510] == 0x55) && (ipod->sectorbuf[511] == 0xaa)) {
+ /* DOS partition table */
+ ipod->macpod = 0;
+ /* parse partitions */
+ for ( i = 0; i < 4; i++ ) {
+ unsigned char* ptr = ipod->sectorbuf + 0x1be + 16*i;
+ ipod->pinfo[i].type = ptr[4];
+ ipod->pinfo[i].start = BYTES2INT32(ptr, 8);
+ ipod->pinfo[i].size = BYTES2INT32(ptr, 12);
+
+ /* extended? */
+ if ( ipod->pinfo[i].type == 5 ) {
+ /* not handled yet */
+ }
+ }
+ } else if ((ipod->sectorbuf[0] == 'E') && (ipod->sectorbuf[1] == 'R')) {
+ /* Apple Partition Map */
+
+ /* APM parsing code based on the check_mac_partitions() function in
+ ipodloader2 - written by Thomas Tempelmann and released
+ under the GPL. */
+
+ int blkNo = 1;
+ int partBlkCount = 1;
+ int partBlkSizMul = ipod->sectorbuf[2] / 2;
+
+ int pmMapBlkCnt; /* # of blks in partition map */
+ int pmPyPartStart; /* physical start blk of partition */
+ int pmPartBlkCnt; /* # of blks in this partition */
+ int i = 0;
+
+ ipod->macpod = 1;
+
+ memset(ipod->pinfo,0,sizeof(ipod->pinfo));
+
+ while (blkNo <= partBlkCount) {
+ if (ipod_seek(ipod, blkNo * partBlkSizMul * 512) < 0) {
+ fprintf(stderr,"[ERR] Seek failed whilst reading APM\n");
+ return -1;
+ }
+
+ count = ipod_read(ipod, ipod->sector_size);
+
+ if (count <= 0) {
+ ipod_print_error(" Error reading from disk: ");
+ return -1;
+ }
+
+ /* see if it's a partition entry */
+ if ((ipod->sectorbuf[0] != 'P') || (ipod->sectorbuf[1] != 'M')) {
+ /* end of partition table -> leave the loop */
+ break;
+ }
+
+ /* Extract the interesting entries */
+ pmMapBlkCnt = be2int(ipod->sectorbuf + 4);
+ pmPyPartStart = be2int(ipod->sectorbuf + 8);
+ pmPartBlkCnt = be2int(ipod->sectorbuf + 12);
+
+ /* update the number of part map blocks */
+ partBlkCount = pmMapBlkCnt;
+
+ if (strncmp((char*)(ipod->sectorbuf + 48), "Apple_MDFW", 32)==0) {
+ /* A Firmware partition */
+ ipod->pinfo[i].start = pmPyPartStart;
+ ipod->pinfo[i].size = pmPartBlkCnt;
+ ipod->pinfo[i].type = 0;
+ i++;
+ } else if (strncmp((char*)(ipod->sectorbuf + 48), "Apple_HFS", 32)==0) {
+ /* A HFS partition */
+ ipod->pinfo[i].start = pmPyPartStart;
+ ipod->pinfo[i].size = pmPartBlkCnt;
+ ipod->pinfo[i].type = PARTTYPE_HFS;
+ i++;
+ }
+
+ blkNo++; /* read next partition map entry */
+ }
+ } else {
+ if (!silent) fprintf(stderr,"[ERR] Bad boot sector signature\n");
+ return -1;
+ }
+
+ /* Check that the partition table looks like an ipod:
+ 1) Partition 1 is of type 0 (Empty) but isn't empty.
+ 2) Partition 2 is of type 0xb or 0xc (winpod) or -1 (macpod)
+ */
+ if ((ipod->pinfo[0].type != 0) || (ipod->pinfo[0].size == 0) ||
+ ((ipod->pinfo[1].type != 0xb) && (ipod->pinfo[1].type != 0xc) &&
+ (ipod->pinfo[1].type != PARTTYPE_HFS))) {
+ if (!silent) fprintf(stderr,"[ERR] Partition layout is not an ipod\n");
+ return -1;
+ }
+
+ ipod->start = ipod->pinfo[0].start*ipod->sector_size;
+ return 0;
+}
+
+int read_partition(struct ipod_t* ipod, int outfile)
+{
+ int res;
+ ssize_t n;
+ int bytesleft;
+ int chunksize;
+ int count = ipod->pinfo[0].size;
+
+ if (ipod_seek(ipod, ipod->start) < 0) {
+ return -1;
+ }
+ if(ipod->sectorbuf == NULL) {
+ fprintf(stderr,"[ERR] Buffer not initialized.");
+ return -1;
+ }
+
+ fprintf(stderr,"[INFO] Writing %d sectors to output file\n",count);
+
+ bytesleft = count * ipod->sector_size;
+ while (bytesleft > 0) {
+ if (bytesleft > BUFFER_SIZE) {
+ chunksize = BUFFER_SIZE;
+ } else {
+ chunksize = bytesleft;
+ }
+
+ n = ipod_read(ipod, chunksize);
+
+ if (n < 0) {
+ return -1;
+ }
+
+ if (n < chunksize) {
+ fprintf(stderr,
+ "[ERR] Short read in disk_read() - requested %d, got %d\n",
+ chunksize,(int)n);
+ return -1;
+ }
+
+ bytesleft -= n;
+
+ res = write(outfile,ipod->sectorbuf,n);
+
+ if (res < 0) {
+ perror("[ERR] write in disk_read");
+ return -1;
+ }
+
+ if (res != n) {
+ fprintf(stderr,
+ "Short write - requested %d, received %d - aborting.\n",(int)n,res);
+ return -1;
+ }
+ }
+
+ fprintf(stderr,"[INFO] Done.\n");
+ return 0;
+}
+
+int write_partition(struct ipod_t* ipod, int infile)
+{
+ ssize_t res;
+ int n;
+ int bytesread;
+ int byteswritten = 0;
+ int eof;
+ int padding = 0;
+
+ if (ipod_seek(ipod, ipod->start) < 0) {
+ return -1;
+ }
+ if(ipod->sectorbuf == NULL) {
+ fprintf(stderr,"[ERR] Buffer not initialized.");
+ return -1;
+ }
+
+ fprintf(stderr,"[INFO] Writing input file to device\n");
+ bytesread = 0;
+ eof = 0;
+ while (!eof) {
+ n = read(infile,ipod->sectorbuf,BUFFER_SIZE);
+
+ if (n < 0) {
+ perror("[ERR] read in disk_write");
+ return -1;
+ }
+
+ if (n < BUFFER_SIZE) {
+ eof = 1;
+ /* We need to pad the last write to a multiple of SECTOR_SIZE */
+ if ((n % ipod->sector_size) != 0) {
+ padding = (ipod->sector_size-(n % ipod->sector_size));
+ n += padding;
+ }
+ }
+
+ bytesread += n;
+
+ res = ipod_write(ipod, n);
+
+ if (res < 0) {
+ ipod_print_error(" Error writing to disk: ");
+ fprintf(stderr,"Bytes written: %d\n",byteswritten);
+ return -1;
+ }
+
+ if (res != n) {
+ fprintf(stderr,"[ERR] Short write - requested %d, received %d - aborting.\n",n,(int)res);
+ return -1;
+ }
+
+ byteswritten += res;
+ }
+
+ fprintf(stderr,"[INFO] Wrote %d bytes plus %d bytes padding.\n",
+ byteswritten-padding,padding);
+ return 0;
+}
+
+char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE", "OSBK" };
+
+int diskmove(struct ipod_t* ipod, int delta)
+{
+ int src_start;
+ int src_end;
+ int bytesleft;
+ int chunksize;
+ int n;
+
+ src_start = ipod->ipod_directory[1].devOffset;
+ src_end = (ipod->ipod_directory[ipod->nimages-1].devOffset + ipod->sector_size +
+ ipod->ipod_directory[ipod->nimages-1].len +
+ (ipod->sector_size-1)) & ~(ipod->sector_size-1);
+ bytesleft = src_end - src_start;
+
+ if (ipod_verbose) {
+ fprintf(stderr,"[INFO] Need to move images 2-%d forward %08x bytes\n", ipod->nimages,delta);
+ fprintf(stderr,"[VERB] src_start = %08x\n",src_start);
+ fprintf(stderr,"[VERB] src_end = %08x\n",src_end);
+ fprintf(stderr,"[VERB] dest_start = %08x\n",src_start+delta);
+ fprintf(stderr,"[VERB] dest_end = %08x\n",src_end+delta);
+ fprintf(stderr,"[VERB] bytes to copy = %08x\n",bytesleft);
+ }
+
+ while (bytesleft > 0) {
+ if (bytesleft <= BUFFER_SIZE) {
+ chunksize = bytesleft;
+ } else {
+ chunksize = BUFFER_SIZE;
+ }
+
+ if (ipod_verbose) {
+ fprintf(stderr,"[VERB] Copying %08x bytes from %08x to %08x (absolute %08x to %08x)\n",
+ chunksize,
+ src_end-chunksize,
+ src_end-chunksize+delta,
+ (unsigned int)(ipod->start+src_end-chunksize),
+ (unsigned int)(ipod->start+src_end-chunksize+delta));
+ }
+
+
+ if (ipod_seek(ipod, ipod->start+src_end-chunksize) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ if ((n = ipod_read(ipod,chunksize)) < 0) {
+ perror("[ERR] Write failed\n");
+ return -1;
+ }
+
+ if (n < chunksize) {
+ fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
+ chunksize,n);
+ return -1;
+ }
+
+ if (ipod_seek(ipod, ipod->start+src_end-chunksize+delta) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ if ((n = ipod_write(ipod,chunksize)) < 0) {
+ perror("[ERR] Write failed\n");
+ return -1;
+ }
+
+ if (n < chunksize) {
+ fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
+ ,chunksize,n);
+ return -1;
+ }
+
+ src_end -= chunksize;
+ bytesleft -= chunksize;
+ }
+
+ return 0;
+}
+
+static int rename_image(struct ipod_t* ipod, char* from, char* to)
+{
+ int n;
+ int x;
+ int found;
+ int i;
+ unsigned char* p;
+
+ /* diroffset may not be sector-aligned */
+ x = ipod->diroffset % ipod->sector_size;
+
+ if(ipod->sectorbuf == NULL) {
+ fprintf(stderr,"[ERR] Buffer not initialized.");
+ return -1;
+ }
+ /* Read directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
+ fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
+ return -1;
+ }
+
+ n=ipod_read(ipod, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Read of directory failed.\n");
+ return -1;
+ }
+
+ p = ipod->sectorbuf + x;
+
+ /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
+ if (p[0] == 0)
+ {
+ /* Adjust diroffset */
+ ipod->diroffset += ipod->sector_size - x;
+
+ n=ipod_read(ipod, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Read of directory failed.\n");
+ return -1;
+ }
+ p = ipod->sectorbuf;
+ }
+
+ found = 0;
+ for (i=0 ; !found && i < MAX_IMAGES; i++) {
+ if (memcmp(p + 4, from, 4) == 0) {
+ memcpy(p + 4, to, 4);
+
+ found = 1;
+ }
+ p += 40;
+ }
+
+ if (!found) {
+ fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", from);
+ return -1;
+ }
+
+ /* Write directory back to disk */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
+ fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
+ return -1;
+ }
+
+ n=ipod_write(ipod, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Write of directory failed in rename_image.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int delete_image(struct ipod_t* ipod, char* name)
+{
+ int n;
+ int x;
+ int found;
+ int i;
+ unsigned char* p;
+
+ /* diroffset may not be sector-aligned */
+ x = ipod->diroffset % ipod->sector_size;
+
+ /* Read directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
+ fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
+ return -1;
+ }
+
+ n=ipod_read(ipod, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Read of directory failed.\n");
+ return -1;
+ }
+
+ p = ipod->sectorbuf + x;
+
+ /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
+ if (p[0] == 0)
+ {
+ /* Adjust diroffset */
+ ipod->diroffset += ipod->sector_size - x;
+
+ n=ipod_read(ipod, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Read of directory failed.\n");
+ return -1;
+ }
+ p = ipod->sectorbuf;
+ }
+
+ found = 0;
+ for (i=0 ; !found && i < MAX_IMAGES; i++) {
+ if (memcmp(p + 4, name, 4) == 0) {
+ memset(p, 0, 40); /* Delete directory entry */
+ found = 1;
+ }
+ p += 40;
+ }
+
+ if (!found) {
+ fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", name);
+ return -1;
+ }
+
+ /* Write directory back to disk */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
+ fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
+ return -1;
+ }
+
+ n=ipod_write(ipod, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Write of directory failed in delete_image.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int add_new_image(struct ipod_t* ipod, char* imagename, char* filename, int type)
+{
+ int length;
+ int found;
+ int i;
+ int x;
+ int n;
+ int infile;
+ int newsize;
+ unsigned long chksum=0;
+ unsigned long filechksum=0;
+ unsigned long offset;
+ unsigned char header[8]; /* Header for .ipod file */
+ unsigned char* p;
+
+ if(ipod->sectorbuf == NULL) {
+ fprintf(stderr,"[ERR] Buffer not initialized.");
+ return -1;
+ }
+#ifdef WITH_BOOTOBJS
+ if (type == FILETYPE_INTERNAL) {
+ fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
+ length = ipod->bootloader_len;
+ infile = -1;
+ }
+ else
+#endif
+ {
+ /* First check that the input file is the correct type for this ipod. */
+ infile=open(filename,O_RDONLY);
+ if (infile < 0) {
+ fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
+ return -1;
+ }
+
+ if (type==FILETYPE_DOT_IPOD) {
+ n = read(infile,header,8);
+ if (n < 8) {
+ fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
+ close(infile);
+ return -1;
+ }
+
+ if (memcmp(header+4, ipod->modelname,4)!=0) {
+ fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
+ header[4],header[5],header[6],header[7], ipod->modelname);
+ close(infile);
+ return -1;
+ }
+
+ filechksum = be2int(header);
+
+ length = filesize(infile)-8;
+ } else {
+ length = filesize(infile);
+ }
+ }
+
+ newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
+
+ fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
+ length,newsize);
+
+ if (newsize > BUFFER_SIZE) {
+ fprintf(stderr,"[ERR] Input file too big for buffer\n");
+ if (infile >= 0) close(infile);
+ return -1;
+ }
+
+ /* TODO: Check if we have enough space in the partition for the new image */
+
+#ifdef WITH_BOOTOBJS
+ if (type == FILETYPE_INTERNAL) {
+ memcpy(ipod->sectorbuf,ipod->bootloader,ipod->bootloader_len);
+ }
+ else
+#endif
+ {
+ fprintf(stderr,"[INFO] Reading input file...\n");
+
+ n = read(infile,ipod->sectorbuf,length);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Couldn't read input file\n");
+ close(infile);
+ return -1;
+ }
+ close(infile);
+ }
+
+ /* Pad the data with zeros */
+ memset(ipod->sectorbuf+length,0,newsize-length);
+
+ if (type==FILETYPE_DOT_IPOD) {
+ chksum = ipod->modelnum;
+ for (i = 0; i < length; i++) {
+ /* add 8 unsigned bits but keep a 32 bit sum */
+ chksum += ipod->sectorbuf[i];
+ }
+
+ if (chksum == filechksum) {
+ fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
+ } else {
+ fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
+ return -1;
+ }
+ }
+
+
+ offset = ipod->fwoffset + ipod->ipod_directory[ipod->nimages - 1].devOffset +
+ ipod->ipod_directory[ipod->nimages - 1].len + ipod->sector_size;
+
+ /* 2nd Gen Nano has encrypted firmware, and the sector
+ preceeding the firmware contains hashes that need to be
+ preserved. Nano 2G images include these extra 2048 (0x800)
+ bytes
+ */
+ if (ipod_seek(ipod, offset - (ipod->modelnum == 62 ? 0x800 : 0)) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ if ((n = ipod_write(ipod,newsize)) < 0) {
+ perror("[ERR] Write failed\n");
+ return -1;
+ }
+
+ if (n < newsize) {
+ fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
+ ,newsize,n);
+ return -1;
+ }
+ fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
+
+ /* Now we need to create a new directory entry
+
+ NOTE: On the Nano 2G, the checksum is the checksum of the
+ unencrypted firmware. But this isn't checked by the NOR
+ bootloader (there are cryptographic hashes in the
+ firmware itself), so it doesn't matter that this is
+ wrong.
+ */
+ chksum = 0;
+ for (i = 0; i < length; i++) {
+ /* add 8 unsigned bits but keep a 32 bit sum */
+ chksum += ipod->sectorbuf[i];
+ }
+
+ x = ipod->diroffset % ipod->sector_size;
+
+ /* Read directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
+
+ n=ipod_read(ipod, ipod->sector_size);
+ if (n < 0) { return -1; }
+
+ /* Create a new directory entry */
+
+ /* Copy OSOS or OSBK details - we assume one of them exists */
+ p = ipod->sectorbuf + x;
+ found = 0;
+ for (i = 0; !found && i < ipod->nimages; i++) {
+ if ((memcmp(p + 4, "soso", 4)==0) || (memcmp(p + 4, "kbso", 4)==0)) {
+ found = 1;
+ } else {
+ p += 40;
+ }
+ }
+
+ if (!found) {
+ fprintf(stderr,"[ERR] No OSOS or OSBK image to copy directory from\n");
+ return -1;
+ }
+
+ /* Copy directory image */
+ memcpy(ipod->sectorbuf + x + (ipod->nimages * 40), p, 40);
+ p = ipod->sectorbuf + x + (ipod->nimages * 40);
+
+ /* Modify directory. */
+ memcpy(p + 4, imagename, 4);
+ int2le(offset - ipod->fwoffset, p + 12); /* devOffset */
+ int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16); /* len */
+ int2le(chksum, p + 28); /* checksum */
+
+ /* Write directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
+ n=ipod_write(ipod, ipod->sector_size);
+ if (n < 0) { return -1; }
+
+ return 0;
+}
+
+
+int ipod_has_bootloader(struct ipod_t* ipod)
+{
+ /* The 2nd gen Nano is installed differently */
+ if (ipod->modelnum == 62) {
+ int i;
+ int has_osbk = 0;
+ /* Check if we have an OSBK image */
+ for (i = 0; i < ipod->nimages; i++) {
+ if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) {
+ has_osbk = 1;
+ }
+ }
+ return has_osbk;
+ }
+ else {
+ return (ipod->ipod_directory[0].entryOffset != 0);
+ }
+}
+
+
+/*
+ Bootloader installation on the Nano2G consists of renaming the
+ OSOS image to OSBK and then writing the Rockbox bootloader as a
+ new OSOS image.
+
+ Maybe this approach can/should be adapted for other ipods, as it
+ prevents the Apple bootloader loading the original firmware into
+ RAM along with the Rockbox bootloader (and hence will give a
+ faster boot when the user just wants to start Rockbox).
+
+*/
+
+static int add_bootloader_nano2g(struct ipod_t* ipod, char* filename, int type)
+{
+ /* Check if we already have an OSBK image */
+ if (ipod_has_bootloader(ipod) == 0) {
+ /* First-time install - rename OSOS to OSBK and create new OSOS for bootloader */
+ fprintf(stderr,"[INFO] Creating OSBK backup image of original firmware\n");
+
+ if (rename_image(ipod, "soso", "kbso") < 0) {
+ fprintf(stderr,"[ERR] Could not rename OSOS image\n");
+ return -1;
+ }
+
+ /* Add our bootloader as a brand new image */
+ return add_new_image(ipod, "soso", filename, type);
+ } else {
+ /* This is an update, just replace OSOS with our bootloader */
+
+ return write_firmware(ipod, filename, type);
+ }
+}
+
+
+static int delete_bootloader_nano2g(struct ipod_t* ipod)
+{
+ /* Check if we have an OSBK image */
+ if (ipod_has_bootloader(ipod) == 0) {
+ fprintf(stderr,"[ERR] No OSBK image found - nothing to uninstall\n");
+ return -1;
+ } else {
+ /* Delete our bootloader image */
+ if (delete_image(ipod, "soso") < 0) {
+ fprintf(stderr,"[WARN] Could not delete OSOS image\n");
+ } else {
+ fprintf(stderr,"[INFO] OSOS image deleted\n");
+ }
+
+ if (rename_image(ipod, "kbso", "soso") < 0) {
+ fprintf(stderr,"[ERR] Could not rename OSBK image\n");
+ return -1;
+ }
+
+
+ fprintf(stderr,"[INFO] OSBK image renamed to OSOS - bootloader uninstalled.\n");
+ return 0;
+ }
+}
+
+
+int add_bootloader(struct ipod_t* ipod, char* filename, int type)
+{
+ int length;
+ int i;
+ int x;
+ int n;
+ int infile;
+ int paddedlength;
+ int entryOffset;
+ int delta = 0;
+ unsigned long chksum=0;
+ unsigned long filechksum=0;
+ unsigned char header[8]; /* Header for .ipod file */
+ unsigned char* bootloader_buf;
+
+ /* The 2nd gen Nano is installed differently */
+ if (ipod->modelnum == 62) {
+ return add_bootloader_nano2g(ipod, filename, type);
+ }
+ if(ipod->sectorbuf == NULL) {
+ fprintf(stderr,"[ERR] Buffer not initialized.");
+ return -1;
+ }
+
+ /* Calculate the position in the OSOS image where our bootloader will go. */
+ if (ipod->ipod_directory[0].entryOffset>0) {
+ /* Keep the same entryOffset */
+ entryOffset = ipod->ipod_directory[0].entryOffset;
+ } else {
+ entryOffset = (ipod->ipod_directory[0].len+ipod->sector_size-1)&~(ipod->sector_size-1);
+ }
+
+#ifdef WITH_BOOTOBJS
+ if (type == FILETYPE_INTERNAL) {
+ fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
+ memcpy(ipod->sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
+ length = ipod->bootloader_len;
+ paddedlength=(ipod->bootloader_len+ipod->sector_size-1)&~(ipod->sector_size-1);
+ }
+ else
+#endif
+ {
+ infile=open(filename,O_RDONLY);
+ if (infile < 0) {
+ fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
+ return -1;
+ }
+
+ if (type==FILETYPE_DOT_IPOD) {
+ /* First check that the input file is the correct type for this ipod. */
+ n = read(infile,header,8);
+ if (n < 8) {
+ fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
+ close(infile);
+ return -1;
+ }
+
+ if (memcmp(header+4, ipod->modelname,4)!=0) {
+ fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
+ header[4],header[5],header[6],header[7], ipod->modelname);
+ close(infile);
+ return -1;
+ }
+
+ filechksum = be2int(header);
+
+ length=filesize(infile)-8;
+ } else {
+ length=filesize(infile);
+ }
+ paddedlength=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
+
+ bootloader_buf = malloc(length);
+ if (bootloader_buf == NULL) {
+ fprintf(stderr,"[ERR] Can not allocate memory for bootloader\n");
+ return -1;
+ }
+ /* Now read our bootloader - we need to check it before modifying the partition*/
+ n = read(infile,bootloader_buf,length);
+ close(infile);
+
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Couldn't read input file\n");
+ return -1;
+ }
+
+ if (type==FILETYPE_DOT_IPOD) {
+ /* Calculate and confirm bootloader checksum */
+ chksum = ipod->modelnum;
+ for (i = 0; i < length; i++) {
+ /* add 8 unsigned bits but keep a 32 bit sum */
+ chksum += bootloader_buf[i];
+ }
+
+ if (chksum == filechksum) {
+ fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
+ } else {
+ fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
+ return -1;
+ }
+ }
+ }
+
+ if (entryOffset+paddedlength > BUFFER_SIZE) {
+ fprintf(stderr,"[ERR] Input file too big for buffer\n");
+ return -1;
+ }
+
+ if (ipod_verbose) {
+ fprintf(stderr,"[VERB] Original firmware begins at 0x%08x\n", ipod->ipod_directory[0].devOffset + ipod->sector_size);
+ fprintf(stderr,"[VERB] New entryOffset will be 0x%08x\n",entryOffset);
+ fprintf(stderr,"[VERB] End of bootloader will be at 0x%08x\n",entryOffset+paddedlength);
+ }
+
+ /* Check if we have enough space */
+ /* TODO: Check the size of the partition. */
+ if (ipod->nimages > 1) {
+ if ((ipod->ipod_directory[0].devOffset+entryOffset+paddedlength) >
+ ipod->ipod_directory[1].devOffset) {
+ fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
+ delta = ipod->ipod_directory[0].devOffset + entryOffset+paddedlength
+ - ipod->ipod_directory[1].devOffset + ipod->sector_size;
+
+ if (diskmove(ipod, delta) < 0) {
+ fprintf(stderr,"[ERR] Image movement failed.\n");
+ return -1;
+ }
+ }
+ }
+
+
+ /* We have moved the partitions, now we can write our bootloader */
+
+ /* Firstly read the original firmware into ipod->sectorbuf */
+ fprintf(stderr,"[INFO] Reading original firmware...\n");
+ if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ if ((n = ipod_read(ipod,entryOffset)) < 0) {
+ perror("[ERR] Read failed\n");
+ return -1;
+ }
+
+ if (n < entryOffset) {
+ fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
+ ,entryOffset,n);
+ return -1;
+ }
+
+#ifdef WITH_BOOTOBJS
+ if (type == FILETYPE_INTERNAL) {
+ memcpy(ipod->sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
+ }
+ else
+#endif
+ {
+ memcpy(ipod->sectorbuf+entryOffset,bootloader_buf,length);
+ free(bootloader_buf);
+ }
+
+ /* Calculate new checksum for combined image */
+ chksum = 0;
+ for (i=0;i<entryOffset + length; i++) {
+ chksum += ipod->sectorbuf[i];
+ }
+
+ /* Now write the combined firmware image to the disk */
+
+ if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ if ((n = ipod_write(ipod,entryOffset+paddedlength)) < 0) {
+ perror("[ERR] Write failed\n");
+ return -1;
+ }
+
+ if (n < (entryOffset+paddedlength)) {
+ fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
+ ,entryOffset+paddedlength,n);
+ return -1;
+ }
+
+ fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",entryOffset+paddedlength);
+
+ x = ipod->diroffset % ipod->sector_size;
+
+ /* Read directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ n=ipod_read(ipod, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Directory read failed\n");
+ return -1;
+ }
+
+ /* Update entries for image 0 */
+ int2le(entryOffset+length,ipod->sectorbuf+x+16);
+ int2le(entryOffset,ipod->sectorbuf+x+24);
+ int2le(chksum,ipod->sectorbuf+x+28);
+ int2le(0xffffffff,ipod->sectorbuf+x+36); /* loadAddr */
+
+ /* Update devOffset entries for other images, if we have moved them */
+ if (delta > 0) {
+ for (i=1;i<ipod->nimages;i++) {
+ int2le(le2int(ipod->sectorbuf+x+i*40+12)+delta,ipod->sectorbuf+x+i*40+12);
+ }
+ }
+
+ /* Write directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
+ fprintf(stderr,"[ERR] Seek to %d failed\n", (int)(ipod->start+ipod->diroffset-x));
+ return -1;
+ }
+ n=ipod_write(ipod, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Directory write failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int delete_bootloader(struct ipod_t* ipod)
+{
+ int length;
+ int i;
+ int x;
+ int n;
+ unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
+
+ /* The 2nd gen Nano is installed differently */
+ if (ipod->modelnum == 62) {
+ return delete_bootloader_nano2g(ipod);
+ }
+ if(ipod->sectorbuf == NULL) {
+ fprintf(stderr,"[ERR] Buffer not initialized.");
+ return -1;
+ }
+
+ /* Removing the bootloader involves adjusting the "length",
+ "chksum" and "entryOffset" values in the osos image's directory
+ entry. */
+
+ /* Firstly check we have a bootloader... */
+
+ if (ipod_has_bootloader(ipod) == 0) {
+ fprintf(stderr,"[ERR] No bootloader found.\n");
+ return -1;
+ }
+
+ length = ipod->ipod_directory[0].entryOffset;
+
+ /* Read the firmware so we can calculate the checksum */
+ fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
+
+ if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
+ return -1;
+ }
+
+ i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
+ fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
+ length,i);
+
+ if ((n = ipod_read(ipod,i)) < 0) {
+ return -1;
+ }
+
+ if (n < i) {
+ fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
+ i,n);
+ return -1;
+ }
+
+ chksum = 0;
+ for (i = 0; i < length; i++) {
+ /* add 8 unsigned bits but keep a 32 bit sum */
+ chksum += ipod->sectorbuf[i];
+ }
+
+ /* Now write back the updated directory entry */
+
+ fprintf(stderr,"[INFO] Updating firmware checksum\n");
+
+ x = ipod->diroffset % ipod->sector_size;
+
+ /* Read directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
+
+ n=ipod_read(ipod, ipod->sector_size);
+ if (n < 0) { return -1; }
+
+ /* Update entries for image 0 */
+ int2le(length,ipod->sectorbuf+x+16);
+ int2le(0,ipod->sectorbuf+x+24);
+ int2le(chksum,ipod->sectorbuf+x+28);
+
+ /* Write directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
+ n=ipod_write(ipod, ipod->sector_size);
+ if (n < 0) { return -1; }
+
+ return 0;
+}
+
+int write_firmware(struct ipod_t* ipod, char* filename, int type)
+{
+ int length;
+ int i;
+ int x;
+ int n;
+ int infile;
+ int newsize;
+ int bytesavailable;
+ unsigned long chksum=0;
+ unsigned long filechksum=0;
+ unsigned long offset;
+ unsigned char header[8]; /* Header for .ipod file */
+ unsigned char* p;
+
+ if(ipod->sectorbuf == NULL) {
+ fprintf(stderr,"[ERR] Buffer not initialized.");
+ return -1;
+ }
+#ifdef WITH_BOOTOBJS
+ if (type == FILETYPE_INTERNAL) {
+ fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
+ length = ipod->bootloader_len;
+ infile = -1;
+ }
+ else
+#endif
+ {
+ /* First check that the input file is the correct type for this ipod. */
+ infile=open(filename,O_RDONLY);
+ if (infile < 0) {
+ fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
+ return -1;
+ }
+
+ if (type==FILETYPE_DOT_IPOD) {
+ n = read(infile,header,8);
+ if (n < 8) {
+ fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
+ close(infile);
+ return -1;
+ }
+
+ if (memcmp(header+4, ipod->modelname,4)!=0) {
+ fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
+ header[4],header[5],header[6],header[7], ipod->modelname);
+ close(infile);
+ return -1;
+ }
+
+ filechksum = be2int(header);
+
+ length = filesize(infile)-8;
+ } else {
+ length = filesize(infile);
+ }
+ }
+
+ newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
+
+ fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
+ length,newsize);
+
+ if (newsize > BUFFER_SIZE) {
+ fprintf(stderr,"[ERR] Input file too big for buffer\n");
+ if (infile >= 0) close(infile);
+ return -1;
+ }
+
+ /* Check if we have enough space */
+ /* TODO: Check the size of the partition. */
+ if (ipod->nimages > 1) {
+ bytesavailable=ipod->ipod_directory[1].devOffset-ipod->ipod_directory[0].devOffset;
+ if (bytesavailable < newsize) {
+ fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
+
+ /* TODO: Implement image movement */
+ fprintf(stderr,"[ERR] Image movement not yet implemented.\n");
+ close(infile);
+ return -1;
+ }
+ }
+
+#ifdef WITH_BOOTOBJS
+ if (type == FILETYPE_INTERNAL) {
+ memcpy(ipod->sectorbuf,ipod->bootloader,ipod->bootloader_len);
+ }
+ else
+#endif
+ {
+ fprintf(stderr,"[INFO] Reading input file...\n");
+ /* We now know we have enough space, so write it. */
+ n = read(infile,ipod->sectorbuf,length);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Couldn't read input file\n");
+ close(infile);
+ return -1;
+ }
+ close(infile);
+ }
+
+ /* Pad the data with zeros */
+ memset(ipod->sectorbuf+length,0,newsize-length);
+
+ if (type==FILETYPE_DOT_IPOD) {
+ chksum = ipod->modelnum;
+ for (i = 0; i < length; i++) {
+ /* add 8 unsigned bits but keep a 32 bit sum */
+ chksum += ipod->sectorbuf[i];
+ }
+
+ if (chksum == filechksum) {
+ fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
+ } else {
+ fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
+ return -1;
+ }
+ }
+
+
+ offset = ipod->fwoffset+ipod->ipod_directory[ipod->ososimage].devOffset;
+
+ if (ipod->modelnum==62) {
+
+ /* 2nd Gen Nano has encrypted firmware, and the sector
+ preceeding the firmware contains hashes that need to be
+ preserved. Nano 2G images include these extra 2048 (0x800)
+ bytes
+ */
+
+ offset -= 0x800;
+
+ /* TODO: The above checks need to take into account this 0x800 bytes */
+ }
+
+ if (ipod_seek(ipod, offset) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ if ((n = ipod_write(ipod,newsize)) < 0) {
+ perror("[ERR] Write failed\n");
+ return -1;
+ }
+
+ if (n < newsize) {
+ fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
+ ,newsize,n);
+ return -1;
+ }
+ fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
+
+ /* Now we need to update the "len", "entryOffset" and "chksum" fields
+
+ NOTE: On the Nano 2G, the checksum is the checksum of the
+ unencrypted firmware. But this isn't checked by the NOR
+ bootloader (there are cryptographic hashes in the
+ firmware itself), so it doesn't matter that this is
+ wrong.
+ */
+ chksum = 0;
+ for (i = 0; i < length; i++) {
+ /* add 8 unsigned bits but keep a 32 bit sum */
+ chksum += ipod->sectorbuf[i];
+ }
+
+ x = ipod->diroffset % ipod->sector_size;
+
+ /* Read directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
+
+ n=ipod_read(ipod, ipod->sector_size);
+ if (n < 0) { return -1; }
+
+ /* Update entries for image */
+ p = ipod->sectorbuf + x + (ipod->ososimage * 40);
+ int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16);
+ int2le(0, p + 24);
+ int2le(chksum, p + 28);
+
+ /* Write directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
+ n=ipod_write(ipod, ipod->sector_size);
+ if (n < 0) { return -1; }
+
+ return 0;
+}
+
+int read_firmware(struct ipod_t* ipod, char* filename, int type)
+{
+ int length;
+ int i;
+ int outfile;
+ int n;
+ unsigned long offset;
+ unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
+ unsigned char header[8]; /* Header for .ipod file */
+
+ if(ipod->sectorbuf == NULL) {
+ fprintf(stderr,"[ERR] Buffer not initialized.");
+ return -1;
+ }
+ if (ipod->ipod_directory[ipod->ososimage].entryOffset != 0) {
+ /* We have a bootloader... */
+ length = ipod->ipod_directory[ipod->ososimage].entryOffset;
+ } else {
+ length = ipod->ipod_directory[ipod->ososimage].len;
+ }
+
+ fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
+
+ offset = ipod->fwoffset + ipod->ipod_directory[ipod->ososimage].devOffset;
+ i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
+ fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
+ length,i);
+
+ if (ipod->modelnum==62) {
+ /* 2nd Gen Nano has encrypted firmware, and we need to dump the
+ sector preceeding the image - it contains hashes */
+ offset -= 0x800;
+ length += 0x800;
+ i += 0x800;
+ }
+
+ if (ipod_seek(ipod, offset)) {
+ return -1;
+ }
+
+ if ((n = ipod_read(ipod,i)) < 0) {
+ return -1;
+ }
+
+ if (n < i) {
+ fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
+ i,n);
+ return -1;
+ }
+
+ outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
+ if (outfile < 0) {
+ fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
+ return -1;
+ }
+
+ if (type == FILETYPE_DOT_IPOD) {
+ chksum = ipod->modelnum;
+ for (i = 0; i < length; i++) {
+ /* add 8 unsigned bits but keep a 32 bit sum */
+ chksum += ipod->sectorbuf[i];
+ }
+
+ int2be(chksum,header);
+ memcpy(header+4, ipod->modelname,4);
+
+ n = write(outfile,header,8);
+ if (n != 8) {
+ fprintf(stderr,"[ERR] Write error - %d\n",n);
+ }
+ }
+
+ n = write(outfile,ipod->sectorbuf,length);
+ if (n != length) {
+ fprintf(stderr,"[ERR] Write error - %d\n",n);
+ }
+ close(outfile);
+
+ return 0;
+}
+
+int read_directory(struct ipod_t* ipod)
+{
+ ssize_t n;
+ int x;
+ unsigned char* p;
+ unsigned short version;
+
+ ipod->nimages=0;
+
+ /* Read firmware partition header (first 512 bytes of disk - but
+ let's read a whole sector) */
+
+ if (ipod_seek(ipod, ipod->start) < 0) {
+ fprintf(stderr,"[ERR] Seek to 0x%08x in read_directory() failed.\n",
+ (unsigned int)(ipod->start));
+ return -1;
+ }
+
+ n=ipod_read(ipod, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] ipod_read(ipod,0x%08x) failed in read_directory()\n", ipod->sector_size);
+ return -1;
+ }
+
+ if (memcmp(ipod->sectorbuf,apple_stop_sign,sizeof(apple_stop_sign))!=0) {
+ fprintf(stderr,"[ERR] Firmware partition doesn't contain Apple copyright, aborting.\n");
+ return -1;
+ }
+
+ if (memcmp(ipod->sectorbuf+0x100,"]ih[",4)!=0) {
+ fprintf(stderr,"[ERR] Bad firmware directory\n");
+ return -1;
+ }
+
+ version = le2ushort(ipod->sectorbuf+0x10a);
+ if ((version != 2) && (version != 3)) {
+ fprintf(stderr,"[ERR] Unknown firmware format version %04x\n",
+ version);
+ }
+ ipod->diroffset=le2int(ipod->sectorbuf+0x104) + 0x200;
+
+ /* diroffset may not be sector-aligned */
+ x = ipod->diroffset % ipod->sector_size;
+
+ /* Read directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
+ fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
+ return -1;
+ }
+
+ n=ipod_read(ipod, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Read of directory failed.\n");
+ return -1;
+ }
+
+ p = ipod->sectorbuf + x;
+
+ /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
+ if (p[0] == 0)
+ {
+ /* Adjust diroffset */
+ ipod->diroffset += ipod->sector_size - x;
+
+ n=ipod_read(ipod, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Read of directory failed.\n");
+ return -1;
+ }
+ p = ipod->sectorbuf;
+ }
+
+ ipod->ososimage = -1;
+ while ((ipod->nimages < MAX_IMAGES) && (p < (ipod->sectorbuf + x + 400)) &&
+ ((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) {
+ p+=4;
+ if (memcmp(p,"soso",4)==0) {
+ ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS;
+ ipod->ososimage = ipod->nimages;
+ } else if (memcmp(p,"crsr",4)==0) {
+ ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC;
+ } else if (memcmp(p,"dpua",4)==0) {
+ ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD;
+ } else if (memcmp(p,"kbso",4)==0) {
+ ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSBK;
+ } else if (memcmp(p,"ebih",4)==0) {
+ ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE;
+ } else {
+ fprintf(stderr,"[ERR] Unknown image type %c%c%c%c\n",
+ p[0],p[1],p[2],p[3]);
+ }
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].id=le2int(p);
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].devOffset=le2int(p);
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].len=le2int(p);
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].addr=le2int(p);
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].entryOffset=le2int(p);
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].chksum=le2int(p);
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].vers=le2int(p);
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].loadAddr=le2int(p);
+ p+=4;
+ ipod->nimages++;
+ }
+
+ if (ipod->ososimage < 0) {
+ fprintf(stderr,"[ERR] No OSOS image found.\n");
+ return -1;
+ }
+
+ if ((ipod->nimages > 1) && (version==2)) {
+ /* The 3g firmware image doesn't appear to have a version, so
+ let's make one up... Note that this is never written back to the
+ ipod, so it's OK to do. */
+
+ if (ipod->ipod_directory[ipod->ososimage].vers == 0) { ipod->ipod_directory[ipod->ososimage].vers = 3; }
+
+ ipod->fwoffset = ipod->start;
+ } else {
+ ipod->fwoffset = ipod->start + ipod->sector_size;
+ }
+
+ return 0;
+}
+
+int list_images(struct ipod_t* ipod)
+{
+ int i;
+
+ if (ipod_verbose) {
+ printf(" Type id devOffset len addr entryOffset chksum vers loadAddr devOffset+len\n");
+ for (i = 0 ; i < ipod->nimages; i++) {
+ printf("%d - %s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",i,
+ ftypename[ipod->ipod_directory[i].ftype],
+ ipod->ipod_directory[i].id,
+ ipod->ipod_directory[i].devOffset,
+ ipod->ipod_directory[i].len,
+ ipod->ipod_directory[i].addr,
+ ipod->ipod_directory[i].entryOffset,
+ ipod->ipod_directory[i].chksum,
+ ipod->ipod_directory[i].vers,
+ ipod->ipod_directory[i].loadAddr,
+ ipod->ipod_directory[i].devOffset+((ipod->ipod_directory[i].len+ipod->sector_size-1)&~(ipod->sector_size-1)));
+ }
+ }
+
+ printf("\n");
+ printf("Listing firmware partition contents:\n");
+ printf("\n");
+
+ for (i = 0 ; i < ipod->nimages; i++) {
+ printf("Image %d:\n",i+1);
+ switch(ipod->ipod_directory[i].ftype) {
+ case FTYPE_OSOS:
+ if (ipod->ipod_directory[i].entryOffset==0) {
+ printf(" Main firmware - %d bytes\n",
+ ipod->ipod_directory[i].len);
+ } else {
+ printf(" Main firmware - %d bytes\n",
+ ipod->ipod_directory[i].entryOffset);
+ printf(" Third-party bootloader - %d bytes\n",
+ ipod->ipod_directory[i].len-ipod->ipod_directory[i].entryOffset);
+ }
+ break;
+ default:
+ printf(" %s - %d bytes\n",
+ ftypename[ipod->ipod_directory[i].ftype],
+ ipod->ipod_directory[i].len);
+ }
+ }
+ printf("\n");
+
+ return 0;
+}
+
+int getmodel(struct ipod_t* ipod, int ipod_version)
+{
+ switch (ipod_version) {
+ case 0x01:
+ ipod->modelstr="1st or 2nd Generation";
+ ipod->modelnum = 19;
+ ipod->modelname = "1g2g";
+ ipod->targetname = "ipod1g2g";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipod1g2g;
+ ipod->bootloader_len = LEN_ipod1g2g;
+#endif
+ break;
+ case 0x02:
+ ipod->modelstr="3rd Generation";
+ ipod->modelnum = 7;
+ ipod->modelname = "ip3g";
+ ipod->targetname = "ipod3g";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipod3g;
+ ipod->bootloader_len = LEN_ipod3g;
+#endif
+ break;
+ case 0x40:
+ ipod->modelstr="1st Generation Mini";
+ ipod->modelnum = 9;
+ ipod->modelname = "mini";
+ ipod->targetname = "ipodmini1g";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipodmini1g;
+ ipod->bootloader_len = LEN_ipodmini1g;
+#endif
+ break;
+ case 0x50:
+ ipod->modelstr="4th Generation";
+ ipod->modelnum = 8;
+ ipod->modelname = "ip4g";
+ ipod->targetname = "ipod4gray";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipod4g;
+ ipod->bootloader_len = LEN_ipod4g;
+#endif
+ break;
+ case 0x60:
+ ipod->modelstr="Photo/Color";
+ ipod->modelnum = 3;
+ ipod->modelname = "ipco";
+ ipod->targetname = "ipodcolor";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipodcolor;
+ ipod->bootloader_len = LEN_ipodcolor;
+#endif
+ break;
+ case 0x70:
+ ipod->modelstr="2nd Generation Mini";
+ ipod->modelnum = 11;
+ ipod->modelname = "mn2g";
+ ipod->targetname = "ipodmini2g";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipodmini2g;
+ ipod->bootloader_len = LEN_ipodmini2g;
+#endif
+ break;
+ case 0xc0:
+ ipod->modelstr="1st Generation Nano";
+ ipod->modelnum = 4;
+ ipod->modelname = "nano";
+ ipod->targetname = "ipodnano1g";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipodnano1g;
+ ipod->bootloader_len = LEN_ipodnano1g;
+#endif
+ break;
+ case 0xb0:
+ ipod->modelstr="Video (aka 5th Generation)";
+ ipod->modelnum = 5;
+ ipod->modelname = "ipvd";
+ ipod->targetname = "ipodvideo";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipodvideo;
+ ipod->bootloader_len = LEN_ipodvideo;
+#endif
+ break;
+ case 0x100:
+ ipod->modelstr="2nd Generation Nano";
+ ipod->modelnum = 62;
+ ipod->modelname = "nn2x";
+ ipod->targetname = "ipodnano2g";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipodnano2g;
+ ipod->bootloader_len = LEN_ipodnano2g;
+#endif
+ break;
+ default:
+ ipod->modelname = NULL;
+ ipod->modelnum = 0;
+ ipod->targetname = NULL;
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = NULL;
+ ipod->bootloader_len = 0;
+#endif
+ return -1;
+ }
+ return 0;
+}
+
+/* returns number of found ipods or -1 if no ipods found and permission
+ * for raw disc access was denied. */
+int ipod_scan(struct ipod_t* ipod)
+{
+ int i;
+ int n = 0;
+ int ipod_version;
+ struct ipod_t ipod_found;
+ int denied = 0;
+ int result;
+
+ printf("[INFO] Scanning disk devices...\n");
+
+ for (i = 0; i <= 25 ; i++) {
+#ifdef __WIN32__
+ sprintf(ipod->diskname,"\\\\.\\PhysicalDrive%d",i);
+#elif defined(linux) || defined (__linux)
+ sprintf(ipod->diskname,"/dev/sd%c",'a'+i);
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
+ || defined(__bsdi__) || defined(__DragonFly__)
+ sprintf(ipod->diskname,"/dev/da%d",i);
+#elif defined(__APPLE__) && defined(__MACH__)
+ sprintf(ipod->diskname,"/dev/disk%d",i);
+#else
+ #error No disk paths defined for this platform
+#endif
+ if ((result = ipod_open(ipod, 1)) < 0) {
+ if(result == -2) {
+ denied++;
+ }
+ ipod_close(ipod);
+ continue;
+ }
+
+ if (read_partinfo(ipod,1) < 0) {
+ ipod_close(ipod);
+ continue;
+ }
+
+ if ((ipod->pinfo[0].start==0) || (ipod->pinfo[0].type != 0)) {
+ ipod_close(ipod);
+ continue;
+ }
+
+ if (read_directory(ipod) < 0) {
+ ipod_close(ipod);
+ continue;
+ }
+
+ ipod_version=(ipod->ipod_directory[ipod->ososimage].vers>>8);
+ ipod->ramsize = 0;
+#ifdef __WIN32__
+ /* Windows requires the ipod in R/W mode for SCSI Inquiry.
+ * ipod_reopen_rw does unmount the player on OS X so do this on
+ * W32 only during scanning. */
+ ipod_reopen_rw(ipod);
+#endif
+ ipod_get_xmlinfo(ipod);
+ ipod_get_ramsize(ipod);
+ if (getmodel(ipod,ipod_version) < 0) {
+ ipod_close(ipod);
+ continue;
+ }
+
+#ifdef __WIN32__
+ printf("[INFO] Ipod found - %s (\"%s\") - disk device %d\n",
+ ipod->modelstr,ipod->macpod ? "macpod" : "winpod",i);
+#else
+ printf("[INFO] Ipod found - %s (\"%s\") - %s\n",
+ ipod->modelstr,ipod->macpod ? "macpod" : "winpod",ipod->diskname);
+#endif
+ n++;
+ /* save the complete ipod_t structure for match. The for loop might
+ * overwrite it, so we need to restore it later if only one found. */
+ memcpy(&ipod_found, ipod, sizeof(struct ipod_t));
+ ipod_close(ipod);
+ }
+
+ if (n==1) {
+ /* restore the ipod_t structure, it might have been overwritten */
+ memcpy(ipod, &ipod_found, sizeof(struct ipod_t));
+ }
+ else if(n == 0 && denied) {
+ printf("[ERR] FATAL: Permission denied on %d device(s) and no ipod detected.\n", denied);
+#ifdef __WIN32__
+ printf("[ERR] You need to run this program with administrator priviledges!\n");
+#else
+ printf("[ERR] You need permissions for raw disc access for this program to work!\n");
+#endif
+ }
+ return (n == 0 && denied) ? -1 : n;
+}
+
+static void put_int32le(uint32_t x, unsigned char* p)
+{
+ p[0] = x & 0xff;
+ p[1] = (x >> 8) & 0xff;
+ p[2] = (x >> 16) & 0xff;
+ p[3] = (x >> 24) & 0xff;
+}
+
+int write_dos_partition_table(struct ipod_t* ipod)
+{
+ unsigned char* p;
+ int i, n;
+ uint32_t type;
+
+ /* Only support 512-byte sectors at the moment */
+ if ( ipod->sector_size != 512 )
+ {
+ fprintf(stderr,"[ERR] Only ipods with 512 bytes per sector are supported.\n");
+ return -1;
+ }
+ if(ipod->sectorbuf == NULL) {
+ fprintf(stderr,"[ERR] Buffer not initialized.");
+ return -1;
+ }
+
+ /* Firstly zero the entire MBR */
+ memset(ipod->sectorbuf, 0, ipod->sector_size);
+
+ /* Now add the partition info */
+ for (i=0; i < 4 ; i++)
+ {
+ p = ipod->sectorbuf + 0x1be + i*16;
+
+ /* Ensure first partition is type 0, and second is 0xb */
+ if (i==0) { type = 0; }
+ else if (i==1) { type = 0xb; }
+ else { type = ipod->pinfo[i].type; }
+
+ put_int32le(type, p + 4);
+ put_int32le(ipod->pinfo[i].start, p + 8);
+ put_int32le(ipod->pinfo[i].size, p + 12);
+ }
+
+ /* Finally add the magic */
+ ipod->sectorbuf[0x1fe] = 0x55;
+ ipod->sectorbuf[0x1ff] = 0xaa;
+
+ if (ipod_seek(ipod, 0) < 0) {
+ fprintf(stderr,"[ERR] Seek failed writing MBR\n");
+ return -1;
+ }
+
+ /* Write MBR */
+ if ((n = ipod_write(ipod, ipod->sector_size)) < 0) {
+ perror("[ERR] Write failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Get the XML Device Information, as documented here:
+
+ http://www.ipodlinux.org/wiki/Device_Information
+*/
+
+int ipod_get_xmlinfo(struct ipod_t* ipod)
+{
+ unsigned char hdr[255];
+ unsigned char buf[255];
+ char* p;
+ int psize;
+ int npages;
+ int i;
+
+ if (ipod_scsi_inquiry(ipod, 0xc0, buf, sizeof(buf)) < 0)
+ {
+ fprintf(stderr,"[ERR] Sending SCSI Command failed.\n");
+ return -1;
+ }
+
+ /* Reading directly into hdr[] causes problems (for an unknown reason) on
+ win32 */
+ memcpy(hdr, buf, sizeof(hdr));
+
+ npages = hdr[3];
+
+ psize = npages * 0xf8; /* Hopefully this is enough. */
+
+ ipod->xmlinfo = malloc(psize);
+ ipod->xmlinfo_len = 0;
+
+ if (ipod->xmlinfo == NULL) {
+ fprintf(stderr,"[ERR] Could not allocate RAM for xmlinfo\n");
+ return -1;
+ }
+
+ p = ipod->xmlinfo;
+
+ for (i=0; i < npages; i++) {
+ if (ipod_scsi_inquiry(ipod, hdr[i+4], buf, sizeof(buf)) < 0) {
+ fprintf(stderr,"[ERR] Sending SCSI Command failed.\n");
+ return -1;
+ }
+
+ if ((buf[3] + ipod->xmlinfo_len) > psize) {
+ fprintf(stderr,"[ERR] Ran out of memory reading xmlinfo\n");
+ free(ipod->xmlinfo);
+ ipod->xmlinfo = NULL;
+ ipod->xmlinfo_len = 0;
+ return -1;
+ }
+
+ memcpy(p, buf + 4, buf[3]);
+ p += buf[3];
+ ipod->xmlinfo_len += buf[3];
+ }
+
+ /* NULL-terminate the XML info */
+ *p = 0;
+
+ fprintf(stderr,"[INFO] Read XML info (%d bytes)\n",ipod->xmlinfo_len);
+
+ return 0;
+}
+
+void ipod_get_ramsize(struct ipod_t* ipod)
+{
+ const char needle[] = "<key>RAM</key>\n<integer>";
+ char* p;
+
+ if (ipod->xmlinfo == NULL)
+ return;
+
+ p = strstr(ipod->xmlinfo, needle);
+
+ if (p) {
+ ipod->ramsize = atoi(p + sizeof(needle) - 1);
+ }
+}
+
diff --git a/utils/ipodpatcher/ipodpatcher.h b/utils/ipodpatcher/ipodpatcher.h
new file mode 100644
index 0000000000..2cd2331666
--- /dev/null
+++ b/utils/ipodpatcher/ipodpatcher.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006-2007 Dave Chapman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef IPODPATCHER_H
+#define IPODPATCHER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ipodio.h"
+
+/* exit codes */
+#define IPOD_OK 0
+#define IPOD_WRONG_ARGUMENTS 1
+#define IPOD_OPEN_INFILE_FAILED 2
+#define IPOD_PARTITION_ERROR 3
+#define IPOD_OPEN_OUTFILE_FAILED 4
+#define IPOD_CANNOT_REOPEN 5
+#define IPOD_ACCESS_DENIED 10
+#define IPOD_NOT_FOUND 11
+#define IPOD_WRONG_DEVICE_COUNT 12
+#define IPOD_IMAGE_ERROR 13
+#define IPOD_DUMP_FAILED 14
+#define IPOD_MULTIPLE_DEVICES 15
+#define IPOD_WRONG_TYPE 16
+#define IPOD_UNKNOWN_FW_VERSION -1
+
+/* Size of buffer for disk I/O - 8MB is large enough for any version
+ of the Apple firmware, but not the Nano's RSRC image. */
+#define BUFFER_SIZE 8*1024*1024
+
+extern int ipod_verbose;
+
+#define FILETYPE_DOT_IPOD 0
+#define FILETYPE_DOT_BIN 1
+#ifdef WITH_BOOTOBJS
+ #define FILETYPE_INTERNAL 2
+#endif
+
+char* get_parttype(unsigned int pt);
+int read_partinfo(struct ipod_t* ipod, int silent);
+int read_partition(struct ipod_t* ipod, int outfile);
+int write_partition(struct ipod_t* ipod, int infile);
+int diskmove(struct ipod_t* ipod, int delta);
+int add_bootloader(struct ipod_t* ipod, char* filename, int type);
+int delete_bootloader(struct ipod_t* ipod);
+int write_firmware(struct ipod_t* ipod, char* filename, int type);
+int read_firmware(struct ipod_t* ipod, char* filename, int type);
+int read_directory(struct ipod_t* ipod);
+int list_images(struct ipod_t* ipod);
+int getmodel(struct ipod_t* ipod, int ipod_version);
+int ipod_scan(struct ipod_t* ipod);
+int write_dos_partition_table(struct ipod_t* ipod);
+int ipod_get_xmlinfo(struct ipod_t* ipod);
+void ipod_get_ramsize(struct ipod_t* ipod);
+int read_aupd(struct ipod_t* ipod, char* filename);
+int write_aupd(struct ipod_t* ipod, char* filename);
+off_t filesize(int fd);
+int ipod_has_bootloader(struct ipod_t* ipod);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/utils/ipodpatcher/ipodpatcher.manifest b/utils/ipodpatcher/ipodpatcher.manifest
new file mode 100644
index 0000000000..695ecb26ea
--- /dev/null
+++ b/utils/ipodpatcher/ipodpatcher.manifest
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="ipodpatcher.exe" type="win32"/>
+
+ <!-- Identify the application security requirements. -->
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="requireAdministrator"/>
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+</assembly>
diff --git a/utils/ipodpatcher/ipodpatcher.rc b/utils/ipodpatcher/ipodpatcher.rc
new file mode 100644
index 0000000000..e440b51271
--- /dev/null
+++ b/utils/ipodpatcher/ipodpatcher.rc
@@ -0,0 +1 @@
+1 24 MOVEABLE PURE "ipodpatcher.manifest"
diff --git a/utils/ipodpatcher/main.c b/utils/ipodpatcher/main.c
new file mode 100644
index 0000000000..7b0a909178
--- /dev/null
+++ b/utils/ipodpatcher/main.c
@@ -0,0 +1,622 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006-2007 Dave Chapman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "ipodpatcher.h"
+#include "ipodio.h"
+
+#ifdef RELEASE
+#undef VERSION
+#define VERSION "5.0 with v4.0 bootloaders (v1.0 for 2nd Gen Nano)"
+#endif
+
+
+enum {
+ NONE,
+#ifdef WITH_BOOTOBJS
+ INSTALL,
+#endif
+ INTERACTIVE,
+ SHOW_INFO,
+ LIST_IMAGES,
+ DELETE_BOOTLOADER,
+ ADD_BOOTLOADER,
+ READ_FIRMWARE,
+ WRITE_FIRMWARE,
+ READ_AUPD,
+ WRITE_AUPD,
+ READ_PARTITION,
+ WRITE_PARTITION,
+ FORMAT_PARTITION,
+ DUMP_XML,
+ CONVERT_TO_FAT32
+};
+
+void print_macpod_warning(void)
+{
+ printf("[INFO] ************************************************************************\n");
+ printf("[INFO] *** WARNING FOR ROCKBOX USERS\n");
+ printf("[INFO] *** You must convert this ipod to FAT32 format (aka a \"winpod\")\n");
+ printf("[INFO] *** if you want to run Rockbox. Rockbox WILL NOT work on this ipod.\n");
+ printf("[INFO] *** See http://www.rockbox.org/wiki/IpodConversionToFAT32\n");
+ printf("[INFO] ************************************************************************\n");
+}
+
+void print_usage(void)
+{
+ fprintf(stderr,"Usage: ipodpatcher --scan\n");
+#ifdef __WIN32__
+ fprintf(stderr," or ipodpatcher [DISKNO] [action]\n");
+#else
+ fprintf(stderr," or ipodpatcher [device] [action]\n");
+#endif
+ fprintf(stderr,"\n");
+ fprintf(stderr,"Where [action] is one of the following options:\n");
+#ifdef WITH_BOOTOBJS
+ fprintf(stderr," --install\n");
+#endif
+ fprintf(stderr," -l, --list\n");
+ fprintf(stderr," -r, --read-partition bootpartition.bin\n");
+ fprintf(stderr," -w, --write-partition bootpartition.bin\n");
+ fprintf(stderr," -rf, --read-firmware filename.ipod[x]\n");
+ fprintf(stderr," -rfb, --read-firmware-bin filename.bin\n");
+ fprintf(stderr," -wf, --write-firmware filename.ipod[x]\n");
+ fprintf(stderr," -wfb, --write-firmware-bin filename.bin\n");
+#ifdef WITH_BOOTOBJS
+ fprintf(stderr," -we, --write-embedded\n");
+#endif
+ fprintf(stderr," -a, --add-bootloader filename.ipod[x]\n");
+ fprintf(stderr," -ab, --add-bootloader-bin filename.bin\n");
+ fprintf(stderr," -d, --delete-bootloader\n");
+ fprintf(stderr," -f, --format\n");
+ fprintf(stderr," -c, --convert\n");
+ fprintf(stderr," --read-aupd filename.bin\n");
+ fprintf(stderr," --write-aupd filename.bin\n");
+ fprintf(stderr," -x --dump-xml filename.xml\n");
+ fprintf(stderr,"\n");
+
+ fprintf(stderr,"The .ipodx extension is used for encrypted images for the 2nd Gen Nano.\n\n");
+
+#ifdef __WIN32__
+ fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n");
+ fprintf(stderr,"The first hard disk in your computer (i.e. C:\\) will be disk 0, the next disk\n");
+ fprintf(stderr,"will be disk 1 etc. ipodpatcher will refuse to access a disk unless it\n");
+ fprintf(stderr,"can identify it as being an ipod.\n");
+ fprintf(stderr,"\n");
+#else
+#if defined(linux) || defined (__linux)
+ fprintf(stderr,"\"device\" is the device node (e.g. /dev/sda) assigned to your ipod.\n");
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+ fprintf(stderr,"\"device\" is the device node (e.g. /dev/da1) assigned to your ipod.\n");
+#elif defined(__APPLE__) && defined(__MACH__)
+ fprintf(stderr,"\"device\" is the device node (e.g. /dev/disk1) assigned to your ipod.\n");
+#endif
+ fprintf(stderr,"ipodpatcher will refuse to access a disk unless it can identify it as being\n");
+ fprintf(stderr,"an ipod.\n");
+#endif
+}
+
+void display_partinfo(struct ipod_t* ipod)
+{
+ int i;
+ double sectors_per_MB = (1024.0*1024.0)/ipod->sector_size;
+
+ printf("[INFO] Part Start Sector End Sector Size (MB) Type\n");
+ for ( i = 0; i < 4; i++ ) {
+ if (ipod->pinfo[i].start != 0) {
+ printf("[INFO] %d %10ld %10ld %10.1f %s (0x%02x)\n",
+ i,
+ (long int)ipod->pinfo[i].start,
+ (long int)ipod->pinfo[i].start+ipod->pinfo[i].size-1,
+ ipod->pinfo[i].size/sectors_per_MB,
+ get_parttype(ipod->pinfo[i].type),
+ (int)ipod->pinfo[i].type);
+ }
+ }
+}
+
+
+int main(int argc, char* argv[])
+{
+ char yesno[4];
+ int i;
+ int n;
+ int infile, outfile;
+ unsigned int inputsize;
+ char* filename;
+ int action = SHOW_INFO;
+ int type;
+ struct ipod_t ipod;
+
+ fprintf(stderr,"ipodpatcher " VERSION "\n");
+ fprintf(stderr,"(C) Dave Chapman 2006-2009\n");
+ fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
+ fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
+
+ if ((argc > 1) && ((strcmp(argv[1],"-h")==0) || (strcmp(argv[1],"--help")==0))) {
+ print_usage();
+ return IPOD_OK;
+ }
+
+ if (ipod_alloc_buffer(&ipod,BUFFER_SIZE) < 0) {
+ fprintf(stderr,"Failed to allocate memory buffer\n");
+ }
+
+ if ((argc > 1) && (strcmp(argv[1],"--scan")==0)) {
+ if (ipod_scan(&ipod) == 0)
+ fprintf(stderr,"[ERR] No ipods found.\n");
+ return IPOD_NOT_FOUND;
+ }
+
+ /* If the first parameter doesn't start with -, then we interpret it as a device */
+ if ((argc > 1) && (argv[1][0] != '-')) {
+ ipod.diskname[0]=0;
+#ifdef __WIN32__
+ snprintf(ipod.diskname,sizeof(ipod.diskname),"\\\\.\\PhysicalDrive%s",argv[1]);
+#else
+ strncpy(ipod.diskname,argv[1],sizeof(ipod.diskname));
+#endif
+ i = 2;
+ } else {
+ /* Autoscan for ipods */
+ n = ipod_scan(&ipod);
+ if (n==0) {
+ fprintf(stderr,"[ERR] No ipods found, aborting\n");
+ fprintf(stderr,"[ERR] Please connect your ipod and ensure it is in disk mode\n");
+#if defined(__APPLE__) && defined(__MACH__)
+ fprintf(stderr,"[ERR] Also ensure that itunes is closed, and that your ipod is not mounted.\n");
+#elif !defined(__WIN32__)
+ if (geteuid()!=0) {
+ fprintf(stderr,"[ERR] You may also need to run ipodpatcher as root.\n");
+ }
+#endif
+ fprintf(stderr,"[ERR] Please refer to the Rockbox manual if you continue to have problems.\n");
+ } else if (n > 1) {
+ fprintf(stderr,"[ERR] %d ipods found, aborting\n",n);
+ fprintf(stderr,"[ERR] Please connect only one ipod and re-run ipodpatcher.\n");
+ return IPOD_MULTIPLE_DEVICES;
+ } else if (n == 1 && ipod.macpod) {
+ return IPOD_WRONG_TYPE;
+ }
+
+ if (n != 1) {
+#ifdef WITH_BOOTOBJS
+ if (argc==1) {
+ printf("\nPress ENTER to exit ipodpatcher :");
+ fgets(yesno,4,stdin);
+ }
+#endif
+ return IPOD_NOT_FOUND;
+ }
+
+ i = 1;
+ }
+
+#ifdef WITH_BOOTOBJS
+ action = INTERACTIVE;
+#else
+ action = NONE;
+#endif
+
+ while (i < argc) {
+ if ((strcmp(argv[i],"-l")==0) || (strcmp(argv[i],"--list")==0)) {
+ action = LIST_IMAGES;
+ i++;
+#ifdef WITH_BOOTOBJS
+ } else if (strcmp(argv[i],"--install")==0) {
+ action = INSTALL;
+ i++;
+#endif
+ } else if ((strcmp(argv[i],"-d")==0) ||
+ (strcmp(argv[i],"--delete-bootloader")==0)) {
+ action = DELETE_BOOTLOADER;
+ i++;
+ } else if ((strcmp(argv[i],"-a")==0) ||
+ (strcmp(argv[i],"--add-bootloader")==0)) {
+ action = ADD_BOOTLOADER;
+ type = FILETYPE_DOT_IPOD;
+ i++;
+ if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-ab")==0) ||
+ (strcmp(argv[i],"--add-bootloader-bin")==0)) {
+ action = ADD_BOOTLOADER;
+ type = FILETYPE_DOT_BIN;
+ i++;
+ if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-rf")==0) ||
+ (strcmp(argv[i],"--read-firmware")==0)) {
+ action = READ_FIRMWARE;
+ type = FILETYPE_DOT_IPOD;
+ i++;
+ if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-rfb")==0) ||
+ (strcmp(argv[i],"--read-firmware-bin")==0)) {
+ action = READ_FIRMWARE;
+ type = FILETYPE_DOT_BIN;
+ i++;
+ if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
+ filename=argv[i];
+ i++;
+#ifdef WITH_BOOTOBJS
+ } else if ((strcmp(argv[i],"-we")==0) ||
+ (strcmp(argv[i],"--write-embedded")==0)) {
+ action = WRITE_FIRMWARE;
+ type = FILETYPE_INTERNAL;
+ filename="[embedded bootloader]"; /* Only displayed for user */
+ i++;
+#endif
+ } else if ((strcmp(argv[i],"-wf")==0) ||
+ (strcmp(argv[i],"--write-firmware")==0)) {
+ action = WRITE_FIRMWARE;
+ type = FILETYPE_DOT_IPOD;
+ i++;
+ if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-wfb")==0) ||
+ (strcmp(argv[i],"--write-firmware-bin")==0)) {
+ action = WRITE_FIRMWARE;
+ type = FILETYPE_DOT_BIN;
+ i++;
+ if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-r")==0) ||
+ (strcmp(argv[i],"--read-partition")==0)) {
+ action = READ_PARTITION;
+ i++;
+ if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-w")==0) ||
+ (strcmp(argv[i],"--write-partition")==0)) {
+ action = WRITE_PARTITION;
+ i++;
+ if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-v")==0) ||
+ (strcmp(argv[i],"--verbose")==0)) {
+ ipod_verbose++;
+ i++;
+ } else if ((strcmp(argv[i],"-f")==0) ||
+ (strcmp(argv[i],"--format")==0)) {
+ action = FORMAT_PARTITION;
+ i++;
+ } else if (strcmp(argv[i],"--read-aupd")==0) {
+ action = READ_AUPD;
+ i++;
+ if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
+ filename=argv[i];
+ i++;
+ } else if (strcmp(argv[i],"--write-aupd")==0) {
+ action = WRITE_AUPD;
+ i++;
+ if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-x")==0) ||
+ (strcmp(argv[i],"--dump-xml")==0)) {
+ action = DUMP_XML;
+ i++;
+ if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-c")==0) ||
+ (strcmp(argv[i],"--convert")==0)) {
+ action = CONVERT_TO_FAT32;
+ i++;
+ } else {
+ print_usage(); return IPOD_WRONG_ARGUMENTS;
+ }
+ }
+
+ if (ipod.diskname[0]==0) {
+ print_usage();
+ return 1;
+ }
+
+ if (ipod_open(&ipod, 0) < 0) {
+ return IPOD_ACCESS_DENIED;
+ }
+
+ fprintf(stderr,"[INFO] Reading partition table from %s\n",ipod.diskname);
+ fprintf(stderr,"[INFO] Sector size is %d bytes\n",ipod.sector_size);
+
+ if (read_partinfo(&ipod,0) < 0) {
+ return IPOD_PARTITION_ERROR;
+ }
+
+ display_partinfo(&ipod);
+
+ if (ipod.pinfo[0].start==0) {
+ fprintf(stderr,"[ERR] No partition 0 on disk:\n");
+ display_partinfo(&ipod);
+ return IPOD_PARTITION_ERROR;
+ }
+
+ read_directory(&ipod);
+
+ if (ipod.nimages <= 0) {
+ fprintf(stderr,"[ERR] Failed to read firmware directory - nimages=%d\n",ipod.nimages);
+ return IPOD_IMAGE_ERROR;
+ }
+
+ if (getmodel(&ipod,(ipod.ipod_directory[ipod.ososimage].vers>>8)) < 0) {
+ fprintf(stderr,"[ERR] Unknown version number in firmware (%08x)\n",
+ ipod.ipod_directory[ipod.ososimage].vers);
+ return IPOD_UNKNOWN_FW_VERSION;
+ }
+
+#ifdef __WIN32__
+ /* Windows requires the ipod in R/W mode for SCSI Inquiry */
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return IPOD_CANNOT_REOPEN;
+ }
+#endif
+
+
+ /* Read the XML info, and if successful, look for the ramsize
+ (only available for some models - set to 0 if not known) */
+
+ ipod.ramsize = 0;
+
+ if (ipod_get_xmlinfo(&ipod) == 0) {
+ ipod_get_ramsize(&ipod);
+ }
+
+ printf("[INFO] Ipod model: %s ",ipod.modelstr);
+ if (ipod.ramsize > 0) { printf("(%dMB RAM) ",ipod.ramsize); }
+ printf("(\"%s\")\n",ipod.macpod ? "macpod" : "winpod");
+
+ if (ipod.macpod) {
+ print_macpod_warning();
+ }
+
+ if (action==LIST_IMAGES) {
+ list_images(&ipod);
+#ifdef WITH_BOOTOBJS
+ } else if (action==INTERACTIVE) {
+
+ printf("Enter i to install the Rockbox bootloader, u to uninstall\n or c to cancel and do nothing (i/u/c) :");
+
+ if (fgets(yesno,4,stdin)) {
+ if (yesno[0]=='i') {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return IPOD_CANNOT_REOPEN;
+ }
+
+ if (add_bootloader(&ipod, NULL, FILETYPE_INTERNAL)==0) {
+ fprintf(stderr,"[INFO] Bootloader installed successfully.\n");
+ } else {
+ fprintf(stderr,"[ERR] --install failed.\n");
+ }
+ } else if (yesno[0]=='u') {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return IPOD_CANNOT_REOPEN;
+ }
+
+ if (delete_bootloader(&ipod)==0) {
+ fprintf(stderr,"[INFO] Bootloader removed.\n");
+ } else {
+ fprintf(stderr,"[ERR] Bootloader removal failed.\n");
+ }
+ }
+ }
+#endif
+ } else if (action==DELETE_BOOTLOADER) {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return IPOD_CANNOT_REOPEN;
+ }
+
+ if (ipod.ipod_directory[0].entryOffset==0) {
+ fprintf(stderr,"[ERR] No bootloader detected.\n");
+ } else {
+ if (delete_bootloader(&ipod)==0) {
+ fprintf(stderr,"[INFO] Bootloader removed.\n");
+ } else {
+ fprintf(stderr,"[ERR] --delete-bootloader failed.\n");
+ }
+ }
+ } else if (action==ADD_BOOTLOADER) {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return IPOD_CANNOT_REOPEN;
+ }
+
+ if (add_bootloader(&ipod, filename, type)==0) {
+ fprintf(stderr,"[INFO] Bootloader %s written to device.\n",filename);
+ } else {
+ fprintf(stderr,"[ERR] --add-bootloader failed.\n");
+ }
+#ifdef WITH_BOOTOBJS
+ } else if (action==INSTALL) {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return IPOD_CANNOT_REOPEN;
+ }
+
+ if (add_bootloader(&ipod, NULL, FILETYPE_INTERNAL)==0) {
+ fprintf(stderr,"[INFO] Bootloader installed successfully.\n");
+ } else {
+ fprintf(stderr,"[ERR] --install failed.\n");
+ }
+#endif
+ } else if (action==WRITE_FIRMWARE) {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return IPOD_CANNOT_REOPEN;
+ }
+
+ if (write_firmware(&ipod, filename,type)==0) {
+ fprintf(stderr,"[INFO] Firmware %s written to device.\n",filename);
+ } else {
+ fprintf(stderr,"[ERR] --write-firmware failed.\n");
+ }
+ } else if (action==READ_FIRMWARE) {
+ if (read_firmware(&ipod, filename, type)==0) {
+ fprintf(stderr,"[INFO] Firmware read to file %s.\n",filename);
+ } else {
+ fprintf(stderr,"[ERR] --read-firmware failed.\n");
+ }
+ } else if (action==READ_AUPD) {
+ if (read_aupd(&ipod, filename)==0) {
+ fprintf(stderr,"[INFO] AUPD image read to file %s.\n",filename);
+ } else {
+ fprintf(stderr,"[ERR] --read-aupd failed.\n");
+ }
+ } else if (action==WRITE_AUPD) {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return IPOD_CANNOT_REOPEN;
+ }
+
+ if (write_aupd(&ipod, filename)==0) {
+ fprintf(stderr,"[INFO] AUPD image %s written to device.\n",filename);
+ } else {
+ fprintf(stderr,"[ERR] --write-aupd failed.\n");
+ }
+ } else if (action==DUMP_XML) {
+ if (ipod.xmlinfo == NULL) {
+ fprintf(stderr,"[ERR] No XML to write\n");
+ return IPOD_DUMP_FAILED;
+ }
+
+ outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE);
+ if (outfile < 0) {
+ perror(filename);
+ return IPOD_OPEN_OUTFILE_FAILED;
+ }
+
+ if (write(outfile, ipod.xmlinfo, ipod.xmlinfo_len) < 0) {
+ fprintf(stderr,"[ERR] --dump-xml failed.\n");
+ } else {
+ fprintf(stderr,"[INFO] XML info written to %s.\n",filename);
+ }
+ close(outfile);
+ } else if (action==READ_PARTITION) {
+ outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE);
+ if (outfile < 0) {
+ perror(filename);
+ return IPOD_OPEN_OUTFILE_FAILED;
+ }
+
+ if (read_partition(&ipod, outfile) < 0) {
+ fprintf(stderr,"[ERR] --read-partition failed.\n");
+ } else {
+ fprintf(stderr,"[INFO] Partition extracted to %s.\n",filename);
+ }
+ close(outfile);
+ } else if (action==WRITE_PARTITION) {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return IPOD_CANNOT_REOPEN;
+ }
+
+ infile = open(filename,O_RDONLY|O_BINARY);
+ if (infile < 0) {
+ perror(filename);
+ return IPOD_OPEN_INFILE_FAILED;
+ }
+
+ /* Check filesize is <= partition size */
+ inputsize=filesize(infile);
+ if (inputsize > 0) {
+ if (inputsize <= (ipod.pinfo[0].size*ipod.sector_size)) {
+ fprintf(stderr,"[INFO] Input file is %u bytes\n",inputsize);
+ if (write_partition(&ipod,infile) < 0) {
+ fprintf(stderr,"[ERR] --write-partition failed.\n");
+ } else {
+ fprintf(stderr,"[INFO] %s restored to partition\n",filename);
+ }
+ } else {
+ fprintf(stderr,"[ERR] File is too large for firmware partition, aborting.\n");
+ }
+ }
+
+ close(infile);
+ } else if (action==FORMAT_PARTITION) {
+ printf("WARNING!!! YOU ARE ABOUT TO USE AN EXPERIMENTAL FEATURE.\n");
+ printf("ALL DATA ON YOUR IPOD WILL BE ERASED.\n");
+ printf("Are you sure you want to format your ipod? (y/n):");
+
+ if (fgets(yesno,4,stdin)) {
+ if (yesno[0]=='y') {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return IPOD_CANNOT_REOPEN;
+ }
+
+ if (format_partition(&ipod,1) < 0) {
+ fprintf(stderr,"[ERR] Format failed.\n");
+ }
+ } else {
+ fprintf(stderr,"[INFO] Format cancelled.\n");
+ }
+ }
+ } else if (action==CONVERT_TO_FAT32) {
+ if (!ipod.macpod) {
+ printf("[ERR] Ipod is already FAT32, aborting\n");
+ } else {
+ printf("WARNING!!! YOU ARE ABOUT TO USE AN EXPERIMENTAL FEATURE.\n");
+ printf("ALL DATA ON YOUR IPOD WILL BE ERASED.\n");
+ printf("Are you sure you want to convert your ipod to FAT32? (y/n):");
+
+ if (fgets(yesno,4,stdin)) {
+ if (yesno[0]=='y') {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return IPOD_CANNOT_REOPEN;
+ }
+
+ if (write_dos_partition_table(&ipod) < 0) {
+ fprintf(stderr,"[ERR] Partition conversion failed.\n");
+ }
+
+ if (format_partition(&ipod,1) < 0) {
+ fprintf(stderr,"[ERR] Format failed.\n");
+ }
+ } else {
+ fprintf(stderr,"[INFO] Format cancelled.\n");
+ }
+ }
+ }
+ }
+
+ ipod_close(&ipod);
+
+#ifdef WITH_BOOTOBJS
+ if (action==INTERACTIVE) {
+ printf("Press ENTER to exit ipodpatcher :");
+ fgets(yesno,4,stdin);
+ }
+#endif
+
+ ipod_dealloc_buffer(&ipod);
+ return IPOD_OK;
+}
diff --git a/utils/ipodpatcher/parttypes.h b/utils/ipodpatcher/parttypes.h
new file mode 100644
index 0000000000..f8de303553
--- /dev/null
+++ b/utils/ipodpatcher/parttypes.h
@@ -0,0 +1,109 @@
+/* DOS partition types - taken from fdisk */
+
+struct parttype {
+ unsigned char type;
+ char *name;
+};
+
+struct parttype parttypes[] = {
+ {0x00, "Empty"},
+ {0x01, "FAT12"},
+ {0x02, "XENIX root"},
+ {0x03, "XENIX usr"},
+ {0x04, "FAT16 <32M"},
+ {0x05, "Extended"}, /* DOS 3.3+ extended partition */
+ {0x06, "FAT16"}, /* DOS 16-bit >=32M */
+ {0x07, "HPFS/NTFS"}, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
+ {0x08, "AIX"}, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
+ {0x09, "AIX bootable"}, /* AIX data or Coherent */
+ {0x0a, "OS/2 Boot Manager"},/* OS/2 Boot Manager */
+ {0x0b, "W95 FAT32"},
+ {0x0c, "W95 FAT32 (LBA)"},/* LBA really is `Extended Int 13h' */
+ {0x0e, "W95 FAT16 (LBA)"},
+ {0x0f, "W95 Ext'd (LBA)"},
+ {0x10, "OPUS"},
+ {0x11, "Hidden FAT12"},
+ {0x12, "Compaq diagnostics"},
+ {0x14, "Hidden FAT16 <32M"},
+ {0x16, "Hidden FAT16"},
+ {0x17, "Hidden HPFS/NTFS"},
+ {0x18, "AST SmartSleep"},
+ {0x1b, "Hidden W95 FAT32"},
+ {0x1c, "Hidden W95 FAT32 (LBA)"},
+ {0x1e, "Hidden W95 FAT16 (LBA)"},
+ {0x24, "NEC DOS"},
+ {0x39, "Plan 9"},
+ {0x3c, "PartitionMagic recovery"},
+ {0x40, "Venix 80286"},
+ {0x41, "PPC PReP Boot"},
+ {0x42, "SFS"},
+ {0x4d, "QNX4.x"},
+ {0x4e, "QNX4.x 2nd part"},
+ {0x4f, "QNX4.x 3rd part"},
+ {0x50, "OnTrack DM"},
+ {0x51, "OnTrack DM6 Aux1"}, /* (or Novell) */
+ {0x52, "CP/M"}, /* CP/M or Microport SysV/AT */
+ {0x53, "OnTrack DM6 Aux3"},
+ {0x54, "OnTrackDM6"},
+ {0x55, "EZ-Drive"},
+ {0x56, "Golden Bow"},
+ {0x5c, "Priam Edisk"},
+ {0x61, "SpeedStor"},
+ {0x63, "GNU HURD or SysV"}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
+ {0x64, "Novell Netware 286"},
+ {0x65, "Novell Netware 386"},
+ {0x70, "DiskSecure Multi-Boot"},
+ {0x75, "PC/IX"},
+ {0x80, "Old Minix"}, /* Minix 1.4a and earlier */
+ {0x81, "Minix / old Linux"},/* Minix 1.4b and later */
+ {0x82, "Linux swap / Solaris"},
+ {0x83, "Linux"},
+ {0x84, "OS/2 hidden C: drive"},
+ {0x85, "Linux extended"},
+ {0x86, "NTFS volume set"},
+ {0x87, "NTFS volume set"},
+ {0x88, "Linux plaintext"},
+ {0x8e, "Linux LVM"},
+ {0x93, "Amoeba"},
+ {0x94, "Amoeba BBT"}, /* (bad block table) */
+ {0x9f, "BSD/OS"}, /* BSDI */
+ {0xa0, "IBM Thinkpad hibernation"},
+ {0xa5, "FreeBSD"}, /* various BSD flavours */
+ {0xa6, "OpenBSD"},
+ {0xa7, "NeXTSTEP"},
+ {0xa8, "Darwin UFS"},
+ {0xa9, "NetBSD"},
+ {0xab, "Darwin boot"},
+ {0xb7, "BSDI fs"},
+ {0xb8, "BSDI swap"},
+ {0xbb, "Boot Wizard hidden"},
+ {0xbe, "Solaris boot"},
+ {0xbf, "Solaris"},
+ {0xc1, "DRDOS/sec (FAT-12)"},
+ {0xc4, "DRDOS/sec (FAT-16 < 32M)"},
+ {0xc6, "DRDOS/sec (FAT-16)"},
+ {0xc7, "Syrinx"},
+ {0xda, "Non-FS data"},
+ {0xdb, "CP/M / CTOS / ..."},/* CP/M or Concurrent CP/M or
+ Concurrent DOS or CTOS */
+ {0xde, "Dell Utility"}, /* Dell PowerEdge Server utilities */
+ {0xdf, "BootIt"}, /* BootIt EMBRM */
+ {0xe1, "DOS access"}, /* DOS access or SpeedStor 12-bit FAT
+ extended partition */
+ {0xe3, "DOS R/O"}, /* DOS R/O or SpeedStor */
+ {0xe4, "SpeedStor"}, /* SpeedStor 16-bit FAT extended
+ partition < 1024 cyl. */
+ {0xeb, "BeOS fs"},
+ {0xee, "EFI GPT"}, /* Intel EFI GUID Partition Table */
+ {0xef, "EFI (FAT-12/16/32)"},/* Intel EFI System Partition */
+ {0xf0, "Linux/PA-RISC boot"},/* Linux/PA-RISC boot loader */
+ {0xf1, "SpeedStor"},
+ {0xf4, "SpeedStor"}, /* SpeedStor large partition */
+ {0xf2, "DOS secondary"}, /* DOS 3.3+ secondary */
+ {0xfd, "Linux raid autodetect"},/* New (2.2.x) raid partition with
+ autodetect using persistent
+ superblock */
+ {0xfe, "LANstep"}, /* SpeedStor >1024 cyl. or LANstep */
+ {0xff, "BBT"}, /* Xenix Bad Block Table */
+ { 0, 0 }
+};
diff --git a/utils/jztool/Makefile b/utils/jztool/Makefile
new file mode 100644
index 0000000000..d1bbae578c
--- /dev/null
+++ b/utils/jztool/Makefile
@@ -0,0 +1,47 @@
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+
+CFLAGS += -Wall -Wextra -Iinclude -I../../tools/ucl/include -I../../lib/microtar/src
+OUTPUT = jztool
+
+ifdef RELEASE
+CFLAGS += -Os -DNDEBUG
+else
+CFLAGS += -O0 -ggdb
+endif
+
+LIBSOURCES := src/buffer.c src/context.c src/device_info.c \
+ src/identify_file.c src/ucl_unpack.c src/usb.c src/x1000.c
+SOURCES := $(LIBSOURCES) jztool.c
+EXTRADEPS := libucl.a libmicrotar.a
+
+CPPDEFINES := $(shell echo foo | $(CROSS)$(CC) -dM -E -)
+
+ifeq ($(findstring WIN32,$(CPPDEFINES)),WIN32)
+# TODO: support Windows
+else
+ifeq ($(findstring APPLE,$(CPPDEFINES)),APPLE)
+# Mac, tested on x86 only -- may need to adjust paths if building on ARM.
+# paths should work with homebrew libusb.
+LIBUSB_CFLAGS ?= -I/usr/local/include/libusb-1.0
+ifdef STATIC
+LIBUSB_LDOPTS ?= /usr/local/lib/libusb-1.0.a -framework IOKit -framework CoreFoundation
+else
+LIBUSB_LDOPTS ?= -L/usr/local/lib -lusb-1.0
+endif
+else
+# Linux; note for static builds you need to build a copy of libusb without
+# udev support and specify the includes / libs manually
+LIBUSB_CFLAGS ?= `pkg-config --cflags libusb-1.0`
+LIBUSB_LDOPTS ?= `pkg-config --libs libusb-1.0`
+endif
+endif
+
+CFLAGS += $(LIBUSB_CFLAGS)
+LDOPTS += $(LIBUSB_LDOPTS)
+
+include ../libtools.make
diff --git a/utils/jztool/README.md b/utils/jztool/README.md
new file mode 100644
index 0000000000..72c630c6c3
--- /dev/null
+++ b/utils/jztool/README.md
@@ -0,0 +1,135 @@
+# jztool -- Ingenic device utility & bootloader installer
+
+The `jztool` utility can help install, backup, and restore the bootloader on
+Rockbox players based on a supported Ingenic SoC (currently only the X1000).
+
+## Running jztool
+
+### Getting a bootloader
+
+To use `jztool` you need to compile or download a bootloader for your player.
+It's recommended to use only official released bootloaders, since bootloaders
+compiled from Git are not tested and might be buggy.
+
+You can download released bootloaders from <https://download.rockbox.org/>.
+
+The bootloader file is named after the target: for example, the FiiO M3K
+bootloader is called `bootloader.m3k`. The FiiO M3K is used as an example
+here, but the instructions apply to all X1000-based players.
+
+Use `jztool --help` to find out the model name of your player.
+
+### Entering USB boot mode
+
+USB boot mode is a low-level mode provided by the CPU which allows a computer
+to load firmware onto the device. You need to put your player into this mode
+manually before using `jztool` (unfortunately, it can't be done automatically.)
+
+To connect the player in USB boot mode, follow these steps:
+
+1. Ensure the player is fully powered off.
+2. Plug one end of the USB cable into your player.
+3. Hold down your player's USB boot key (see below).
+4. Plug the other end of the USB cable into your computer.
+5. Let go of the USB boot key.
+
+The USB boot key depends on your player:
+
+- FiiO M3K: Volume Down
+- Shanling Q1: Play
+- Eros Q: Menu
+
+### Linux/Mac
+
+Run the following command in a terminal. Note that on Linux, you will need to
+have root access to allow libusb to access the USB device.
+
+```sh
+# Linux / Mac
+# NOTE: root permissions are required on Linux to access the USB device
+# eg. with 'sudo' or 'su -c' depending on your distro.
+$ ./jztool fiiom3k load bootloader.m3k
+```
+
+### Windows
+
+To allow `jztool` access to your player in USB boot mode, you need to install
+the WinUSB driver. The recommended way to install it is using Zadig, which
+may be downloaded from its homepage <https://zadig.akeo.ie>. Please note
+this is 3rd party software not maintained or supported by Rockbox developers.
+(Zadig will require administrator access on the machine you are using.)
+
+When running Zadig you must select the WinUSB driver; the other driver options
+will not work properly with `jztool`. You will have to select the correct USB
+device in Zadig. All X1000-based players use the same USB ID while in USB boot
+mode, listed below. NOTE: the device name may show only as "X" and a hollow
+square in Zadig. The IDs will not change, so those are the most reliable way
+to confirm you have selected the correct device.
+
+```
+Name: Ingenic Semiconductor Co.,Ltd X1000
+USB ID: A108 1000
+```
+
+Assuming you installed the WinUSB driver successfully, open a command prompt
+in the folder containing `jztool`. Administrator access is not required for
+this step.
+
+Type the following command to load the Rockbox bootloader:
+
+```sh
+# Windows
+$ jztool.exe fiiom3k load bootloader.m3k
+```
+
+## Using the recovery menu
+
+If `jztool` runs successfully your player will display the Rockbox bootloader's
+recovery menu. If you want to permanently install Rockbox