Pastebin
API
tools
faq
paste
Login
Sign up
Please fix the following errors:
New Paste
Syntax Highlighting
/* || A Brief History It's 2018 and PRS; a rather commonly used non-supertrivial compression format has either never seen a piece of documentation or the documentation was lost through time. This has happened despite the first decompressor appearing around in the early 2000s (Nemesis' prsdec), which (did not?) appear to have a release of the source code and also shipped an anti-compressing compressor (basically an encoder that produced format compatible files, albeit larger as it did not attempt compression). A few years later, one named fuzziqer has also produced a compressor and decompressor combo, this time with a source release and a compressor which did actual compression. While the source did not ship with a license, and the author stated that using the source freely was fine as long as he would have been credited for the compression and decompression code, the source was not very well documented - as to truely describe the format and was not trivial to follow. Aaaand well... FraGag ported fuzziqer's utility to .NET and that's about it... nothing... */ /* || Why? Well, after a good while, the speed of the .NET implementation of PRS Compression/Decompression has started to bother me when using existing modding tools for Sonic Heroes and Sonic Adventure, two of SEGA published titles which have used this compression scheme employed since the era of the failed SEGA Saturn. Quite frankly, I thought that they could do with just a tiiny bit of optimization and/or perhaps simply more options for compression intensity - but the moment I started researching... well.. above. No documentation, only one piece of not yet fully optimized, uncommented source code and a port of it... and not much more - which surprised me especially given how much these libraries have been used over the overall course of time. I originally only planned to write a PRS Compressor/Decompressor in D as a small challenge, and to learn a bit of the programming language by writing my first program with it... However after I've seen the whole situation, and began to see possible optimizations as I dug through the non-trivial to understand source code - I thought it would just be straight up better to document the format entirely, while providing a new, better implementation for the communities. */ /* || PRS Specifics: Summary PRS is a LZ77 based compression algorithm with some RLE shenanigans whereby the file is split into blocks consisting of control bytes + data. (ctrlByte, byte[]) (ctrlByte, byte[]) (ctrlByte, byte[]) The control bytes contain variable length codes stored as bits (max length: 2 bits) which tell the decoder how to treat the individual bytes of data up till the next control byte. They are read in a right to left order, i.e. with `controlByte & 1` and bitshifted right in order to acquire the next entry. With that said, each block has an undefined data length in that there are no headers in any of the blocks in question. As variable length codes are added onto the control bytes from right to left, the control byte is written, following by the data related to it once the individual control byte is full. The variable length codes themselves consist of 3 modes, a direct byte copy, short copy and two variants of long copy as is to be seen below using run length encoding (size & offset). The dictionary from which the copying is performed is actually the last N bytes of data, hence this is also an algorithm using a sliding window for compression. */ /* || PRS Specifics: Control Byte Variable Length Codes The following is a listing of the various variable length codes packed into the individual control bytes: Mode 0 (Direct Byte) : 1 Mode 1 (Short Copy) : 00XX (XX stores the size) Mode 2 (Long Copy, Small Size) : 01 Mode 3 (Long Copy, Large Size) : 01 (This is not a typo, you will learn why later) The individual variable length codes also contain some additional information appended as regular bytes, these vary on the individual mode used. */ /* || PRS Specifics: Decoding a control byte example. As specified before, the bits in the control bytes are read from right to left order, therefore using the table of variable length codes above we can decode a control byte as such: Example control byte (binary) | 0101 1001 1 - Direct Byte 00XX - Short Copy 01 - Long Copy 0. - Short or Long Copy (the first bit of the next control byte would decide) In the case of the last opcode, the actual next control byte would be the next byte in a valid PRS file, assuming the byte array/file pointer has been correctly moved after each successive short/long and direct byte copy. */ /* || PRS Mode 0: Direct Byte (Opcode 1) A single byte is to be read from the data stream/array at the current pointer position. That's it. Decoding (Simplified): if (bit == 1) read and append byte to file stream Encoding (Simplified): Append Control Byte Variable Length Code: `1` and a byte to the file stream. */ /* || PRS Mode 1: Short Copy (Opcode 00) The length of the copy is in the range of 2-5 inclusive (2, 3, 4, 5) and stored directly inside the opcode read from the control byte (albeit as a 0-3 value, as the minimum copy length implicitly is 2, thus the value stored is `actual length - 2`). The actual offset for where to copy from is appended as a singular byte and is stored as 256 - positive offset, i.e. assuming the offset is `-5`, it would be stored as 256 - (-5*-1) = 251. Quick ways to convert to `256 - positive offset` format include `(offset & 0xFF)` and simply adding 256 to the number `offset + 256`. || || Example : Opcode : 00XX Could be: 0010 Which yields a size of 10 (binary) which is 2 (decimal). Offset the value back by 2 to get the actual length; 2 + 2 = 4. Then to obtain the offset, you would just read the next byte from the stream/file/byte array. */ /* || PRS Mode 2: Long Copy, Small Size (Opcode 01) An offset and size combination is written directly as 2 bytes to the array/file/stream with the offset taking 13 bits and size 3 bits. The maximum offset is thus 0x1FFF and size 0-7 bytes (albeit actually 2-9, as the 2 offset is applied here like before). The actual 2 bytes are packed as such: XXXX XXXX XXXX XYYY Where the X represent the offset and Y represent the size. The two bytes are written with the rightmost 8 bits written first and the leftmost 8 bits written last, thus is in Big Endian order. ---------- If the size is greater than 9, then you fall back to Mode 3 for compression as a greater size could not fit the 3 bits. In this mode, you cannot also encode a size of 2, as taking away 2 and writing it would cause 000 to be written to the size part of the short - which is reserved for falling back to PRS Mode 3 (See below). || || Example : Offset of 2100 and Size of 5: 2100 (decimal) = 0000 1100 0001 1100 3 (decimal) = 0000 0000 0000 0011 // 5 - 2, offset applied Packed in the XXXX XXXX XXXX XYYY format: 0110 0000 1110 0000 (2100 left shifted by 3) 0000 0000 0000 0011 (3) Final result: 0110 0000 1110 0011 First written byte would equal 1110 0011 and the second written byte would equal 0110 0000. */ /* || PRS Mode 3: Long Copy, Large Size A fallback of PRS Mode 2 where the size is greater than 9. Used by the decoder when the size in the first (right to left) 3 bits of mode 2 reads 0 (i.e. would be 2 (decimal) after incrementing). An additional byte is appended onto the stream/file/byte array which contains the length of the match (size) minus 1. */ /* The file is terminated with the variable length code 01 (long copy) and bytes 00 00 (no offset, no size). Nothing more needs to be explained that the reader could not come into conclusion with themselves or figure out from the source code. */
Optional Paste Settings
Category:
None
Cryptocurrency
Cybersecurity
Fixit
Food
Gaming
Haiku
Help
History
Housing
Jokes
Legal
Money
Movies
Music
Pets
Photo
Science
Software
Source Code
Spirit
Sports
Travel
TV
Writing
Tags:
Syntax Highlighting:
None
Bash
C
C#
C++
CSS
HTML
JSON
Java
JavaScript
Lua
Markdown (PRO members only)
Objective C
PHP
Perl
Python
Ruby
Swift
4CS
6502 ACME Cross Assembler
6502 Kick Assembler
6502 TASM/64TASS
ABAP
AIMMS
ALGOL 68
APT Sources
ARM
ASM (NASM)
ASP
ActionScript
ActionScript 3
Ada
Apache Log
AppleScript
Arduino
Asymptote
AutoIt
Autohotkey
Avisynth
Awk
BASCOM AVR
BNF
BOO
Bash
Basic4GL
Batch
BibTeX
Blitz Basic
Blitz3D
BlitzMax
BrainFuck
C
C (WinAPI)
C Intermediate Language
C for Macs
C#
C++
C++ (WinAPI)
C++ (with Qt extensions)
C: Loadrunner
CAD DCL
CAD Lisp
CFDG
CMake
COBOL
CSS
Ceylon
ChaiScript
Chapel
Clojure
Clone C
Clone C++
CoffeeScript
ColdFusion
Cuesheet
D
DCL
DCPU-16
DCS
DIV
DOT
Dart
Delphi
Delphi Prism (Oxygene)
Diff
E
ECMAScript
EPC
Easytrieve
Eiffel
Email
Erlang
Euphoria
F#
FO Language
Falcon
Filemaker
Formula One
Fortran
FreeBasic
FreeSWITCH
GAMBAS
GDB
GDScript
Game Maker
Genero
Genie
GetText
Go
Godot GLSL
Groovy
GwBasic
HQ9 Plus
HTML
HTML 5
Haskell
Haxe
HicEst
IDL
INI file
INTERCAL
IO
ISPF Panel Definition
Icon
Inno Script
J
JCL
JSON
Java
Java 5
JavaScript
Julia
KSP (Kontakt Script)
KiXtart
Kotlin
LDIF
LLVM
LOL Code
LScript
Latex
Liberty BASIC
Linden Scripting
Lisp
Loco Basic
Logtalk
Lotus Formulas
Lotus Script
Lua
M68000 Assembler
MIX Assembler
MK-61/52
MPASM
MXML
MagikSF
Make
MapBasic
Markdown (PRO members only)
MatLab
Mercury
MetaPost
Modula 2
Modula 3
Motorola 68000 HiSoft Dev
MySQL
Nagios
NetRexx
Nginx
Nim
NullSoft Installer
OCaml
OCaml Brief
Oberon 2
Objeck Programming Langua
Objective C
Octave
Open Object Rexx
OpenBSD PACKET FILTER
OpenGL Shading
Openoffice BASIC
Oracle 11
Oracle 8
Oz
PARI/GP
PCRE
PHP
PHP Brief
PL/I
PL/SQL
POV-Ray
ParaSail
Pascal
Pawn
Per
Perl
Perl 6
Phix
Pic 16
Pike
Pixel Bender
PostScript
PostgreSQL
PowerBuilder
PowerShell
ProFTPd
Progress
Prolog
Properties
ProvideX
Puppet
PureBasic
PyCon
Python
Python for S60
QBasic
QML
R
RBScript
REBOL
REG
RPM Spec
Racket
Rails
Rexx
Robots
Roff Manpage
Ruby
Ruby Gnuplot
Rust
SAS
SCL
SPARK
SPARQL
SQF
SQL
SSH Config
Scala
Scheme
Scilab
SdlBasic
Smalltalk
Smarty
StandardML
StoneScript
SuperCollider
Swift
SystemVerilog
T-SQL
TCL
TeXgraph
Tera Term
TypeScript
TypoScript
UPC
Unicon
UnrealScript
Urbi
VB.NET
VBScript
VHDL
VIM
Vala
Vedit
VeriLog
Visual Pro Log
VisualBasic
VisualFoxPro
WHOIS
WhiteSpace
Winbatch
XBasic
XML
XPP
Xojo
Xorg Config
YAML
YARA
Z80 Assembler
ZXBasic
autoconf
jQuery
mIRC
newLISP
q/kdb+
thinBasic
Paste Expiration:
Never
Burn after read
10 Minutes
1 Hour
1 Day
1 Week
2 Weeks
1 Month
6 Months
1 Year
Paste Exposure:
Public
Unlisted
Private
Folder:
(members only)
Password
NEW
Enabled
Disabled
Burn after read
NEW
Paste Name / Title:
Create New Paste
Hello
Guest
Sign Up
or
Login
Sign in with Facebook
Sign in with Twitter
Sign in with Google
You are currently not logged in, this means you can not edit or delete anything you paste.
Sign Up
or
Login
Public Pastes
I made $15,000 * 2 hours
CSS | 9 min ago | 0.99 KB
✅ API Glitch (Docs Leak)
CSS | 13 min ago | 0.99 KB
[TLF - A KING'S MEMORY]
55 min ago | 1.62 KB
ccounter.cpp
C++ | 4 hours ago | 3.61 KB
Untitled
5 hours ago | 3.94 KB
arasaka
C | 1 day ago | 3.14 KB
new
C | 1 day ago | 3.06 KB
old
C | 1 day ago | 3.06 KB
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the
Cookies Policy
.
OK, I Understand
Not a member of Pastebin yet?
Sign Up
, it unlocks many cool features!