OPTION COLLAPSE TRUE
SPLIT ARGUMENT$ BY " " TO arg$ SIZE amount
IF amount < 2 THEN
PRINT "Usage: ", arg$[0], " <file>"
END
ENDIF
IF NOT(FILEEXISTS(arg$[1])) THEN
PRINT "File ", arg$[1], " not found!"
END 1
END IF
FileSize = FILELEN(arg$[1])
FileData = MEMORY(FileSize)
OPEN arg$[1] FOR READING AS myfile
GETBYTE FileData FROM myfile SIZE FileSize
CLOSE FILE myfile
FileDest = MEMORY(FileSize+(FileSize/127))
pos = 0
amount_rle = 0
amount_raw = 0
chunk_rle = -1
chunk_raw = -1
FOR x = 0 TO FileSize-2
IF PEEK(FileData+x) = PEEK(FileData+x+1) AND PEEK(FileData+x+1) = PEEK(FileData+x+2) THEN
IF amount_raw > 0 THEN
POKE FileDest+pos, 128|amount_raw
FOR y = chunk_raw TO x
POKE FileDest+pos+1, PEEK(FileData+y)
INCR pos
NEXT
chunk_raw = -1
amount_raw = 0
END IF
chunk_rle = PEEK(FileData+x)
INCR amount_rle
IF amount_rle = 125 THEN
POKE FileDest+pos, amount_rle+2
POKE FileDest+pos+1, chunk_rle
chunk_rle = -1
amount_rle = 0
INCR pos, 2
INCR x, 2
END IF
ELSE
IF amount_rle > 0 THEN
POKE FileDest+pos, amount_rle+2
POKE FileDest+pos+1, chunk_rle
INCR pos, 2
INCR x, 2
chunk_rle = -1
amount_rle = 0
END IF
INCR amount_raw
IF chunk_raw = -1 THEN chunk_raw = x
IF amount_raw = 127 THEN
POKE FileDest+pos, 128|amount_raw
FOR y = chunk_raw TO x
INCR pos
POKE FileDest+pos, PEEK(FileData+y)
NEXT
INCR pos
amount_raw = 0
chunk_raw = -1
END IF
ENDIF
NEXT
IF amount_raw > 0 THEN
POKE FileDest+pos, 128|(amount_raw+1)
FOR y = chunk_raw TO x
INCR pos
POKE FileDest+pos, PEEK(FileData+y)
NEXT
END IF
IF amount_raw = 0 THEN
POKE FileDest+pos, 128|1
INCR pos
POKE FileDest+pos, PEEK(FileData+FileSize-1)
END IF
IF amount_rle > 0 THEN
POKE FileDest+pos, amount_rle+2
POKE FileDest+pos+1, chunk_rle
INCR pos, 2
END IF
PRINT "Compression ratio: ", 100-pos*100/FileSize, "%. ";
newname$ = CONCAT$(arg$[1], ".rle")
OPEN newname$ FOR WRITING AS myfile
PUTBYTE FileDest TO myfile SIZE pos
CLOSE FILE myfile
PRINT "File '", arg$[1], "' compressed with RLE and saved as '", newname$, "'."
FREE FileData
FREE FileDest
END