[Android Software/Hacking General [Developers Only]] makers_mark:
RUN_length_imager_v1.2.bat

@echo off
setlocal enabledelayedexpansion
color 0b
set "vers=1.2"
title Run Length Imager v%vers%
set "device_dir=sdcard"
set "partitionfind=mmc"
set autozero=sure
set outfiletype=png
set autoopen=sure
set "outfilefolder=output"
set "loglevel=-loglevel debug"
set "hidebanner=-hide_banner"
set "adblog=>>"%~dp0sys\adb_log.txt" 2>&1"
set "ffmlog=>>"%~dp0sys\ffmpeg_log.txt" 2>&1"
IF "%~1"=="-d" (
set ffmlog=
set adblog=
set "loglevel=-loglevel debug"
set hidebanner=
mode con:cols=1000 lines=4000
color 07
shift
)
cd /d "%~dp0"
if not exist "%~dp0%outfilefolder%\" mkdir "%~dp0%outfilefolder%"
if exist "%~dp0sys\adb_log.txt" del /q "%~dp0sys\adb_log.txt"
if exist "%~dp0sys\ffmpeg_log.txt" del /q "%~dp0sys\ffmpeg_log.txt"
if exist "%~dp0sys\rli_log.txt" del /q "%~dp0sys\rli_log.txt"
if exist "%~dp0sys\needfiles" del /q "%~dp0sys\needfiles"
if not exist "%~dp0bin\ffmpeg.exe" echo.FFMPEG Program "%~dp0bin\ffmpeg.exe">>"%~dp0sys\needfiles"
if not exist "%~dp0bin\rlimager1.2.exe" echo.rlimager1.2.exe "%~dp0bin\rlimager1.2.exe">>"%~dp0sys\needfiles"
if exist "%~dp0sys\needfiles" goto :help
if not exist "%~dp0sys\definitions" call :make_definitions_file
if "[%~1]" neq "[]" if exist "%~1" echo.%1>"%~dp0sys\last_file"
if exist "%~dp0sys\settings" (call :load_settings) else (
set "maxcount=0"
set "offset=0"
set /a "bpp=4"
set "pixel_format=bgr0"
set "line_length=50,1,180"
set "rldecode_on=1"
call :save_settings
)
if exist "%~dp0sys\last_file" call :load_last_file
goto :menu

:help
echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
echo.The following necessary file^(s^) are not found in their proper location:
echo.&echo.
type "%~dp0sys\needfiles"
echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
pause>nul
goto :egress

:make_definitions_file
cls&echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
if not exist "%~dp0sys\" mkdir "%~dp0sys"
echo.Building FFmpeg Pixel Format List..
echo.This should only take a minute...&echo.
if exist "%~dp0sys\definitions" del /q "%~dp0sys\definitions"
echo.rgb565 2 >>"%~dp0sys\definitions"
echo.bgr565 2 >>"%~dp0sys\definitions"
for /f "skip=1 tokens=2" %%p in ('bin\ffmpeg -pix_fmts 2^>^&1^|findstr /rxic:"^I.*"') do (
%ffmlog%"%~dp0bin\ffmpeg.exe" -f rawvideo -s 1x1 -pix_fmt rgba -i "%~dp0sys\getres" -f rawvideo -s 1x1 -pix_fmt %%p -y "%~dp0sys\%%p"
for %%? in ("%~dp0sys\%%p") do if not "%%~z?"=="0" set /a bval=%%~z?/3&echo.%%~n? !bval!>>"%~dp0sys\definitions"
del /q "%~dp0sys\%%p"
)
echo.Finished!&call :load_settings
goto :eof

:make_images
call :drawhead
call :drawsettings
if defined list (set "for_type=for /l") else (set "for_type=for")
for %%p in (%pixel_format%) do (
call :setbpp %%p
if "!rldecode_on!"=="1" (
set "out_file=decoded_raw_!bpp!_byte_%in_filename%"
set "out_path=%~dp0%outfilefolder%\%in_filename%_max_%maxcount%_offset_%offset%"
if not exist "!out_path!\" mkdir "!out_path!"
if not exist "!out_path!\!out_file!" (echo.Decoding !bpp! byte rle)&("%~dp0bin\rlimager1.2.exe" -d !bpp! -m %maxcount% -o %offset% < %file% > "!out_path!\!out_file!")||(call :rli_help&goto :menu)
for %%? in ("!out_path!\!out_file!") do set /a "out_filesize=%%~z?"
if not exist "!out_path!\%%p\" mkdir "!out_path!\%%p"
if defined autoopen start "" "!out_path!\%%p\"
%for_type% %%R in (%line_length%) do (
set /a height=!out_filesize!/%%R/!bpp!
echo.Using ffmpeg to generate %%Rx!height! image from %%p pixel format.
if !height! NEQ 0 %ffmlog%"%~dp0bin\ffmpeg.exe" %hidebanner% %loglevel% -f rawvideo -vcodec rawvideo -pix_fmt %%p -s %%Rx!height! -i "!out_path!\!out_file!" -vframes 1 -y "!out_path!\%%p\%%Rx!height!.%outfiletype%"
)
) else (
set "out_path=%~dp0%outfilefolder%\%in_filename%_no_rldecode\%%p"
if not exist "!out_path!\" mkdir "!out_path!"
if defined autoopen start "" "!out_path!\"
%for_type% %%R in (%line_length%) do (
set /a height=!in_filesize!/%%R/!bpp!
if /i "%%p"=="monow" set /a height*=8
if /i "%%p"=="monob" set /a height*=8
echo.Using ffmpeg to generate %%Rx!height! image from %%p pixel format.
if !height! NEQ 0 %ffmlog%"%~dp0bin\ffmpeg.exe" %hidebanner% %loglevel% -f rawvideo -vcodec rawvideo -pix_fmt %%p -s %%Rx!height! -i %file% -vframes 1 -y "!out_path!\%%Rx!height!.%outfiletype%"
)
)
if "!auto_turn_back_on!"=="1" (set "rldecode_on=1"&set auto_turn_back_on=)
)
goto :eof

:rle_image
set "out_path=%outfilefolder%\Run Length Encoded_%in_filename%"
for %%p in (%pixel_format%) do (
call :setbpp %%p
if "%%p"=="rgb0" (set "zoffset=8"&set "zero=8")
if "%%p"=="0rgb" (set "zoffset=5"&set "zero=8")
if "%%p"=="bgr0" (set "zoffset=8"&set "zero=8")
if "%%p"=="0bgr" (set "zoffset=5"&set "zero=8")
set "out_file=encoded_raw_!bpp!_byte_%in_filename%"
if not exist "%~dp0!out_path!\" mkdir "%~dp0!out_path!\"
%ffmlog%"%~dp0bin\ffmpeg.exe" %hidebanner% %loglevel% -i %file% -f rawvideo -vcodec rawvideo -pix_fmt %%p -y "%~dp0!out_path!\raw_%%p"
if defined autozero (echo.Encoding !bpp! byte rle&"%~dp0bin\rlimager1.2.exe" -z 8 -o !zoffset! -i "%~dp0!out_path!\%in_filename%_rl_encoded_with_!bpp!_byte_pattern_and_%%p_pixel_format" -e !bpp! < "%~dp0!out_path!\raw_%%p" > "%~dp0!out_path!\%in_filename%_rl_encoded_with_!bpp!_byte_pattern_and_%%p_pixel_format"||(call :rli_help&goto :menu)
) else (echo.Encoding !bpp! byte rle&"%~dp0bin\rlimager1.2.exe" -e !bpp! < "%~dp0!out_path!\raw_%%p" > "%~dp0!out_path!\%in_filename%_rl_encoded_with_!bpp!_byte_pattern_and_%%p_pixel_format"||(call :rli_help&goto :menu))
set zoffset=&set zero=
)
if defined autoopen start "" "%~dp0!out_path!\"
goto :eof

:rli_help
echo.There was a problem encoding^/decoding the file:&echo.%file%
echo.Bpp is: %bpp%&echo.Pixel format is: %pixel_format%&echo.Offset is: %offset%
echo.Max run is: %maxcount%&echo.Width is: %line_length%&echo.Working file name is: %in_filename%&echo.&pause >nul
goto :eof

:load_last_file
set "encode="
set /p file=<"%~dp0sys\last_file"
for %%? in (%file%) do set /a "in_filesize=%%~z?" &set "in_filename=%%~n?" &set "ext=%%~x?"
if [%ext%]==[] goto :eof
if "%ext%"==".jpg" set "encode=true"
if "%ext%"==".png" set "encode=true"
if "%ext%"==".bmp" set "encode=true"
if "%ext%"==".jpeg" set "encode=true"
goto :eof

:load_settings
<"%~dp0sys\settings" (
set /p pixel_format=
set /p bpp=
set /p offset=
set /p maxcount=
set /p line_length=
set /p rldecode_on=
)
set /a bpp
echo.%line_length%|findstr ".*,.*,"&&set "list=1"||set list=
goto :eof

:save_settings
>"%~dp0sys\settings" (
echo.%pixel_format%
echo.%bpp%
echo.%offset%
echo.%maxcount%
echo.%line_length%
echo.%rldecode_on%
)
goto :eof

:menu
set auto_turn_back_on=&call :load_last_file&call :drawhead&call :drawsettings
echo.&echo.&echo.1 - Make Image(s)
echo.&echo.2 - Change Output Line Length ^(width^)
echo.&echo.3 - Change Pixel Format
echo.&echo.4 - Use ADB To List/Pull A Partition
echo.&if defined rldecode_on (echo.5 - Turn Off Run Length Decoding) else (echo.5 - Turn On Run Length Decoding)
echo.&if defined rldecode_on (echo.6 - Change Offset) else (echo.	- - Change Offset ^(run length decoding is off^))
echo.&if defined rldecode_on (echo.7 - Change Max Run Length) else (echo.	- - Change Max Run Length ^(run length decoding is off^))
echo.&if defined encode (echo.8 - Encode image) else (echo.8 - Extract Jpgs From File)
echo.&echo.9 - Exit&echo.
choice /n /m "Select A Menu Number:" /C:123456789
if errorlevel 1 set k=1
if errorlevel 2 set k=2
if errorlevel 3 set k=3
if errorlevel 4 set k=4
if errorlevel 5 set k=5
if errorlevel 6 set k=6
if errorlevel 7 set k=7
if errorlevel 8 set k=8
if errorlevel 9 set k=9
if %k%==1 call :make_images
if %k%==8 if "%encode%"=="true" (call :rle_image) else (call :jextract %file%)
if %k%==4 call :getpartitions
if %k%==3 call :change_pf
if %k%==2 call :change_line_length
if %k%==5 call :rle_toggle
if %k%==6 if defined rldecode_on call :change_offset
if %k%==7 if defined rldecode_on call :change_max_run
if %k%==9 goto :egress
goto :menu

:jextract
call :drawhead&call :drawsettings
set "out_path=%~dp0%outfilefolder%\%in_filename%_extracted_jpgs"
if not exist "%out_path%\" mkdir "%out_path%"
echo.&echo.Working...
"%~dp0bin\rlimager1.2.exe" -o %offset% -j "%out_path%\%in_filename%" <%file%
if defined autoopen start "" "%out_path%\"
echo.&echo.&echo Press any key to continue to the main menu..
pause>nul
goto :eof

:change_max_run
call :drawhead&call :drawsettings
echo.over 4 billion times. With a 3 Bpp rle pattern the highest value 0xFF will repeat the
echo.pixel 255 times maximum. And with a 2 Bpp rle pattern the value 0xFFFF will repeat
echo.a pixel 65535 times.&echo.
echo.When searching this way you need to set the max pixel run count to around ~1000-2000 to avoid
echo.unusable image files that can take forever to generate.&echo.
echo.Just press enter for a default value of 0 which will let the decoding process run its
echo.natural course.&echo.
set /p maxcount=Max pixel run:||set "maxcount=0"
call :save_settings
goto :eof

:change_offset
call :drawhead&call :drawsettings
echo.Enter the byte offset for the file.&echo.
echo.This should always be 0 when dealing with pure rle image files.
echo.The reason it is in here is because if you load an entire file with data/images all
echo.mixed together; the start of the Pixel count read for an image might just not be in
echo.the right spot, and the count will be read as color data instead of count data, resulting
echo.in really long^/short runs and no image. If using a whole partition^/file and a standard
echo.0 as the offset at several resolutions isn't generating the image you are looking for,
echo.taking the offset up, 1 by 1 until you get to 7 for 4 Bpp raw files, or an offset of
echo.3 for 2 ^& 3 Bpp raw files. It is advised to set your max pixel run count to ^~1000-2000
echo.when searching through complete files/partitions like this.&echo.
echo.This is the same thing as deleting "x" bytes from the beginning of the file.&echo.
echo.If you are using an image that starts with the count byte^(s^) at byte 1 in the file, then
echo.you don't have to worry about it.&echo.
echo.Just press enter for the default offset of 0.&echo.
set /p offset=Offset:||set "offset=0"
call :save_settings
goto :eof

:egress
"%~dp0bin\adb.exe" kill-server>nul 2>&1
endlocal&exit
goto :eof

:rle_toggle
if defined rldecode_on (set rldecode_on=) else (set "rldecode_on=1")
call :save_settings
goto :eof

:change_pf
:keepitinthecall
call :drawhead
call :drawsettings
echo.Enter the pixel format to use. The run length decoder will automatically adjust format accordingly.
echo.You may enter multiple pixel formats, but of course if will take longer and produce double the
echo.images if you enter two, or triple if you choose three. If you enter multiple pixel formats
echo.seperate them with a space or a comma. The bytes per pixel number seen at the top of the screen
echo.will only reflect the correct value when one pixel format is chosen, this however will have
echo.no bearing when you go to make images as the bpp is determined before each set of images is made.&echo.
echo.Note that any pixel format over 4 bytes per pixel will probably never be used in Android, for the
echo.purpose of displaying a static image at least.
echo.Threre is no run length decoding of those pixel formats over 4 bytes per pixel as of right now.&echo.
echo.The ones listed below, grouped by their bytes per pixel, are some of the more common pixel formats.
echo.Hit enter to see all input formats available with your FFmpeg build.
echo.&echo.Enter pixel formats in LOWER CASE ONLY.&echo.
echo.Enter "build" if you have updated your ffmpeg, and would like to update the pixel formats also.&echo.
echo.Enter "show" to show available pixel formats with your ffmpeg build.
echo.Common 2 Bpp android pixel formats ^[rgb565le, bgr565le^]
echo.Common 3 Bpp android pixel formats ^[rgb24, bgr24^]
echo.Common 4 Bpp android pixel formats ^[rgb0, 0rgb, 0bgr, bgr0, rgba, argb, abgr, bgra^]&echo.
set "old=%pixel_format%"
set /p pixel_format=Pixel format^(s^):||goto :eof
if /i "%pixel_format%"=="build" (set "pixel_format=%old%"&call :make_definitions_file&goto :keepitinthecall)
if /i "%pixel_format%"=="show" (set "pixel_format=%old%"&call :show_pixel_formats&goto :keepitinthecall)
call :setbpp %pixel_format%
call :save_settings
goto :eof

:setbpp
for /f "tokens=1,2" %%a in ('type "%~dp0sys\definitions"') do if /i "%~1"=="%%a" set /a "bpp=%%b"
if %bpp% GEQ 5 if defined rldecode_on (set "auto_turn_back_on=1"&set rldecode_on=)
if %bpp% EQU 1 if defined rldecode_on (set "auto_turn_back_on=1"&set rldecode_on=)
call :save_settings
goto :eof

:show_pixel_formats
cls&echo.Input pixel formats supported with your FFmpeg build:
for /f "skip=1 tokens=2,4" %%A in ('bin\ffmpeg -pix_fmts 2^>^&1^|FINDSTR /rxic:"^I.*"') DO echo.%%A---	%%B ^<^<^<BITS per pixel
echo.&echo.Press enter to continue...
pause>nul
goto :eof

:drawsettings
echo.Working Name: %in_filename%&echo.File Name: %file%&echo.Size: %in_filesize% bytes
echo.__________________________________&echo.______________________________________&echo.
echo.Pixel Format: %pixel_format%&echo.Line Length: %line_length%
if defined rldecode_on (
echo.Rle Format: %bpp% byte pp&echo.Max Run Length: %maxcount% pixels
echo.Offset: %offset%) else (echo.&echo.Run Length Decoding Is Turned Off.&echo.)
echo.______________________________________&echo.
goto :eof

:change_line_length
call :drawhead&call :drawsettings
echo.Enter the line length ^(width^) that you want to use. You can enter several, SEPERATED BY SPACES;
echo.or you can use a range SEPERATED BY COMMAS, in this format: start resolution, skips, ending resolution.&echo.
echo.Example: If you want to use the widths of 150 25 3000 400 98 16. You would enter in any order:
echo.150 25 3000 400 16 98&echo.
echo.Example: If you want a line length starting at 100 pixels going to 1200 pixels, while skipping to every
echo.10th pixel. You would enter:
echo.100,10,1200&echo.
set /p "line_length=Line length:"
echo.%line_length%|findstr ".*,.*,.*"&&set "list=1"||set list=
call :save_settings
goto :eof

:drawhead
cls&echo.&echo.___________________________________-_-
echo.__________________________________&echo.&echo.Run Length Imager: v%vers% by makers_mark
echo.__________________________________&echo.______________________________________&echo.
goto :eof

:getpartitions
if not exist "%~dp0partitions\" mkdir "%~dp0partitions"
call :drawhead&set /a index=1
"%~dp0bin\adb.exe" -d start-server
if %ERRORLEVEL% GTR 0 call :adb_error&goto :eof
for /f "skip=1 tokens=3,4" %%s in ('bin\adb.exe -d shell cat /proc/partitions^|findstr /rxic:".*%partitionfind%.*"') do (
if not "%%s"=="" (call set /a "_size[!index!]=%%s"&&call set "_partition[!index!]=%%t") else (set /a index=1)
call set /a index+=1
)
if %ERRORLEVEL% GTR 0 call :adb_error&goto :eof
set /a index-=1
echo. Partition	Size&echo.
for /l %%c in (1,1,%index%) do (
if %%c LSS 10 (echo. %%c. !_partition[%%c]!	!_size[%%c]!) else (
echo.%%c. !_partition[%%c]!	!_size[%%c]!)
)
echo.&echo.If you want to pull one of these partitions from your device, enter the number
echo.to the left of it and press enter. Just press enter to go back to the Main Menu&echo.
set /p _pick=:||goto :eof
2>nul set /a _pick=%_pick%/1 || GOTO :eof
IF %_pick% LSS 1 GOTO :eof
if %_pick% GTR %index% goto :eof
cls&echo.&echo.&echo.WARNING:	WARNING:	WARNING:	WARNING:	WARNING:&echo.WARNING:	WARNING:	WARNING:	WARNING:	WARNING:
echo.WARNING:	WARNING:	WARNING:	WARNING:	WARNING:&echo.WARNING:	WARNING:	WARNING:	WARNING:	WARNING:&echo.&echo.&echo.&echo.&echo.
echo.Issuing this command:&echo.
call echo.bin^\adb.exe -d shell dd if^=^/dev^/block^/%%_partition[!_pick!]%% of^=^/%device_dir%^/%%_partition[!_pick!]%%
echo.&echo.PLEASE READ THIS TWICE....&echo.
echo.DD is a VERY powerful tool, and if the output directory^/file; listed after ^"of^=^" is not the
echo.name of the partition you chose to pull, DO NOT CONTINUE. If you are not sure what you are doing;
echo.what this command is, or what you are even looking at. DO NOT CONTINUE.&echo.
set "guess=%random%"
echo.Enter this number to continue: %guess%
echo.&set /p answer=:||goto :eof
if not "%guess%"=="%answer%" goto :eof
echo.&echo.Copying data into a file on your device...
call echo."%~dp0bin\adb.exe" -d shell "dd if=/dev/block/%%_partition[!_pick!]%% of=/%device_dir%/%%_partition[!_pick!]%%"|cmd /v:on%adblog%&&echo.&&echo.Copying file from your device to your computer...&&call echo."%~dp0bin\adb.exe" -d pull "/%device_dir%/%%_partition[!_pick!]%%" "%~dp0partitions\%%_partition[!_pick!]%%"|cmd /v:on%adblog%&&echo.&&echo.Deleting the file from your device...&&call echo."%~dp0bin\adb.exe" -d shell rm "/%device_dir%/%%_partition[!_pick!]%%"|cmd /v:on%adblog%
call echo."%~dp0partitions\%%_partition[!_pick!]%%">"%~dp0sys\last_file"
echo.&echo.&echo.Finished. The partition has been loaded and is saved as:&echo.&call echo."%~dp0partitions\%%_partition[!_pick!]%%"&echo.&echo.Press any key to continue.
call :save_settings
pause>nul
goto :eof

:adb_error
echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
echo.	ADB is not connected, working properly, or you have
echo.	more than one device connected.
echo.	Try "Safely Removing" your device from your computer.
echo.	Then unplug your usb cable, and reinsert it.
echo.&echo.&echo.&echo.&echo.&echo.&echo.&echo.
pause>nul
goto :eof

rlimager1.2.c

/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
&	NOTICE:
&	May 5th, 2014
&
&	makers_mark @ xda-developers.com
& http://xdaforums.com/showthread.php?t=2764354
&
&	Original source:
&	https://android.googlesource.com/platform/build/+/b6c1cf6de79035f58b512f4400db458c8401379a/tools/rgb2565/to565.c
&	Based off of the original to565.c program to convert raw rgb888 r=8 g=8 b=8 images
&	to, 2 byte count, 2 byte color run length encoded rgb565 r=5 g=6 b=5 files.
&	Mainly, if not always to my knowledge, used for creating initlogo.rle files for kernel splash
&	screens.
&
&	Added decoding of 2, 3, and 4 byte rgb(x) patterns
&	Added encoding of 3 and 4 byte rgb(x) patterns
&	Added byte offsets and maximum pixel runs for decoding files not totally
&	encoded in a run length manner
& Version 1.2 added:
& Jpeg extractor, to pull jpegs from any file or drive/device image
& A zero byte writer, to undo what ffmpeg does to rgb0, 0rgb, bgr0, and 0bgr pixel formats

*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

unsigned int _CRT_fmode = _O_BINARY;
static char fileName[1024];
void zeroBytes(long long, long, char *);
void jpegExtract(char *, unsigned long long);
void headerToFooter(int);
int getFilename(char *);
void decode_rgb16_rle(unsigned int, unsigned long long int);
void decode_rgb24_rle(unsigned int, unsigned long long int);
void decode_rgbx32_rle(unsigned long int, unsigned long long int);
void encode_rgb16_rle(void);
void encode_rgb24_rle(void);
void encode_rgbx32_rle(void);

void zeroBytes(long long offset, long z, char *inputFile)
{
int readByte;
FILE *zeroStream;
FILE *inStream;
long long int cursorPosition;
char outputFile[1024];

sprintf(outputFile, "%s.zero", inputFile);
if ((inStream = fopen(inputFile, "rb")) == NULL){
fclose(inStream);
return;
}
if ((zeroStream = fopen(outputFile, "wb")) == NULL){
fclose(inStream);
fclose(zeroStream);
return;
}
fprintf(stderr,"\nZeroing every %ld bytes starting at %lld", z, offset);
fprintf(stderr,"\nInput file: %s", inputFile);
while ((readByte = fgetc(inStream)) != EOF){
cursorPosition = ftell(inStream);
if (((cursorPosition - offset) % z) == 0 && cursorPosition >= offset){
fputc(0,zeroStream);
}else{
fputc(readByte,zeroStream);
}
}
fclose(inStream);
fclose(zeroStream);
}

void jpegExtract(char outname[1024], unsigned long long o)
{
int readByte;
FILE *fileStream;
unsigned int header;

if (o != 0){
fseek(stdin, o, SEEK_SET);
}
while ((readByte = fgetc(stdin)) != EOF){
if (readByte == 0xff){
readByte = fgetc(stdin);
if (readByte == 0xd8){
readByte = fgetc(stdin);
if (readByte == 0xff){
readByte = fgetc(stdin);
if (readByte == 0xe0 || readByte == 0xe1){
header = 0x00ffd8ff | (readByte << 24);
if (!getFilename(outname)){
if ((fileStream = fopen(fileName, "wb")) == NULL){
fclose(fileStream);
return;
}
int streamNumber = fileno(fileStream);
fprintf(stderr, "\n%s", fileName);
write(streamNumber, &header, 4);
headerToFooter(streamNumber);
close(streamNumber);
continue;
}else{
break;
}
}
}
}
}
}
fclose(stdin);
}

void headerToFooter(int streamNumber)
{
short notFinished = 1;
int polarity = 1;
int readByte;

while((readByte = fgetc(stdin)) != EOF){
if (readByte == 0xff){
readByte = fgetc(stdin);
if (readByte == EOF){
readByte = 0xff;
write(streamNumber, &readByte, 1);
break;
}else if (readByte == 0xd8){
polarity += 1;
readByte = 0xd8ff;
write(streamNumber, &readByte, 2);
}else if (readByte == 0xd9){
polarity -= 1;
readByte = 0xd9ff;
write(streamNumber, &readByte, 2);
if (polarity == 0){
break;
}
}else{
readByte = 0x00ff | (readByte << 8);
write(streamNumber, &readByte, 2);
}
}else{
write(streamNumber, &readByte, 1);
}
}
}

int getFilename(char outputbase[1024])
{
unsigned int counter;
FILE *stream;

for (counter = 1; counter <= 99999; counter++){
sprintf(fileName, "%s_%05d.jpg", outputbase, counter);
if ((stream = fopen(fileName, "r+")) != NULL){
fclose(stream);
continue;
} else {
fclose(stream);
return(0);
}
}
fclose(stream);
return(1);
}

void decode_rgb16_rle(unsigned int m, unsigned long long int o)
{
unsigned short data[2], repeats;

if (o != 0){
fseek(stdin, o, SEEK_SET);
}

while(read(0,data,4) == 4){

if (data[0] > m){
continue;
}
for (repeats = 0; repeats < data[0]; repeats++){
write(1, &data[1], 2);
}
}
}

void decode_rgb24_rle(unsigned int m, unsigned long long int o)
{

unsigned char repeats, data[4];
unsigned long color;

if (o != 0){
fseek(stdin, o, SEEK_SET);
}

while(read(0, data, 4) == 4){

if (data[0] > m){
continue;
}
color = ((data[1]) | (data[2] << 8) | (data[3]) << 16);
for (repeats = 0;repeats < data[0]; repeats++){
write(1, &color, 3);
}
}
}

void decode_rgbx32_rle(unsigned long int m, unsigned long long int o)
{
unsigned long repeats;
unsigned long data[2];

if (o != 0){
fseek(stdin, o, SEEK_SET);
}

while(read(0, data, 8) == 8){
if (data[0] > m){
continue;
}
for (repeats = 0; repeats < data[0]; repeats++){
write(1, &data[1], 4);
}
}
}

void encode_rgbx32_rle(void)
{
unsigned long color, last, count;
count = 0;
while(read(0, &color, 4) == 4){
if (count){
if ((color == last) && (count != 0xFFFFFFFF)){
count++;
continue;
} else {
write(1, &count, 4);
write(1, &last, 4);
}
}
last = color;
count = 1;
}
if (count){
write(1, &count, 4);
write(1, &last, 4);
}
}

void encode_rgb16_rle(void)
{
unsigned short int last, color, count;

count = 0;
while(read(0, &color, 2) == 2){
if (count){
if ((color == last) && (count != 0xFFFF)){
count++;
continue;
} else {
write(1, &count, 2);
write(1, &last, 2);
}
}
last = color;
count = 1;
}
if (count){
write(1, &count, 2);
write(1, &last, 2);
}
}

void encode_rgb24_rle(void)
{
unsigned char count;
unsigned long int last, color;

count = 0;
while(read(0, &color, 3) == 3){
if (count){
if ((color == last) && (count != 0xFF)){
count++;
continue;
} else {
write(1, &count, 1);
write(1, &last, 3);
}
}
last = color;
count = 1;
}
if (count){
write(1, &count, 1);
write(1, &last, 3);
}
}

int usage(void){
fprintf(stderr, "\n\n\nUsage:\n\nrlimager.exe ([-e] [2-4] | [-d] [2-4] [-m] [max run] [-o] [offset]) < input_file > output_file\n\n");
fprintf(stderr, "Mandatory, one or the other\n\n");
fprintf(stderr, "-d (2-4)	Run Length Decode input_file from 2, 3, or 4 byte color pattern\n");
fprintf(stderr, "-e (2-4)	Run Length Encode input_file to 2, 3, or 4 byte color pattern\n");
fprintf(stderr, "-j (output root name)	Extract Jpegs from file. Output name can include a full path.\n");
fprintf(stderr, "-z (skip) -o (offset)	Zero every (skip) bytes, starting with (offset)\n\n");
fprintf(stderr, "Optional for [-d] decoding only:\n\n");
fprintf(stderr, "-m (max run)	Maximum pixel run to decode. Default is 0, which defaults to the maximum allowable for each color pattern\n");
fprintf(stderr, "-o (offset)	Offset (in bytes) to start decoding. Default is 0\n");
fprintf(stderr, "\n\nExamples:\n\nrlimager1.2 -d 4 -m 8064 < \"C:\\example_file.rle\" > \"C:\\output\\rle_decoded\\example_file.rgb0\"\n");
fprintf(stderr, "rlimager1.2 -j root_name < \"C:\\users\\downloads\\system.img\"\n\n");
fprintf(stderr, "Notice with the jpeg extractor example above you have to use: < \"inputfile\"\n\n");
fprintf(stderr, "rlimager1.2 -z 8 -o 5 -i \"C:\\output\\example_file.rle\" -e 4 < \"C:\\example_file.rgb0\" > \"C:\\output\\example_file.rle\"\n\n");
fprintf(stderr, "The above example rle encodes the input file, then takes the output file and zeros every eighth byte starting at 5\n");
fprintf(stderr, "You can also zero byte any file without doing it all on one line, like:\n\n");
fprintf(stderr, "rlimager1.2 -z 5 -o 8 -i \"C:\\file_to_be_zeroed_every_5th_byte_strarting_with_the_8th.raw\"\n");
return(1);
}

int main(int argc, char **argv)
{
unsigned int decode_opt = 0, encode_opt = 0;
unsigned long long int maxrun = 0;
long long int offset = 0;
long zeroByte = 0;
short jflag = 0;
char *d_string, *e_string, *m_string, *o_string, *j_string, *z_string, *inputFile;
int c;

while ((c = getopt (argc, argv, "i:z:j:m:o:e:d:")) != -1)
switch(c)
{

case 'i':
inputFile = optarg;
break;

case 'z':
z_string = optarg;
zeroByte = atol(z_string);
break;

case 'j':
jflag = 1;
j_string = optarg;
break;

case 'm':
m_string = optarg;
maxrun = atoll(m_string);
break;

case 'o':
o_string = optarg;
offset = atoll(o_string);
break;

case 'e':
e_string = optarg;
encode_opt = atoi(e_string);
break;

case 'd':
d_string = optarg;
decode_opt = atoi(d_string);
break;
}

if ((encode_opt > 1) && (encode_opt < 5)){

if (maxrun != 0 || decode_opt != 0){
usage();
return(1);
}

if (encode_opt == 2){
encode_rgb16_rle();
return(0);
}

if (encode_opt == 3){
encode_rgb24_rle();
}

if (encode_opt == 4){
encode_rgbx32_rle();
}

if (zeroByte){
zeroBytes(offset, zeroByte, inputFile);
}
return(0);
} else if (zeroByte){
zeroBytes(offset, zeroByte, inputFile);
return(0);

} else if ((decode_opt > 1) && (decode_opt < 5)){

if (encode_opt != 0){
usage();
return(1);
}

if (decode_opt == 2){
if (maxrun == 0){
maxrun = 0xFFFF;
}
fprintf(stderr, "Maximum pixel run set at %d\n",maxrun);
decode_rgb16_rle(maxrun, offset);
return(0);
}

if (decode_opt == 3){
if (maxrun == 0){
maxrun = 0xFF;
}
fprintf(stderr, "Maximum pixel run set at %d\n",maxrun);
decode_rgb24_rle(maxrun, offset);
return(0);
}

if (decode_opt == 4){
if (maxrun == 0){
maxrun = 0xFFFFFFFF;
}
fprintf(stderr, "Maximun pixel run set at %lld\n",maxrun);
decode_rgbx32_rle(maxrun, offset);
return(0);
}

return(0);
} else if (jflag){
jpegExtract(j_string, offset);
} else usage();

return(1);
}