From 90371f0a8df83127c426c5156943373b4642089b Mon Sep 17 00:00:00 2001 From: CrashOveride95 Date: Mon, 25 Jan 2021 22:21:15 -0500 Subject: [PATCH] Add RNC compression and make cpp preprocess asm --- Makefile | 43 +- README.md | 12 +- asm/rnc1.s | 507 +++++++++++++ asm/rnc2.s | 673 +++++++++++++++++ gziprules.mk | 19 + include/rnc.h | 24 + lib/rsp.s | 158 ++-- rnc1rules.mk | 9 + rnc2rules.mk | 9 + sm64.ld | 9 + src/game/memory.c | 11 + tools/.gitignore | 1 + tools/Makefile | 4 +- tools/rncpack.c | 1747 +++++++++++++++++++++++++++++++++++++++++++++ yay0rules.mk | 9 + 15 files changed, 3122 insertions(+), 113 deletions(-) create mode 100755 asm/rnc1.s create mode 100755 asm/rnc2.s create mode 100644 gziprules.mk create mode 100755 include/rnc.h create mode 100644 rnc1rules.mk create mode 100644 rnc2rules.mk create mode 100644 tools/rncpack.c create mode 100644 yay0rules.mk diff --git a/Makefile b/Makefile index c0d8816d..6dcc9ff2 100644 --- a/Makefile +++ b/Makefile @@ -58,10 +58,14 @@ else ifeq ($(SAVETYPE),sram) endif COMPRESS ?= yay0 -$(eval $(call validate-option,COMPRESS,yay0 gzip)) +$(eval $(call validate-option,COMPRESS,yay0 gzip rnc1 rnc2)) ifeq ($(COMPRESS),gzip) DEFINES += GZIP=1 SRC_DIRS += src/gzip +else ifeq ($(COMPRESS),rnc1) + DEFINES += RNC1=1 +else ifeq ($(COMPRESS),rnc2) + DEFINES += RNC2=1 else ifeq ($(COMPRESS),yay0) DEFINES += YAY0=1 endif @@ -427,6 +431,7 @@ export LANG := C # N64 tools YAY0TOOL := $(TOOLS_DIR)/slienc +RNCPACK := $(TOOLS_DIR)/rncpack ROMALIGN := $(TOOLS_DIR)/romalign BFSIZE := $(TOOLS_DIR)/bfsize FILESIZER := $(TOOLS_DIR)/filesizer @@ -607,35 +612,13 @@ $(BUILD_DIR)/levels/%/leveldata.bin: $(BUILD_DIR)/levels/%/leveldata.elf $(V)$(EXTRACT_DATA_FOR_MIO) $< $@ ifeq ($(COMPRESS),gzip) -# Compress binary file to gzip -$(BUILD_DIR)/%.gz: $(BUILD_DIR)/%.bin - $(call print,Compressing:,$<,$@) -ifeq ($(GZIPVER),std) - $(V)$(GZIP) -c -9 -n $< > $@ +include gziprules.mk +else ifeq ($(COMPRESS),rnc1) +include rnc1rules.mk +else ifeq ($(COMPRESS),rnc2) +include rnc2rules.mk else - $(V)$(GZIP) -c -12 -n $< > $@ -endif - -# Strip gzip header -$(BUILD_DIR)/%.szp: $(BUILD_DIR)/%.gz - $(call print,Converting:,$<,$@) - $(V)dd bs=10 skip=1 if=$< of=$@ - $(V)$(FILESIZER) $(<:.gz=.bin) $@ - -# convert binary szp to object file -$(BUILD_DIR)/%.szp.o: $(BUILD_DIR)/%.szp - $(call print,Converting GZIP to ELF:,$<,$@) - $(V)printf ".section .data\n\n.incbin \"$<\"\n" | $(AS) $(ASFLAGS) -o $@ -else -# Compress binary file -$(BUILD_DIR)/%.szp: $(BUILD_DIR)/%.bin - $(call print,Compressing:,$<,$@) - $(V)$(YAY0TOOL) $< $@ - -# convert binary szp to object file -$(BUILD_DIR)/%.szp.o: $(BUILD_DIR)/%.szp - $(call print,Converting YAY0 to ELF:,$<,$@) - $(V)printf ".section .data\n\n.incbin \"$<\"\n" | $(AS) $(ASFLAGS) -o $@ +include yay0rules.mk endif #==============================================================================# @@ -807,7 +790,7 @@ endif # Assemble assembly code $(BUILD_DIR)/%.o: %.s $(call print,Assembling:,$<,$@) - $(V)$(AS) $(ASFLAGS) -MD $(BUILD_DIR)/$*.d -o $@ $< + $(V)$(CPP) $(CPPFLAGS) $< | $(AS) $(ASFLAGS) -MD $(BUILD_DIR)/$*.d -o $@ # Assemble RSP assembly code $(BUILD_DIR)/rsp/%.bin $(BUILD_DIR)/rsp/%_data.bin: rsp/%.s diff --git a/README.md b/README.md index 9957555f..036a7b9b 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ I may attempt FlashRAM in the future. The repository supports targeting the iQue Player in addition to the N64. The iQue libultra is ***NOT*** compatible with N64 in many ways, so it is currently NOT possible to have one build for both consoles. -To target iQue, run make with the ``CONSOLE=BB`` argument. +To target iQue, run make with the ``CONSOLE=bb`` argument. ## Compression @@ -33,13 +33,19 @@ On average I'd estimate that the bottleneck on decompression is about 1-2 second To switch to gzip, run make with the ``COMPRESS=gzip`` argument. -Additionally, the repo also supports compressing with ``libdeflate-gzip``. This compresses at a slightly better ratio than standard ``gzip``, with no real downside from a decompression standpoint. +The repo also supports gziping with ``libdeflate-gzip``. This compresses at a slightly better ratio than standard ``gzip``, with no real downside from a decompression standpoint. To use ``libdeflate-gzip``, first clone the [repo](https://github.com/ebiggers/libdeflate), then make and make install it. Then run make for sm64 with ``GZIPVER=libdef`` in addition to ``COMPRESS=gzip`` -This argument makes the makefile use ``libdeflate`` with it's highest compression setting, ``-12``. +The repo also supports RNC (Rob Northen Compression). RNC has two methods. + +Method 1 is designed to compress as small as possible, while method 2 is designed so that decompression is as fast as possible. + +Both methods are fast. Method 1 has better compression than 2, so I suggest using method 1 if using RNC. + +To switch to RNC, run make with either ``COMPRESS=rnc1`` or ``COMPRESS=rnc2``, depending on preferred method. ## FAQ diff --git a/asm/rnc1.s b/asm/rnc1.s new file mode 100755 index 00000000..660e74fe --- /dev/null +++ b/asm/rnc1.s @@ -0,0 +1,507 @@ +/*------------------------------------------------------------------------------ +* PROPACK Unpack Source Code - Sony PSX, Method 1 +* +* Copyright (c) 1991-96 Rob Northen Computing, U.K. All Rights Reserved. +* +* Conversion from 68000 by Brian Watson, Iguana Entertainment Limited. +* Converted to compile with SGI 'as' 10/31/96 by Biscuit +* +* File: rnc1.s +* +* Date: 10.21.96 +*------------------------------------------------------------------------------ +*/ +/*------------------------------------------------------------------------------ +* Equates +*------------------------------------------------------------------------------ +*/ +#define HEADER_LEN 18 +#define crc_poly 0xa001 + +#define RAW_TABLE 0 +#define POS_TABLE (RAW_TABLE+16*8) +#define LEN_TABLE (POS_TABLE+16*8) +#define BUFSIZE (16*8*3) + +#define ra $31 /* ra */ +#define d0 $8 /* t0 */ +#define d1 $9 /* t1 */ +#define d2 $10 /* t2 */ +#define d3 $11 /* t3 */ +#define d4 $12 /* t4 */ +#define d5 $13 /* t5 */ +#define d6 $14 /* t6 */ +#define d7 $15 /* t7 */ + +#define xa0 $16 /* s0 */ +#define xa1 $17 /* s1 */ +#define xa2 $18 /* s2 */ +#define xa3 $19 /* s3 */ +#define xa4 $20 /* s4 */ +#define xa5 $21 /* s5 */ +#define xa6 $22 /* s6 */ +#define xa7 $23 /* s7 */ + +#define TEMP $2 /* v1 */ +#define input xa3 /* s3 */ +#define output xa4 /* s4 */ +#define output_hi xa5 /* s5 */ + +#define counts d4 /* t4 */ +#define bit_buffer d6 /* t6 */ +#define bit_count d7 /* t7 */ + + +#define zero $0 /* zero */ +#define tmp $1 /* at */ +#define tmp2 $2 /* v0 */ +#define const_ff $3 /* v1 */ +#define const_ff000000 $4 /* a0 */ +#define const_80000000 $5 /* a1 */ +#define const_ffffff00 $6 /* a2 */ +#define const_8000 $7 /* a3 */ +#define a0 $4 +#define a1 $5 +/*------------------------------------------------------------------------------ +* Macros +*------------------------------------------------------------------------------ +*/ +#define pop(reg) lw reg,0($sp) ; add $sp,$sp,8 + +#define dbra reg,dest bne reg,zero,dest ; sub reg,reg,1 +/*------------------------------------------------------------------------------ +* PROPACK Unpack Routine (Compact Version) - MC68000, Method 1 +* +* on entry, +* a0.l = start address of packed file +* a1.l = start address to unpack file +* (note: a1 cannot be equal to a0) +* stack space required: $1DC bytes +* +* all other registers are preserved +* Note: +* lines with a comment beginning with '*' are delay slot instructions +* beware the delay slot, it can really screw you up! +*------------------------------------------------------------------------------ +*/ + .text + .set noreorder + .option pic0 + .set noat + + .globl Propack_UnpackM1 + .ent Propack_UnpackM1 2 +Propack_UnpackM1: + .frame $sp, 0, $31 + /* + Save any registers required here + */ + sub $sp, $sp, 88 + sw $4, 0($sp) + sw $5, 4($sp) + sw $6, 8($sp) + sw $7, 12($sp) + sw $8, 16($sp) + sw $9, 20($sp) + sw $10,24($sp) + sw $11,28($sp) + sw $12,32($sp) + sw $13,36($sp) + sw $14,40($sp) + sw $15,44($sp) + sw $16,48($sp) + sw $17,52($sp) + sw $18,56($sp) + sw $19,60($sp) + sw $20,64($sp) + sw $21,68($sp) + sw $22,72($sp) + sw $23,76($sp) + sw $31,80($sp) + /* Set up entry parameters, the RNC code always uses a0, a1 for */ + /* the I/O datastream and we must use R3K registers A0,A1 */ + move xa0,a0 /* move input,a0 */ + move xa1,a1 /* move output,a1 */ + jal pp_Unpack /* bsr pp_Unpack */ + nop + + /* + Restore previously saved registers here + */ + lw $4, 0($sp) + lw $5, 4($sp) + lw $6, 8($sp) + lw $7, 12($sp) + lw $8, 16($sp) + lw $9, 20($sp) + lw $10,24($sp) + lw $11,28($sp) + lw $12,32($sp) + lw $13,36($sp) + lw $14,40($sp) + lw $15,44($sp) + lw $16,48($sp) + lw $17,52($sp) + lw $18,56($sp) + lw $19,60($sp) + lw $20,64($sp) + lw $21,68($sp) + lw $22,72($sp) + lw $23,76($sp) + lw $31,80($sp) + + add $sp, $sp, 88 + j ra /* rts */ + nop +pp_Unpack: + sub const_ff,zero,1 /* Set up constant 0xff */ + and const_ff,const_ff,0x00ff + sll const_ff000000,const_ff,24 /* Set up constant 0xff000000 */ + sll const_80000000,const_ff,31 /* Set up constant 0x80000000 */ + srl const_8000,const_80000000,16 /* Set up constant 0x8000 */ + nor const_ffffff00,zero,const_ff /* Set up constant 0xffffff00 */ + + sub $sp,$sp,BUFSIZE /* sub.w #bufsize,sp */ + move xa2,$sp /* move.w sp,a2 */ + sub $sp,$sp,8 /* Preserve link address for return*/ + sw ra,($sp) + add xa0,xa0,4 /* addq #4,a0 (skip past comp'd length) */ + jal read_long /* bsr read_long (get uncomp'd length) */ + nop + add input,xa0,HEADER_LEN-8 /* lea HEADER_LEN-8(a0),input (skip past rest of header) */ + move output,xa1 /* move.l a1,output */ + lbu bit_buffer,1(input) /* move.b 1(input),bit_buffer */ + lbu tmp,0(input) /* move.b 0(input),bit_buffer (after bit_buffer is rotated) */ + move bit_count,zero /* moveq.l #0,bit_count */ + sll bit_buffer,bit_buffer,8 /* " " rotate high byte into position */ + or bit_buffer,bit_buffer,tmp /* " " and or it in to the bit_buffer */ + add output_hi,output,d0 /* lea (output,d0.l),output_hi */ + add d0,zero,2 /* moveq.l #2,d0 */ + add d1,zero,2 /* moveq.l #2,d1 */ + jal input_bits /* bsr input_bits */ + nop + lw ra,($sp) /* Restore from linked jumps */ + add $sp,$sp,8 +unpack2: + sub $sp,$sp,8 /* Preserve link address for return*/ + sw ra,($sp) + /* */ + /* Fill the hufftables with a set value so we can see if they work */ + /* */ + move xa0,xa2 /* move.l a2,a0 */ + jal make_huftable /* bsr make_huftable */ + nop + add xa0,xa2,POS_TABLE /* lea POS_TABLE(a2),a0 */ + jal make_huftable /* bsr make_huftable */ + nop + add xa0,xa2,LEN_TABLE /* lea LEN_TABLE(a2),a0 */ + jal make_huftable /* bsr make_huftable */ + nop + add d0,zero,-1 /* moveq.l #-1,d0 */ + add d1,zero,16 /* moveq.l #16,d1 */ + jal input_bits /* bsr input_bits */ + nop + lw ra,($sp) /* Restore from linked jumps */ + add $sp,$sp,8 + move counts,d0 /* move.w d0,counts */ + sub tmp,zero,1 + srl tmp,tmp,16 + sub counts,counts,1 /* subq.w #1,counts */ + and counts,tmp,counts + j unpack5 /* bra.s unpack5 */ + nop +unpack3: + add xa0,xa2,POS_TABLE /* lea POS_TABLE(a2),a0 */ + sub $sp,$sp,8 /* Preserve link address for return*/ + sw ra,($sp) + move d0,zero /* moveq.l #0,d0 */ + jal input_value /* bsr.s input_value */ + nop + subu d0,zero,d0 /* neg.l d0 */ + add xa1,output,d0 /* lea -1(output,d0.l),a1 */ + add xa1,xa1,-1 /* " " */ + add xa0,xa2,LEN_TABLE /* lea LEN_TABLE(a2),a0 */ + jal input_value /* bsr.s input_value */ + nop + lw ra,($sp) /* Restore from linked jumps */ + add $sp,$sp,8 + add output,output,1 /* move.b (a1)+,(output)+ */ + lbu tmp,(xa1) /* " " */ + add xa1,xa1,1 /* " " */ + sb tmp,-1(output) /* " " */ +unpack4: + add output,output,1 /* move.b (a1)+,(output)+ */ + lbu tmp,(xa1) /* " " */ + add xa1,xa1,1 /* " " */ + sb tmp,-1(output) /* " " */ + bne d0,zero,unpack4 /* dbra d0,unpack4 */ + sub d0,d0,1 +unpack5: + sub $sp,$sp,8 /* Preserve link address for return*/ + sw ra,($sp) + move xa0,xa2 /* move.l a2,a0 */ + jal input_value /* bsr.s input_value */ + nop + lw ra,($sp) /* Restore from linked jumps */ + add $sp,$sp,8 + sub d0,d0,1 /* subq.w #1,d0 */ + bltz d0,unpack6 /* bmi.s unpack6 */ + nop + sub $sp,$sp,8 /* Preserve link address for return*/ + sw ra,($sp) + jal getrawREP /* getrawREP */ + nop /* */ + lw ra,($sp) /* Restore from linked jumps */ + add $sp,$sp,8 + lbu tmp,1(input) /* move.b 1(input),d0 */ + lbu d0,0(input) /* move.b (input),d0 */ + sll tmp,tmp,8 /* rol.w #8,d0 */ + or d0,tmp,d0 /* " " */ + + sll d0,d0,bit_count /* lsl.l bit_count,d0 */ + add d1,zero,1 /* moveq.l #1,d1 */ + sll d1,d1,bit_count /* lsl.w bit_count,d1 */ + subu d1,d1,1 /* subq.w #1,d1 */ + and bit_buffer,bit_buffer,d1 /* and.l d1,bit_buffer */ + or bit_buffer,d0,bit_buffer /* or.l d0,bit_buffer */ +unpack6: + bne counts,zero,unpack3 /* dbra counts,unpack3 */ + sub counts,counts,1 + sub tmp,output,output_hi /* cmp.l output_hi,output */ + bltz tmp,unpack2 /* bcs.s unpack2 */ + nop /* " " */ + add $sp, $sp, BUFSIZE /* lea BUFSIZE(sp),sp */ + jr ra /* rts */ + nop +input_value: + lbu d0,0(xa0) /* move.w (a0)+,d0 */ + lbu tmp,1(xa0) /* " " */ + add xa0,xa0,2 /* " " */ + sll d0,d0,8 /* " " */ + or d0,tmp,d0 /* " " */ + and d0,d0,bit_buffer /* and.w bit_buffer,d0 */ + lbu tmp,0(xa0) /* sub.w (a0)+,d0 */ + lbu tmp2,1(xa0) /* " " */ + add xa0,xa0,2 /* " " */ + sll tmp,tmp,8 /* " " */ + or tmp,tmp,tmp2 /* " " */ + sub d0,d0,tmp /* " " */ + bne d0,zero,input_value /* bne.s input_value */ + nop + lbu d1,16*4-4(xa0) /* move.b 16*4-4(a0),d1 */ + nop + sub bit_count,bit_count,d1 /* sub.b d1,bit_count */ + bgez bit_count,input_value2 /* bge.s input_value2 */ + nop /*(Delay Slot) */ + sub $sp,$sp,8 /* Preserve link address for return*/ + sw ra,($sp) + jal input_bits3 /* bsr.s input_bits3 */ + nop /* * */ + lw ra,($sp) /* Restore from linked jumps */ + add $sp,$sp,8 +input_value2: + srl bit_buffer,bit_buffer,d1 /* lsr.l d1,bit_buffer */ + lbu d0,16*4-3(xa0) /* move.b 16*4-3(a0),d0 */ + nop + sub tmp,d0,2 /* cmp.b #2,d0 */ + bltz tmp,input_value4 /* blt.s input_value4 */ + nop + sub d0,d0,1 /* subq.b #1,d0 */ + move d1,d0 /* move.b d0,d1 */ + move d2,d0 /* move.b d0,d2 */ + lbu tmp,16*4-2(xa0) /* move.w 16*4-2(a0),d0 */ + lbu d0,16*4-2+1(xa0) /* " " */ + sll tmp,tmp,8 + or d0,tmp,d0 + and d0,d0,bit_buffer /* and.w bit_buffer,d0 */ + sub bit_count,bit_count,d1 /* sub.b d1,bit_count */ + bgez bit_count,input_value3 /* bge.s input_value3 */ + nop + sub $sp,$sp,8 /* Preserve link address for return*/ + sw ra,($sp) + jal input_bits3 /* bsr.s input_bits3 */ + nop /* */ + lw ra,($sp) /* Restore from linked jumps */ + add $sp,$sp,8 +input_value3: + srl bit_buffer,bit_buffer,d1 /* lsr.l d1,bit_buffer */ + add tmp,zero,1 + sll tmp,tmp,d2 /* bset d2,d0 */ + or d0,tmp,d0 /* " " */ +input_value4: + jr ra + nop /*(Delay Slot) */ + +/*------------------------------------------------------------------------------ +/ input_bits - Entry: +// D0 - Mask to and output data with +// D1 - Number of bits to fetch +// Exit: +// D0 - Value read from buffer +//------------------------------------------------------------------------------ +*/ +input_bits: + and d0,bit_buffer,d0 /* and.w bit_buffer,d0 */ + sub bit_count,bit_count,d1 /* sub.b d1,bit_count */ + bgez bit_count,input_bits2 /* bge.s input_bits2 */ + nop + sub $sp,$sp,8 /* Preserve link address for return*/ + sw ra,($sp) + jal input_bits3 /* bsr.s input_bits3 */ + nop + lw ra,($sp) /* Restore from linked jumps */ + add $sp,$sp,8 +input_bits2: + srl bit_buffer,bit_buffer,d1 /*(Delay Slot)lsr.l d1,bit_buffer */ + jr ra /* return */ + nop + +input_bits3: + add bit_count,bit_count,d1 /* Make sure we have correct # of bits left in buffer */ + srl bit_buffer,bit_buffer,bit_count /* lsr.l bit_count,bit_buffer */ + + add input,input,4 /* jump passed our data for some odd reason */ + lbu tmp,-2(input) /* Get our new word to add into bit buffer */ + lbu tmp2,-1(input) /* byte at a time..... */ + sub input,input,2 + sll tmp,tmp,16 /* shift this into the right place */ + sll tmp2,tmp2,24 + or bit_buffer,bit_buffer,tmp2 /* OR in the 2 new bytes read to the bit buffer */ + or bit_buffer,bit_buffer,tmp + + sub d1,d1,bit_count /* sub.b bit_count,d1 */ + add bit_count,zero,16 /* moveq.l #16,bit_count */ + sub bit_count,bit_count,d1 /* sub.b d1,bit_count */ + jr ra /* rts */ + nop +read_long: + add d1,zero,3 /* moveq.l #3,d1 */ +read_long2: + sll d0,d0,8 /* lsl.l #8,d0 */ + lbu tmp,0(xa0) /* move.b (a0)+,d0 */ + add xa0,xa0,1 /* " " */ + or d0,tmp,d0 /* " " */ + bne d1,zero,read_long2 /* dbra d1,read_long2 */ + sub d1,d1,1 + jr ra + nop /*(Delay Slot) */ +/*------------------------------------------------------------------------------ +// Make_HufTable - Builds huffman decode table +//------------------------------------------------------------------------------ +*/ +make_huftable: + add d0,zero,0x1f /* moveq.l #$1f,d0 */ + add d1,zero,0x5 /* moveq.l #5,d1 */ + sub $sp,$sp,8 /* Preserve link address for return*/ + sw ra,($sp) + jal input_bits /* bsr.s input_bits */ + nop /*(Delay Slot) */ + lw ra,($sp) /* Restore from linked jumps */ + add $sp,$sp,8 + + sub d0,d0,1 /* subq.w #1,d0 */ + bltz d0,make_huftable8 /* bmi.s make_huftable8 */ + nop + move d2,d0 /* move.w d0,d2 */ + move d3,d0 /* move.w d0,d3 */ + sub $sp,$sp,16 /* lea -16(sp),sp */ + move xa1,$sp /* move.l sp,a1 */ +make_huftable3: + add d0,zero,15 /* moveq.l #$f,d0 */ + add d1,zero,4 /* moveq.l #4,d1 */ + sub $sp,$sp,8 /* Preserve link address for return*/ + sw ra,($sp) + jal input_bits /* bsr.s input_bits */ + nop /*(Delay Slot) */ + lw ra,($sp) /* Restore from linked jumps */ + add $sp,$sp,8 + sb d0,(xa1) /* move.b d0,(a1)+ */ + add xa1,xa1,1 /* " " */ + bne d2,zero,make_huftable3 /* dbra d2,make_huftable3 */ + sub d2,d2,1 + move d0,const_80000000 /* moveq.l #1,d0 (with shift == 0x8000000) */ + add d1,zero,1 /* moveq.l #1,d1 */ + move d2,zero /* moveq.l #0,d2 */ + sub $sp,$sp,16 /* movem.l d5-d7,-(sp) */ + sw d5,0($sp) /* " " */ + sw d6,4($sp) /* " " */ + sw d7,8($sp) /* " " */ +make_huftable4: + move d4,d3 /* move.w d3,d4 */ + add xa1,$sp,16 /* lea 12(sp),a1 */ +make_huftable5: + lbu tmp,0(xa1) /* cmp.b (a1)+,d1 */ + add xa1,xa1,1 /* " " */ + bne d1,tmp,make_huftable7 /* bne.s make_huftable7 */ + nop /*(Delay Slot) */ + add d5,zero,1 /* moveq.l #1,d5 */ + sll d5,d5,d1 /* lsl.w d1,d5 */ + sub d5,d5,1 /* subq.w #1,d5 */ + sb d5,1(xa0) /* move.w d5,(a0)+ */ + srl tmp,d5,8 /* " " */ + sb tmp,(xa0) /* " " */ + add xa0,xa0,2 /* " " */ + move d5,d2 /* move.l d2,d5 */ + sll tmp,d5,16 /* swap d5 */ + srl d5,d5,16 /* " " */ + or d5,d5,tmp /* " " */ + move d7,d1 /* move.w d1,d7 */ + sub d7,d7,1 /* subq.w #1,d7 */ +make_huftable6: + sub tmp,zero,1 + srl tmp,tmp,16 + and d6,tmp,d6 + and tmp,d5,const_8000 /* roxl.w #1,d5 */ + sll d5,d5,1 /* " " */ + srl d6,d6,1 /* " " */ + beq tmp,zero,make_ht6_1 /* roxr.w #1,d6 */ + nop + or d6,d6,const_8000 /* " " */ +make_ht6_1: bne d7,zero,make_huftable6 /* dbra d7,make_huftable6 */ + sub d7,d7,1 + add d5,zero,16 /* moveq.l #16,d5 */ + sub d5,d5,d1 /* sub.b d1,d5 */ + srl d6,d6,d5 /* lsr.w d5,d6 */ + sb d6,1(xa0) /* move.w d6,(a0)+ */ + srl tmp,d6,8 /* " " */ + sb tmp,0(xa0) /* " " */ + add xa0,xa0,2 /* " " */ + sb d1,16*4-4(xa0) /* move.b d1,16*4-4(a0) */ + move d5,d3 /* move.b d3,d5 */ + subu d5,d5,d4 /* sub.b d4,d5 */ + sb d5,16*4-3(xa0) /* move.b d5,16*4-3(a0) */ + add d6,zero,1 /* moveq.l #1,d6 */ + subu d5,d5,1 /* subq.b #1,d5 */ + sll d6,d6,d5 /* lsl.w d5,d6 */ + subu d6,d6,1 /* subq.w #1,d6 */ + sb d6,16*4-2+1(xa0) + srl tmp,d6,8 + sb tmp,16*4-2(xa0) /* move.w d6,16*4-2(a0) */ + addu d2,d2,d0 /* add.l d0,d2 */ +make_huftable7: + bne d4,zero,make_huftable5 /* dbra d4,make_huftable5 */ + sub d4,d4,1 + srl d0,d0,1 /* lsr.l #1,d0 */ + add d1,d1,1 /* addq.b #1,d1 */ + add tmp,zero,17 /* cmp.b #17,d1 */ + bne d1,tmp,make_huftable4 /* bne.s make_huftable4 */ + lw d5,0($sp) /* movem.l (sp)+,d5-d7 */ + lw d6,4($sp) /* " " */ + lw d7,8($sp) /* " " */ + add $sp,$sp,16 /* " " */ + add $sp,$sp,16 /* lea 16(sp),sp */ +make_huftable8: + jr ra + nop /*(Delay Slot) */ +getrawREP: + lbu tmp,0(input) + nop + sb tmp,0(output) + add output,output,1 + add input,input,1 + bne d0,zero,getrawREP /* dbra d0,getrawREP */ + sub d0,d0,1 + jr ra + nop /*(Delay Slot) */ + + .end diff --git a/asm/rnc2.s b/asm/rnc2.s new file mode 100755 index 00000000..d3a2ca94 --- /dev/null +++ b/asm/rnc2.s @@ -0,0 +1,673 @@ +/*------------------------------------------------------------------------------ +* PROPACK Unpack Source Code - Sony PSX, Method 2 +* +* Copyright (c) 1991-95 Rob Northen Computing, U.K. All Rights Reserved. +* +* Conversion from 68000 by Chris Kirby, Iguana Entertainment Limited. +* Converted to compile with SGI as, 9/13/96 Biscuit +* Beware the commentless void......... +* +* File: rnc2.s +* +* Date: 16.03.95 +*------------------------------------------------------------------------------*/ + +#define header_len 18 +#define crc_poly 0xa001 + +#define r0 $0 +#define r4 $4 +#define r5 $5 + +#define input $3 +#define input_hi $4 +#define output $5 +#define output_hi $6 +#define len $8 +#define pos $9 +#define bitbuf $10 +#define xsp $11 +#define temp $12 +#define xd0 $13 +#define xa0 $14 +#define ext $15 +#define xd1 $16 +#define xa1 $17 +#define temp2 $18 +#define postop $19 +#define ra $31 +#define retval $2 + + .text + .set noreorder + .option pic0 + + .globl Propack_UnpackM2 + .ent Propack_UnpackM2 2 +Propack_UnpackM2: + + .frame $sp, 0, $31 + + sub $sp, $sp, 72 + sw $4, 0($sp) + sw $5, 4($sp) + sw $6, 8($sp) + sw $7, 12($sp) + sw $8, 16($sp) + sw $9, 20($sp) + sw $10, 24($sp) + sw $11, 28($sp) + sw $12, 32($sp) + sw $13, 36($sp) + sw $14, 40($sp) + sw $15, 44($sp) + sw $16, 48($sp) + sw $17, 52($sp) + sw $18, 56($sp) + sw $19, 60($sp) + sw $31, 64($sp) + la temp, __PPUnpack + nop + jalr temp + nop + + lw $4, 0($sp) + lw $5, 4($sp) + lw $6, 8($sp) + lw $7, 12($sp) + lw $8, 16($sp) + lw $9, 20($sp) + lw $10, 24($sp) + lw $11, 28($sp) + lw $12, 32($sp) + lw $13, 36($sp) + lw $14, 40($sp) + lw $15, 44($sp) + lw $16, 48($sp) + lw $17, 52($sp) + lw $18, 56($sp) + lw $19, 60($sp) + lw $31, 64($sp) + + add $sp, $sp, 72 + jr ra + +__PPUnpack: +/* addi r4,r4,9 - what the hell was this for?*/ + move xa0,r4 /* source */ + move xa1,r5 /* dest */ + li xd0,0 + + la xsp,mystack +#if 0 + lbu temp,0(xa0) + nop + seq xa0,temp, "R" + beq xa0,0, RNC_Error + + lbu temp,1(xa0) + nop + seq xa0,temp, "N" + beq xa0,0, RNC_Error + + lbu temp,2(xa0) + nop + seq xa0,temp, "C" + beq xa0,0, RNC_Error + + lbu temp,3(xa0) + nop + seq xa0, temp, 2 + beq xa0, 0, RNC_BadFormat +#endif + + + addiu xa0,xa0,4 + lbu xd0,0(xa0) + lbu temp,1(xa0) + lbu temp2,2(xa0) + lbu ext,3(xa0) + sll xd0,xd0,24 + sll temp,temp,16 + sll temp2,temp2,8 + or xd0,xd0,temp + or xd0,xd0,temp2 + or xd0,xd0,ext + + addiu xa0,xa0,4 + + sw xd0,0(xsp) + move input,xa0 + addi input,input,header_len-8 + + move output,xa1 + move output_hi,output + addu output_hi,output_hi,xd0 + + lbu xd0,0(xa0) + lbu temp,1(xa0) + lbu temp2,2(xa0) + lbu ext,3(xa0) + sll xd0,xd0,24 + sll temp,temp,16 + sll temp2,temp2,8 + or xd0,xd0,temp + or xd0,xd0,temp2 + or xd0,xd0,ext + + + addu xa0,xa0,4 + + move input_hi,input + add input_hi,input_hi,xd0 + + sub xsp,xsp,2 + sh r0,0(xsp) + + +unpack7: + lui bitbuf,0xffff + ori bitbuf,0xff00 + + li ext,1 + + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + addu bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + + j xloop + andi ext,ext,1 + +RNC_Error: + li retval, -1 /* Error Bad Header */ + j ra + nop + +RNC_BadFormat: + li retval, -2 /* Error Unknown format */ + j ra + nop + +fetch0: + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + j back0 + andi ext,ext,1 +fetch1: + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + j back1 + andi ext,ext,1 +fetch2: + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + j back2 + andi ext,ext,1 +fetch3: + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + j back3 + andi ext,ext,1 +fetch4: + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + j back4 + andi ext,ext,1 +fetch5: + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + j back5 + andi ext,ext,1 +fetch6: + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + j back6 + andi ext,ext,1 +fetch7: + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + j back7 + andi ext,ext,1 + + +raw: + li len,3 + +x4bits: + addu bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + andi bitbuf,bitbuf,0xff + beq r0,bitbuf,fetch0 + nop + + +back0: + addu pos,pos,pos + addu pos,pos,ext + srl ext,pos,16 + andi ext,ext,1 + + sub len,len,1 + bgez len,x4bits + nop + addi pos,pos,2 + +getrawrep2: + lbu temp,0(input) + lbu temp2,1(input) + sb temp,0(output) + sb temp2,1(output) + + lbu temp,2(input) + lbu temp2,3(input) + sb temp,2(output) + sb temp2,3(output) + + + + addiu input,input,4 + sub pos,pos,1 + + bgez pos,getrawrep2 + addi output,output,4 + + j xloop + nop + +getlen: + addu bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + andi bitbuf,bitbuf,0xff + beq r0,bitbuf,fetch1 + nop +back1: + addu len,len,len + addu len,len,ext + + addu bitbuf,bitbuf,bitbuf + + srl ext,bitbuf,8 + andi ext,ext,1 + andi bitbuf,bitbuf,0xff + beq r0,bitbuf,fetch2 + nop + + +back2: + beq r0,ext,copy + nop + sub len,len,1 + add bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + andi bitbuf,bitbuf,0xff + beq r0,bitbuf,fetch3 + nop + +back3: + addu len,len,len + addu len,len,ext + srl ext,len,16 + andi ext,ext,1 + + sub temp,len,9 + beq r0,temp,raw + nop + + +copy: + addu bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + andi bitbuf,bitbuf,0xff + beq r0,bitbuf,fetch4 + nop + + +back4: + beq r0,ext,bytedisp2 + nop + addu bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + andi bitbuf,bitbuf,0xff + beq r0,bitbuf,fetch5 + nop + +back5: + addu pos,pos,pos + addu pos,pos,ext + + addu bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + andi bitbuf,bitbuf,0xff + beq r0,bitbuf,fetch6 + nop + +back6: + bne r0,ext,bigdisp + nop + bne r0,pos,bytedisp + nop + addi pos,pos,1 + +another: + addu bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + andi bitbuf,bitbuf,0xff + beq r0,bitbuf,fetch7 + nop + +back7: + addu pos,pos,pos + addu pos,pos,ext + srl ext,pos,16 + andi ext,ext,1 + +bytedisp: + sll temp,pos,8 + andi temp,temp,0xff00 + srl pos,pos,8 + or pos,pos,temp + + +bytedisp2: + andi postop,pos,0xff00 + + lbu pos,0(input) + + addiu input,input,1 + or pos,pos,postop + move xa0,output + sub xa0,xa0,pos + sub xa0,xa0,1 + andi ext,len,1 + srl len,len,1 + beq r0,ext,bytedisp3 + nop + + lbu temp,0(xa0) + addi xa0,xa0,1 + sb temp,0(output) + addi output,output,1 + + +bytedisp3: + sub len,len,1 + bne r0,pos,bytedisp5 + nop + + andi postop,pos,0xff00 + lbu pos,0(xa0) + nop + or pos,pos,postop +bytedisp4: + sb pos,0(output) + sub len,len,1 + sb pos,1(output) + + bgez len,bytedisp4 + addi output,output,2 + + j xloop + nop +bytedisp5: + lbu temp2,1(xa0) + lbu temp,0(xa0) + sb temp2,1(output) + sb temp,0(output) + + addi xa0,xa0,2 + + sub len,len,1 + bgez len,bytedisp5 + addi output,output,2 + + j xloop + nop + + +getbits: + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + andi ext,ext,1 + bne r0,ext,string + nop + +xbyte: + lbu temp,0(input) + addi input,input,1 + sb temp,0(output) + addi output,output,1 + + +xloop: + addu bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + bne r0,ext,chkz + nop + + lbu temp,0(input) + addi input,input,1 + sb temp,0(output) + addi output,output,1 + + addu bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + beq r0,ext,xbyte + nop +chkz: + andi bitbuf,bitbuf,0xff + beq r0,bitbuf,getbits + nop + + +string: + li len,2 + li pos,0 + + addu bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + andi bitbuf,bitbuf,0xff + beq r0,bitbuf,fetch8 + nop + + +back8: + beq r0,ext,getlen + nop + +smalls: + addu bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + + andi bitbuf,bitbuf,0xff + beq r0,bitbuf,fetch9 + nop + +back9: + + beq r0,ext,bytedisp2 + nop + addi len,len,1 + add bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + + andi bitbuf,bitbuf,0xff + beq r0,bitbuf,fetch10 + nop + +back10: + beq r0,ext,copy + nop + + lbu len,0(input) + addi input,input,1 + nop + beq r0,len,overnout + addi len,len,8 + j copy + nop + +bigdisp: + addu bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + + andi bitbuf,bitbuf,0xff + beq r0,bitbuf,fetch11 + nop + +back11: + addu pos,pos,pos + addu pos,pos,ext + srl ext,pos,16 + andi ext,ext,1 + ori pos,pos,4 + + addu bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + + andi bitbuf,bitbuf,0xff + beq r0,bitbuf,fetch12 + nop + +back12: + bne r0,ext,bytedisp + nop + j another + nop + +fetch8: + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + j back8 + andi ext,ext,1 +fetch9: + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + j back9 + andi ext,ext,1 +fetch10: + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + j back10 + andi ext,ext,1 +fetch11: + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + j back11 + andi ext,ext,1 +fetch12: + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + j back12 + andi ext,ext,1 + +overnout: + addu bitbuf,bitbuf,bitbuf + srl ext,bitbuf,8 + andi ext,ext,1 + andi bitbuf,bitbuf,0xff + bne r0,bitbuf,check4end + nop + + lbu bitbuf,0(input) + addi input,input,1 + addu bitbuf,bitbuf,bitbuf + addu bitbuf,bitbuf,ext + srl ext,bitbuf,8 + andi ext,ext,1 + +check4end: + bne r0,ext,xloop + nop + + lhu xd0,0(xsp) + addi xsp,xsp,2 + beq r0,xd0,unpack9 + nop + +unpack8: + lh xd1,0(xsp) + addi xsp,xsp,2 + sb xd1,0(output) + addi output,output,1 + sub xd0,xd0,1 + bne r0,xd0,unpack8 + nop + +unpack9: + j unpack11 + nop +unpack10: + sw xd1,0(xsp) + +unpack11: + li retval,0 + jr ra + nop + + .data + .align 4 + + .word 0,0,0,0,0,0,0,0,0,0,0,0 +mystack: + .word 0 + + .end diff --git a/gziprules.mk b/gziprules.mk new file mode 100644 index 00000000..be79b67d --- /dev/null +++ b/gziprules.mk @@ -0,0 +1,19 @@ +# Compress binary file to gzip +$(BUILD_DIR)/%.gz: $(BUILD_DIR)/%.bin + $(call print,Compressing:,$<,$@) +ifeq ($(GZIPVER),std) + $(V)$(GZIP) -c -9 -n $< > $@ +else + $(V)$(GZIP) -c -12 -n $< > $@ +endif + +# Strip gzip header +$(BUILD_DIR)/%.szp: $(BUILD_DIR)/%.gz + $(call print,Converting:,$<,$@) + $(V)dd bs=10 skip=1 if=$< of=$@ + $(V)$(FILESIZER) $(<:.gz=.bin) $@ + +# convert binary szp to object file +$(BUILD_DIR)/%.szp.o: $(BUILD_DIR)/%.szp + $(call print,Converting GZIP to ELF:,$<,$@) + $(V)printf ".section .data\n\n.incbin \"$<\"\n" | $(AS) $(ASFLAGS) -o $@ \ No newline at end of file diff --git a/include/rnc.h b/include/rnc.h new file mode 100755 index 00000000..eb02f4e0 --- /dev/null +++ b/include/rnc.h @@ -0,0 +1,24 @@ +#ifndef _IE_PACK_H +#define _IE_PACK_H + +typedef struct s_Propack +{ + u8 Id[3]; // MUST be RNC + u8 Method; // MUST be 0,1,2 (will have 0x80 added if indexed type) + u32 UnpackedSize; + u32 PackedSize; // Including size of ALL data + u16 BlockCount; // Indexed method block count + u8 BlockSize; // When method is indexed, this gives us the block size in KB. + u8 Reserved[3]; + u8 Data[0]; +} t_Propack; + + +/* Prototypes for unpack routines in assembly - Note: these just do the raw unpacking + everything else is done at a level above +*/ + +extern void Propack_UnpackM1(void *FilePtr, void *OutputBuffer); +extern void Propack_UnpackM2(void *FilePtr, void *OutputBuffer); + +#endif // _IE_PACK_H diff --git a/lib/rsp.s b/lib/rsp.s index 969b7f68..f9616d88 100644 --- a/lib/rsp.s +++ b/lib/rsp.s @@ -1,4 +1,4 @@ -.include "macros.inc" +#include "macros.inc" .set UCODE_SIZE, 0x800 .section .text @@ -10,34 +10,34 @@ glabel rspbootTextStart glabel rspbootTextEnd .balign 16 -.ifndef F3DEX_GBI_SHARED -.if SUPER3D_GBI == 1 +#ifndef F3DEX_GBI_SHARED +#if SUPER3D_GBI == 1 glabel gspSuper3D_fifoTextStart .incbin "lib/PR/super3d/Super3D.bin" glabel gspSuper3D_fifoTextEnd -.else +#else glabel gspFast3D_fifoTextStart /* Use regular Fast3D bins (default) */ .incbin "rsp/fast3d.bin" glabel gspFast3D_fifoTextEnd -.endif +#endif -.else /* Use one of the Fast3DEX series grucodes. */ - .ifndef F3DZEX_GBI_2 - .if F3DEX_GBI_2 == 1 +#else /* Use one of the Fast3DEX series grucodes. */ + #ifndef F3DZEX_GBI_2 + #if F3DEX_GBI_2 == 1 glabel gspF3DEX2_fifoTextStart .incbin "lib/PR/f3dex2/F3DEX2.bin" glabel gspF3DEX2_fifoTextEnd - .elseif F3DEX_GBI == 1 + #elseif F3DEX_GBI == 1 glabel gspF3DEX_fifoTextStart .incbin "lib/PR/f3dex/F3DEX.bin" glabel gspF3DEX_fifoTextEnd - .endif - .else /* Fast3DZEX */ + #endif + #else /* Fast3DZEX */ glabel gspF3DZEX2_PosLight_fifoTextStart .incbin "lib/PR/f3dzex/F3DZEX.bin" glabel gspF3DZEX2_PosLight_fifoTextEnd - .endif -.endif + #endif +#endif /* Audio Bins */ @@ -48,11 +48,11 @@ glabel gspFast3D_fifoTextEnd .balign 16 glabel aspMainTextStart -.if VERSION_SH == 1 +#if VERSION_SH == 1 .incbin "rsp/audio.bin" -.else +#else .incbin "lib/PR/audio/aspMain.bin" -.endif +#endif glabel aspMainTextEnd /* @@ -61,145 +61,145 @@ glabel aspMainTextEnd */ /* Fast3DEX NoN Text */ -.ifdef F3DEX_NON_GBI +#ifdef F3DEX_NON_GBI glabel gspF3DEX_NoN_fifoTextStart .balign 16 .incbin "lib/PR/f3dex/F3DEX_NoN.bin" glabel gspF3DEX_NoN_fifoTextEnd -.endif +#endif /* Fast3DLX Text */ -.ifdef F3DLX_GBI +#ifdef F3DLX_GBI glabel gspF3DLX_fifoTextStart .incbin "lib/PR/f3dex/F3DLX.bin" glabel gspF3DLX_fifoTextEnd -.endif +#endif /* Fast3DLX NoN Text */ -.ifdef F3DLX_NON_GBI +#ifdef F3DLX_NON_GBI glabel gspF3DLX_NoN_fifoTextStart .balign 16 .incbin "lib/PR/f3dex/F3DLX_NoN.bin" glabel gspF3DLX_NoN_fifoTextEnd -.endif +#endif /* Fast3DLX Rej Text */ -.ifdef F3DLX_REJ_GBI +#ifdef F3DLX_REJ_GBI glabel gspF3DLX_Rej_fifoTextStart .balign 16 .incbin "lib/PR/f3dex/F3DLX_Rej.bin" glabel gspF3DLX_Rej_fifoTextEnd -.endif +#endif /* Line3DEX Text */ -.ifdef L3DEX_GBI +#ifdef L3DEX_GBI glabel gspL3DEX_fifoTextStart .balign 16 .incbin "lib/PR/f3dex/L3DEX.bin" glabel gspL3DEX_fifoTextEnd -.endif +#endif /* S2DEX Text */ -.ifdef S2DEX_GBI +#ifdef S2DEX_GBI glabel gspS2DEX_fifoTextStart .balign 16 .incbin "lib/PR/s2dex/S2DEX.bin" glabel gspS2DEX_fifoTextEnd -.endif +#endif /* Fast3DEX2 series */ /* Fast3DEX2 NoN Text */ -.ifdef F3DEX2_NON_GBI +#ifdef F3DEX2_NON_GBI .balign 16 glabel gspF3DEX2_NoN_fifoTextStart .incbin "lib/PR/f3dex2/F3DEX2_NoN.bin" glabel gspF3DEX2_NoN_fifoTextEnd -.endif +#endif /* Fast3DZEX NoN Text */ -.ifdef F3DZEX_NON_GBI_2 +#ifdef F3DZEX_NON_GBI_2 .balign 16 glabel gspF3DZEX2_NoN_PosLight_fifoTextStart .incbin "lib/PR/f3dzex/F3DZEX_NoN.bin" glabel gspF3DZEX2_NoN_PosLight_fifoTextEnd -.endif +#endif /* Fast3DEX2 Rej Text */ -.ifdef F3DEX2_REJ_GBI +#ifdef F3DEX2_REJ_GBI .balign 16 glabel gspF3DEX2_Rej_fifoTextStart .incbin "lib/PR/f3dex2/F3DEX2_Rej.bin" glabel gspF3DEX2_Rej_fifoTextEnd -.endif +#endif /* Line3DEX2 Text */ -.ifdef L3DEX2_GBI +#ifdef L3DEX2_GBI .balign 16 glabel gspL3DEX2_fifoTextStart .incbin "lib/PR/f3dex2/L3DEX2.bin" glabel gspL3DEX2_fifoTextEnd -.endif +#endif /* Line3DZEX Text */ -.ifdef L3DZEX_GBI +#ifdef L3DZEX_GBI .balign 16 glabel gspL3DZEX2_PosLight_fifoTextStart .incbin "lib/PR/f3dzex/L3DZEX.bin" glabel gspL3DZEX2_PosLight_fifoTextEnd -.endif +#endif /* S2DEX2 Text */ -.ifdef S2DEX_GBI_2 +#ifdef S2DEX_GBI_2 .balign 16 glabel gspS2DEX2_fifoTextStart .incbin "lib/PR/s2dex2/S2DEX2.bin" glabel gspS2DEX2_fifoTextEnd -.endif +#endif /* DATA SECTION START */ .section .rodata .balign 16 -.ifndef F3DEX_GBI_SHARED /* Use regular Fast3D data (default) */ - .if SUPER3D_GBI == 1 +#ifndef F3DEX_GBI_SHARED /* Use regular Fast3D data (default) */ + #if SUPER3D_GBI == 1 glabel gspSuper3D_fifoDataStart .incbin "lib/PR/super3d/Super3D_data.bin" glabel gspSuper3D_fifoDataEnd -.else +#else glabel gspFast3D_fifoDataStart .incbin "rsp/fast3d_data.bin" glabel gspFast3D_fifoDataEnd -.endif +#endif -.else /* Using one of the Fast3DEX series grucodes */ - .ifndef F3DZEX_GBI_2 - .if F3DEX_GBI_2 == 1 +#else /* Using one of the Fast3DEX series grucodes */ + #ifndef F3DZEX_GBI_2 + #if F3DEX_GBI_2 == 1 glabel gspF3DEX2_fifoDataStart .incbin "lib/PR/f3dex2/F3DEX2_data.bin" glabel gspF3DEX2_fifoDataEnd - .elseif F3DEX_GBI == 1 + #elseif F3DEX_GBI == 1 glabel gspF3DEX_fifoDataStart .incbin "lib/PR/f3dex/F3DEX_data.bin" glabel gspF3DEX_fifoDataEnd - .endif - .else /* Fast3DZEX */ + #endif + #else /* Fast3DZEX */ glabel gspF3DZEX2_PosLight_fifoDataStart .incbin "lib/PR/f3dzex/F3DZEX_data.bin" glabel gspF3DZEX2_PosLight_fifoDataEnd - .endif -.endif + #endif +#endif /* Audio Data */ .balign 16 glabel aspMainDataStart -.if VERSION_SH == 1 +#if VERSION_SH == 1 .incbin "rsp/audio_data.bin" -.else +#else .incbin "lib/PR/audio/aspMain_data.bin" -.endif +#endif glabel aspMainDataEnd /* LESS COMMON MICROCODES */ @@ -207,99 +207,99 @@ glabel aspMainDataEnd /* Fast3DEX Series */ /* Fast3DEX NoN Data */ -.ifdef F3DEX_NON_GBI +#ifdef F3DEX_NON_GBI .balign 16 glabel gspF3DEX_NoN_fifoDataStart .incbin "lib/PR/f3dex/F3DEX_NoN_data.bin" glabel gspF3DEX_NoN_fifoDataEnd -.endif +#endif /* Fast3DLX Data */ -.ifdef F3DLX_GBI +#ifdef F3DLX_GBI .balign 16 glabel gspF3DLX_fifoDataStart .incbin "lib/PR/f3dex/F3DLX_data.bin" glabel gspF3DLX_fifoDataEnd -.endif +#endif /* Fast3DLX NoN Data */ -.ifdef F3DLX_NON_GBI +#ifdef F3DLX_NON_GBI .balign 16 glabel gspF3DLX_NoN_fifoDataStart .incbin "lib/PR/f3dex/F3DLX_NoN_data.bin" glabel gspF3DLX_NoN_fifoDataEnd -.endif +#endif /* Fast3DLX Rej Data */ -.ifdef F3DLX_REJ_GBI +#ifdef F3DLX_REJ_GBI .balign 16 glabel gspF3DLX_Rej_fifoDataStart .incbin "lib/PR/f3dex/F3DLX_Rej_data.bin" glabel gspF3DLX_Rej_fifoDataEnd -.endif +#endif /* Line3DEX Data */ -.ifdef L3DEX_GBI +#ifdef L3DEX_GBI .balign 16 glabel gspL3DEX_fifoDataStart .incbin "lib/PR/f3dex/L3DEX_data.bin" glabel gspL3DEX_fifoDataEnd -.endif +#endif /* S2DEX Data */ -.ifdef S2DEX_GBI +#ifdef S2DEX_GBI .balign 16 glabel gspS2DEX_fifoDataStart .incbin "lib/PR/s2dex/S2DEX_data.bin" glabel gspS2DEX_fifoDataEnd -.endif +#endif /* Fast3DEX2 Series */ /* Fast3DEX2 NoN Data */ -.ifdef F3DEX2_NON_GBI +#ifdef F3DEX2_NON_GBI .balign 16 glabel gspF3DEX2_NoN_fifoDataStart .incbin "lib/PR/f3dex2/F3DEX2_NoN_data.bin" glabel gspF3DEX2_NoN_fifoDataEnd -.endif +#endif /* Fast3DZEX NoN Data */ -.ifdef F3DZEX_NON_GBI_2 +#ifdef F3DZEX_NON_GBI_2 .balign 16 glabel gspF3DZEX2_NoN_PosLight_fifoDataStart .incbin "lib/PR/f3dzex/F3DZEX_NoN_data.bin" glabel gspF3DZEX2_NoN_PosLight_fifoDataEnd -.endif +#endif /* Fast3DEX2 Rej Data */ -.ifdef F3DEX2_REJ_GBI +#ifdef F3DEX2_REJ_GBI .balign 16 glabel gspF3DEX2_Rej_fifoDataStart .incbin "lib/PR/f3dex2/F3DEX2_Rej_data.bin" glabel gspF3DEX2_Rej_fifoDataEnd -.endif +#endif /* Line3DEX2 Data */ -.ifdef L3DEX2_GBI +#ifdef L3DEX2_GBI .balign 16 glabel gspL3DEX2_fifoDataStart .incbin "lib/PR/f3dex2/L3DEX2_data.bin" glabel gspL3DEX2_fifoDataEnd -.endif +#endif /* Line3DZEX Text */ -.ifdef L3DZEX_GBI +#ifdef L3DZEX_GBI .balign 16 glabel gspL3DZEX2_PosLight_fifoDataStart .incbin "lib/PR/f3dzex/L3DZEX_data.bin" glabel gspL3DZEX2_PosLight_fifoDataEnd -.endif +#endif /* S2DEX2 Data */ -.ifdef S2DEX_GBI_2 +#ifdef S2DEX_GBI_2 .balign 16 glabel gspS2DEX2_fifoDataStart .incbin "lib/PR/s2dex2/S2DEX2_data.bin" glabel gspS2DEX2_fifoDataEnd -.endif +#endif diff --git a/rnc1rules.mk b/rnc1rules.mk new file mode 100644 index 00000000..900d04a1 --- /dev/null +++ b/rnc1rules.mk @@ -0,0 +1,9 @@ +# Compress binary file +$(BUILD_DIR)/%.szp: $(BUILD_DIR)/%.bin + $(call print,Compressing:,$<,$@) + $(V)$(RNCPACK) p $< $@ -m1 + +# convert binary szp to object file +$(BUILD_DIR)/%.szp.o: $(BUILD_DIR)/%.szp + $(call print,Converting RNC to ELF:,$<,$@) + $(V)printf ".section .data\n\n.incbin \"$<\"\n" | $(AS) $(ASFLAGS) -o $@ \ No newline at end of file diff --git a/rnc2rules.mk b/rnc2rules.mk new file mode 100644 index 00000000..6b8bda56 --- /dev/null +++ b/rnc2rules.mk @@ -0,0 +1,9 @@ +# Compress binary file +$(BUILD_DIR)/%.szp: $(BUILD_DIR)/%.bin + $(call print,Compressing:,$<,$@) + $(V)$(RNCPACK) p $< $@ -m2 + +# convert binary szp to object file +$(BUILD_DIR)/%.szp.o: $(BUILD_DIR)/%.szp + $(call print,Converting RNC to ELF:,$<,$@) + $(V)printf ".section .data\n\n.incbin \"$<\"\n" | $(AS) $(ASFLAGS) -o $@ \ No newline at end of file diff --git a/sm64.ld b/sm64.ld index 589cb012..6b3c50df 100755 --- a/sm64.ld +++ b/sm64.ld @@ -122,6 +122,12 @@ SECTIONS #endif #ifdef YAY0 BUILD_DIR/asm/slidec.o(.text); +#endif +#ifdef RNC1 + BUILD_DIR/asm/rnc1.o(.text); +#endif +#ifdef RNC2 + BUILD_DIR/asm/rnc2.o(.text); #endif */libultra_rom.a:*.o(.text); */libnustd.a:*.o(.text); @@ -160,6 +166,9 @@ SECTIONS #ifdef GZIP BUILD_DIR/src/gzip*.o(.data*); #endif +#ifdef RNC2 + BUILD_DIR/asm/rnc2.o(.data*); +#endif */libultra_rom.a:*.o(.data*); */libultra_rom.a:*.o(.sdata*); diff --git a/src/game/memory.c b/src/game/memory.c index a1bcb9d7..ee03567f 100644 --- a/src/game/memory.c +++ b/src/game/memory.c @@ -14,6 +14,9 @@ #ifdef GZIP #include "gzip/gzip.h" #endif +#if defined(RNC1) || defined(RNC2) +#include +#endif // round up to the next multiple @@ -345,6 +348,10 @@ void *load_segment_decompress(s32 segment, u8 *srcStart, u8 *srcEnd) { if (dest != NULL) { #ifdef GZIP expand_gzip(compressed, dest, compSize, (u32)size); +#elif RNC1 + Propack_UnpackM1(compressed, dest); +#elif RNC2 + Propack_UnpackM2(compressed, dest); #else slidstart(compressed, dest); #endif @@ -374,6 +381,10 @@ void *load_segment_decompress_heap(u32 segment, u8 *srcStart, u8 *srcEnd) { dma_read(compressed, srcStart, srcEnd); #ifdef GZIP expand_gzip(compressed, gDecompressionHeap, compSize, (u32)size); +#elif RNC1 + Propack_UnpackM1(compressed, gDecompressionHeap); +#elif RNC2 + Propack_UnpackM2(compressed, gDecompressionHeap); #else slidstart(compressed, gDecompressionHeap); #endif diff --git a/tools/.gitignore b/tools/.gitignore index fcfd9466..9dddd0ca 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -9,6 +9,7 @@ /n64graphics /n64graphics_ci /patch_libultra_math +/rncpack /skyconv /tabledesign /textconv diff --git a/tools/Makefile b/tools/Makefile index 4a2062c7..33b8bd71 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -7,7 +7,7 @@ CC := gcc CXX := g++ CFLAGS := -I . -Wall -Wextra -Wno-unused-parameter -pedantic -O2 -s LDFLAGS := -lm -ALL_PROGRAMS := armips bfsize filesizer n64graphics n64graphics_ci mio0 slienc n64cksum textconv patch_libultra_math aifc_decode aiff_extract_codebook vadpcm_enc tabledesign extract_data_for_mio skyconv +ALL_PROGRAMS := armips bfsize filesizer rncpack n64graphics n64graphics_ci mio0 slienc n64cksum textconv patch_libultra_math aifc_decode aiff_extract_codebook vadpcm_enc tabledesign extract_data_for_mio skyconv LIBAUDIOFILE := audiofile/libaudiofile.a # Only build armips from tools if it is not found on the system @@ -23,6 +23,8 @@ bfsize_SOURCES := bfsize.c filesizer_SOURCES := filesizer.c +rncpack_SOURCES := rncpack.c + n64graphics_SOURCES := n64graphics.c utils.c n64graphics_CFLAGS := -DN64GRAPHICS_STANDALONE diff --git a/tools/rncpack.c b/tools/rncpack.c new file mode 100644 index 00000000..3017b8a2 --- /dev/null +++ b/tools/rncpack.c @@ -0,0 +1,1747 @@ +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#else +#include +#define mkdir(name, mode) mkdir(name) +#endif + +#ifndef _countof +#ifndef __cplusplus +#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) +#else +extern "C++" { + template char(*__countof_helper(UNALIGNED _CountofType(&_Array)[_SizeOfArray]))[_SizeOfArray]; +#define _countof(_Array) sizeof(*__countof_helper(_Array)) +} +#endif +#endif + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; + +#pragma pack(push, 1) +typedef struct huftable_s { + uint32 l1; // +0 + uint16 l2; // +4 + uint32 l3; // +6 + uint16 bit_depth; // +A +} huftable_t; + +#pragma pack(pop) + +typedef struct vars_s { + uint16 max_matches; + uint16 enc_key; + uint32 pack_block_size; + uint16 dict_size; + uint32 method; + uint32 puse_mode; + uint32 input_size; + uint32 file_size; + + // inner + uint32 bytes_left; + uint32 packed_size; + uint32 processed_size; + uint32 v7; + uint32 pack_block_pos; + uint16 pack_token, bit_count, v11; + uint16 last_min_offset; + uint32 v17; + uint32 pack_block_left_size; + uint16 match_count; + uint16 match_offset; + uint32 v20, v21; + uint32 bit_buffer; + + uint32 unpacked_size; + uint32 rnc_data_size; + uint16 unpacked_crc, unpacked_crc_real; + uint16 packed_crc; + uint32 leeway; + uint32 chunks_count; + + uint8 *mem1; + uint8 *pack_block_start; + uint8 *pack_block_max; + uint8 *pack_block_end; + uint16 *mem2; + uint16 *mem3; + uint16 *mem4; + uint16 *mem5; + + uint8 *decoded; + uint8 *window; + + size_t read_start_offset, write_start_offset; + uint8 *input, *output, *temp; + size_t input_offset, output_offset, temp_offset; + + uint8 tmp_crc_data[2048]; + huftable_t raw_table[16]; + huftable_t pos_table[16]; + huftable_t len_table[16]; +} vars_t; + +#define RNC_SIGN 0x524E43 // RNC +#define RNC_HEADER_SIZE 0x12 +#define MAX_BUF_SIZE 0x1E00000 + +static const uint16 crc_table[] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 +}; + +static const uint8 match_count_bits_table[] = { 0x00, 0x0E, 0x08, 0x0A, 0x012, 0x013, 0x016 }; +static const uint8 match_count_bits_count_table[] = { 0, 4, 4, 4, 5, 5, 5 }; +static const uint8 match_offset_bits_table[] = { 0x00, 0x06, 0x08, 0x09, 0x15, 0x17, 0x1D, 0x1F, 0x28, 0x29, 0x2C, 0x2D, 0x38, 0x39, 0x3C, 0x3D }; +static const uint8 match_offset_bits_count_table[] = { 1, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6 }; + +uint8 peek_byte(uint8 *buf, size_t offset) +{ + return buf[offset]; +} + +uint8 read_byte(uint8 *buf, size_t *offset) +{ + return buf[(*offset)++]; +} + +void write_byte(uint8 *buf, size_t *offset, uint8 b) +{ + buf[(*offset)++] = b; +} + +uint16 peek_word_be(uint8 *buf, size_t offset) +{ + uint8 b1 = peek_byte(buf, offset + 0); + uint8 b2 = peek_byte(buf, offset + 1); + + return (b1 << 8) | b2; +} + +uint16 read_word_be(uint8 *buf, size_t *offset) +{ + uint8 b1 = read_byte(buf, offset); + uint8 b2 = read_byte(buf, offset); + + return (b1 << 8) | b2; +} + +void write_word_be(uint8 *buf, size_t *offset, uint16 val) +{ + write_byte(buf, offset, (val >> 8) & 0xFF); + write_byte(buf, offset, (val >> 0) & 0xFF); +} + +uint32 peek_dword_be(uint8 *buf, size_t offset) +{ + uint16 w1 = peek_word_be(buf, offset + 0); + uint16 w2 = peek_word_be(buf, offset + 2); + + return (w1 << 16) | w2; +} + +uint32 read_dword_be(uint8 *buf, size_t *offset) +{ + uint16 w1 = read_word_be(buf, offset); + uint16 w2 = read_word_be(buf, offset); + + return (w1 << 16) | w2; +} + +void write_dword_be(uint8 *buf, size_t *offset, uint32 val) +{ + write_word_be(buf, offset, (val >> 16)); + write_word_be(buf, offset, (val & 0xFFFF)); +} + +void read_buf(uint8 *dest, uint8 *source, size_t *offset, int size) +{ + memmove(dest, &source[*offset], size); + *offset += size; +} + +void write_buf(uint8 *dest, size_t *offset, uint8 *source, int size) +{ + memmove(&dest[*offset], source, size); + *offset += size; +} + +uint16 crc_block(uint8 *buf, size_t offset, int size) +{ + uint16 crc = 0; + + while (size--) + { + crc ^= read_byte(buf, &offset); + crc = (crc >> 8) ^ crc_table[crc & 0xFF]; + } + + return crc; +} + +void ror_w(uint16 *x) +{ + if (*x & 1) + *x = 0x8000 | (*x >> 1); + else + *x >>= 1; +} + +vars_t *init_vars() +{ + vars_t *v = (vars_t*)malloc(sizeof(vars_t)); + v->enc_key = 0; + v->max_matches = 0x1000; + v->unpacked_crc_real = 0; + v->pack_block_size = 0x3000; + v->dict_size = 0xFFFF; + v->method = 1; + v->puse_mode = 'p'; + + v->read_start_offset = 0; + v->write_start_offset = 0; + v->input_offset = 0; + v->output_offset = 0; + v->temp_offset = 0; + + memset(v->tmp_crc_data, 0, sizeof(v->tmp_crc_data)); + memset(v->raw_table, 0, sizeof(v->raw_table)); + memset(v->pos_table, 0, sizeof(v->pos_table)); + memset(v->len_table, 0, sizeof(v->len_table)); + + return v; +} + +void init_dicts(vars_t *v) +{ + uint16 dict_size = v->dict_size; + + for (int i = 0; i < 0x800; ++i) + { + v->mem2[i * 0x10 + 0x0] = dict_size; v->mem2[i * 0x10 + 0x1] = dict_size; + v->mem2[i * 0x10 + 0x2] = dict_size; v->mem2[i * 0x10 + 0x3] = dict_size; + v->mem2[i * 0x10 + 0x4] = dict_size; v->mem2[i * 0x10 + 0x5] = dict_size; + v->mem2[i * 0x10 + 0x6] = dict_size; v->mem2[i * 0x10 + 0x7] = dict_size; + v->mem2[i * 0x10 + 0x8] = dict_size; v->mem2[i * 0x10 + 0x9] = dict_size; + v->mem2[i * 0x10 + 0xA] = dict_size; v->mem2[i * 0x10 + 0xB] = dict_size; + v->mem2[i * 0x10 + 0xC] = dict_size; v->mem2[i * 0x10 + 0xD] = dict_size; + v->mem2[i * 0x10 + 0xE] = dict_size; v->mem2[i * 0x10 + 0xF] = dict_size; + + v->mem3[i * 0x10 + 0x0] = dict_size; v->mem3[i * 0x10 + 0x1] = dict_size; + v->mem3[i * 0x10 + 0x2] = dict_size; v->mem3[i * 0x10 + 0x3] = dict_size; + v->mem3[i * 0x10 + 0x4] = dict_size; v->mem3[i * 0x10 + 0x5] = dict_size; + v->mem3[i * 0x10 + 0x6] = dict_size; v->mem3[i * 0x10 + 0x7] = dict_size; + v->mem3[i * 0x10 + 0x8] = dict_size; v->mem3[i * 0x10 + 0x9] = dict_size; + v->mem3[i * 0x10 + 0xA] = dict_size; v->mem3[i * 0x10 + 0xB] = dict_size; + v->mem3[i * 0x10 + 0xC] = dict_size; v->mem3[i * 0x10 + 0xD] = dict_size; + v->mem3[i * 0x10 + 0xE] = dict_size; v->mem3[i * 0x10 + 0xF] = dict_size; + } + + for (int i = 0; i < dict_size; ++i) + { + v->mem5[i & 0x7FFF] = 0; + v->mem4[i & 0x7FFF] = i; + } + + v->last_min_offset = 0; +} + +void update_packed_crc(vars_t *v, uint8 b) +{ + uint16 crc = v->packed_crc; + v->packed_crc = crc_table[(crc & 0xFF) ^ b] ^ (crc >> 8); + v->packed_size++; +} + +void update_unpacked_crc(vars_t *v, uint8 b) +{ + uint16 crc = v->unpacked_crc; + v->unpacked_crc = crc_table[(crc & 0xFF) ^ b] ^ (crc >> 8); + v->processed_size++; +} + +void write_to_output(vars_t *v, uint8 b) +{ + if (v->packed_size >= (v->file_size - RNC_HEADER_SIZE)) + return; + + write_byte(v->output, &v->output_offset, b); + update_packed_crc(v, b); +} + +uint8 read_from_input(vars_t *v) +{ + uint8 b = read_byte(v->input, &v->input_offset); + update_unpacked_crc(v, b); + + return b; +} + +void write_bits_m2(vars_t *v, uint16 value, int count) +{ + uint32 mask = (1 << (count - 1)); + + while (count--) + { + v->pack_token <<= 1; + + if (value & mask) + v->pack_token++; + + mask >>= 1; + v->bit_count++; + + if (v->bit_count == 8) + { + write_to_output(v, (v->pack_token >> 0) & 0xFF); + + for (int i = 0; i < v->v11; ++i) + write_to_output(v, v->tmp_crc_data[i]); + + v->v11 = 0; + + if ((v->processed_size > v->packed_size) && (v->processed_size - v->packed_size > v->leeway)) + v->leeway = v->processed_size - v->packed_size; + + v->bit_count = 0; + v->pack_token = 0; + } + } +} + +void write_bits_m1(vars_t *v, uint16 value, int count) +{ + while (count--) + { + v->pack_token >>= 1; + v->pack_token |= (value & 1) ? 0x8000 : 0; + + value >>= 1; + v->bit_count++; + + if (v->bit_count == 16) + { + write_to_output(v, (v->pack_token >> 0) & 0xFF); + write_to_output(v, (v->pack_token >> 8) & 0xFF); + + for (int i = 0; i < v->v11; ++i) + write_to_output(v, v->tmp_crc_data[i]); + + v->v11 = 0; + + if ((v->processed_size > v->packed_size) && (v->processed_size - v->packed_size > v->leeway)) + v->leeway = v->processed_size - v->packed_size; + + v->bit_count = 0; + v->pack_token = 0; + } + } +} + +void write_bits(vars_t *v, uint16 bits, int count) +{ + if (v->method == 2) + write_bits_m2(v, bits, count); + else + write_bits_m1(v, bits, count); +} + +int find_matches(vars_t *v) +{ + v->match_count = 1; + v->match_offset = 0; + + int match_offset = 1; + while (match_offset < (v->pack_block_end - v->pack_block_start) && (v->pack_block_start[match_offset] == v->pack_block_start[0])) + match_offset++; + + uint16 first_word = peek_word_be(v->pack_block_start, 0); + uint16 offset = v->mem2[first_word & 0x7FFF]; + + while (1) + { + if (offset == v->dict_size) + { + if ((v->match_count == 2) && (v->match_offset > 0x100)) + { + v->match_count = 1; + v->match_offset = 0; + } + + break; + } + + uint16 restore = v->mem4[offset & 0x7FFF]; + uint16 min_offset = v->last_min_offset; + + if (min_offset <= offset) + min_offset += v->dict_size; + + min_offset -= offset; + if (peek_word_be(v->pack_block_start, -min_offset) == peek_word_be(v->pack_block_start, 0)) + { + uint16 max_count = v->mem5[offset & 0x7FFF]; + + if (max_count <= min_offset) + { + if (max_count > match_offset) + { + min_offset = min_offset - max_count + match_offset; + max_count = match_offset; + } + + int max_size = v->pack_block_end - v->pack_block_start; + if (max_count == match_offset) + { + while (max_count < max_size && (v->pack_block_start[max_count] == v->pack_block_start[max_count - min_offset])) + max_count++; + } + } + else + { + min_offset = 1; + max_count = match_offset; + } + + if (max_count > v->max_matches) + max_count = v->max_matches; + + if (max_count >= v->match_count) + { + v->match_count = max_count; + v->match_offset = min_offset; + } + } + + offset = restore; + } + + return 0; +} + +void find_and_check_matches(vars_t *v) +{ + find_matches(v); + + if (v->match_count >= 2) + { + if (v->pack_block_max - v->pack_block_start >= 3) + { + uint16 count = v->match_count; + uint16 offset = v->match_offset; + uint16 min_offset = v->last_min_offset; + + v->last_min_offset = (v->last_min_offset + 1) % v->dict_size; + + v->pack_block_start++; + find_matches(v); + v->pack_block_start--; + + v->last_min_offset = min_offset; + + if (count < v->match_count) + { + count = 1; + offset = 0; + } + + v->match_count = count; + v->match_offset = offset; + } + } +} + +int bits_count(int value) +{ + int count = 1; + while (value >>= 1) + count++; + + return count; +} + +void update_bits_table(vars_t *v, huftable_t *data, uint16 bits) +{ + if (bits <= 1) + data[bits].l1++; + else + data[bits_count(bits)].l1++; + + write_word_be(v->temp, &v->temp_offset, bits); +} + +void encode_matches(vars_t *v, uint16 w) +{ + while (1) + { + uint16 restore = v->mem4[v->last_min_offset & 0x7FFF]; + v->mem4[v->last_min_offset & 0x7FFF] = v->dict_size; + + if (restore != v->last_min_offset) + { + uint16 buffer_word = peek_word_be(v->pack_block_start, -v->dict_size); + v->mem2[buffer_word & 0x7FFF] = restore; + + if (v->dict_size == restore) + v->mem3[buffer_word & 0x7FFF] = v->dict_size; + } + + uint16 buffer_word = peek_word_be(v->pack_block_start, 0); + + if (v->mem2[buffer_word & 0x7FFF] == v->dict_size) + v->mem2[buffer_word & 0x7FFF] = v->last_min_offset; + else + v->mem4[v->mem3[buffer_word & 0x7FFF] & 0x7FFF] = v->last_min_offset; + + v->mem3[buffer_word & 0x7FFF] = v->last_min_offset; + + int count = 1; + while ((count < (v->pack_block_end - v->pack_block_start)) && (v->pack_block_start[count] == v->pack_block_start[0])) + count++; + + v->mem5[v->last_min_offset & 0x7FFF] = count; + + while (1) + { + v->last_min_offset = (v->last_min_offset + 1) % v->dict_size; + + v->pack_block_start++; + + if (!(--w)) + return; + + if ((--count) <= 1) + break; + + v->mem5[v->last_min_offset & 0x7FFF] = count; + + if (v->last_min_offset != v->mem4[v->last_min_offset & 0x7FFF]) + { + restore = v->mem4[v->last_min_offset & 0x7FFF]; + v->mem4[v->last_min_offset & 0x7FFF] = v->last_min_offset; + + buffer_word = peek_word_be(v->pack_block_start, -v->dict_size); + v->mem2[buffer_word & 0x7FFF] = restore; + + if (v->dict_size == restore) + v->mem3[buffer_word & 0x7FFF] = v->dict_size; + } + } + } +} + +void proc_6(vars_t *v) +{ + v->v17 = 0; + v->pack_block_left_size = v->pack_block_size; + v->input_offset = v->read_start_offset + v->v7 + v->pack_block_pos; + v->temp_offset = 0; + + uint32 data_length = 0; + + while (v->bytes_left || v->pack_block_pos) + { + uint16 size_to_read = 0xFFFF - v->dict_size - v->pack_block_pos; + + if (v->bytes_left < size_to_read) + size_to_read = v->bytes_left; + + v->pack_block_start = &v->mem1[v->dict_size]; + read_buf(&v->pack_block_start[v->pack_block_pos], v->input, &v->input_offset, size_to_read); + + v->bytes_left -= size_to_read; + v->pack_block_pos += size_to_read; + + v->pack_block_max = &v->pack_block_start[v->pack_block_pos]; + v->pack_block_end = &v->pack_block_start[v->pack_block_pos]; + + if (v->pack_block_left_size < v->pack_block_pos) + v->pack_block_max = &v->pack_block_start[v->pack_block_left_size]; + + while ((v->pack_block_start < v->pack_block_max - 1) && v->v17 < 0xFFFE) + { + find_and_check_matches(v); + + if (v->match_count >= 2) + { + if (v->pack_block_start + v->match_count <= v->pack_block_max) + { + update_bits_table(v, v->raw_table, data_length); + update_bits_table(v, v->pos_table, v->match_count - 2); + update_bits_table(v, v->len_table, v->match_offset - 1); + + encode_matches(v, v->match_count); + v->v17++; + data_length = 0; + } + else + { + if (v->v17 != 0) + break; + + v->match_count = v->pack_block_max - v->pack_block_start; + } + } + else + { + encode_matches(v, 1); + data_length++; + } + } + + v->pack_block_pos = v->pack_block_end - v->pack_block_start; + + memmove(v->mem1, &v->pack_block_start[-v->dict_size], v->dict_size + v->pack_block_pos); + + if ((v->pack_block_max < v->pack_block_end) || ((v->pack_block_max == v->pack_block_end) && !v->bytes_left) || v->v17 == 0xFFFE) + break; + + v->pack_block_left_size -= &v->pack_block_start[-v->dict_size] - v->mem1; + } + + if (v->pack_block_max == v->pack_block_end && !v->bytes_left && v->v17 != 0xFFFE) + data_length += v->pack_block_pos; + + update_bits_table(v, v->raw_table, data_length); + v->v17++; + + v->temp_offset = 0; +} + +void update_tmp_crc_data(vars_t *v, uint8 b) +{ + if (v->bit_count) + { + v->tmp_crc_data[v->v11] = b; + v->v11++; + } + else + write_to_output(v, b); +} + +void encode_matches_count(vars_t *v, int count) +{ + while (count > 0) + { + if (count >= 12) + { + if (count & 3) + { + write_bits_m2(v, 0, 1); + + uint8 b = read_from_input(v); + update_tmp_crc_data(v, (v->enc_key ^ b) & 0xFF); + + count--; + } + else + { + write_bits_m2(v, 0x17, 5); + + if (count >= 72) + { + write_bits_m2(v, 0xF, 4); + + for (int i = 0; i < 72; ++i) + { + uint8 b = read_from_input(v); + update_tmp_crc_data(v, (v->enc_key ^ b) & 0xFF); + } + + count -= 72; + } + else + { + write_bits_m2(v, (count - 12) >> 2, 4); + + while (count--) + { + uint8 b = read_from_input(v); + update_tmp_crc_data(v, (v->enc_key ^ b) & 0xFF); + } + } + } + + ror_w(&v->enc_key); + } + else while (count != 0) + { + write_bits_m2(v, 0, 1); + + uint8 b = read_from_input(v); + update_tmp_crc_data(v, (v->enc_key ^ b) & 0xFF); + + ror_w(&v->enc_key); + + count--; + } + } +} + +void clear_table(huftable_t *data, int count) +{ + for (int i = 0; i < count; ++i) + { + data[i].l1 = 0; + data[i].l2 = 0xFFFF; + data[i].l3 = 0; + data[i].bit_depth = 0; + } +} + +int proc_17(vars_t *v, huftable_t *data, int count) +{ + uint32 d6 = 0xFFFFFFFF; + uint32 d5 = 0xFFFFFFFF; + + int i = 0; + while (i < count) + { + if (data[i].l1) + { + if (data[i].l1 < d5) + { + d6 = d5; + v->v21 = v->v20; + d5 = data[i].l1; + v->v20 = i; + } + else if (data[i].l1 < d6) + { + d6 = data[i].l1; + v->v21 = i; + } + } + + i++; + } + + return (d5 != 0xFFFFFFFF && d6 != 0xFFFFFFFF); +} + +uint32 inverse_bits(uint32 value, int count) +{ + int i = 0; + while (count--) + { + i <<= 1; + + if (value & 1) + i |= 1; + + value >>= 1; + } + + return i; +} + +void proc_20(huftable_t *data, int count) +{ + int val = 0; + uint32 div = 0x80000000; + int bits_count = 1; + + while (bits_count <= 16) + { + int i = 0; + + while (1) + { + if (i >= count) + { + bits_count++; + div >>= 1; + break; + } + + if (data[i].bit_depth == bits_count) + { + data[i].l3 = inverse_bits(val / div, bits_count); + val += div; + } + + i++; + } + } +} + +void proc_16(vars_t *v, huftable_t *data, int count) +{ + int d4 = 0; + int ve = 0; + + for (int i = 0; i < count; ++i) + { + if (data[i].l1) + { + d4++; + ve = i; + } + } + + if (!d4) + return; + + if (d4 == 1) + { + data[ve].bit_depth++; + return; + } + + while (proc_17(v, data, count)) + { + data[v->v20].l1 += data[v->v21].l1; + data[v->v21].l1 = 0; + data[v->v20].bit_depth++; + + while (data[v->v20].l2 != 0xFFFF) + { + v->v20 = data[v->v20].l2; + data[v->v20].bit_depth++; + } + + data[v->v20].l2 = v->v21; + data[v->v21].bit_depth++; + + while (data[v->v21].l2 != 0xFFFF) + { + v->v21 = data[v->v21].l2; + data[v->v21].bit_depth++; + } + } + + proc_20(data, count); +} + +void proc_18(vars_t *v, huftable_t *data, int count) +{ + int cnt = count; + + while (cnt && !data[--cnt].bit_depth) + count--; + + write_bits_m1(v, count, 5); + + for (int i = 0; i < count; ++i) + write_bits_m1(v, data[i].bit_depth, 4); +} + +void proc_19(vars_t *v, huftable_t *data, int count) +{ + int bits; + + if (count > 1) + bits = bits_count(count); + else + bits = count; + + write_bits_m1(v, data[bits].l3, data[bits].bit_depth); + + if (bits > 1) + write_bits_m1(v, count - (1 << (bits - 1)), bits - 1); +} + +void compress_data_2(vars_t *v) +{ + int src_offset = v->read_start_offset; + + while (v->v7 < v->unpacked_size) + { + proc_6(v); + v->input_offset = src_offset; + + while (v->v17--) + { + uint32 data_length = read_word_be(v->temp, &v->temp_offset); + v->v7 += data_length; + + encode_matches_count(v, data_length); + + if (v->v17) + { + v->match_count = read_word_be(v->temp, &v->temp_offset); + v->match_offset = read_word_be(v->temp, &v->temp_offset); + + if (v->match_count) + { + if (v->match_count >= 7) + { + write_bits_m2(v, 0xF, 4); + update_tmp_crc_data(v, (v->match_count - 6) & 0xFF); + } + else + write_bits_m2(v, match_count_bits_table[v->match_count], match_count_bits_count_table[v->match_count]); + + write_bits_m2(v, match_offset_bits_table[v->match_offset >> 8], match_offset_bits_count_table[v->match_offset >> 8]); + } + else + write_bits_m2(v, 6, 3); + + update_tmp_crc_data(v, v->match_offset & 0xFF); + + v->match_count += 2; + v->v7 += v->match_count; + + while (v->match_count--) + read_from_input(v); + } + } + + write_bits_m2(v, 0xF, 4); + update_tmp_crc_data(v, 0); + + if (v->v7 >= v->unpacked_size) + write_bits_m2(v, 0, 1); + else + write_bits_m2(v, 1, 1); + + if (!v->bit_count) + { + for (int i = 0; i < v->v11; ++i) + write_to_output(v, v->tmp_crc_data[i]); + + v->v11 = 0; + } + + v->chunks_count++; + src_offset = v->input_offset; + } + + v->pack_token <<= (8 - v->bit_count); + + if (v->bit_count || v->v11) + write_to_output(v, v->pack_token & 0xFF); +} + +void compress_data_1(vars_t *v) +{ + int src_offset = v->read_start_offset; + + while (v->v7 < v->unpacked_size) + { + clear_table(v->len_table, _countof(v->len_table)); + clear_table(v->pos_table, _countof(v->pos_table)); + clear_table(v->raw_table, _countof(v->raw_table)); + + proc_6(v); + v->input_offset = src_offset; + + proc_16(v, v->raw_table, _countof(v->raw_table)); + proc_16(v, v->len_table, _countof(v->len_table)); + proc_16(v, v->pos_table, _countof(v->pos_table)); + + proc_18(v, v->raw_table, _countof(v->raw_table)); + proc_18(v, v->len_table, _countof(v->len_table)); + proc_18(v, v->pos_table, _countof(v->pos_table)); + + write_bits_m1(v, v->v17, 16); + + while (v->v17--) + { + uint32 data_length = read_word_be(v->temp, &v->temp_offset); + v->v7 += data_length; + + proc_19(v, v->raw_table, data_length); + + if (data_length) + { + while (data_length--) + { + uint8 b = read_from_input(v); + + if (!v->bit_count) + write_to_output(v, (v->enc_key ^ b) & 0xFF); + else + { + v->tmp_crc_data[v->v11] = (v->enc_key ^ b) & 0xFF; + v->v11++; + } + } + + ror_w(&v->enc_key); + } + + if (v->v17) + { + v->match_count = read_word_be(v->temp, &v->temp_offset); + v->match_offset = read_word_be(v->temp, &v->temp_offset); + + proc_19(v, v->len_table, v->match_offset); + proc_19(v, v->pos_table, v->match_count); + + v->match_count += 2; + v->v7 += v->match_count; + + while (v->match_count--) + read_from_input(v); + } + } + + if (!v->bit_count) + { + for (int i = 0; i < v->v11; ++i) + write_to_output(v, v->tmp_crc_data[i]); + + v->v11 = 0; + } + + v->chunks_count++; + src_offset = v->input_offset; + } + + v->pack_token >>= (16 - v->bit_count); + + if (v->bit_count || v->v11) + write_to_output(v, v->pack_token & 0xFF); + + if (v->bit_count > 8 || v->v11) + write_to_output(v, v->pack_token >> 8); +} + +void do_pack_data(vars_t *v) +{ + v->unpacked_size = v->file_size; + v->packed_size = v->file_size; + v->bytes_left = v->file_size; + + if (v->file_size <= RNC_HEADER_SIZE) + return; + + v->unpacked_crc = 0; + v->packed_crc = 0; + + v->packed_size = 0; + v->processed_size = 0; + v->v7 = 0; + v->pack_block_pos = 0; + v->pack_token = 0; + v->bit_count = 0; + v->v11 = 0; + v->leeway = 0; + v->chunks_count = 0; + + v->mem1 = (uint8 *)malloc(0xFFFF); + v->mem2 = (uint16 *)malloc(0x10000); + v->mem3 = (uint16 *)malloc(0x10000); + v->mem4 = (uint16 *)malloc(0x10000); + v->mem5 = (uint16 *)malloc(0x10000); + + init_dicts(v); + + write_dword_be(v->output, &v->output_offset, (RNC_SIGN << 8) | (v->method & 0xFF)); + write_dword_be(v->output, &v->output_offset, v->unpacked_size); + write_dword_be(v->output, &v->output_offset, 0); + write_word_be(v->output, &v->output_offset, 0); + write_word_be(v->output, &v->output_offset, 0); + write_word_be(v->output, &v->output_offset, 0); + + uint16 key = v->enc_key; + write_bits(v, 0, 1); // no lock + write_bits(v, (v->enc_key ? 1 : 0), 1); + + switch (v->method) + { + case 1: compress_data_1(v); break; + case 2: compress_data_2(v); + } + + for (int i = 0; i < v->v11; ++i) + write_to_output(v, v->tmp_crc_data[i]); + + v->v11 = 0; + + v->enc_key = key; + + if (v->leeway >(v->unpacked_size - v->packed_size)) + v->leeway -= (v->unpacked_size - v->packed_size); + else + v->leeway = 0; + + if (v->method == 2) + v->leeway += 2; + + v->packed_size = v->output_offset - v->write_start_offset; + + v->output_offset = v->write_start_offset + 8; + + write_dword_be(v->output, &v->output_offset, v->packed_size - RNC_HEADER_SIZE); + write_word_be(v->output, &v->output_offset, v->unpacked_crc); + write_word_be(v->output, &v->output_offset, v->packed_crc); + + write_byte(v->output, &v->output_offset, v->leeway); + write_byte(v->output, &v->output_offset, v->chunks_count); + + v->output_offset = v->packed_size + v->write_start_offset; + v->input_offset = v->unpacked_size + v->read_start_offset; + + free(v->mem1); + free(v->mem2); + free(v->mem3); + free(v->mem4); + free(v->mem5); +} + +int do_pack(vars_t *v) +{ + if (v->file_size <= RNC_HEADER_SIZE) + return 2; + + v->input_offset = 0; + v->output_offset = 0; + + if ((peek_dword_be(v->input, v->input_offset) >> 8) == RNC_SIGN) + return 3; + + do_pack_data(v); + + return 0; +} + +uint8 read_source_byte(vars_t *v) +{ + if (v->pack_block_start == &v->mem1[0xFFFD]) + { + int left_size = v->file_size - v->input_offset; + + int size_to_read; + if (left_size <= 0xFFFD) + size_to_read = left_size; + else + size_to_read = 0xFFFD; + + v->pack_block_start = v->mem1; + + read_buf(v->pack_block_start, v->input, &v->input_offset, size_to_read); + + if (left_size - size_to_read > 2) + left_size = 2; + else + left_size -= size_to_read; + + read_buf(&v->mem1[size_to_read], v->input, &v->input_offset, left_size); + v->input_offset -= left_size; + } + + return *v->pack_block_start++; +} + +uint32 input_bits_m2(vars_t *v, short count) +{ + uint32 bits = 0; + + while (count--) + { + if (!v->bit_count) + { + v->bit_buffer = read_source_byte(v); + v->bit_count = 8; + } + + bits <<= 1; + + if (v->bit_buffer & 0x80) + bits |= 1; + + v->bit_buffer <<= 1; + v->bit_count--; + } + + return bits; +} + +uint32 input_bits_m1(vars_t *v, short count) +{ + uint32 bits = 0; + uint32 prev_bits = 1; + + while (count--) + { + if (!v->bit_count) + { + uint8 b1 = read_source_byte(v); + uint8 b2 = read_source_byte(v); + v->bit_buffer = (v->pack_block_start[1] << 24) | (v->pack_block_start[0] << 16) | (b2 << 8) | b1; + + v->bit_count = 16; + } + + if (v->bit_buffer & 1) + bits |= prev_bits; + + v->bit_buffer >>= 1; + prev_bits <<= 1; + v->bit_count--; + } + + return bits; +} + +int input_bits(vars_t *v, short count) +{ + if (v->method != 2) + return input_bits_m1(v, count); + else + return input_bits_m2(v, count); +} + +void decode_match_count(vars_t *v) +{ + v->match_count = input_bits_m2(v, 1) + 4; + + if (input_bits_m2(v, 1)) + v->match_count = ((v->match_count - 1) << 1) + input_bits_m2(v, 1); +} + +void decode_match_offset(vars_t *v) +{ + v->match_offset = 0; + if (input_bits_m2(v, 1)) + { + v->match_offset = input_bits_m2(v, 1); + + if (input_bits_m2(v, 1)) + { + v->match_offset = ((v->match_offset << 1) | input_bits_m2(v, 1)) | 4; + + if (!input_bits_m2(v, 1)) + v->match_offset = (v->match_offset << 1) | input_bits_m2(v, 1); + } + else if (!v->match_offset) + v->match_offset = input_bits_m2(v, 1) + 2; + } + + v->match_offset = ((v->match_offset << 8) | read_source_byte(v)) + 1; +} + +void write_decoded_byte(vars_t *v, uint8 b) +{ + if (&v->decoded[0xFFFF] == v->window) + { + write_buf(v->output, &v->output_offset, &v->decoded[v->dict_size], 0xFFFF - v->dict_size); + memmove(v->decoded, &v->window[-v->dict_size], v->dict_size); + v->window = &v->decoded[v->dict_size]; + } + + *v->window++ = b; + v->unpacked_crc_real = crc_table[(v->unpacked_crc_real ^ b) & 0xFF] ^ (v->unpacked_crc_real >> 8); +} + +int unpack_data_m2(vars_t *v) +{ + while (v->processed_size < v->input_size) + { + while (1) + { + if (!input_bits_m2(v, 1)) + { + write_decoded_byte(v, (v->enc_key ^ read_source_byte(v)) & 0xFF); + + ror_w(&v->enc_key); + + v->processed_size++; + } + else + { + if (input_bits_m2(v, 1)) + { + if (input_bits_m2(v, 1)) + { + if (input_bits_m2(v, 1)) + { + v->match_count = read_source_byte(v) + 8; + + if (v->match_count == 8) + { + input_bits_m2(v, 1); + break; + } + } + else + v->match_count = 3; + + decode_match_offset(v); + } + else + { + v->match_count = 2; + v->match_offset = read_source_byte(v) + 1; + } + + v->processed_size += v->match_count; + + while (v->match_count--) + write_decoded_byte(v, v->window[-v->match_offset]); + } + else + { + decode_match_count(v); + + if (v->match_count != 9) + { + decode_match_offset(v); + v->processed_size += v->match_count; + + while (v->match_count--) + write_decoded_byte(v, v->window[-v->match_offset]); + } + else + { + uint32 data_length = (input_bits_m2(v, 4) << 2) + 12; + v->processed_size += data_length; + + while (data_length--) + write_decoded_byte(v, (v->enc_key ^ read_source_byte(v)) & 0xFF); + + ror_w(&v->enc_key); + } + } + } + } + } + + write_buf(v->output, &v->output_offset, &v->decoded[v->dict_size], v->window - &v->decoded[v->dict_size]); + return 0; +} + +void make_huftable(vars_t *v, huftable_t *data, int count) +{ + clear_table(data, count); + + int leaf_nodes = input_bits_m1(v, 5); + + if (leaf_nodes) + { + if (leaf_nodes > 16) + leaf_nodes = 16; + + for (int i = 0; i < leaf_nodes; ++i) + data[i].bit_depth = input_bits_m1(v, 4); + + proc_20(data, leaf_nodes); + } +} + +uint32 decode_table_data(vars_t *v, huftable_t *data) +{ + uint32 i = 0; + + while (1) + { + if (data[i].bit_depth && (data[i].l3 == (v->bit_buffer & ((1 << data[i].bit_depth) - 1)))) + { + input_bits_m1(v, data[i].bit_depth); + + if (i < 2) + return i; + + return input_bits_m1(v, i - 1) | (1 << (i - 1)); + } + + i++; + } +} + +int unpack_data_m1(vars_t *v) +{ + while (v->processed_size < v->input_size) + { + make_huftable(v, v->raw_table, _countof(v->raw_table)); + make_huftable(v, v->len_table, _countof(v->len_table)); + make_huftable(v, v->pos_table, _countof(v->pos_table)); + + int subchunks = input_bits_m1(v, 16); + + while (subchunks--) + { + uint32 data_length = decode_table_data(v, v->raw_table); + v->processed_size += data_length; + + if (data_length) + { + while (data_length--) + write_decoded_byte(v, (v->enc_key ^ read_source_byte(v)) & 0xFF); + + ror_w(&v->enc_key); + + v->bit_buffer = (((v->pack_block_start[2] << 16) | (v->pack_block_start[1] << 8) | v->pack_block_start[0]) << v->bit_count) | (v->bit_buffer & ((1 << v->bit_count) - 1)); + } + + if (subchunks) + { + v->match_offset = decode_table_data(v, v->len_table) + 1; + v->match_count = decode_table_data(v, v->pos_table) + 2; + v->processed_size += v->match_count; + + while (v->match_count--) + write_decoded_byte(v, v->window[-v->match_offset]); + } + } + } + + write_buf(v->output, &v->output_offset, &v->decoded[v->dict_size], v->window - &v->decoded[v->dict_size]); + return 0; +} + +int do_unpack_data(vars_t *v) +{ + int start_pos = v->input_offset; + + uint32 sign = read_dword_be(v->input, &v->input_offset); + if ((sign >> 8) != RNC_SIGN) + return 6; + + v->method = sign & 3; + v->input_size = read_dword_be(v->input, &v->input_offset); + v->packed_size = read_dword_be(v->input, &v->input_offset); + if (v->file_size < v->packed_size) + return 7; + v->unpacked_crc = read_word_be(v->input, &v->input_offset); + v->packed_crc = read_word_be(v->input, &v->input_offset); + + /*v->leeway = */read_byte(v->input, &v->input_offset); + /*v->chunks_count = */read_byte(v->input, &v->input_offset); + + if (crc_block(v->input, v->input_offset, v->packed_size) != v->packed_crc) + return 4; + + v->mem1 = (uint8*)malloc(0xFFFF); + v->decoded = (uint8*)malloc(0xFFFF); + v->pack_block_start = &v->mem1[0xFFFD]; + v->window = &v->decoded[v->dict_size]; + + v->unpacked_crc_real = 0; + v->bit_count = 0; + v->bit_buffer = 0; + v->processed_size = 0; + + uint16 specified_key = v->enc_key; + + int error_code = 0; + if (input_bits(v, 1) && v->puse_mode == 'p') + error_code = 9; + + if (!error_code) + { + if (input_bits(v, 1) && !v->enc_key) // key is needed, but not specified as argument + error_code = 10; + } + + if (!error_code) + { + switch (v->method) + { + case 1: error_code = unpack_data_m1(v); break; + case 2: error_code = unpack_data_m2(v); break; + } + } + + v->enc_key = specified_key; + + free(v->mem1); + free(v->decoded); + + v->input_offset = start_pos + v->packed_size + RNC_HEADER_SIZE; + + if (error_code) + return error_code; + + if (v->unpacked_crc != v->unpacked_crc_real) + return 5; + + return 0; +} + +int do_unpack(vars_t *v) +{ + v->packed_size = v->file_size; + + if (v->file_size < RNC_HEADER_SIZE) + return 6; + + return do_unpack_data(v); // data +} + +int do_search(vars_t *v, size_t input_size, int save) +{ + int error_code = 11; + int has_rncs = 0; + + for (uint32 i = 0; i < input_size - RNC_HEADER_SIZE; ) + { + v->read_start_offset = i; + v->file_size = input_size - i; + v->input_offset = 0; + v->output_offset = 0; + + uint8 *input_ptr = v->input; + v->input = &v->input[i]; + + if (!(error_code = do_unpack(v))) + { + printf("RNC archive found: 0x%.6x (%.6d/%.6zu bytes)\n", i, v->packed_size + RNC_HEADER_SIZE, v->output_offset); + i += v->packed_size + RNC_HEADER_SIZE; + error_code = 0; + has_rncs = 1; + + if (save) { + FILE* out; + + int dir_res = mkdir("extracted", S_IRWXU | S_IRWXG | S_IRWXO); + if (dir_res == -1 && errno != EEXIST) { + error_code = 12; + break; + } + + char out_name[256]; + snprintf(out_name, sizeof(out_name), "%s/data_%.6zx.bin", "extracted", v->read_start_offset); + + out = fopen(out_name, "wb"); + + if (out == NULL) + { + error_code = 12; + break; + } + + fwrite(v->output, v->output_offset, 1, out); + fclose(out); + } + } + else + { + switch (error_code) + { + case 4: printf("Position 0x%.6X: Packed CRC is wrong!\n", i); break; + case 5: printf("Position 0x%.6X: Unpacked CRC is wrong!\n", i); break; + case 9: printf("Position 0x%.6X: File already packed!\n", i); break; + case 10: printf("Position 0x%.6X: Decryption key required!\n", i); break; + } + + i++; + } + + v->input = input_ptr; + } + + return has_rncs ? 0 : ((error_code == 6) ? 11 : error_code); +} + +void print_usage() +{ + printf("Unpack : [outfile.bin] [-i=hex_offset_to_read_from] [-k=hex_key_if_protected]\n"); + printf("Search : \n"); + printf("Seach&Extract : \n"); + printf("Pack :

[outfile.bin] <-m=1|2> [-k=hex_key_to_protect]\n"); +} + +int parse_args(int argc, char **argv, vars_t *vars) +{ + if (argc < 2) + return 1; + + if (strchr("puse", argv[1][0])) + { + switch (argv[1][0]) + { + case 'p': + case 'u': + case 's': + case 'e': + vars->puse_mode = argv[1][0]; break; + } + } + else + return 1; + + int i = 3; + while (i < argc) + { + if (((argv[i][0] == '-') || (argv[i][0] == '/'))) { + char which = argv[i][1]; + // If argument is just the letter, use next arg; otherwise, use what's after it + char const *arg_ptr = argv[i][2] ? &argv[i][2] : argv[++i]; + + // Argument list ends with a NULL ptr, error out if reached + if (!arg_ptr) + return 3; + + switch (which) + { + case 'k': + sscanf(arg_ptr, "%hx", &vars->enc_key); + if (!vars->enc_key) + return 3; + break; + case 'd': + sscanf(arg_ptr, "%hx", &vars->dict_size); + if (vars->dict_size < 0x400) + vars->dict_size = 0x400; + break; + case 'i': + sscanf(arg_ptr, "%zx", &vars->read_start_offset); + break; + case 'o': + sscanf(arg_ptr, "%zx", &vars->write_start_offset); + break; + case 'm': + sscanf(arg_ptr, "%uint32 *", &vars->method); + if (!vars->method || vars->method > 2) + return 3; + break; + default: + break; + } + } + i++; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + printf("-= RNC ProPackED v1.5 [by Lab 313] (12/02/2020) =-\n"); + printf("-----------------------------\n"); + + if (argc <= 2) { + printf("Compression type: Huffman + LZ77\n"); + printf("De/Compressor: Dr.MefistO\n"); + printf("Coding: Dr. MefistO\n"); + printf("Original: Rob Northen Computing\n"); + printf("Info: De(re)compiled source of the famous RNC ProPack compression tool\n\n"); + print_usage(); + printf("-----------------------------\n\n"); + } + + vars_t *v = init_vars(); + if (parse_args(argc, argv, v)) { + printf("Wrong command line specified!\n"); + return 1; + } + + if (v->method == 1) + { + if (v->dict_size > 0x8000) + v->dict_size = 0x8000; + v->max_matches = 0x1000; + } + else if (v->method == 2) + { + if (v->dict_size > 0x1000) + v->dict_size = 0x1000; + v->max_matches = 0xFF; + } + + FILE *in = fopen(argv[2], "rb"); + if (in == NULL) + { + free(v); + printf("Cannot open input file!\n"); + return -1; + } + fseek(in, 0, SEEK_END); + v->file_size = ftell(in) - v->read_start_offset; + fseek(in, v->read_start_offset, SEEK_SET); + v->input = (uint8*)malloc(v->file_size); + fread(v->input, v->file_size, 1, in); + fclose(in); + + v->output = (uint8*)malloc(MAX_BUF_SIZE); + v->temp = (uint8*)malloc(MAX_BUF_SIZE); + + int error_code = 0; + switch (v->puse_mode) + { + case 'p': error_code = do_pack(v); break; + case 'u': error_code = do_unpack(v); break; + case 's': + case 'e': error_code = do_search(v, v->file_size, v->puse_mode == 'e'); break; + } + + if (!error_code && v->puse_mode != 's' && v->puse_mode != 'e') + { + FILE *out; + if (argc <= 3 || ((argv[3][0] == '-') || (argv[3][0] == '/'))) + { + char out_name[256]; + snprintf(out_name, sizeof(out_name), "%s.%.6zx.bin", argv[2], v->read_start_offset); + + out = fopen(out_name, "wb"); + } + else + out = fopen(argv[3], "wb"); + + if (out == NULL) + { + free(v->input); + free(v->output); + free(v->temp); + free(v); + printf("Cannot create output file!\n"); + return -1; + } + + fwrite(v->output, v->output_offset, 1, out); + fclose(out); + + printf("File successfully %s!\n", ((v->puse_mode == 'p') ? "packed" : "unpacked")); + printf("Original/new size: %d/%zd bytes\n", (v->puse_mode == 'u') ? (v->packed_size + RNC_HEADER_SIZE) : v->file_size, v->output_offset); + } + else { + switch (error_code) { + case 0: break; + case 4: printf("Corrupted input data.\n"); break; + case 5: printf("CRC check failed.\n"); break; + case 6: + case 7: printf("Wrong RNC header.\n"); break; + case 10: printf("Decryption key required.\n"); break; + case 11: printf("No RNC archives were found.\n"); break; + default: printf("Cannot process file. Error code: %x\n", error_code); break; + } + } + + free(v->input); + free(v->output); + free(v->temp); + free(v); + + return error_code; +} diff --git a/yay0rules.mk b/yay0rules.mk new file mode 100644 index 00000000..c75b4db3 --- /dev/null +++ b/yay0rules.mk @@ -0,0 +1,9 @@ +# Compress binary file +$(BUILD_DIR)/%.szp: $(BUILD_DIR)/%.bin + $(call print,Compressing:,$<,$@) + $(V)$(YAY0TOOL) $< $@ + +# convert binary szp to object file +$(BUILD_DIR)/%.szp.o: $(BUILD_DIR)/%.szp + $(call print,Converting YAY0 to ELF:,$<,$@) + $(V)printf ".section .data\n\n.incbin \"$<\"\n" | $(AS) $(ASFLAGS) -o $@ \ No newline at end of file