From aca48568164e2001c98129675f125797c329006b Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 8 May 2016 12:32:50 +0200 Subject: [PATCH 001/259] Create Makefile --- screeninit/Makefile | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 screeninit/Makefile diff --git a/screeninit/Makefile b/screeninit/Makefile new file mode 100644 index 0000000..28ed64b --- /dev/null +++ b/screeninit/Makefile @@ -0,0 +1,47 @@ +rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2)) + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/3ds_rules + +CC := arm-none-eabi-gcc +AS := arm-none-eabi-as +LD := arm-none-eabi-ld +OC := arm-none-eabi-objcopy + +name := $(shell basename $(CURDIR)) + +dir_source := source +dir_build := build + +ASFLAGS := -mcpu=mpcore -mfloat-abi=hard +CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math +LDFLAGS := -nostdlib + +objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ + $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ + $(call rwildcard, $(dir_source), *.s *.c))) + +.PHONY: all +all: $(name).bin + +.PHONY: clean +clean: + @rm -rf $(dir_build) + +$(name).bin: $(dir_build)/$(name).elf + $(OC) -S -O binary $< $@ + +$(dir_build)/$(name).elf: $(objects) + $(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^ + +$(dir_build)/%.o: $(dir_source)/%.c + @mkdir -p "$(@D)" + $(COMPILE.c) $(OUTPUT_OPTION) $< + +$(dir_build)/%.o: $(dir_source)/%.s + @mkdir -p "$(@D)" + $(COMPILE.s) $(OUTPUT_OPTION) $< +include $(call rwildcard, $(dir_build), *.d) From 344cb353ec78c66dc0250d9531c62a18e0769b8f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 8 May 2016 12:35:41 +0200 Subject: [PATCH 002/259] Create screeninit.h --- build/screeninit.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 build/screeninit.h diff --git a/build/screeninit.h b/build/screeninit.h new file mode 100644 index 0000000..4874089 --- /dev/null +++ b/build/screeninit.h @@ -0,0 +1,31 @@ +const char screeninit[]={ +0xc0,0x01,0x0c,0xf1,0x01,0x00,0x00,0xea,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0xe1,0x00,0xc0,0x9f,0xe5,0x1c,0xff,0x2f,0xe1,0x21,0xfc,0xff,0x24,0x00,0x00,0x00,0x00,0x30 +,0xb5,0x85,0xb0,0x69,0x46,0x7b,0x4a,0x31,0xca,0x31,0xc1,0x12,0x68,0x7a,0x48,0x0a,0x60,0x7a,0x49,0x7a,0x4a,0x12,0x68,0x08,0x60,0x01,0x20,0x6b,0x46,0x79,0x49,0x79 +,0x4c,0x08,0x60,0x79,0x49,0x25,0x68,0x29,0x40,0x21,0x60,0x92,0x00,0xd4,0x58,0x77,0x49,0x0c,0x60,0xd2,0x58,0x77,0x4b,0x1a,0x60,0x77,0x4b,0x77,0x4a,0x13,0x60,0x77 +,0x4a,0x13,0x60,0xe1,0x22,0x77,0x4b,0x52,0x00,0x1a,0x60,0x76,0x4b,0xf1,0x3a,0x1a,0x60,0xc2,0x23,0x75,0x49,0xff,0x33,0x0b,0x60,0x75,0x49,0x0b,0x60,0x00,0x23,0xcf +,0x24,0x74,0x49,0x0b,0x60,0x74,0x49,0x0c,0x60,0x74,0x49,0x0a,0x60,0x74,0x49,0x74,0x4a,0x11,0x60,0x80,0x21,0x74,0x4a,0x49,0x02,0x11,0x60,0x9e,0x21,0x73,0x4a,0xff +,0x31,0x11,0x60,0x72,0x4a,0x9c,0x39,0xff,0x39,0x11,0x60,0xc9,0x22,0x71,0x4c,0x52,0x00,0x22,0x60,0x70,0x4c,0x22,0x60,0x70,0x4c,0x22,0x60,0x70,0x4a,0x10,0x60,0x70 +,0x4a,0x11,0x60,0x70,0x49,0x71,0x4a,0x11,0x60,0x71,0x4a,0x13,0x60,0x71,0x4a,0x71,0x49,0x13,0x60,0x71,0x4a,0x11,0x60,0x71,0x49,0x72,0x4a,0x11,0x60,0x72,0x49,0x72 +,0x4a,0x11,0x60,0x72,0x49,0x73,0x4a,0x11,0x60,0x73,0x49,0x73,0x4a,0x11,0x60,0x73,0x49,0x74,0x4a,0x11,0x60,0xb4,0x21,0x73,0x4a,0x13,0x60,0x73,0x4a,0x89,0x00,0x11 +,0x60,0x73,0x4a,0x73,0x49,0x13,0x60,0x73,0x4a,0x74,0x48,0x84,0x46,0x0b,0x60,0x63,0x44,0x93,0x42,0xf9,0xd1,0xe1,0x22,0x71,0x4b,0x52,0x00,0x1a,0x60,0xd1,0x23,0x70 +,0x4a,0x13,0x60,0xc2,0x22,0x70,0x49,0xff,0x32,0x0a,0x60,0x6f,0x49,0x0a,0x60,0xcd,0x21,0x6f,0x4a,0x11,0x60,0x6f,0x4a,0x02,0x31,0x11,0x60,0x6e,0x4a,0x13,0x60,0x47 +,0x4a,0x6e,0x4b,0x1a,0x60,0x80,0x22,0x6d,0x4b,0x52,0x02,0x1a,0x60,0x9e,0x22,0x6c,0x4b,0xff,0x32,0x1a,0x60,0x52,0x23,0x6b,0x4a,0x13,0x60,0xc9,0x22,0x6b,0x49,0x52 +,0x00,0x0a,0x60,0x6a,0x49,0x0a,0x60,0x4f,0x21,0x6a,0x4a,0x11,0x60,0x6a,0x4a,0x01,0x31,0x11,0x60,0x69,0x4a,0x13,0x60,0x69,0x4a,0x6a,0x4b,0x1a,0x60,0x00,0x23,0x69 +,0x4a,0x13,0x60,0x69,0x4a,0x3f,0x39,0x11,0x60,0x69,0x49,0x69,0x4a,0x11,0x60,0x43,0x49,0x69,0x4a,0x11,0x60,0x69,0x49,0x69,0x4a,0x11,0x60,0x69,0x49,0x6a,0x4a,0x11 +,0x60,0x6a,0x49,0x6a,0x4a,0x11,0x60,0x45,0x49,0x6a,0x4a,0x11,0x60,0xb4,0x21,0x69,0x4a,0x13,0x60,0x69,0x4a,0x89,0x00,0x11,0x60,0x69,0x4a,0x69,0x49,0x13,0x60,0x45 +,0x4a,0x46,0x48,0x84,0x46,0x0b,0x60,0x63,0x44,0x93,0x42,0xf9,0xd1,0x38,0x4b,0x38,0x4a,0x13,0x60,0x64,0x4a,0x13,0x60,0x64,0x4a,0x13,0x60,0x64,0x4a,0x5a,0x49,0x13 +,0x60,0x58,0x4a,0x0a,0x60,0x63,0x49,0x0a,0x60,0x63,0x49,0x0b,0x60,0x63,0x49,0x0b,0x60,0x63,0x4b,0x1a,0x60,0x00,0x23,0x62,0x4a,0x13,0x60,0x13,0x68,0x00,0x2b,0xfc +,0xd0,0x60,0x4b,0x1b,0x68,0x00,0xf0,0xbf,0xf8,0x05,0xb0,0x30,0xbc,0x01,0xbc,0x00,0x47,0xc0,0x46,0x8c,0xff,0xff,0x24,0x7f,0x00,0x01,0x00,0x00,0x12,0x14,0x10,0x08 +,0xfc,0xff,0x24,0x14,0x20,0x20,0x10,0x0c,0x20,0x20,0x10,0xfe,0xff,0xfe,0xff,0x40,0x22,0x20,0x10,0x40,0x2a,0x20,0x10,0x3e,0x02,0x01,0x00,0x44,0x22,0x20,0x10,0x44 +,0x2a,0x20,0x10,0x00,0x04,0x40,0x10,0x04,0x04,0x40,0x10,0x08,0x04,0x40,0x10,0x0c,0x04,0x40,0x10,0x10,0x04,0x40,0x10,0x14,0x04,0x40,0x10,0x18,0x04,0x40,0x10,0xc1 +,0x01,0xc5,0x01,0x1c,0x04,0x40,0x10,0x20,0x04,0x40,0x10,0x24,0x04,0x40,0x10,0x28,0x04,0x40,0x10,0x2c,0x04,0x40,0x10,0x30,0x04,0x40,0x10,0x34,0x04,0x40,0x10,0x38 +,0x04,0x40,0x10,0x3c,0x04,0x40,0x10,0x92,0x01,0x96,0x01,0x40,0x04,0x40,0x10,0x44,0x04,0x40,0x10,0x48,0x04,0x40,0x10,0x90,0x01,0xf0,0x00,0x5c,0x04,0x40,0x10,0xd1 +,0x00,0xc1,0x01,0x60,0x04,0x40,0x10,0x02,0x00,0x92,0x01,0x64,0x04,0x40,0x10,0x00,0x00,0x30,0x18,0x68,0x04,0x40,0x10,0x41,0x03,0x08,0x00,0x70,0x04,0x40,0x10,0x01 +,0x05,0x01,0x00,0x74,0x04,0x40,0x10,0x78,0x04,0x40,0x10,0x90,0x04,0x40,0x10,0x9c,0x04,0x40,0x10,0x84,0x04,0x40,0x10,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00 +,0x05,0x40,0x10,0x04,0x05,0x40,0x10,0x08,0x05,0x40,0x10,0x0c,0x05,0x40,0x10,0x10,0x05,0x40,0x10,0x14,0x05,0x40,0x10,0x18,0x05,0x40,0x10,0x1c,0x05,0x40,0x10,0x20 +,0x05,0x40,0x10,0x24,0x05,0x40,0x10,0x28,0x05,0x40,0x10,0x2c,0x05,0x40,0x10,0x30,0x05,0x40,0x10,0x34,0x05,0x40,0x10,0x38,0x05,0x40,0x10,0x3c,0x05,0x40,0x10,0x94 +,0x01,0x98,0x01,0x40,0x05,0x40,0x10,0x44,0x05,0x40,0x10,0x48,0x05,0x40,0x10,0x40,0x01,0xf0,0x00,0x5c,0x05,0x40,0x10,0x60,0x05,0x40,0x10,0x52,0x00,0x92,0x01,0x64 +,0x05,0x40,0x10,0x00,0x65,0x34,0x18,0x68,0x05,0x40,0x10,0x01,0x03,0x08,0x00,0x70,0x05,0x40,0x10,0x74,0x05,0x40,0x10,0x78,0x05,0x40,0x10,0x90,0x05,0x40,0x10,0x9c +,0x05,0x40,0x10,0x84,0x05,0x40,0x10,0x6c,0x04,0x40,0x10,0x94,0x04,0x40,0x10,0x98,0x04,0x40,0x10,0x6c,0x05,0x40,0x10,0x00,0xfe,0xff,0x23,0x04,0xfe,0xff,0x23,0x08 +,0xfe,0xff,0x23,0xf8,0xff,0xff,0x1f,0x18,0x47,0xc0,0x46,0x5f,0x00,0x00,0x00,0x4c,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x26,0x00,0x00,0x00}; +const int screeninit_size=924; From 6b9b59f09fc386eb91dbd5aa78d614cbf8e943da Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 8 May 2016 12:36:24 +0200 Subject: [PATCH 003/259] Create linker.ld --- screeninit/linker.ld | 47 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 screeninit/linker.ld diff --git a/screeninit/linker.ld b/screeninit/linker.ld new file mode 100644 index 0000000..28ed64b --- /dev/null +++ b/screeninit/linker.ld @@ -0,0 +1,47 @@ +rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2)) + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/3ds_rules + +CC := arm-none-eabi-gcc +AS := arm-none-eabi-as +LD := arm-none-eabi-ld +OC := arm-none-eabi-objcopy + +name := $(shell basename $(CURDIR)) + +dir_source := source +dir_build := build + +ASFLAGS := -mcpu=mpcore -mfloat-abi=hard +CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math +LDFLAGS := -nostdlib + +objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ + $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ + $(call rwildcard, $(dir_source), *.s *.c))) + +.PHONY: all +all: $(name).bin + +.PHONY: clean +clean: + @rm -rf $(dir_build) + +$(name).bin: $(dir_build)/$(name).elf + $(OC) -S -O binary $< $@ + +$(dir_build)/$(name).elf: $(objects) + $(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^ + +$(dir_build)/%.o: $(dir_source)/%.c + @mkdir -p "$(@D)" + $(COMPILE.c) $(OUTPUT_OPTION) $< + +$(dir_build)/%.o: $(dir_source)/%.s + @mkdir -p "$(@D)" + $(COMPILE.s) $(OUTPUT_OPTION) $< +include $(call rwildcard, $(dir_build), *.d) From 94e9be4e5ae729ea9134ba966054cadf51b0909e Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 8 May 2016 12:36:59 +0200 Subject: [PATCH 004/259] Create main.c --- screeninit/main.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 screeninit/main.c diff --git a/screeninit/main.c b/screeninit/main.c new file mode 100644 index 0000000..0f3328d --- /dev/null +++ b/screeninit/main.c @@ -0,0 +1,105 @@ +#include "types.h" + +void main(void) +{ + const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26}; + u32 brightnessLevel = *(vu32 *)0x24FFFC08; + vu32 *const arm11 = (u32 *)0x1FFFFFF8; + + *(vu32 *)0x10141200 = 0x1007F; + *(vu32 *)0x10202014 = 0x00000001; + *(vu32 *)0x1020200C &= 0xFFFEFFFE; + *(vu32 *)0x10202240 = brightness[brightnessLevel]; + *(vu32 *)0x10202A40 = brightness[brightnessLevel]; + *(vu32 *)0x10202244 = 0x1023E; + *(vu32 *)0x10202A44 = 0x1023E; + + // Top screen + *(vu32 *)0x10400400 = 0x000001c2; + *(vu32 *)0x10400404 = 0x000000d1; + *(vu32 *)0x10400408 = 0x000001c1; + *(vu32 *)0x1040040c = 0x000001c1; + *(vu32 *)0x10400410 = 0x00000000; + *(vu32 *)0x10400414 = 0x000000cf; + *(vu32 *)0x10400418 = 0x000000d1; + *(vu32 *)0x1040041c = 0x01c501c1; + *(vu32 *)0x10400420 = 0x00010000; + *(vu32 *)0x10400424 = 0x0000019d; + *(vu32 *)0x10400428 = 0x00000002; + *(vu32 *)0x1040042c = 0x00000192; + *(vu32 *)0x10400430 = 0x00000192; + *(vu32 *)0x10400434 = 0x00000192; + *(vu32 *)0x10400438 = 0x00000001; + *(vu32 *)0x1040043c = 0x00000002; + *(vu32 *)0x10400440 = 0x01960192; + *(vu32 *)0x10400444 = 0x00000000; + *(vu32 *)0x10400448 = 0x00000000; + *(vu32 *)0x1040045C = 0x00f00190; + *(vu32 *)0x10400460 = 0x01c100d1; + *(vu32 *)0x10400464 = 0x01920002; + *(vu32 *)0x10400468 = 0x18300000; + *(vu32 *)0x10400470 = 0x80341; + *(vu32 *)0x10400474 = 0x00010501; + *(vu32 *)0x10400478 = 0; + *(vu32 *)0x10400490 = 0x000002D0; + *(vu32 *)0x1040049C = 0x00000000; + + // Disco register + for(u32 i = 0; i < 256; i++) + *(vu32 *)0x10400484 = 0x10101 * i; + + // Bottom screen + *(vu32 *)0x10400500 = 0x000001c2; + *(vu32 *)0x10400504 = 0x000000d1; + *(vu32 *)0x10400508 = 0x000001c1; + *(vu32 *)0x1040050c = 0x000001c1; + *(vu32 *)0x10400510 = 0x000000cd; + *(vu32 *)0x10400514 = 0x000000cf; + *(vu32 *)0x10400518 = 0x000000d1; + *(vu32 *)0x1040051c = 0x01c501c1; + *(vu32 *)0x10400520 = 0x00010000; + *(vu32 *)0x10400524 = 0x0000019d; + *(vu32 *)0x10400528 = 0x00000052; + *(vu32 *)0x1040052c = 0x00000192; + *(vu32 *)0x10400530 = 0x00000192; + *(vu32 *)0x10400534 = 0x0000004f; + *(vu32 *)0x10400538 = 0x00000050; + *(vu32 *)0x1040053c = 0x00000052; + *(vu32 *)0x10400540 = 0x01980194; + *(vu32 *)0x10400544 = 0x00000000; + *(vu32 *)0x10400548 = 0x00000011; + *(vu32 *)0x1040055C = 0x00f00140; + *(vu32 *)0x10400560 = 0x01c100d1; + *(vu32 *)0x10400564 = 0x01920052; + *(vu32 *)0x10400568 = 0x18300000 + 0x46500; + *(vu32 *)0x10400570 = 0x80301; + *(vu32 *)0x10400574 = 0x00010501; + *(vu32 *)0x10400578 = 0; + *(vu32 *)0x10400590 = 0x000002D0; + *(vu32 *)0x1040059C = 0x00000000; + + // Disco register + for(u32 i = 0; i < 256; i++) + *(vu32 *)0x10400584 = 0x10101 * i; + + *(vu32 *)0x10400468 = 0x18300000; + *(vu32 *)0x1040046c = 0x18300000; + *(vu32 *)0x10400494 = 0x18300000; + *(vu32 *)0x10400498 = 0x18300000; + *(vu32 *)0x10400568 = 0x18346500; + *(vu32 *)0x1040056c = 0x18346500; + + //Set CakeBrah framebuffers + *((vu32 *)0x23FFFE00) = 0x18300000; + *((vu32 *)0x23FFFE04) = 0x18300000; + *((vu32 *)0x23FFFE08) = 0x18346500; + + //Clear ARM11 entry offset + *arm11 = 0; + + //Wait for the entry to be set + while(!*arm11); + + //Jump to it + ((void (*)())*arm11)(); +} From 04f05b26cc5e1adca150fc133d67b00d6b0307fb Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 8 May 2016 12:37:29 +0200 Subject: [PATCH 005/259] Rename screeninit/main.c to screeninit/source/main.c --- screeninit/{ => source}/main.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename screeninit/{ => source}/main.c (100%) diff --git a/screeninit/main.c b/screeninit/source/main.c similarity index 100% rename from screeninit/main.c rename to screeninit/source/main.c From 566556b80f0ceb178a4c44e343840b7bcba840f6 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 8 May 2016 12:38:19 +0200 Subject: [PATCH 006/259] Create start.s --- screeninit/source/start.s | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 screeninit/source/start.s diff --git a/screeninit/source/start.s b/screeninit/source/start.s new file mode 100644 index 0000000..40392d1 --- /dev/null +++ b/screeninit/source/start.s @@ -0,0 +1,10 @@ +.section .text.start +.align 4 +.global _start +_start: + @ Disable interrupts + CPSID aif + + b main + + .word 0 From 3a8da4b8041fde96db7d88dcfcbacb2b354d46f8 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 8 May 2016 12:38:54 +0200 Subject: [PATCH 007/259] Create types.h --- screeninit/source/types.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 screeninit/source/types.h diff --git a/screeninit/source/types.h b/screeninit/source/types.h new file mode 100644 index 0000000..fb0cf31 --- /dev/null +++ b/screeninit/source/types.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +//Common data types +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +typedef volatile u8 vu8; +typedef volatile u16 vu16; +typedef volatile u32 vu32; +typedef volatile u64 vu64; From 005ba50c80ea25edbe2d26d449df09e8592917da Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 8 May 2016 12:40:05 +0200 Subject: [PATCH 008/259] Update README.md --- README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5a33881..dbb5f9f 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,9 @@ CtrBootManager is a boot manager for some 3DS homebrew applications, like HBL an 1. `mkdir build/` 2. `cd build/` 3. `cmake -DCMAKE_TOOLCHAIN_FILE=../DevkitArm3DS.cmake ../` - 4. `cmake --build . --target CtrBootManager_a9lh` + 4. `cmake --build . --target screeninit_a9lh` + 5. `bin2h -c screeninit < screeninit.bin > screeninit.h` + 6. `cmake --build . --target CtrBootManager_a9lh` Binaries should now be in the `build` folder. @@ -24,7 +26,14 @@ Binaries should now be in the `build` folder. * Fluto : graphics * Arkhandar : graphics * dotjasp : graphics (regionfree icon) - +###For screeninit: + * Aurora Wright + * dark_samus + * bil1s + * Normmatt + * delebile + * tiniVi + * ###Other credits: Readme by gemarcano -This project also uses [Brahma](https://github.com/patois/Brahma). See its repository for its credits. \ No newline at end of file +This project also uses [Brahma](https://github.com/patois/Brahma). See its repository for its credits. From a89893153e856191955ec2589150545ca72743b4 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 8 May 2016 12:40:26 +0200 Subject: [PATCH 009/259] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dbb5f9f..1e31ed1 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ Binaries should now be in the `build` folder. * Fluto : graphics * Arkhandar : graphics * dotjasp : graphics (regionfree icon) + ###For screeninit: * Aurora Wright * dark_samus @@ -33,7 +34,7 @@ Binaries should now be in the `build` folder. * Normmatt * delebile * tiniVi - * + ###Other credits: Readme by gemarcano This project also uses [Brahma](https://github.com/patois/Brahma). See its repository for its credits. From 22152e84f362d650fca644ab2d0483f8bbbda300 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 8 May 2016 12:41:27 +0200 Subject: [PATCH 010/259] Update CMakeLists.txt --- CMakeLists.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b91dba..3e4a602 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,9 @@ file(GLOB_RECURSE SOURCE_FILES file(GLOB_RECURSE SOURCE_FILES_ARM9 source/arm9/source/* ) +file(GLOB_RECURSE SOURCE_FILES_SCREENINIT + screeninit/source/* +) # Filter file(GLOB FILTER_FILES @@ -59,6 +62,18 @@ add_netload_target(CtrBootManager_3dslink CtrBootManager) add_citra_target(CtrBootManager_Citra CtrBootManager) #set_target_properties(CtrBootManager PROPERTIES COMPILE_FLAGS "-DCITRA") +################### +# Screen init +################### +add_executable(screeninit ${SOURCE_FILES_SCREENINIT}) +set(ASFLAGS "-mcpu=mpcore -mfloat-abi=hard") +set(CFLAGS "-Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math") +set_target_properties(screeninit PROPERTIES COMPILE_FLAGS ${CFLAGS}) +set_source_files_properties(screeninit/source/start.s PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp ${CFLAGS}") +set_target_properties(screeninit PROPERTIES LINK_FLAGS + "-nostdlib -nostartfiles -g -mthumb -mthumb-interwork -Wl,-Map,screeninit.map -T ${CMAKE_SOURCE_DIR}/screeninit/linker.ld ") +add_a9lh_target(screeninit_a9lh screeninit) + ################### # CtrBootManager9 ################### From 28bf61ae7b988c7d9334a26a88a67221408e6c8c Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 8 May 2016 12:42:08 +0200 Subject: [PATCH 011/259] Create screeninit.h --- source/screeninit.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 source/screeninit.h diff --git a/source/screeninit.h b/source/screeninit.h new file mode 100644 index 0000000..d6f0739 --- /dev/null +++ b/source/screeninit.h @@ -0,0 +1,15 @@ +/* +* screeninit.h +* +* Screen init code by dark_samus, bil1s, Normmatt, delebile and others. +* Screen deinit code by tiniVi. +*/ + +#pragma once + +#include "arm9/source/common.h" + +#define PDN_GPU_CNT (*(vu8 *)0x10141200) + +void deinitScreens(void); +void initScreens(void); From 5fcf8093db1fc93ef8e1adce2c33b7a1e7672837 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 8 May 2016 12:42:49 +0200 Subject: [PATCH 012/259] Create screeninit.c --- source/screeninit.c | 64 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 source/screeninit.c diff --git a/source/screeninit.c b/source/screeninit.c new file mode 100644 index 0000000..bffbdd3 --- /dev/null +++ b/source/screeninit.c @@ -0,0 +1,64 @@ +/* +* screeninit.c +* +* Screen init code by dark_samus, bil1s, Normmatt, delebile and others. +* Screen deinit code by tiniVi. +*/ + +#include "screeninit.h" + +#include +#include "arm9/source/i2c.h" +#include "../build/screeninit.h" + +vu32 *arm11Entry = (u32 *)0x1FFFFFF8; + +void deinitScreens(void) +{ + void __attribute__((naked)) ARM11(void) + { + //Disable interrupts + __asm(".word 0xF10C01C0"); + + //Clear ARM11 entry offset + *arm11Entry = 0; + + //Shutdown LCDs + *(vu32 *)0x10202A44 = 0; + *(vu32 *)0x10202244 = 0; + *(vu32 *)0x10202014 = 0; + + //Wait for the entry to be set + while(!*arm11Entry); + + //Jump to it + ((void (*)())*arm11Entry)(); + } + + if(PDN_GPU_CNT != 1) + { + *arm11Entry = (u32)ARM11; + while(*arm11Entry); + } +} + +void initScreens(void) +{ + if(PDN_GPU_CNT == 1) + { + u32 *const screenInitAddress = (u32 *)0x24FFFC00; + + memcpy(screenInitAddress, screeninit, screeninit_size); + + //Write brightness level for the stub to pick up + //screenInitAddress[2] = MULTICONFIG(0); + + *arm11Entry = (u32)screenInitAddress; + while(*arm11Entry); + + //Turn on backlight + i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A); + } + + //clearScreens(); +} From 70bc364dc5b99dd9f754866cacc4174e048f58a2 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 8 May 2016 12:43:18 +0200 Subject: [PATCH 013/259] Update main.c --- source/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/main.c b/source/main.c index 47ae98b..82a9770 100644 --- a/source/main.c +++ b/source/main.c @@ -10,6 +10,7 @@ #include "arm9/source/common.h" #include "arm9/source/hid.h" #include "arm9/source/fatfs/ff.h" +#include "screeninit.h" #else #include <3ds.h> @@ -60,6 +61,7 @@ int main() { *(u32 *) 0x10000020 = 0x340; FATFS fs; f_mount(&fs, "0:", 0); + initScreens(); #else if (netloader_init() != 0) { // fix SOC_Initialize From 319d290f414bfa6d2e360b9365b20bb1daadd078 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 17:35:14 +0200 Subject: [PATCH 014/259] Update config.h --- source/config.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/source/config.h b/source/config.h index aa67e89..22d7a78 100644 --- a/source/config.h +++ b/source/config.h @@ -8,22 +8,29 @@ extern "C" { #ifdef ARM9 #include "arm9/source/common.h" - #define CONFIG_PATH "/a9lh.cfg" + #else + #include <3ds.h> #include "utility.h" #define CONFIG_PATH "/boot.cfg" + #endif +#include "loader.h" // Binary patches define + #define BIT(n) (1U<<(n)) #define CONFIG_MAX_ENTRIES 11 +#define PATCHES_MAX_PER_ENTRY 4 typedef struct { char title[64]; char path[128]; int key; long offset; + binary_patch patches[PATCHES_MAX_PER_ENTRY]; + int patchesCount; } boot_entry_s; typedef struct { From 25cc254aa9da1d9897ecbc14754616c2dab9de76 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 17:35:42 +0200 Subject: [PATCH 015/259] Update config.c --- source/config.c | 93 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 7 deletions(-) diff --git a/source/config.c b/source/config.c index 419a230..87e13d0 100644 --- a/source/config.c +++ b/source/config.c @@ -43,6 +43,39 @@ void setColorAlpha(u8 *cfgColor, const char *color) { } } +void readStrAsHexData(const char *dataAsStr, char *data, int* dataSize) { + *dataSize = strlen(dataAsStr)/2; + for (int i = 0; i < *dataSize; i++) + { + if ( dataAsStr[0] >= '0' && dataAsStr[0] <= '9' ) + data[i] = (dataAsStr[0]-'0')<<4; + else if ( dataAsStr[0] >= 'A' && dataAsStr[0] <= 'F' ) + data[i] = (10+dataAsStr[0]-'A')<<4; + else if ( dataAsStr[0] >= 'a' && dataAsStr[0] <= 'f' ) + data[i] = (10+dataAsStr[0]-'a')<<4; + else + data[i] = 0; + if ( dataAsStr[1] >= '0' && dataAsStr[1] <= '9' ) + data[i] += (dataAsStr[1]-'0'); + else if ( dataAsStr[1] >= 'A' && dataAsStr[1] <= 'F' ) + data[i] += (10+dataAsStr[1]-'A'); + else if ( dataAsStr[1] >= 'a' && dataAsStr[1] <= 'f' ) + data[i] += (10+dataAsStr[1]-'a'); + dataAsStr+=2; + } +} + +void writeHexDataAsStr(const char *data, int dataSize, char* dataAsStr) { + + char const hex_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + for (int i = 0; i < dataSize; i++) + { + dataAsStr[0] = hex_chars[data[i]/16]; + dataAsStr[1] = hex_chars[data[i]%16]; + dataAsStr += 2; + } +} + static char *ini_buffer_reader(char *str, int num, void *stream) { buffer_ctx *ctx = (buffer_ctx *) stream; int idx = 0; @@ -101,7 +134,7 @@ static int handler(void *user, const char *section, const char *name, config->autobootfix = atoi(item); } - // theme + // theme else if (MATCH("theme", "bgTop1")) { setColor(config->bgTop1, item); } else if (MATCH("theme", "bgTop2")) { @@ -122,14 +155,41 @@ static int handler(void *user, const char *section, const char *name, strncpy(config->bgImgBot, item, 128); } - // entries + // entries else if (MATCH("entry", "title")) { strncpy(config->entries[config->count].title, item, 64); } else if (MATCH("entry", "path")) { strncpy(config->entries[config->count].path, item, 128); } else if (MATCH("entry", "offset")) { config->entries[config->count].offset = strtoul(item, NULL, 16); - } else if (MATCH("entry", "key")) { + } + // Binary patches for current entry + else if (MATCH("entry", "patchMemSearch")) { + binary_patch* curPatch = &config->entries[config->count].patches[config->entries[config->count].patchesCount]; + readStrAsHexData(item, curPatch->memToSearch, &curPatch->memToSearchSize); + } else if (MATCH("entry", "patchMemOverwrite")) { + binary_patch* curPatch = &config->entries[config->count].patches[config->entries[config->count].patchesCount]; + readStrAsHexData(item, curPatch->memOverwrite, &curPatch->memOverwriteSize); + } else if (MATCH("entry", "patchMemOverwriteStr")) { + binary_patch* curPatch = &config->entries[config->count].patches[config->entries[config->count].patchesCount]; + curPatch->memOverwriteSize = strlen(item)+1; + memcpy(curPatch->memOverwrite, item, curPatch->memOverwriteSize); + } else if (MATCH("entry", "patchMemOverwriteWStr")) { + binary_patch* curPatch = &config->entries[config->count].patches[config->entries[config->count].patchesCount]; + int strSize = strlen(item)+1; + curPatch->memOverwriteSize = strSize*2; + for (int i = 0; i < strSize; i++) + { + curPatch->memOverwrite[2*i] = item[i]; + curPatch->memOverwrite[2*i+1] = '\0'; + } + } else if (MATCH("entry", "patchOccurence")) { + int prevPatchesCount = config->entries[config->count].patchesCount; + config->entries[config->count].patches[prevPatchesCount].occurence = atoi(item); + config->entries[config->count].patchesCount = (prevPatchesCount < PATCHES_MAX_PER_ENTRY) ? (prevPatchesCount+1) : prevPatchesCount; + } + // End current entry + else if (MATCH("entry", "key")) { if(strlen(config->entries[config->count].title) > 0) { config->entries[config->count].key = atoi(item); config->count++; @@ -201,10 +261,14 @@ int configInit() { } int configAddEntry(char *title, char *path, long offset) { + + if (config->count >= CONFIG_MAX_ENTRIES) + return 1; strncpy(config->entries[config->count].title, title, 64); strncpy(config->entries[config->count].path, path, 128); config->entries[config->count].offset = offset; + config->entries[config->count].patchesCount = 0; config->entries[config->count].key = -1; config->count++; configSave(); @@ -214,6 +278,9 @@ int configAddEntry(char *title, char *path, long offset) { int configRemoveEntry(int index) { + if ( index >= config->count ) + return 1; + int i = 0; for(i=0; icount; i++) { if(i > index) { @@ -255,10 +322,10 @@ void configSave() { size += snprintf(cfg+size, 256, "bgTop1=%02X%02X%02X;\n", config->bgTop1[0], config->bgTop1[1], config->bgTop1[2]); size += snprintf(cfg+size, 256, "bgTop2=%02X%02X%02X;\n", config->bgTop2[0], config->bgTop2[1], config->bgTop2[2]); size += snprintf(cfg+size, 256, "bgBottom=%02X%02X%02X;\n", config->bgBot[0], config->bgBot[1], config->bgBot[2]); - if ( config->highlight[3] < 0xFF ) - size += snprintf(cfg+size, 256, "highlight=%02X%02X%02X%02X;\n", config->highlight[2], config->highlight[1], config->highlight[0], config->highlight[3]); - else - size += snprintf(cfg+size, 256, "highlight=%02X%02X%02X;\n", config->highlight[0], config->highlight[1], config->highlight[2]); + if ( config->highlight[3] < 0xFF ) + size += snprintf(cfg+size, 256, "highlight=%02X%02X%02X%02X;\n", config->highlight[2], config->highlight[1], config->highlight[0], config->highlight[3]); + else + size += snprintf(cfg+size, 256, "highlight=%02X%02X%02X;\n", config->highlight[0], config->highlight[1], config->highlight[2]); size += snprintf(cfg+size, 256, "borders=%02X%02X%02X;\n", config->borders[0], config->borders[1], config->borders[2]); size += snprintf(cfg+size, 256, "font1=%02X%02X%02X;\n", config->fntDef[0], config->fntDef[1], config->fntDef[2]); size += snprintf(cfg+size, 256, "font2=%02X%02X%02X;\n", config->fntSel[0], config->fntSel[1], config->fntSel[2]); @@ -270,6 +337,18 @@ void configSave() { size += snprintf(cfg+size, 256, "title=%s;\n", config->entries[i].title); size += snprintf(cfg+size, 256, "path=%s;\n", config->entries[i].path); size += snprintf(cfg+size, 256, "offset=%x;\n", (int)config->entries[i].offset); + int patchesCount = config->entries[i].patchesCount; + for (int j = 0; j < patchesCount; j++) + { + binary_patch* curPatch = &config->entries[i].patches[j]; + size += snprintf(cfg+size, 256, "patchMemSearch="); + writeHexDataAsStr(curPatch->memToSearch, curPatch->memToSearchSize, cfg+size); + size += curPatch->memToSearchSize*2; + size += snprintf(cfg+size, 256, ";\npatchMemOverwrite="); + writeHexDataAsStr(curPatch->memOverwrite, curPatch->memOverwriteSize, cfg+size); + size += curPatch->memOverwriteSize*2; + size += snprintf(cfg+size, 256, ";\npatchOccurence=%i;\n", curPatch->occurence); + } size += snprintf(cfg+size, 256, "key=%i;\n\n", config->entries[i].key); } #ifdef ARM9 From 07e22e6c53e9b027bbda7380e3531661b165ad9d Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 17:36:16 +0200 Subject: [PATCH 016/259] Update loader.h --- source/loader.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/source/loader.h b/source/loader.h index 4b26e03..873c90c 100644 --- a/source/loader.h +++ b/source/loader.h @@ -1,12 +1,14 @@ #ifndef _loader_h_ #define _loader_h_ -int load(char *path, long offset); - -int load_bin(char *path, long offset); - -#ifndef ARM9 -int load_3dsx(char *path); -#endif +typedef struct { + char memToSearch[256]; + char memOverwrite[256]; + int memToSearchSize; + int memOverwriteSize; + int occurence; +} binary_patch; + +int load(char *path, long offset, binary_patch* patches, int patchesCount); #endif // _loader_h_ From b6cbfd200332fb0f8e67ccb3b7d3f9d56d119b98 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 17:36:42 +0200 Subject: [PATCH 017/259] Update loader.c --- source/loader.c | 59 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/source/loader.c b/source/loader.c index 9735552..45f04fe 100644 --- a/source/loader.c +++ b/source/loader.c @@ -12,13 +12,41 @@ #endif +#include "loader.h" #include "utility.h" #include "memory.h" #ifdef ARM9 -int load_bin(char *path, long offset) { +unsigned char *memsearch(unsigned char *startPos, const void *pattern, int size, int patternSize) // From Luma3DS' pathchanger.c +{ + const unsigned char *patternc = (const unsigned char *)pattern; + //Preprocessing + int table[256]; + + int i; + for(i = 0; i < 256; ++i) + table[i] = patternSize + 1; + for(i = 0; i < patternSize; ++i) + table[patternc[i]] = patternSize - i; + + //Searching + int j = 0; + + while(j <= size - patternSize) + { + if(memcmp(patternc, startPos + j, patternSize) == 0) + return startPos + j; + j += table[startPos[j + patternSize]]; + } + + return NULL; +} + +int load_bin(char *path, long offset, binary_patch* patches, int patchesCount) { + + // Load binary size_t size = fileSize(path); if (!size) { return -1; @@ -27,7 +55,30 @@ int load_bin(char *path, long offset) { if (fileReadOffset(path, (void *) PTR_PAYLOAD_MAIN_DATA, PTR_PAYLOAD_SIZE_MAX, offset) != 0) { return -1; } + + // Apply patches + unsigned char* oriBinary = (unsigned char*)PTR_PAYLOAD_MAIN_DATA; + for (int i = 0 ; i < patchesCount ; i++) + { + unsigned char* binFound = oriBinary; + int curOccurence = 0; + while ( NULL != (binFound = memsearch(binFound, patches[i].memToSearch, size-offset+oriBinary-binFound, patches[i].memToSearchSize)) ) + { + curOccurence++; + if ( patches[i].occurence == 0 || curOccurence == patches[i].occurence ) + { + memcpy(binFound, patches[i].memOverwrite, patches[i].memOverwriteSize); + + if ( patches[i].occurence > 0 ) + break; + binFound += patches[i].memOverwriteSize; + } + else + binFound += patches[i].memToSearchSize; + } + } + // Start binary gfxClear(); memcpy((void *) PTR_PAYLOAD_STAGE2, stage2_bin, stage2_bin_size); @@ -47,7 +98,7 @@ int load_3dsx(char *path) { return 0; } -int load_bin(char *path, long offset) { +int load_bin(char *path, long offset, binary_patch* patches, int patchesCount) { gfxExit(); @@ -69,7 +120,7 @@ int load_bin(char *path, long offset) { #endif -int load(char *path, long offset) { +int load(char *path, long offset, binary_patch* patches, int patchesCount) { // check for reboot/poweroff if (strcasecmp(path, "reboot") == 0) { reboot(); @@ -83,7 +134,7 @@ int load(char *path, long offset) { const char *ext = get_filename_ext(path); if (strcasecmp(ext, "bin") == 0 || strcasecmp(ext, "dat") == 0) { - return load_bin(path, offset); + return load_bin(path, offset, patches, patchesCount); #ifndef ARM9 } else if (strcasecmp(ext, "3dsx") == 0) { return load_3dsx(path); From 93c5e470016ed5aaaf35deb727e35d706f5de264 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 17:37:30 +0200 Subject: [PATCH 018/259] Update menu_boot.c --- source/menu_boot.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/menu_boot.c b/source/menu_boot.c index aecf81e..c6f45da 100644 --- a/source/menu_boot.c +++ b/source/menu_boot.c @@ -37,7 +37,9 @@ int boot(int index) { #ifdef ARM9 return load(config->entries[index].path, - config->entries[index].offset); + config->entries[index].offset, + config->entries[index].patches, + config->entries[index].patchesCount); #else int delay = config->autobootfix; while (aptMainLoop() && delay > 0) { @@ -45,7 +47,9 @@ int boot(int index) { delay--; } return load(config->entries[index].path, - config->entries[index].offset); + config->entries[index].offset, + config->entries[index].patches, + config->entries[index].patchesCount); #endif } From 66acb5ef5a0579ca6722b57bd165e142e22f7fa4 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 17:38:14 +0200 Subject: [PATCH 019/259] Update menu_more.c --- source/menu_more.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/menu_more.c b/source/menu_more.c index 46db358..4644337 100644 --- a/source/menu_more.c +++ b/source/menu_more.c @@ -33,7 +33,7 @@ int menu_choose() { pick_file(&picked, "/"); if (strlen(picked.path) > 0) { - return load(picked.path, 0); + return load(picked.path, 0, NULL, 0); } return -1; From d418394d50578c779dbbbc8a1b07a3fed6a75c9b Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 19:34:26 +0200 Subject: [PATCH 020/259] Update config.c --- source/config.c | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/source/config.c b/source/config.c index 87e13d0..5f944ed 100644 --- a/source/config.c +++ b/source/config.c @@ -31,9 +31,9 @@ void setColorAlpha(u8 *cfgColor, const char *color) { if ( (color[6] >= '0' && color[6] <= '9') || (color[6] >= 'A' && color[6] <= 'F') || (color[6] >= 'a' && color[6] <= 'f') ) { long l = strtoul(color, NULL, 16); - cfgColor[0] = (u8) (l >> 8 & 0xFF); + cfgColor[0] = (u8) (l >> 24 & 0xFF); cfgColor[1] = (u8) (l >> 16 & 0xFF); - cfgColor[2] = (u8) (l >> 24 & 0xFF); + cfgColor[2] = (u8) (l >> 8 & 0xFF); cfgColor[3] = (u8) (l & 0xFF); } else @@ -144,11 +144,11 @@ static int handler(void *user, const char *section, const char *name, } else if (MATCH("theme", "highlight")) { setColorAlpha(config->highlight, item); } else if (MATCH("theme", "borders")) { - setColor(config->borders, item); + setColorAlpha(config->borders, item); } else if (MATCH("theme", "font1")) { - setColor(config->fntDef, item); + setColorAlpha(config->fntDef, item); } else if (MATCH("theme", "font2")) { - setColor(config->fntSel, item); + setColorAlpha(config->fntSel, item); } else if (MATCH("theme", "bgImgTop")) { strncpy(config->bgImgTop, item, 128); } else if (MATCH("theme", "bgImgBot")) { @@ -207,10 +207,10 @@ void configThemeInit() { memcpy(config->bgTop1, (u8[3]) {0x4a, 0x00, 0x31}, sizeof(u8[3])); memcpy(config->bgTop2, (u8[3]) {0x6f, 0x01, 0x49}, sizeof(u8[3])); memcpy(config->bgBot, (u8[3]) {0x6f, 0x01, 0x49}, sizeof(u8[3])); - memcpy(config->highlight, (u8[3]) {0xdc, 0xdc, 0xdc}, sizeof(u8[3])); - memcpy(config->borders, (u8[3]) {0xff, 0xff, 0xff}, sizeof(u8[3])); - memcpy(config->fntDef, (u8[3]) {0xff, 0xff, 0xff}, sizeof(u8[3])); - memcpy(config->fntSel, (u8[3]) {0x00, 0x00, 0x00}, sizeof(u8[3])); + memcpy(config->highlight, (u8[4]) {0xdc, 0xdc, 0xdc, 0xff}, sizeof(u8[4])); + memcpy(config->borders, (u8[4]) {0xff, 0xff, 0xff, 0xff}, sizeof(u8[4])); + memcpy(config->fntDef, (u8[4]) {0xff, 0xff, 0xff, 0xff}, sizeof(u8[4])); + memcpy(config->fntSel, (u8[4]) {0x00, 0x00, 0x00, 0xff}, sizeof(u8[4])); } int configInit() { @@ -253,7 +253,7 @@ int configInit() { return -1; } - memcpy(fontDefault.color, config->fntDef, sizeof(u8[3])); + memcpy(fontDefault.color, config->fntDef, sizeof(u8[4])); loadBg(GFX_TOP); loadBg(GFX_BOTTOM); @@ -322,13 +322,27 @@ void configSave() { size += snprintf(cfg+size, 256, "bgTop1=%02X%02X%02X;\n", config->bgTop1[0], config->bgTop1[1], config->bgTop1[2]); size += snprintf(cfg+size, 256, "bgTop2=%02X%02X%02X;\n", config->bgTop2[0], config->bgTop2[1], config->bgTop2[2]); size += snprintf(cfg+size, 256, "bgBottom=%02X%02X%02X;\n", config->bgBot[0], config->bgBot[1], config->bgBot[2]); + if ( config->highlight[3] < 0xFF ) - size += snprintf(cfg+size, 256, "highlight=%02X%02X%02X%02X;\n", config->highlight[2], config->highlight[1], config->highlight[0], config->highlight[3]); + size += snprintf(cfg+size, 256, "highlight=%02X%02X%02X%02X;\n", config->highlight[0], config->highlight[1], config->highlight[2], config->highlight[3]); + else + size += snprintf(cfg+size, 256, "highlight=%02X%02X%02X;\n", config->highlight[0], config->highlight[1], config->highlight[2]); + + if ( config->borders[3] < 0xFF ) + size += snprintf(cfg+size, 256, "borders=%02X%02X%02X%02X;\n", config->borders[0], config->borders[1], config->borders[2], config->borders[3]); + else + size += snprintf(cfg+size, 256, "borders=%02X%02X%02X;\n", config->borders[0], config->borders[1], config->borders[2]); + + if ( config->fntDef[3] < 0xFF ) + size += snprintf(cfg+size, 256, "font1=%02X%02X%02X%02X;\n", config->fntDef[0], config->fntDef[1], config->fntDef[2], config->fntDef[3]); + else + size += snprintf(cfg+size, 256, "font1=%02X%02X%02X;\n", config->fntDef[0], config->fntDef[1], config->fntDef[2]); + + if ( config->fntSel[3] < 0xFF ) + size += snprintf(cfg+size, 256, "font2=%02X%02X%02X%02X;\n", config->fntSel[0], config->fntSel[1], config->fntSel[2], config->fntSel[3]); else - size += snprintf(cfg+size, 256, "highlight=%02X%02X%02X;\n", config->highlight[0], config->highlight[1], config->highlight[2]); - size += snprintf(cfg+size, 256, "borders=%02X%02X%02X;\n", config->borders[0], config->borders[1], config->borders[2]); - size += snprintf(cfg+size, 256, "font1=%02X%02X%02X;\n", config->fntDef[0], config->fntDef[1], config->fntDef[2]); - size += snprintf(cfg+size, 256, "font2=%02X%02X%02X;\n", config->fntSel[0], config->fntSel[1], config->fntSel[2]); + size += snprintf(cfg+size, 256, "font2=%02X%02X%02X;\n", config->fntSel[0], config->fntSel[1], config->fntSel[2]); + size += snprintf(cfg+size, 256, "bgImgTop=%s;\n", config->bgImgTop); size += snprintf(cfg+size, 256, "bgImgBot=%s;\n\n", config->bgImgBot); From 03ff3f73f87aedcb64a2c0beb168224658210904 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 19:35:13 +0200 Subject: [PATCH 021/259] Update config.h --- source/config.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/config.h b/source/config.h index 22d7a78..081bbef 100644 --- a/source/config.h +++ b/source/config.h @@ -44,9 +44,9 @@ typedef struct { u8 bgTop2[3]; u8 bgBot[3]; u8 highlight[4]; - u8 borders[3]; - u8 fntDef[3]; - u8 fntSel[3]; + u8 borders[4]; + u8 fntDef[4]; + u8 fntSel[4]; char bgImgTop[128]; char bgImgBot[128]; bool imgError; From 2daee4e1d01c2e7e6c74a6fd5cea616114b23aae Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 19:35:57 +0200 Subject: [PATCH 022/259] Update font.c --- source/font.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/font.c b/source/font.c index 7fe9292..509bce3 100644 --- a/source/font.c +++ b/source/font.c @@ -13,5 +13,5 @@ font_s fontDefault = defaultData, defaultDesc, 16, - (u8[]) {0xFF, 0xFF, 0xFF} - }; \ No newline at end of file + (u8[]) {0xFF, 0xFF, 0xFF, 0xFF} + }; From 6e0914d6230140275004b690344b932b2cd69eac Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 19:36:24 +0200 Subject: [PATCH 023/259] Update font.h --- source/font.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/font.h b/source/font.h index c155605..166bf4e 100644 --- a/source/font.h +++ b/source/font.h @@ -10,7 +10,7 @@ typedef struct { u8 *data; charDesc_s *desc; u8 height; - u8 color[3]; + u8 color[4]; } font_s; extern u8 defaultData[]; From e99d5de38a35421fa81f5e8bd53edb9bd7854af8 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 19:38:02 +0200 Subject: [PATCH 024/259] Update gfx.c --- source/gfx.c | 74 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/source/gfx.c b/source/gfx.c index 7b55c5a..410d2a3 100644 --- a/source/gfx.c +++ b/source/gfx.c @@ -39,29 +39,55 @@ void drawPixel(int x, int y, char r, char g, char b, u8 *screen) { screen[v + 2] = r; } -void drawLine(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, char r, char g, char b) { +void drawPixelAlpha(int x, int y, char r, char g, char b, char a, u8 *screen) { + int height = 240; + + u32 v = (height - 1 - y + x * height) * 3; + + float alpha = (float)a / 255.f; + float one_minus_alpha = 1.f - alpha; + + screen[v + 0] = (u8)(alpha*b+one_minus_alpha*(float)screen[v + 0]); + screen[v + 1] = (u8)(alpha*g+one_minus_alpha*(float)screen[v + 1]); + screen[v + 2] = (u8)(alpha*r+one_minus_alpha*(float)screen[v + 2]); +} + +void drawLine(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, char r, char g, char b, char a) { u16 fbWidth, fbHeight; u8 *fbAdr = gfxGetFramebuffer(screen, side, &fbWidth, &fbHeight); int x, y; - if (x1 == x2) { - if (y1 < y2) for (y = y1; y < y2; y++) drawPixel(x1, y, r, g, b, fbAdr); - else for (y = y2; y < y1; y++) drawPixel(x1, y, r, g, b, fbAdr); - } else { - if (x1 < x2) for (x = x1; x < x2; x++) drawPixel(x, y1, r, g, b, fbAdr); - else for (x = x2; x < x1; x++) drawPixel(x, y1, r, g, b, fbAdr); + if ( a == 0xFF ) + { + if (x1 == x2) { + if (y1 < y2) for (y = y1; y < y2; y++) drawPixel(x1, y, r, g, b, fbAdr); + else for (y = y2; y < y1; y++) drawPixel(x1, y, r, g, b, fbAdr); + } else { + if (x1 < x2) for (x = x1; x < x2; x++) drawPixel(x, y1, r, g, b, fbAdr); + else for (x = x2; x < x1; x++) drawPixel(x, y1, r, g, b, fbAdr); + } + } + else if ( a > 0 ) + { + if (x1 == x2) { + if (y1 < y2) for (y = y1; y < y2; y++) drawPixelAlpha(x1, y, r, g, b, a, fbAdr); + else for (y = y2; y < y1; y++) drawPixelAlpha(x1, y, r, g, b, a, fbAdr); + } else { + if (x1 < x2) for (x = x1; x < x2; x++) drawPixelAlpha(x, y1, r, g, b, a, fbAdr); + else for (x = x2; x < x1; x++) drawPixelAlpha(x, y1, r, g, b, a, fbAdr); + } } } -void drawRect(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, char r, char g, char b) { - drawLine(screen, side, x1, y1, x2, y1, r, g, b); - drawLine(screen, side, x2, y1, x2, y2, r, g, b); - drawLine(screen, side, x1, y2, x2, y2, r, g, b); - drawLine(screen, side, x1, y1, x1, y2, r, g, b); +void drawRect(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, char r, char g, char b, char a) { + drawLine(screen, side, x1+1, y1, x2, y1, r, g, b, a); + drawLine(screen, side, x2, y1, x2, y2, r, g, b, a); + drawLine(screen, side, x1, y2, x2+1, y2, r, g, b, a); + drawLine(screen, side, x1, y1, x1, y2, r, g, b, a); } -void drawRectColor(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, u8 *color) { - drawRect(screen, side, x1, y1, x2, y2, color[0], color[1], color[2]); +void drawRectColor(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, u8 *rgbaColor) { + drawRect(screen, side, x1, y1, x2, y2, rgbaColor[0], rgbaColor[1], rgbaColor[2], rgbaColor[3]); } void gfxDrawTextf(gfxScreen_t screen, gfx3dSide_t side, font_s *f, s16 x, s16 y, const char *fmt, ...) { @@ -132,7 +158,7 @@ void gfxFillColorGradient(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColorStart } } -void _gfxDrawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[4], s16 x, s16 y, u16 width, u16 height) { +void _gfxDrawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbaColor[4], s16 x, s16 y, u16 width, u16 height) { u16 fbWidth, fbHeight; u8 *fbAdr = gfxGetFramebuffer(screen, side, &fbWidth, &fbHeight); @@ -150,15 +176,15 @@ void _gfxDrawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[4], s16 if (x + width >= fbWidth)width = fbWidth - x; if (y + height >= fbHeight)height = fbHeight - y; - if ( rgbColor[3] == 0xFF ) + if ( rgbaColor[3] == 0xFF ) { u8 colorLine[width * 3]; int j; for (j = 0; j < width; j++) { - colorLine[j * 3 + 0] = rgbColor[2]; - colorLine[j * 3 + 1] = rgbColor[1]; - colorLine[j * 3 + 2] = rgbColor[0]; + colorLine[j * 3 + 0] = rgbaColor[2]; + colorLine[j * 3 + 1] = rgbaColor[1]; + colorLine[j * 3 + 2] = rgbaColor[0]; } fbAdr += fbWidth * 3 * y; @@ -167,9 +193,9 @@ void _gfxDrawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[4], s16 fbAdr += fbWidth * 3; } } - else + else if ( rgbaColor[3] > 0 ) { - float alpha = (float)rgbColor[3] / 255.f; + float alpha = (float)rgbaColor[3] / 255.f; float one_minus_alpha = 1.f - alpha; int i, j; fbAdr += fbWidth * 3 * y; @@ -177,9 +203,9 @@ void _gfxDrawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[4], s16 { for (i = 0; i < width; i++) { - fbAdr[3*(i+x)+0] = (u8)(alpha*(float)rgbColor[0]+one_minus_alpha*(float)fbAdr[3*(i+x)+0]); - fbAdr[3*(i+x)+1] = (u8)(alpha*(float)rgbColor[1]+one_minus_alpha*(float)fbAdr[3*(i+x)+1]); - fbAdr[3*(i+x)+2] = (u8)(alpha*(float)rgbColor[2]+one_minus_alpha*(float)fbAdr[3*(i+x)+2]); + fbAdr[3*(i+x)+0] = (u8)(alpha*(float)rgbaColor[2]+one_minus_alpha*(float)fbAdr[3*(i+x)+0]); + fbAdr[3*(i+x)+1] = (u8)(alpha*(float)rgbaColor[1]+one_minus_alpha*(float)fbAdr[3*(i+x)+1]); + fbAdr[3*(i+x)+2] = (u8)(alpha*(float)rgbaColor[0]+one_minus_alpha*(float)fbAdr[3*(i+x)+2]); } fbAdr += fbWidth * 3; } From 227ce47a63da7853e3959789ca6136488f7522ec Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 19:38:22 +0200 Subject: [PATCH 025/259] Update gfx.h --- source/gfx.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/gfx.h b/source/gfx.h index 6bc6d65..bef3fb6 100644 --- a/source/gfx.h +++ b/source/gfx.h @@ -15,9 +15,9 @@ u8 *gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16 *width, u16 *hei #include "font.h" //rendering stuff -void drawLine(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, char r, char g, char b); +void drawLine(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, char r, char g, char b, char a); -void drawRectColor(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, u8 *color); +void drawRectColor(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, u8 *rgbaColor); void gfxDrawText(gfxScreen_t screen, gfx3dSide_t side, font_s *f, char *str, s16 x, s16 y); @@ -29,7 +29,7 @@ void gfxFillColor(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[3]); void gfxFillColorGradient(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColorStart[3], u8 rgbColorEnd[3]); -void gfxDrawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[3], s16 x, s16 y, u16 width, u16 height); +void gfxDrawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbaColor[4], s16 x, s16 y, u16 width, u16 height); void gfxClearTop(u8 top1[3], u8 top2[3]); From cbafa2903afc47a8e68e86c1056806d3d5513e2c Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 19:39:14 +0200 Subject: [PATCH 026/259] Update menu.c --- source/menu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/menu.c b/source/menu.c index ce1e769..2125a5f 100644 --- a/source/menu.c +++ b/source/menu.c @@ -48,11 +48,11 @@ void drawItem(bool selected, int y, const char *format, ...) { if (selected) { gfxDrawRectangle(GFX_TOP, GFX_LEFT, config->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); } - memcpy(fontDefault.color, selected ? config->fntSel : config->fntDef, sizeof(u8[3])); + memcpy(fontDefault.color, selected ? config->fntSel : config->fntDef, sizeof(u8[4])); gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, msg, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); - memcpy(fontDefault.color, config->fntDef, sizeof(u8[3])); + memcpy(fontDefault.color, config->fntDef, sizeof(u8[4])); } void drawItemN(bool selected, int maxChar, int y, const char *format, ...) { @@ -66,11 +66,11 @@ void drawItemN(bool selected, int maxChar, int y, const char *format, ...) { if (selected) { gfxDrawRectangle(GFX_TOP, GFX_LEFT, config->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); } - memcpy(fontDefault.color, selected ? config->fntSel : config->fntDef, sizeof(u8[3])); + memcpy(fontDefault.color, selected ? config->fntSel : config->fntDef, sizeof(u8[4])); gfxDrawTextN(GFX_TOP, GFX_LEFT, &fontDefault, msg, maxChar, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); - memcpy(fontDefault.color, config->fntDef, sizeof(u8[3])); + memcpy(fontDefault.color, config->fntDef, sizeof(u8[4])); } void drawInfo(const char *format, ...) { From 3b2fffba4d701e27b6b0d14cedf6a689fc7eeaf3 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 19:40:01 +0200 Subject: [PATCH 027/259] Update menu_boot.c --- source/menu_boot.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/source/menu_boot.c b/source/menu_boot.c index c6f45da..c5667f6 100644 --- a/source/menu_boot.c +++ b/source/menu_boot.c @@ -147,10 +147,23 @@ static void draw(int boot_index, time_t elapsed) { for (i = 0; i < config->count; i++) { drawItem(i == boot_index, 16 * i, config->entries[i].title); if (i == boot_index) { - drawInfo("Name: %s\nPath: %s\nOffset: 0x%lx\n\n\nPress (A) to launch\nPress (X) to remove entry\n", - config->entries[i].title, - config->entries[i].path, - config->entries[i].offset); + #ifdef ARM9 + if ( config->entries[i].patchesCount > 0 ) + { + drawInfo("Name: %s\nPath: %s\nOffset: 0x%lx\nPatches count: %d\n\nPress (A) to launch\nPress (X) to remove entry\n", + config->entries[i].title, + config->entries[i].path, + config->entries[i].offset, + config->entries[i].patchesCount); + } + else + #endif + { + drawInfo("Name: %s\nPath: %s\nOffset: 0x%lx\n\n\nPress (A) to launch\nPress (X) to remove entry\n", + config->entries[i].title, + config->entries[i].path, + config->entries[i].offset); + } } } drawItem(boot_index == config->count, 16 * i, "More..."); From e6bc4bccf5f75991e979cb7842ec61e31f851356 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 19:41:19 +0200 Subject: [PATCH 028/259] Update text.c --- source/text.c | 50 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/source/text.c b/source/text.c index 204d901..2c2dcf6 100644 --- a/source/text.c +++ b/source/text.c @@ -32,20 +32,46 @@ int drawCharacter(u8 *fb, font_s *f, char c, s16 x, s16 y, u16 w, u16 h) { } else if (y + ch > h)ch = h - y; fb += (x * h + cy) * 3; - const u8 r = f->color[0], g = f->color[1], b = f->color[2]; - for (i = 0; i < cd->w; i++) { - charData += cyo; - for (j = 0; j < ch; j++) { - u8 v = *(charData++); - if (v) { - fb[0] = (fb[0] * (0xFF - v) + (b * v)) >> 8; - fb[1] = (fb[1] * (0xFF - v) + (g * v)) >> 8; - fb[2] = (fb[2] * (0xFF - v) + (r * v)) >> 8; + const u8 r = f->color[0], g = f->color[1], b = f->color[2], a = f->color[3]; + if ( a < 0xFF ) + { + float alpha = (float)a / 255.f; + float one_minus_alpha = 1.f - alpha; + + for (i = 0; i < cd->w; i++) { + charData += cyo; + for (j = 0; j < ch; j++) { + u8 v = *(charData++); + if (v) { + u8 blend[3] = { (fb[0] * (0xFF - v) + (b * v)) >> 8, + (fb[1] * (0xFF - v) + (g * v)) >> 8, + (fb[2] * (0xFF - v) + (r * v)) >> 8 }; + fb[0] = (u8)(alpha*blend[0]+one_minus_alpha*(float)fb[0]); + fb[1] = (u8)(alpha*blend[1]+one_minus_alpha*(float)fb[1]); + fb[2] = (u8)(alpha*blend[2]+one_minus_alpha*(float)fb[2]); + } + fb += 3; + } + charData += (cd->h - (cyo + ch)); + fb += (h - ch) * 3; + } + } + else if ( a > 0 ) + { + for (i = 0; i < cd->w; i++) { + charData += cyo; + for (j = 0; j < ch; j++) { + u8 v = *(charData++); + if (v) { + fb[0] = (fb[0] * (0xFF - v) + (b * v)) >> 8; + fb[1] = (fb[1] * (0xFF - v) + (g * v)) >> 8; + fb[2] = (fb[2] * (0xFF - v) + (r * v)) >> 8; + } + fb += 3; } - fb += 3; + charData += (cd->h - (cyo + ch)); + fb += (h - ch) * 3; } - charData += (cd->h - (cyo + ch)); - fb += (h - ch) * 3; } return cd->xa; } From 02da0af8b0931e375e17b7747759b6d81fe95878 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 21 May 2016 21:25:43 +0200 Subject: [PATCH 029/259] Update config.c --- source/config.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/source/config.c b/source/config.c index 5f944ed..7d6197f 100644 --- a/source/config.c +++ b/source/config.c @@ -233,24 +233,25 @@ int configInit() { // read config file to buffer size_t size = fileSize(CONFIG_PATH); - if (!size) { - return -1; - } - - char buffer[size]; - memset(buffer, 0, size); - if (fileRead(CONFIG_PATH, buffer, size) != 0) { - debug("Could not read config file, creating one..."); - configSave(); // write new config file - return -1; - } - ctx.ptr = buffer; - ctx.bytes_left = strlen(ctx.ptr); + if ( size != -1 && size > 0 ) + { + char buffer[size]; + memset(buffer, 0, size); + if (fileRead(CONFIG_PATH, buffer, size) != 0) + { + debug("Could not read config file, creating one..."); + configSave(); + } + else + { + ctx.ptr = buffer; + ctx.bytes_left = strlen(ctx.ptr); - if (ini_parse_stream((ini_reader) ini_buffer_reader, &ctx, handler, config) < 0) { - debug("Could not parse config file, creating one..."); - configSave(); // write new config file - return -1; + if (ini_parse_stream((ini_reader) ini_buffer_reader, &ctx, handler, config) < 0) { + debug("Could not parse config file, creating one..."); + configSave(); // write new config file + } + } } memcpy(fontDefault.color, config->fntDef, sizeof(u8[4])); From cf47e1cf87ece4d086d6aef7b57ee2fac749be7f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:19:22 +0200 Subject: [PATCH 030/259] Update config.c --- source/config.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/config.c b/source/config.c index 7d6197f..5f135c2 100644 --- a/source/config.c +++ b/source/config.c @@ -204,6 +204,8 @@ static int handler(void *user, const char *section, const char *name, void configThemeInit() { config->imgError = true; config->imgErrorBot = true; + config->bgImgTop[0] = '\0'; + config->bgImgBot[0] = '\0'; memcpy(config->bgTop1, (u8[3]) {0x4a, 0x00, 0x31}, sizeof(u8[3])); memcpy(config->bgTop2, (u8[3]) {0x6f, 0x01, 0x49}, sizeof(u8[3])); memcpy(config->bgBot, (u8[3]) {0x6f, 0x01, 0x49}, sizeof(u8[3])); @@ -253,7 +255,7 @@ int configInit() { } } } - + memcpy(fontDefault.color, config->fntDef, sizeof(u8[4])); loadBg(GFX_TOP); loadBg(GFX_BOTTOM); @@ -403,7 +405,7 @@ void loadBg(gfxScreen_t screen) { const char *path = screen == GFX_TOP ? config->bgImgTop : config->bgImgBot; size_t size = fileSize(path); - if (!size) { + if ( size == -1 || size == 0 ) { return; } From ce6324130ef43fa5e1b44626811dfcbd5dd9690c Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:20:06 +0200 Subject: [PATCH 031/259] Update memory.h --- source/memory.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/memory.h b/source/memory.h index 5f0be6d..7ad68fc 100644 --- a/source/memory.h +++ b/source/memory.h @@ -7,10 +7,10 @@ #define PTR_TOP_SCREEN (u8*)(*(u32*)0x23FFFE00) #define PTR_BOT_SCREEN (u8*)(*(u32*)0x23FFFE08) -#define PTR_TOP_SCREEN_BUF (u8*)(0x2507E700) -#define PTR_BOT_SCREEN_BUF (u8*)(0x250C4A00) +#define PTR_TOP_SCREEN_BUF (u8*)(0x2507E900) +#define PTR_BOT_SCREEN_BUF (u8*)(0x250C4E00) #define PTR_TOP_BG (u8*)(0x25000000) -#define PTR_BOT_BG (u8*)(0x25046300) +#define PTR_BOT_BG (u8*)(0x25046500) #define PTR_CFG (u8*)(0x25200000) #define PTR_CFG_TMP (u8*)(0x25230000) #define PTR_PICKER (u8*)(0x25210000) From 79656a13fea446c316e19f9182c4106167701d02 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:20:48 +0200 Subject: [PATCH 032/259] Update menu_more.c --- source/menu_more.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/menu_more.c b/source/menu_more.c index 4644337..ab19711 100644 --- a/source/menu_more.c +++ b/source/menu_more.c @@ -32,8 +32,10 @@ int menu_choose() { memset(&picked, 0, sizeof(file_s)); pick_file(&picked, "/"); - if (strlen(picked.path) > 0) { - return load(picked.path, 0, NULL, 0); + int pathLength = 0; + if ((pathLength = strlen(picked.path)) > 0) { + int offset = ( pathLength > 3 && strcasecmp(&picked.path[pathLength-3], "dat") == 0 ) ? 0x12000 : 0; + return load(picked.path, offset, NULL, 0); } return -1; From e8487663d77f10314b6d2b48074fb983c0f47fe0 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:21:34 +0200 Subject: [PATCH 033/259] Update menu_picker.c --- source/menu_picker.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/menu_picker.c b/source/menu_picker.c index de7dabc..3e8b219 100644 --- a/source/menu_picker.c +++ b/source/menu_picker.c @@ -244,15 +244,17 @@ void pick_file(file_s *picked, const char *path) { int index = picker->file_index; if (!picker->files[index].isDir) { const char *ext = get_filename_ext(picker->files[index].name); + int noOffsetReq = 1; #ifdef ARM9 - if (strcasecmp(ext, "bin") == 0 || strcasecmp(ext, "dat") == 0) { + if (strcasecmp(ext, "bin") == 0 || (noOffsetReq = strcasecmp(ext, "dat")) == 0) { + #else if (strcasecmp(ext, "3dsx") == 0) { #endif if (confirm(3, "Add entry to boot menu: \"%s\" ?", picker->files[index].name)) { if (config->count > CONFIG_MAX_ENTRIES - 1) { debug("Maximum entries reached (%i)\n", CONFIG_MAX_ENTRIES); - } else if (configAddEntry(picker->files[index].name, picker->files[index].path, 0) == 0) { + } else if (configAddEntry(picker->files[index].name, picker->files[index].path, noOffsetReq?0:0x12000) == 0) { debug("Added entry: %s\n", picker->files[index].name); } else { debug("Error adding entry: %s\n", picker->files[index].name); From 18f9a1b42dab947db26392b6447330add87cf420 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:22:14 +0200 Subject: [PATCH 034/259] Update text.c --- source/text.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/source/text.c b/source/text.c index 2c2dcf6..f61e6d6 100644 --- a/source/text.c +++ b/source/text.c @@ -33,22 +33,16 @@ int drawCharacter(u8 *fb, font_s *f, char c, s16 x, s16 y, u16 w, u16 h) { else if (y + ch > h)ch = h - y; fb += (x * h + cy) * 3; const u8 r = f->color[0], g = f->color[1], b = f->color[2], a = f->color[3]; - if ( a < 0xFF ) + if ( a == 0xFF ) { - float alpha = (float)a / 255.f; - float one_minus_alpha = 1.f - alpha; - for (i = 0; i < cd->w; i++) { charData += cyo; for (j = 0; j < ch; j++) { u8 v = *(charData++); if (v) { - u8 blend[3] = { (fb[0] * (0xFF - v) + (b * v)) >> 8, - (fb[1] * (0xFF - v) + (g * v)) >> 8, - (fb[2] * (0xFF - v) + (r * v)) >> 8 }; - fb[0] = (u8)(alpha*blend[0]+one_minus_alpha*(float)fb[0]); - fb[1] = (u8)(alpha*blend[1]+one_minus_alpha*(float)fb[1]); - fb[2] = (u8)(alpha*blend[2]+one_minus_alpha*(float)fb[2]); + fb[0] = (fb[0] * (0xFF - v) + (b * v)) >> 8; + fb[1] = (fb[1] * (0xFF - v) + (g * v)) >> 8; + fb[2] = (fb[2] * (0xFF - v) + (r * v)) >> 8; } fb += 3; } @@ -58,14 +52,20 @@ int drawCharacter(u8 *fb, font_s *f, char c, s16 x, s16 y, u16 w, u16 h) { } else if ( a > 0 ) { + float alpha = (float)a / 255.f; + float one_minus_alpha = 1.f - alpha; + for (i = 0; i < cd->w; i++) { charData += cyo; for (j = 0; j < ch; j++) { u8 v = *(charData++); if (v) { - fb[0] = (fb[0] * (0xFF - v) + (b * v)) >> 8; - fb[1] = (fb[1] * (0xFF - v) + (g * v)) >> 8; - fb[2] = (fb[2] * (0xFF - v) + (r * v)) >> 8; + u8 blend[3] = { (fb[0] * (0xFF - v) + (b * v)) >> 8, + (fb[1] * (0xFF - v) + (g * v)) >> 8, + (fb[2] * (0xFF - v) + (r * v)) >> 8 }; + fb[0] = (u8)(alpha*blend[0]+one_minus_alpha*(float)fb[0]); + fb[1] = (u8)(alpha*blend[1]+one_minus_alpha*(float)fb[1]); + fb[2] = (u8)(alpha*blend[2]+one_minus_alpha*(float)fb[2]); } fb += 3; } From 289718aee33dacf8f5b760617e0a44b6fa52f457 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:22:56 +0200 Subject: [PATCH 035/259] Update utility.c --- source/utility.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/utility.c b/source/utility.c index ac07dac..51ab4d2 100644 --- a/source/utility.c +++ b/source/utility.c @@ -21,7 +21,7 @@ #ifdef ARM9 -void waitcycles(uint32_t val); +void ioDelay(uint32_t val); #else FS_Archive sdmcArchive; @@ -42,7 +42,7 @@ void svcSleep(u32 millis) { #ifndef ARM9 svcSleepThread(nano); #else - waitcycles((u32) nano); + ioDelay((u32) nano); #endif } From 130d00b124660180bd49333d302901031e16e7be Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:23:58 +0200 Subject: [PATCH 036/259] Update integer.h --- source/arm9/source/fatfs/integer.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/source/arm9/source/fatfs/integer.h b/source/arm9/source/fatfs/integer.h index f254b2a..5dd8ec3 100644 --- a/source/arm9/source/fatfs/integer.h +++ b/source/arm9/source/fatfs/integer.h @@ -9,25 +9,30 @@ #include #include +typedef unsigned __int64 QWORD; + #else /* Embedded platform */ -/* This type MUST be 8 bit */ +/* These types MUST be 16-bit or 32-bit */ +typedef int INT; +typedef unsigned int UINT; + +/* This type MUST be 8-bit */ typedef unsigned char BYTE; -/* These types MUST be 16 bit */ +/* These types MUST be 16-bit */ typedef short SHORT; typedef unsigned short WORD; typedef unsigned short WCHAR; -/* These types MUST be 16 bit or 32 bit */ -typedef int INT; -typedef unsigned int UINT; - -/* These types MUST be 32 bit */ +/* These types MUST be 32-bit */ typedef long LONG; typedef unsigned long DWORD; +/* This type MUST be 64-bit (Remove this for C89 compatibility) */ +typedef unsigned long long QWORD; + #endif #endif From ebd2ff681f395416f02d0eb3824c6000b5565e1e Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:24:16 +0200 Subject: [PATCH 037/259] Update ffconf.h --- source/arm9/source/fatfs/ffconf.h | 191 +++++++++++++++--------------- 1 file changed, 93 insertions(+), 98 deletions(-) diff --git a/source/arm9/source/fatfs/ffconf.h b/source/arm9/source/fatfs/ffconf.h index 4b863c6..45e8c20 100644 --- a/source/arm9/source/fatfs/ffconf.h +++ b/source/arm9/source/fatfs/ffconf.h @@ -1,21 +1,13 @@ /*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015 +/ FatFs - FAT file system module configuration file R0.12 (C)ChaN, 2016 /---------------------------------------------------------------------------*/ -#define _FFCONF 32020 /* Revision ID */ +#define _FFCONF 88100 /* Revision ID */ /*---------------------------------------------------------------------------/ -/ Functions and Buffer Configurations +/ Function Configurations /---------------------------------------------------------------------------*/ -#define _FS_TINY 0 -/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) -/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS -/ bytes. Instead of private sector buffer eliminated from the file object, -/ common sector buffer in the file system object (FATFS) is used for the file -/ data transfer. */ - - #define _FS_READONLY 0 /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) / Read-only configuration removes writing API functions, f_write(), f_sync(), @@ -27,8 +19,8 @@ /* This option defines minimization level to remove some basic API functions. / / 0: All basic functions are enabled. -/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(), -/ f_truncate() and f_rename() function are removed. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() +/ are removed. / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. / 3: f_lseek() function is removed in addition to 2. */ @@ -43,8 +35,8 @@ #define _USE_FIND 0 -/* This option switches filtered directory read feature and related functions, -/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */ +/* This option switches filtered directory read functions, f_findfirst() and +/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ #define _USE_MKFS 0 @@ -52,7 +44,16 @@ #define _USE_FASTSEEK 0 -/* This option switches fast seek feature. (0:Disable or 1:Enable) */ +/* This option switches fast seek function. (0:Disable or 1:Enable) */ + + +#define _USE_EXPAND 0 +/* This option switches f_expand function. (0:Disable or 1:Enable) */ + + +#define _USE_CHMOD 0 +/* This option switches attribute manipulation functions, f_chmod() and f_utime(). +/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */ #define _USE_LABEL 0 @@ -62,7 +63,7 @@ #define _USE_FORWARD 0 /* This option switches f_forward() function. (0:Disable or 1:Enable) -/ To enable it, also _FS_TINY need to be set to 1. */ +/ To enable it, also _FS_TINY need to be 1. */ /*---------------------------------------------------------------------------/ @@ -73,37 +74,44 @@ /* This option specifies the OEM code page to be used on the target system. / Incorrect setting of the code page can cause a file open failure. / -/ 1 - ASCII (No extended character. Non-LFN cfg. only) -/ 437 - U.S. -/ 720 - Arabic -/ 737 - Greek -/ 775 - Baltic -/ 850 - Multilingual Latin 1 -/ 852 - Latin 2 -/ 855 - Cyrillic -/ 857 - Turkish -/ 858 - Multilingual Latin 1 + Euro -/ 862 - Hebrew -/ 866 - Russian -/ 874 - Thai -/ 932 - Japanese Shift_JIS (DBCS) -/ 936 - Simplified Chinese GBK (DBCS) -/ 949 - Korean (DBCS) -/ 950 - Traditional Chinese Big5 (DBCS) +/ 1 - ASCII (No extended character. Non-LFN cfg. only) +/ 437 - U.S. +/ 720 - Arabic +/ 737 - Greek +/ 771 - KBL +/ 775 - Baltic +/ 850 - Latin 1 +/ 852 - Latin 2 +/ 855 - Cyrillic +/ 857 - Turkish +/ 860 - Portuguese +/ 861 - Icelandic +/ 862 - Hebrew +/ 863 - Canadian French +/ 864 - Arabic +/ 865 - Nordic +/ 866 - Russian +/ 869 - Greek 2 +/ 932 - Japanese (DBCS) +/ 936 - Simplified Chinese (DBCS) +/ 949 - Korean (DBCS) +/ 950 - Traditional Chinese (DBCS) */ #define _USE_LFN 2 #define _MAX_LFN 255 -/* The _USE_LFN option switches the LFN feature. +/* The _USE_LFN switches the support of long file name (LFN). / -/ 0: Disable LFN feature. _MAX_LFN has no effect. +/ 0: Disable support of LFN. _MAX_LFN has no effect. / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. / 2: Enable LFN with dynamic working buffer on the STACK. / 3: Enable LFN with dynamic working buffer on the HEAP. / -/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must -/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. +/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added +/ to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and +/ additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255. +/ It should be set 255 to support full featured LFN operations. / When use stack for the working buffer, take care on stack overflow. When use heap / memory for the working buffer, memory management functions, ff_memalloc() and / ff_memfree(), must be added to the project. */ @@ -111,12 +119,12 @@ #define _LFN_UNICODE 0 /* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) -/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE -/ to 1. This option also affects behavior of string I/O functions. */ +/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. +/ This option also affects behavior of string I/O functions. */ #define _STRF_ENCODE 0 -/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to +/* When _LFN_UNICODE == 1, this option selects the character encoding on the file to / be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). / / 0: ANSI/OEM @@ -124,17 +132,16 @@ / 2: UTF-16BE / 3: UTF-8 / -/ When _LFN_UNICODE is 0, this option has no effect. */ +/ This option has no effect when _LFN_UNICODE == 0. */ #define _FS_RPATH 0 -/* This option configures relative path feature. +/* This option configures support of relative path. / -/ 0: Disable relative path feature and remove related functions. -/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available. +/ 0: Disable relative path and remove related functions. +/ 1: Enable relative path. f_chdir() and f_chdrive() are available. / 2: f_getcwd() function is available in addition to 1. -/ -/ Note that directory items read via f_readdir() are affected by this option. */ +*/ /*---------------------------------------------------------------------------/ @@ -147,7 +154,7 @@ #define _STR_VOLUME_ID 0 #define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" -/* _STR_VOLUME_ID option switches string volume ID feature. +/* _STR_VOLUME_ID switches string support of volume ID. / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive / number in the path name. _VOLUME_STRS defines the drive ID strings for each / logical drives. Number of items must be equal to _VOLUMES. Valid characters for @@ -155,11 +162,12 @@ #define _MULTI_PARTITION 0 -/* This option switches multi-partition feature. By default (0), each logical drive -/ number is bound to the same physical drive number and only an FAT volume found on -/ the physical drive will be mounted. When multi-partition feature is enabled (1), -/ each logical drive number is bound to arbitrary physical drive and partition -/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */ +/* This option switches support of multi-partition on a physical drive. +/ By default (0), each logical drive number is bound to the same physical drive +/ number and only an FAT volume found on the physical drive will be mounted. +/ When multi-partition is enabled (1), each logical drive number can be bound to +/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() +/ funciton will be available. */ #define _MIN_SS 512 @@ -173,8 +181,8 @@ #define _USE_TRIM 0 -/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable) -/ To enable Trim feature, also CTRL_TRIM command should be implemented to the +/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable) +/ To enable Trim function, also CTRL_TRIM command should be implemented to the / disk_ioctl() function. */ @@ -195,40 +203,53 @@ / System Configurations /---------------------------------------------------------------------------*/ +#define _FS_TINY 0 +/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) +/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS bytes. +/ Instead of private sector buffer eliminated from the file object, common sector +/ buffer in the file system object (FATFS) is used for the file data transfer. */ + + +#define _FS_EXFAT 0 +/* This option switches support of exFAT file system in addition to the traditional +/ FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled. +/ Note that enabling exFAT discards C89 compatibility. */ + + #define _FS_NORTC 1 -#define _NORTC_MON 2 +#define _NORTC_MON 3 #define _NORTC_MDAY 1 -#define _NORTC_YEAR 2015 -/* The _FS_NORTC option switches timestamp feature. If the system does not have -/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable -/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp -/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR. -/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need -/ to be added to the project to read current time form RTC. _NORTC_MON, -/ _NORTC_MDAY and _NORTC_YEAR have no effect. -/ These options have no effect at read-only configuration (_FS_READONLY == 1). */ +#define _NORTC_YEAR 2016 +/* The option _FS_NORTC switches timestamp functiton. If the system does not have +/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable +/ the timestamp function. All objects modified by FatFs will have a fixed timestamp +/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time. +/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be +/ added to the project to get current time form real-time clock. _NORTC_MON, +/ _NORTC_MDAY and _NORTC_YEAR have no effect. +/ These options have no effect at read-only configuration (_FS_READONLY = 1). */ #define _FS_LOCK 0 -/* The _FS_LOCK option switches file lock feature to control duplicated file open +/* The option _FS_LOCK switches file lock function to control duplicated file open / and illegal operation to open objects. This option must be 0 when _FS_READONLY / is 1. / -/ 0: Disable file lock feature. To avoid volume corruption, application program +/ 0: Disable file lock function. To avoid volume corruption, application program / should avoid illegal open, remove and rename to the open objects. -/ >0: Enable file lock feature. The value defines how many files/sub-directories +/ >0: Enable file lock function. The value defines how many files/sub-directories / can be opened simultaneously under file lock control. Note that the file -/ lock feature is independent of re-entrancy. */ +/ lock control is independent of re-entrancy. */ #define _FS_REENTRANT 0 #define _FS_TIMEOUT 1000 #define _SYNC_t HANDLE -/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs +/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / and f_fdisk() function, are always not re-entrant. Only file/directory access -/ to the same volume is under control of this feature. +/ to the same volume is under control of this function. / / 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. / 1: Enable re-entrancy. Also user provided synchronization handlers, @@ -242,30 +263,4 @@ / included somewhere in the scope of ff.c. */ -#define _WORD_ACCESS 0 -/* The _WORD_ACCESS option is an only platform dependent option. It defines -/ which access method is used to the word data on the FAT volume. -/ -/ 0: Byte-by-byte access. Always compatible with all platforms. -/ 1: Word access. Do not choose this unless under both the following conditions. -/ -/ * Address misaligned memory access is always allowed to ALL instructions. -/ * Byte order on the memory is little-endian. -/ -/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size. -/ Following table shows allowable settings of some processor types. -/ -/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2 -/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1 -/ Cortex-M0 0 *2 x86 0/1 TLCS-870 0/1 -/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1 -/ AVR32 0 *1 RL78 0 *2 R32C 0 *2 -/ PIC18 0/1 SH-2 0 *1 M16C 0/1 -/ PIC24 0 *2 H8S 0 *1 MSP430 0 *2 -/ PIC32 0 *1 H8/300H 0 *1 8051 0/1 -/ -/ *1:Big-endian. -/ *2:Unaligned memory access is not supported. -/ *3:Some compilers generate LDM/STM for mem_cpy function. -*/ - +/*--- End of configuration options ---*/ From 9d0290dea8b82a9244ebd45b38d46558228b8eb2 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:24:39 +0200 Subject: [PATCH 038/259] Update ff.h --- source/arm9/source/fatfs/ff.h | 172 +++++++++++++++++++--------------- 1 file changed, 94 insertions(+), 78 deletions(-) diff --git a/source/arm9/source/fatfs/ff.h b/source/arm9/source/fatfs/ff.h index 22f1810..6a94693 100644 --- a/source/arm9/source/fatfs/ff.h +++ b/source/arm9/source/fatfs/ff.h @@ -1,10 +1,10 @@ /*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module include R0.11 (C)ChaN, 2015 +/ FatFs - FAT file system module include R0.12 (C)ChaN, 2016 /----------------------------------------------------------------------------/ / FatFs module is a free software that opened under license policy of / following conditions. / -/ Copyright (C) 2015, ChaN, all right reserved. +/ Copyright (C) 2016, ChaN, all right reserved. / / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. @@ -17,7 +17,7 @@ #ifndef _FATFS -#define _FATFS 32020 /* Revision ID */ +#define _FATFS 88100 /* Revision ID */ #ifdef __cplusplus extern "C" { @@ -53,7 +53,7 @@ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ /* Type of path name strings on FatFs API */ #if _LFN_UNICODE /* Unicode string */ -#if !_USE_LFN +#if _USE_LFN == 0 #error _LFN_UNICODE must be 0 at non-LFN cfg. #endif #ifndef _INC_TCHAR @@ -76,51 +76,91 @@ typedef char TCHAR; /* File system object structure (FATFS) */ typedef struct { - BYTE fs_type; /* FAT sub-type (0:Not mounted) */ + BYTE fs_type; /* File system type (0:N/A) */ BYTE drv; /* Physical drive number */ - BYTE csize; /* Sectors per cluster (1,2,4...128) */ - BYTE n_fats; /* Number of FAT copies (1 or 2) */ + BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ WORD id; /* File system mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ + WORD csize; /* Cluster size [sectors] */ #if _MAX_SS != _MIN_SS - WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */ + WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ +#endif +#if _FS_EXFAT + BYTE* dirbuf; /* Directory entry block scratchpad buffer */ #endif #if _FS_REENTRANT _SYNC_t sobj; /* Identifier of sync object */ #endif #if !_FS_READONLY - DWORD last_clust; /* Last allocated cluster */ - DWORD free_clust; /* Number of free clusters */ + DWORD last_clst; /* Last allocated cluster */ + DWORD free_clst; /* Number of free clusters */ #endif -#if _FS_RPATH +#if _FS_RPATH != 0 DWORD cdir; /* Current directory start cluster (0:root) */ +#if _FS_EXFAT + DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ + DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ + DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ +#endif #endif - DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */ - DWORD fsize; /* Sectors per FAT */ - DWORD volbase; /* Volume start sector */ - DWORD fatbase; /* FAT start sector */ - DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */ - DWORD database; /* Data start sector */ + DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ + DWORD fsize; /* Size of an FAT [sectors] */ + DWORD volbase; /* Volume base sector */ + DWORD fatbase; /* FAT base sector */ + DWORD dirbase; /* Root directory base sector/cluster */ + DWORD database; /* Data base sector */ DWORD winsect; /* Current sector appearing in the win[] */ BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ } FATFS; +/* Type of file size variables and object identifier */ + +#if _FS_EXFAT +#if _USE_LFN == 0 +#error LFN must be enabled when enable exFAT +#endif +typedef QWORD FSIZE_t; +#else +typedef DWORD FSIZE_t; +#endif + + + +/* Object ID and allocation information (_FDID) */ + +typedef struct { + FATFS* fs; /* Pointer to the owner file system object */ + WORD id; /* Owner file system mount ID */ + BYTE attr; /* Object attribute */ + BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */ + DWORD sclust; /* Object start cluster (0:no cluster or root directory) */ + FSIZE_t objsize; /* Object size (valid when sclust != 0) */ +#if _FS_EXFAT + DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */ + DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ + DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ + DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */ +#endif +#if _FS_LOCK != 0 + UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ +#endif +} _FDID; + + + /* File object structure (FIL) */ typedef struct { - FATFS* fs; /* Pointer to the related file system object (**do not change order**) */ - WORD id; /* Owner file system mount ID (**do not change order**) */ - BYTE flag; /* Status flags */ + _FDID obj; /* Object identifier */ + BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ - DWORD fptr; /* File read/write pointer (Zeroed on file open) */ - DWORD fsize; /* File size */ - DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */ + FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ - DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */ + DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ #if !_FS_READONLY DWORD dir_sect; /* Sector number containing the directory entry */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ @@ -128,9 +168,6 @@ typedef struct { #if _USE_FASTSEEK DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */ #endif -#if _FS_LOCK - UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ -#endif #if !_FS_TINY BYTE buf[_MAX_SS]; /* File private data read/write window */ #endif @@ -141,23 +178,18 @@ typedef struct { /* Directory object structure (DIR) */ typedef struct { - FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */ - WORD id; /* Owner file system mount ID (**do not change order**) */ - WORD index; /* Current read/write index number */ - DWORD sclust; /* Table start cluster (0:Root dir) */ + _FDID obj; /* Object identifier */ + DWORD dptr; /* Current read/write offset */ DWORD clust; /* Current cluster */ DWORD sect; /* Current sector */ - BYTE* dir; /* Pointer to the current SFN entry in the win[] */ - BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ -#if _FS_LOCK - UINT lockid; /* File lock ID (index of file semaphore table Files[]) */ -#endif -#if _USE_LFN + BYTE* dir; /* Pointer to the directory item in the win[] */ + BYTE* fn; /* Pointer to the SFN (in/out) {body[8],ext[3],status[1]} */ +#if _USE_LFN != 0 + DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ WCHAR* lfn; /* Pointer to the LFN working buffer */ - WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */ #endif #if _USE_FIND - const TCHAR* pat; /* Pointer to the name matching pattern */ + const TCHAR* pat; /* Pointer to the name matching pattern */ #endif } DIR; @@ -166,14 +198,15 @@ typedef struct { /* File information structure (FILINFO) */ typedef struct { - DWORD fsize; /* File size */ - WORD fdate; /* Last modified date */ - WORD ftime; /* Last modified time */ - BYTE fattrib; /* Attribute */ - TCHAR fname[13]; /* Short file name (8.3 format) */ -#if _USE_LFN - TCHAR* lfname; /* Pointer to the LFN buffer */ - UINT lfsize; /* Size of LFN buffer in TCHAR */ + FSIZE_t fsize; /* File size */ + WORD fdate; /* Modified date */ + WORD ftime; /* Modified time */ + BYTE fattrib; /* File attribute */ +#if _USE_LFN != 0 + TCHAR altname[13]; /* Altenative file name */ + TCHAR fname[_MAX_LFN + 1]; /* Primary file name */ +#else + TCHAR fname[13]; /* File name */ #endif } FILINFO; @@ -200,7 +233,7 @@ typedef enum { FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ - FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */ + FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ } FRESULT; @@ -213,8 +246,7 @@ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a f FRESULT f_close (FIL* fp); /* Close an open file object */ FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */ FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */ -FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ -FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */ +FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of a file object */ FRESULT f_truncate (FIL* fp); /* Truncate file */ FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */ FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ @@ -227,13 +259,15 @@ FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or direc FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */ -FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */ +FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of the file/dir */ FRESULT f_chdir (const TCHAR* path); /* Change current directory */ FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ +FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ +FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */ FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */ @@ -242,10 +276,10 @@ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ -#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize)) +#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_error(fp) ((fp)->err) #define f_tell(fp) ((fp)->fptr) -#define f_size(fp) ((fp)->fsize) +#define f_size(fp) ((fp)->obj.objsize) #define f_rewind(fp) f_lseek((fp), 0) #define f_rewinddir(dp) f_readdir((dp), 0) @@ -265,7 +299,7 @@ DWORD get_fattime (void); #endif /* Unicode support functions */ -#if _USE_LFN /* Unicode - OEM code conversion */ +#if _USE_LFN != 0 /* Unicode - OEM code conversion */ WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ #if _USE_LFN == 3 /* Memory functions */ @@ -292,16 +326,13 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ /* File access control and file status flags (FIL.flag) */ #define FA_READ 0x01 -#define FA_OPEN_EXISTING 0x00 - -#if !_FS_READONLY #define FA_WRITE 0x02 +#define FA_OPEN_EXISTING 0x00 #define FA_CREATE_NEW 0x04 #define FA_CREATE_ALWAYS 0x08 #define FA_OPEN_ALWAYS 0x10 -#define FA__WRITTEN 0x20 -#define FA__DIRTY 0x40 -#endif +#define _FA_MODIFIED 0x20 +#define _FA_DIRTY 0x40 /* FAT sub type (FATFS.fs_type) */ @@ -309,6 +340,7 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ #define FS_FAT12 1 #define FS_FAT16 2 #define FS_FAT32 3 +#define FS_EXFAT 4 /* File attribute bits for directory entry */ @@ -323,26 +355,10 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ #define AM_MASK 0x3F /* Mask of defined bits */ -/* Fast seek feature */ -#define CREATE_LINKMAP 0xFFFFFFFF - +/* Fast seek controls */ +#define CREATE_LINKMAP ((FSIZE_t)0 - 1) -/*--------------------------------*/ -/* Multi-byte word access macros */ - -#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */ -#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) -#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) -#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val) -#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) -#else /* Use byte-by-byte access to the FAT structure */ -#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) -#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr)) -#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8) -#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24) -#endif - #ifdef __cplusplus } #endif From 42c03c8623572f194a02a167806ecf446975360a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:25:04 +0200 Subject: [PATCH 039/259] Update ff.c --- source/arm9/source/fatfs/ff.c | 4369 +++++++++++++++++++++------------ 1 file changed, 2731 insertions(+), 1638 deletions(-) diff --git a/source/arm9/source/fatfs/ff.c b/source/arm9/source/fatfs/ff.c index 41de2fc..ac26023 100644 --- a/source/arm9/source/fatfs/ff.c +++ b/source/arm9/source/fatfs/ff.c @@ -1,10 +1,10 @@ /*----------------------------------------------------------------------------/ -/ FatFs - FAT file system module R0.11 (C)ChaN, 2015 +/ FatFs - FAT file system module R0.12 (C)ChaN, 2016 / /-----------------------------------------------------------------------------/ / FatFs module is a free software that opened under license policy of / following conditions. / -/ Copyright (C) 2015, ChaN, all right reserved. +/ Copyright (C) 2016, ChaN, all right reserved. / / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. @@ -26,7 +26,7 @@ ---------------------------------------------------------------------------*/ -#if _FATFS != 32020 /* Revision ID */ +#if _FATFS != 88100 /* Revision ID */ #error Wrong include file (ff.h). #endif @@ -57,7 +57,7 @@ #endif -/* Timestamp feature */ +/* Timestamp */ #if _FS_NORTC == 1 #if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31 #error Invalid _FS_NORTC settings @@ -68,22 +68,22 @@ #endif -/* File access control feature */ -#if _FS_LOCK +/* File lock controls */ +#if _FS_LOCK != 0 #if _FS_READONLY #error _FS_LOCK must be 0 at read-only configuration #endif typedef struct { FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ DWORD clu; /* Object ID 2, directory (0:root) */ - WORD idx; /* Object ID 3, directory index */ + DWORD ofs; /* Object ID 3, directory offset */ WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ } FILESEM; #endif -/* DBCS code ranges and SBCS extend character conversion table */ +/* DBCS code ranges and SBCS upper conversion tables */ #if _CODE_PAGE == 932 /* Japanese Shift-JIS */ #define _DF1S 0x81 /* DBC 1st byte range 1 start */ @@ -121,215 +121,196 @@ typedef struct { #define _DS2S 0xA1 #define _DS2E 0xFE -#elif _CODE_PAGE == 437 /* U.S. (OEM) */ +#elif _CODE_PAGE == 437 /* U.S. */ #define _DF1S 0 -/*#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}*/ - -static -const unsigned short Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */ - 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, - 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, - 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, - 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, - 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, - 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, - 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, - 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, - 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, - 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, - 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, - 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, - 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, - 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, - 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 -}; - -WCHAR ff_convert( /* Converted character, Returns zero on error */ -WCHAR src, /* Character code to be converted */ -UINT dir /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */ -) -{ - WCHAR c; - - if(src < 0x80) - { /* ASCII */ - c = src; - } - else - { - if(dir) - { /* OEMCP to Unicode */ - c = (src >= 0x100) ? 0 : Tbl[src - 0x80]; - } - else - { /* Unicode to OEMCP */ - for(c = 0; c < 0x80; c++) - { - if(src == Tbl[c]) - break; - } - c = (c + 0x80) & 0xFF; - } - } - - return c; -} - -WCHAR ff_wtoupper(WCHAR chr) -{ - if(chr >= 'a' && chr <= 'z') - return (chr - 32); - else - return chr; -} - -#elif _CODE_PAGE == 720 /* Arabic (OEM) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 737 /* Greek (OEM) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ - 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 775 /* Baltic (OEM) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ - 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */ +#define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 720 /* Arabic */ #define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \ - 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} - -#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */ +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 737 /* Greek */ #define _DF1S 0 -#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ - 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ - 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 857 /* Turkish (OEM) */ +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ + 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 771 /* KBL */ #define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ - 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */ +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF} + +#elif _CODE_PAGE == 775 /* Baltic */ #define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ - 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 862 /* Hebrew (OEM) */ +#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 850 /* Latin 1 */ #define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 866 /* Russian (OEM) */ +#define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \ + 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \ + 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 852 /* Latin 2 */ #define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */ +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \ + 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} + +#elif _CODE_PAGE == 855 /* Cyrillic */ #define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */ +#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \ + 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ + 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ + 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \ + 0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 857 /* Turkish */ #define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ - 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} - -#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */ +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 860 /* Portuguese */ #define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ - 0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF} - -#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */ +#define _EXCVT {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \ + 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 861 /* Icelandic */ #define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \ - 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} - -#elif _CODE_PAGE == 1253 /* Greek (Windows) */ +#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 862 /* Hebrew */ #define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \ - 0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF} - -#elif _CODE_PAGE == 1254 /* Turkish (Windows) */ +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 863 /* Canadian-French */ #define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \ - 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} - -#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */ +#define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \ + 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \ + 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 864 /* Arabic */ #define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 1256 /* Arabic (Windows) */ +#define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 865 /* Nordic */ #define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 1257 /* Baltic (Windows) */ +#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 866 /* Russian */ #define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} - -#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */ +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 869 /* Greek 2 */ #define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \ - 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F} +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \ + 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \ + 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \ + 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} #elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ -#if _USE_LFN -#error Cannot use LFN feature without valid code page. +#if _USE_LFN != 0 +#error Cannot enable LFN without valid code page. #endif #define _DF1S 0 @@ -344,7 +325,7 @@ WCHAR ff_wtoupper(WCHAR chr) #define IsLower(c) (((c)>='a')&&((c)<='z')) #define IsDigit(c) (((c)>='0')&&((c)<='9')) -#if _DF1S /* Code page is DBCS */ +#if _DF1S != 0 /* Code page is DBCS */ #ifdef _DF2S /* Two 1st byte areas */ #define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E)) @@ -374,73 +355,122 @@ WCHAR ff_wtoupper(WCHAR chr) #define NS_BODY 0x08 /* Lower case flag (body) */ #define NS_EXT 0x10 /* Lower case flag (ext) */ #define NS_DOT 0x20 /* Dot entry */ +#define NS_NONAME 0x80 /* Not followed */ -/* FAT sub-type boundaries (Differ from specs but correct for real DOS/Windows) */ -#define MIN_FAT16 4086U /* Minimum number of clusters as FAT16 */ -#define MIN_FAT32 65526U /* Minimum number of clusters as FAT32 */ +/* Limits and Boundaries (Differ from specs but correct for real DOS/Windows) */ +#define MIN_FAT16 4086U /* Minimum number of clusters of FAT16 */ +#define MIN_FAT32 65526U /* Minimum number of clusters of FAT32 */ +#define MAX_DIR 0x200000 /* Maximum size of FAT directory */ +#define MAX_DIR_EX 0x10000000 /* Maximum size of exFAT directory */ /* FatFs refers the members in the FAT structures as byte array instead of -/ structure member because the structure is not binary compatible between +/ structure members because the structure is not binary compatible between / different platforms */ -#define BS_jmpBoot 0 /* x86 jump instruction (3) */ -#define BS_OEMName 3 /* OEM name (8) */ -#define BPB_BytsPerSec 11 /* Sector size [byte] (2) */ -#define BPB_SecPerClus 13 /* Cluster size [sector] (1) */ -#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */ -#define BPB_NumFATs 16 /* Number of FAT copies (1) */ -#define BPB_RootEntCnt 17 /* Number of root directory entries for FAT12/16 (2) */ -#define BPB_TotSec16 19 /* Volume size [sector] (2) */ -#define BPB_Media 21 /* Media descriptor (1) */ -#define BPB_FATSz16 22 /* FAT size [sector] (2) */ -#define BPB_SecPerTrk 24 /* Track size [sector] (2) */ -#define BPB_NumHeads 26 /* Number of heads (2) */ -#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */ -#define BPB_TotSec32 32 /* Volume size [sector] (4) */ -#define BS_DrvNum 36 /* Physical drive number (2) */ -#define BS_BootSig 38 /* Extended boot signature (1) */ -#define BS_VolID 39 /* Volume serial number (4) */ -#define BS_VolLab 43 /* Volume label (8) */ -#define BS_FilSysType 54 /* File system type (1) */ -#define BPB_FATSz32 36 /* FAT size [sector] (4) */ -#define BPB_ExtFlags 40 /* Extended flags (2) */ -#define BPB_FSVer 42 /* File system version (2) */ -#define BPB_RootClus 44 /* Root directory first cluster (4) */ -#define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */ -#define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */ -#define BS_DrvNum32 64 /* Physical drive number (2) */ -#define BS_BootSig32 66 /* Extended boot signature (1) */ -#define BS_VolID32 67 /* Volume serial number (4) */ -#define BS_VolLab32 71 /* Volume label (8) */ -#define BS_FilSysType32 82 /* File system type (1) */ -#define FSI_LeadSig 0 /* FSI: Leading signature (4) */ -#define FSI_StrucSig 484 /* FSI: Structure signature (4) */ -#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */ -#define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */ -#define MBR_Table 446 /* MBR: Partition table offset (2) */ +#define BS_jmpBoot 0 /* x86 jump instruction (3-byte) */ +#define BS_OEMName 3 /* OEM name (8-byte) */ +#define BPB_BytsPerSec 11 /* Sector size [byte] (WORD) */ +#define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */ +#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (WORD) */ +#define BPB_NumFATs 16 /* Number of FATs (BYTE) */ +#define BPB_RootEntCnt 17 /* Size of root directory area for FAT12/16 [entry] (WORD) */ +#define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */ +#define BPB_Media 21 /* Media descriptor (BYTE) */ +#define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */ +#define BPB_SecPerTrk 24 /* Track size for int13h [sector] (WORD) */ +#define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */ +#define BPB_HiddSec 28 /* Volume offset from top of the drive (DWORD) */ +#define BPB_TotSec32 32 /* Volume size (32-bit) [sector] (DWORD) */ +#define BS_DrvNum 36 /* Physical drive number for int13h (BYTE) */ +#define BS_NTres 37 /* Error flag (BYTE) */ +#define BS_BootSig 38 /* Extended boot signature (BYTE) */ +#define BS_VolID 39 /* Volume serial number (DWORD) */ +#define BS_VolLab 43 /* Volume label string (8-byte) */ +#define BS_FilSysType 54 /* File system type string (8-byte) */ +#define BPB_FATSz32 36 /* FAT size (32-bit) [sector] (DWORD) */ +#define BPB_ExtFlags 40 /* Extended flags (WORD) */ + +#define BPB_FSVer32 42 /* FAT32: File system version (WORD) */ +#define BPB_RootClus32 44 /* FAT32: Root directory cluster (DWORD) */ +#define BPB_FSInfo32 48 /* FAT32: Offset of FSINFO sector (WORD) */ +#define BPB_BkBootSec32 50 /* FAT32: Offset of backup boot sector (WORD) */ +#define BS_DrvNum32 64 /* FAT32: Physical drive number for int13h (BYTE) */ +#define BS_NTres32 65 /* FAT32: Error flag (BYTE) */ +#define BS_BootSig32 66 /* FAT32: Extended boot signature (BYTE) */ +#define BS_VolID32 67 /* FAT32: Volume serial number (DWORD) */ +#define BS_VolLab32 71 /* FAT32: Volume label string (8-byte) */ +#define BS_FilSysType32 82 /* FAT32: File system type string (8-byte) */ + +#define BPB_ZeroedEx 11 /* exFAT: Must be zero (35-byte) */ +#define BPB_VolOfsEx 64 /* exFAT: Volume offset from top of the drive [sector] (QWORD) */ +#define BPB_TotSecEx 72 /* exFAT: Volume size [sector] (QWORD) */ +#define BPB_FatOfsEx 80 /* exFAT: FAT offset from top of the volume [sector] (DWORD) */ +#define BPB_FatSzEx 84 /* exFAT: FAT size [sector] (DWORD) */ +#define BPB_DataOfsEx 88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */ +#define BPB_NumClusEx 92 /* exFAT: Number of clusters (DWORD) */ +#define BPB_RootClusEx 96 /* exFAT: Root directory cluster (DWORD) */ +#define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ +#define BPB_FSVerEx 104 /* exFAT: File system version (WORD) */ +#define BPB_VolFlagEx 106 /* exFAT: Volume flags (BYTE) */ +#define BPB_ActFatEx 107 /* exFAT: Active FAT flags (BYTE) */ +#define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in byte (BYTE) */ +#define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in sector (BYTE) */ +#define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ +#define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ +#define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ + +#define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */ +#define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ +#define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ +#define FSI_Nxt_Free 492 /* FAT32 FSI: Last allocated cluster (DWORD) */ + +#define MBR_Table 446 /* MBR: Partition table offset */ #define SZ_PTE 16 /* MBR: Size of a partition table entry */ -#define BS_55AA 510 /* Signature word (2) */ + +#define BS_55AA 510 /* Signature word (WORD) */ #define DIR_Name 0 /* Short file name (11) */ #define DIR_Attr 11 /* Attribute (1) */ #define DIR_NTres 12 /* Lower case flag (1) */ -#define DIR_CrtTimeTenth 13 /* Created time sub-second (1) */ +#define DIR_CrtTime10 13 /* Created time sub-second (1) */ #define DIR_CrtTime 14 /* Created time (2) */ #define DIR_CrtDate 16 /* Created date (2) */ #define DIR_LstAccDate 18 /* Last accessed date (2) */ -#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ #define DIR_WrtTime 22 /* Modified time (2) */ #define DIR_WrtDate 24 /* Modified date (2) */ -#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (2) */ -#define DIR_FileSize 28 /* File size (4) */ +#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ +#define DIR_FileSize 28 /* File size (DWORD) */ #define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */ #define LDIR_Attr 11 /* LFN attribute (1) */ #define LDIR_Type 12 /* LFN type (1) */ -#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */ -#define LDIR_FstClusLO 26 /* Must be zero (0) */ -#define SZ_DIRE 32 /* Size of a directory entry */ +#define LDIR_Chksum 13 /* Checksum of the SFN entry */ +#define LDIR_FstClusLO 26 /* Must be zero (WORD) */ +#define XDIR_Type 0 /* Type of exFAT directory entry (BYTE) */ +#define XDIR_NumLabel 1 /* Number of volume label characters (BYTE) */ +#define XDIR_Label 2 /* Volume label (11-WORD) */ +#define XDIR_CaseSum 4 /* Sum of case conversion table (DWORD) */ +#define XDIR_NumSec 1 /* Number of secondary entries (BYTE) */ +#define XDIR_SetSum 2 /* Sum of the set of directory entries (WORD) */ +#define XDIR_Attr 4 /* File attribute (WORD) */ +#define XDIR_CrtTime 8 /* Created time (4) */ +#define XDIR_ModTime 12 /* Modified time (4) */ +#define XDIR_AccTime 16 /* Last accessed time (4) */ +#define XDIR_CrtTime10 20 /* Created time subsecond (1) */ +#define XDIR_ModTime10 21 /* Modified time subsecond (1) */ +#define XDIR_CrtTZ 22 /* Created timezone (1) */ +#define XDIR_ModTZ 23 /* Modified timezone (1) */ +#define XDIR_AccTZ 24 /* Last accessed timezone (1) */ +#define XDIR_GenFlags 33 /* Gneral flags (1) */ +#define XDIR_NumName 35 /* Number of file name characters (BYTE) */ +#define XDIR_NameHash 36 /* Hash of file name (WORD) */ +#define XDIR_ValidFileSize 40 /* Valid file size (QWORD) */ +#define XDIR_FstClus 52 /* First cluster of the File/Directory (DWORD) */ +#define XDIR_FileSize 56 /* File/Directory size (QWORD) */ + +#define SZDIRE 32 /* Size of a directory entry */ #define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ #define DDEM 0xE5 /* Deleted directory entry mark at DIR_Name[0] */ #define RDDEM 0x05 /* Replacement of the character collides with DDEM */ @@ -448,13 +478,16 @@ WCHAR ff_wtoupper(WCHAR chr) -/*------------------------------------------------------------*/ -/* Module private work area */ -/*------------------------------------------------------------*/ -/* Remark: Uninitialized variables with static duration are -/ guaranteed zero/null at start-up. If not, either the linker -/ or start-up routine being used is out of ANSI-C standard. -*/ + +/*-------------------------------------------------------------------------- + + Module Private Work Area + +---------------------------------------------------------------------------*/ + +/* Remark: Variables here without initial value shall be guaranteed zero/null +/ at start-up. If not, either the linker or start-up routine being used is +/ not compliance with C standard. */ #if _VOLUMES < 1 || _VOLUMES > 9 #error Wrong _VOLUMES setting @@ -462,42 +495,79 @@ WCHAR ff_wtoupper(WCHAR chr) static FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ static WORD Fsid; /* File system mount ID */ -#if _FS_RPATH && _VOLUMES >= 2 +#if _FS_RPATH != 0 && _VOLUMES >= 2 static BYTE CurrVol; /* Current drive */ #endif -#if _FS_LOCK +#if _FS_LOCK != 0 static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */ #endif -#if _USE_LFN == 0 /* Non LFN feature */ -#define DEFINE_NAMEBUF BYTE sfn[12] -#define INIT_BUF(dobj) (dobj).fn = sfn -#define FREE_BUF() +#if _USE_LFN == 0 /* Non-LFN configuration */ +#define DEF_NAMBUF BYTE sfn[12] +#define INIT_NAMBUF(dobj) (dobj).fn = sfn +#define FREE_NAMBUF() +#define DEF_DIRBUF +#define INIT_DIRBUF(fs) +#define FREE_DIRBUF() #else #if _MAX_LFN < 12 || _MAX_LFN > 255 #error Wrong _MAX_LFN setting #endif -#if _USE_LFN == 1 /* LFN feature with static working buffer */ -static WCHAR LfnBuf[_MAX_LFN + 1]; -#define DEFINE_NAMEBUF BYTE sfn[12] -#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; } -#define FREE_BUF() -#elif _USE_LFN == 2 /* LFN feature with dynamic working buffer on the stack */ -#define DEFINE_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN + 1] -#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; } -#define FREE_BUF() -#elif _USE_LFN == 3 /* LFN feature with dynamic working buffer on the heap */ -#define DEFINE_NAMEBUF BYTE sfn[12]; WCHAR *lfn -#define INIT_BUF(dobj) { lfn = ff_memalloc((_MAX_LFN + 1) * 2); if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); (dobj).lfn = lfn; (dobj).fn = sfn; } -#define FREE_BUF() ff_memfree(lfn) + +#if _USE_LFN == 1 /* LFN enabled with static working buffer */ +#if _FS_EXFAT +static BYTE DirBuf[SZDIRE*19]; /* Directory entry block scratchpad buffer (19 entries in size) */ +#endif +static WCHAR LfnBuf[_MAX_LFN+1]; /* LFN enabled with static working buffer */ +#define DEF_NAMBUF BYTE sfn[12] +#define INIT_NAMBUF(dj) { (dj).fn = sfn; (dj).lfn = LfnBuf; } +#define FREE_NAMBUF() +#define DEF_DIRBUF +#define INIT_DIRBUF(fs) +#define FREE_DIRBUF() + +#elif _USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ +#if _FS_EXFAT +#define DEF_NAMBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1]; BYTE dbuf[SZDIRE*19] +#define INIT_NAMBUF(dj) { (dj).fn = sfn; (dj).lfn = lbuf; (dj).obj.fs->dirbuf = dbuf; } +#define FREE_NAMBUF() +#define DEF_DIRBUF BYTE dbuf[SZDIRE*19] +#define INIT_DIRBUF(fs) fs->dirbuf = dbuf +#define FREE_DIRBUF() +#else +#define DEF_NAMBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1] +#define INIT_NAMBUF(dj) { (dj).fn = sfn; (dj).lfn = lbuf; } +#define FREE_NAMBUF() +#define DEF_DIRBUF +#define INIT_DIRBUF(fs) +#define FREE_DIRBUF() +#endif + +#elif _USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ +#if _FS_EXFAT +#define DEF_NAMBUF BYTE sfn[12]; WCHAR *lfn +#define INIT_NAMBUF(dj) { lfn = ff_memalloc((_MAX_LFN+1)*2 + SZDIRE*19); if (!lfn) LEAVE_FF((dj).obj.fs, FR_NOT_ENOUGH_CORE); (dj).fn = sfn; (dj).lfn = lfn; (dj).obj.fs->dirbuf = (BYTE*)(lfn+_MAX_LFN+1); } +#define FREE_NAMBUF() ff_memfree(lfn) +#define DEF_DIRBUF BYTE *dirb +#define INIT_DIRBUF(fs) { dirb = ff_memalloc(SZDIRE*19); if (!dirb) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); fs->dirbuf = dirb; } +#define FREE_DIRBUF() ff_memfree(dirb) +#else +#define DEF_NAMBUF BYTE sfn[12]; WCHAR *lfn +#define INIT_NAMBUF(dj) { lfn = ff_memalloc((_MAX_LFN+1)*2); if (!lfn) LEAVE_FF((dj).obj.fs, FR_NOT_ENOUGH_CORE); (dj).fn = sfn; (dj).lfn = lfn; } +#define FREE_NAMBUF() ff_memfree(lfn) +#define DEF_DIRBUF +#define INIT_DIRBUF(fs) +#define FREE_DIRBUF() +#endif + #else #error Wrong _USE_LFN setting #endif #endif #ifdef _EXCVT -static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for extended characters */ +static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended characters */ #endif @@ -512,6 +582,85 @@ static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for extended chara ---------------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------*/ +/* Load/Store multi-byte word in the FAT structure */ +/*-----------------------------------------------------------------------*/ + +static +WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ +{ + WORD rv; + + rv = ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} + +static +DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ +{ + DWORD rv; + + rv = ptr[3]; + rv = rv << 8 | ptr[2]; + rv = rv << 8 | ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} + +#if _FS_EXFAT +static +QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ +{ + QWORD rv; + + rv = ptr[7]; + rv = rv << 8 | ptr[6]; + rv = rv << 8 | ptr[5]; + rv = rv << 8 | ptr[4]; + rv = rv << 8 | ptr[3]; + rv = rv << 8 | ptr[2]; + rv = rv << 8 | ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} +#endif + +#if !_FS_READONLY +static +void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} + +static +void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} + +#if _FS_EXFAT +static +void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} +#endif +#endif /* !_FS_READONLY */ + + + /*-----------------------------------------------------------------------*/ /* String functions */ /*-----------------------------------------------------------------------*/ @@ -522,39 +671,35 @@ void mem_cpy (void* dst, const void* src, UINT cnt) { BYTE *d = (BYTE*)dst; const BYTE *s = (const BYTE*)src; -#if _WORD_ACCESS == 1 - while (cnt >= sizeof (int)) { - *(int*)d = *(int*)s; - d += sizeof (int); s += sizeof (int); - cnt -= sizeof (int); + if (cnt) { + do *d++ = *s++; while (--cnt); } -#endif - while (cnt--) - *d++ = *s++; } -/* Fill memory */ +/* Fill memory block */ static void mem_set (void* dst, int val, UINT cnt) { BYTE *d = (BYTE*)dst; - while (cnt--) - *d++ = (BYTE)val; + do *d++ = (BYTE)val; while (--cnt); } -/* Compare memory to memory */ +/* Compare memory block */ static -int mem_cmp (const void* dst, const void* src, UINT cnt) { +int mem_cmp (const void* dst, const void* src, UINT cnt) { /* ZR:same, NZ:different */ const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; int r = 0; - while (cnt-- && (r = *d++ - *s++) == 0) ; + do { + r = *d++ - *s++; + } while (--cnt && r == 0); + return r; } /* Check if chr is contained in the string */ static -int chk_chr (const char* str, int chr) { +int chk_chr (const char* str, int chr) { /* NZ:contained, ZR:not contained */ while (*str && *str != chr) str++; return *str; } @@ -581,11 +726,7 @@ void unlock_fs ( FRESULT res /* Result code to be returned */ ) { - if (fs && - res != FR_NOT_ENABLED && - res != FR_INVALID_DRIVE && - res != FR_INVALID_OBJECT && - res != FR_TIMEOUT) { + if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { ff_rel_grant(fs->sobj); } } @@ -597,7 +738,7 @@ void unlock_fs ( /*-----------------------------------------------------------------------*/ /* File lock control functions */ /*-----------------------------------------------------------------------*/ -#if _FS_LOCK +#if _FS_LOCK != 0 static FRESULT chk_lock ( /* Check if the file can be accessed */ @@ -610,15 +751,16 @@ FRESULT chk_lock ( /* Check if the file can be accessed */ /* Search file semaphore table */ for (i = be = 0; i < _FS_LOCK; i++) { if (Files[i].fs) { /* Existing entry */ - if (Files[i].fs == dp->fs && /* Check if the object matched with an open object */ - Files[i].clu == dp->sclust && - Files[i].idx == dp->index) break; + if (Files[i].fs == dp->obj.fs && /* Check if the object matched with an open object */ + Files[i].clu == dp->obj.sclust && + Files[i].ofs == dp->dptr) break; } else { /* Blank entry */ be = 1; } } - if (i == _FS_LOCK) /* The object is not opened */ + if (i == _FS_LOCK) { /* The object is not opened */ return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new object? */ + } /* The object has been opened. Reject any open against writing file and all write mode open */ return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; @@ -645,17 +787,17 @@ UINT inc_lock ( /* Increment object open counter and returns its index (0:Intern for (i = 0; i < _FS_LOCK; i++) { /* Find the object */ - if (Files[i].fs == dp->fs && - Files[i].clu == dp->sclust && - Files[i].idx == dp->index) break; + if (Files[i].fs == dp->obj.fs && + Files[i].clu == dp->obj.sclust && + Files[i].ofs == dp->dptr) break; } if (i == _FS_LOCK) { /* Not opened. Register it as new. */ for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; if (i == _FS_LOCK) return 0; /* No free entry to register (int err) */ - Files[i].fs = dp->fs; - Files[i].clu = dp->sclust; - Files[i].idx = dp->index; + Files[i].fs = dp->obj.fs; + Files[i].clu = dp->obj.sclust; + Files[i].ofs = dp->dptr; Files[i].ctr = 0; } @@ -679,9 +821,9 @@ FRESULT dec_lock ( /* Decrement object open counter */ if (--i < _FS_LOCK) { /* Shift index number origin from 0 */ n = Files[i].ctr; if (n == 0x100) n = 0; /* If write mode open, delete the entry */ - if (n) n--; /* Decrement read mode open count */ + if (n > 0) n--; /* Decrement read mode open count */ Files[i].ctr = n; - if (!n) Files[i].fs = 0; /* Delete the entry if open count gets zero */ + if (n == 0) Files[i].fs = 0; /* Delete the entry if open count gets zero */ res = FR_OK; } else { res = FR_INT_ERR; /* Invalid index nunber */ @@ -711,8 +853,8 @@ void clear_lock ( /* Clear lock entries of the volume */ /*-----------------------------------------------------------------------*/ #if !_FS_READONLY static -FRESULT sync_window ( - FATFS* fs /* File system object */ +FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERROR */ + FATFS* fs /* File system object */ ) { DWORD wsect; @@ -740,9 +882,9 @@ FRESULT sync_window ( static -FRESULT move_window ( - FATFS* fs, /* File system object */ - DWORD sector /* Sector number to make appearance in the fs->win[] */ +FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERROR */ + FATFS* fs, /* File system object */ + DWORD sector /* Sector number to make appearance in the fs->win[] */ ) { FRESULT res = FR_OK; @@ -771,7 +913,7 @@ FRESULT move_window ( /*-----------------------------------------------------------------------*/ #if !_FS_READONLY static -FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */ +FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ FATFS* fs /* File system object */ ) { @@ -780,23 +922,22 @@ FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */ res = sync_window(fs); if (res == FR_OK) { - /* Update FSINFO sector if needed */ + /* Update FSInfo sector if needed */ if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { - /* Create FSINFO structure */ + /* Create FSInfo structure */ mem_set(fs->win, 0, SS(fs)); - ST_WORD(fs->win + BS_55AA, 0xAA55); - ST_DWORD(fs->win + FSI_LeadSig, 0x41615252); - ST_DWORD(fs->win + FSI_StrucSig, 0x61417272); - ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust); - ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust); - /* Write it into the FSINFO sector */ + st_word(fs->win + BS_55AA, 0xAA55); + st_dword(fs->win + FSI_LeadSig, 0x41615252); + st_dword(fs->win + FSI_StrucSig, 0x61417272); + st_dword(fs->win + FSI_Free_Count, fs->free_clst); + st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); + /* Write it into the FSInfo sector */ fs->winsect = fs->volbase + 1; disk_write(fs->drv, fs->win, fs->winsect, 1); fs->fsi_flag = 0; } /* Make sure that no pending write process in the physical drive */ - if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) - res = FR_DISK_ERR; + if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; } return res; @@ -809,9 +950,9 @@ FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */ /*-----------------------------------------------------------------------*/ /* Get sector# from cluster# */ /*-----------------------------------------------------------------------*/ -/* Hidden API for hacks and disk tools */ -DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ +static +DWORD clust2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ FATFS* fs, /* File system object */ DWORD clst /* Cluster# to be converted */ ) @@ -827,19 +968,19 @@ DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ /*-----------------------------------------------------------------------*/ /* FAT access - Read value of a FAT entry */ /*-----------------------------------------------------------------------*/ -/* Hidden API for hacks and disk tools */ -DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status */ - FATFS* fs, /* File system object */ - DWORD clst /* FAT index number (cluster number) to get the value */ +static +DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ + _FDID* obj, /* Corresponding object */ + DWORD clst /* Cluster number to get the value */ ) { UINT wc, bc; - BYTE *p; DWORD val; + FATFS *fs = obj->fs; - if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ + if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */ val = 1; /* Internal error */ } else { @@ -857,16 +998,37 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluste case FS_FAT16 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; - p = &fs->win[clst * 2 % SS(fs)]; - val = LD_WORD(p); + val = ld_word(&fs->win[clst * 2 % SS(fs)]); break; case FS_FAT32 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; - p = &fs->win[clst * 4 % SS(fs)]; - val = LD_DWORD(p) & 0x0FFFFFFF; + val = ld_dword(&fs->win[clst * 4 % SS(fs)]) & 0x0FFFFFFF; break; - +#if _FS_EXFAT + case FS_EXFAT : + if (obj->objsize) { + DWORD cofs = clst - obj->sclust; /* Offset from start cluster */ + DWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize; /* Number of clusters - 1 */ + + if (obj->stat == 2) { /* Is there no valid chain on the FAT? */ + if (cofs <= clen) { + val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* Generate the value */ + break; + } + } + if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the contiguous part? */ + val = clst + 1; /* Generate the value */ + break; + } + if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */ + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + val = ld_dword(&fs->win[clst * 4 % SS(fs)]) & 0x7FFFFFFF; + break; + } + } + /* Go default */ +#endif default: val = 1; /* Internal error */ } @@ -881,26 +1043,23 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluste /*-----------------------------------------------------------------------*/ /* FAT access - Change value of a FAT entry */ /*-----------------------------------------------------------------------*/ -/* Hidden API for hacks and disk tools */ #if !_FS_READONLY -FRESULT put_fat ( - FATFS* fs, /* File system object */ - DWORD clst, /* FAT index number (cluster number) to be changed */ - DWORD val /* New value to be set to the entry */ +static +FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ + FATFS* fs, /* Corresponding object */ + DWORD clst, /* FAT index number (cluster number) to be changed */ + DWORD val /* New value to be set to the entry */ ) { UINT bc; BYTE *p; - FRESULT res; + FRESULT res = FR_INT_ERR; - if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ - res = FR_INT_ERR; - - } else { + if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */ switch (fs->fs_type) { - case FS_FAT12 : + case FS_FAT12 : /* Bitfield items */ bc = (UINT)clst; bc += bc / 2; res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; @@ -914,28 +1073,27 @@ FRESULT put_fat ( fs->wflag = 1; break; - case FS_FAT16 : + case FS_FAT16 : /* WORD aligned items */ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); if (res != FR_OK) break; - p = &fs->win[clst * 2 % SS(fs)]; - ST_WORD(p, (WORD)val); + st_word(&fs->win[clst * 2 % SS(fs)], (WORD)val); fs->wflag = 1; break; - case FS_FAT32 : + case FS_FAT32 : /* DWORD aligned items */ +#if _FS_EXFAT + case FS_EXFAT : +#endif res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); if (res != FR_OK) break; - p = &fs->win[clst * 4 % SS(fs)]; - val |= LD_DWORD(p) & 0xF0000000; - ST_DWORD(p, val); + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + val = (val & 0x0FFFFFFF) | (ld_dword(&fs->win[clst * 4 % SS(fs)]) & 0xF0000000); + } + st_dword(&fs->win[clst * 4 % SS(fs)], val); fs->wflag = 1; break; - - default : - res = FR_INT_ERR; } } - return res; } #endif /* !_FS_READONLY */ @@ -943,53 +1101,186 @@ FRESULT put_fat ( +#if _FS_EXFAT && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* exFAT: Accessing FAT and Allocation Bitmap */ +/*-----------------------------------------------------------------------*/ + +/*---------------------------------------------*/ +/* exFAT: Find a contiguous free cluster block */ +/*---------------------------------------------*/ +static +DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Disk error */ + FATFS* fs, /* File system object */ + DWORD clst, /* Cluster number to scan from */ + DWORD ncl /* Number of contiguous clusters to find (1..) */ +) +{ + BYTE bm, bv; + UINT i; + DWORD val, scl, ctr; + + + clst -= 2; /* The first bit in the bitmap corresponds to cluster #2 */ + if (clst >= fs->n_fatent - 2) clst = 0; + scl = val = clst; ctr = 0; + for (;;) { + if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; + i = val / 8 & (SS(fs) - 1); bm = 1 << (val % 8); + do { + do { + bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */ + if (++val >= fs->n_fatent - 2) { /* Next cluster (with wrap-around) */ + val = 0; bm = 0; i = 4096; + } + if (!bv) { /* Is it a free cluster? */ + if (++ctr == ncl) return scl + 2; /* Check run length */ + } else { + scl = val; ctr = 0; /* Encountered a live cluster, restart to scan */ + } + if (val == clst) return 0; /* All cluster scanned? */ + } while (bm); + bm = 1; + } while (++i < SS(fs)); + } +} + +/*------------------------------------*/ +/* exFAT: Set/Clear a block of bitmap */ +/*------------------------------------*/ +static +FRESULT change_bitmap ( + FATFS* fs, /* File system object */ + DWORD clst, /* Cluster number to change from */ + DWORD ncl, /* Number of clusters to be changed */ + int bv /* bit value to be set (0 or 1) */ +) +{ + BYTE bm; + UINT i; + DWORD sect; + + + clst -= 2; /* The first bit corresponds to cluster #2 */ + sect = fs->database + clst / 8 / SS(fs); /* Sector address */ + i = clst / 8 & (SS(fs) - 1); /* Byte offset in the sector */ + bm = 1 << (clst % 8); /* Bit mask in the byte */ + for (;;) { + if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; + do { + do { + if (bv == (int)((fs->win[i] & bm) != 0)) return FR_INT_ERR; /* Is the bit expected value? */ + fs->win[i] ^= bm; /* Flip the bit */ + fs->wflag = 1; + if (--ncl == 0) return FR_OK; /* All bits processed? */ + } while (bm <<= 1); /* Next bit */ + bm = 1; + } while (++i < SS(fs)); /* Next byte */ + } +} + + +/*---------------------------------------------*/ +/* Complement contiguous part of the FAT chain */ +/*---------------------------------------------*/ +static +FRESULT fill_fat_chain ( + _FDID* obj /* Pointer to the corresponding object */ +) +{ + FRESULT res; + DWORD cl, n; + + if (obj->stat == 3) { /* Has the object got fragmented? */ + for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */ + res = put_fat(obj->fs, cl, cl + 1); + if (res != FR_OK) return res; + } + obj->stat = 0; /* Change status 'FAT chain is valid' */ + } + return FR_OK; +} + +#endif + + + /*-----------------------------------------------------------------------*/ /* FAT handling - Remove a cluster chain */ /*-----------------------------------------------------------------------*/ #if !_FS_READONLY static -FRESULT remove_chain ( - FATFS* fs, /* File system object */ - DWORD clst /* Cluster# to remove a chain from */ +FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ + _FDID* obj, /* Corresponding object */ + DWORD clst, /* Cluster to remove a chain from */ + DWORD pclst /* Previous cluster of clst (0:an entire chain) */ ) { - FRESULT res; + FRESULT res = FR_OK; DWORD nxt; + FATFS *fs = obj->fs; +#if _FS_EXFAT || _USE_TRIM + DWORD scl = clst, ecl = clst; +#endif #if _USE_TRIM - DWORD scl = clst, ecl = clst, rt[2]; + DWORD rt[2]; #endif - if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ - res = FR_INT_ERR; + if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Check if in valid range */ - } else { - res = FR_OK; - while (clst < fs->n_fatent) { /* Not a last link? */ - nxt = get_fat(fs, clst); /* Get cluster status */ - if (nxt == 0) break; /* Empty cluster? */ - if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */ - if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */ - res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */ - if (res != FR_OK) break; - if (fs->free_clust != 0xFFFFFFFF) { /* Update FSINFO */ - fs->free_clust++; - fs->fsi_flag |= 1; + /* Mark the previous cluster 'EOC' on the FAT if it exists */ + if (pclst && (!_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) { + res = put_fat(fs, pclst, 0xFFFFFFFF); + if (res != FR_OK) return res; + } + + /* Remove the chain */ + do { + nxt = get_fat(obj, clst); /* Get cluster status */ + if (nxt == 0) break; /* Empty cluster? */ + if (nxt == 1) return FR_INT_ERR; /* Internal error? */ + if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error? */ + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ + if (res != FR_OK) return res; + } + if (fs->free_clst != 0xFFFFFFFF) { /* Update FSINFO */ + fs->free_clst++; + fs->fsi_flag |= 1; + } +#if _FS_EXFAT || _USE_TRIM + if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ + ecl = nxt; + } else { /* End of contiguous cluster block */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */ + if (res != FR_OK) return res; } +#endif #if _USE_TRIM - if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ - ecl = nxt; - } else { /* End of contiguous clusters */ - rt[0] = clust2sect(fs, scl); /* Start sector */ - rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ - disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Erase the block */ - scl = ecl = nxt; - } + rt[0] = clust2sect(fs, scl); /* Start sector */ + rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ + disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Inform device the block can be erased */ #endif - clst = nxt; /* Next cluster */ + scl = ecl = nxt; } - } +#endif + clst = nxt; /* Next cluster */ + } while (clst < fs->n_fatent); /* Repeat while not the last link */ - return res; +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + if (pclst == 0) { /* Does object have no chain? */ + obj->stat = 0; /* Change the object status 'initial' */ + } else { + if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Did the chain got contiguous? */ + obj->stat = 2; /* Change the object status 'contiguous' */ + } + } + } +#endif + return FR_OK; } #endif @@ -997,60 +1288,82 @@ FRESULT remove_chain ( /*-----------------------------------------------------------------------*/ -/* FAT handling - Stretch or Create a cluster chain */ +/* FAT handling - Stretch a chain or Create a new chain */ /*-----------------------------------------------------------------------*/ #if !_FS_READONLY static DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ - FATFS* fs, /* File system object */ - DWORD clst /* Cluster# to stretch. 0 means create a new chain. */ + _FDID* obj, /* Corresponding object */ + DWORD clst /* Cluster# to stretch, 0:Create a new chain */ ) { DWORD cs, ncl, scl; FRESULT res; + FATFS *fs = obj->fs; - if (clst == 0) { /* Create a new chain */ - scl = fs->last_clust; /* Get suggested start point */ - if (!scl || scl >= fs->n_fatent) scl = 1; + if (clst == 0) { /* Create a new chain */ + scl = fs->last_clst; /* Get suggested cluster to start at */ + if (scl == 0 || scl >= fs->n_fatent) scl = 1; } - else { /* Stretch the current chain */ - cs = get_fat(fs, clst); /* Check the cluster status */ - if (cs < 2) return 1; /* Invalid value */ + else { /* Stretch current chain */ + cs = get_fat(obj, clst); /* Check the cluster status */ + if (cs < 2) return 1; /* Invalid value */ if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */ if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ scl = clst; } - ncl = scl; /* Start cluster */ - for (;;) { - ncl++; /* Next cluster */ - if (ncl >= fs->n_fatent) { /* Check wrap around */ - ncl = 2; - if (ncl > scl) return 0; /* No free cluster */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */ + if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */ + res = change_bitmap(fs, ncl, 1, 1); /* Mark the cluster 'in use' */ + if (res == FR_INT_ERR) return 1; + if (res == FR_DISK_ERR) return 0xFFFFFFFF; + if (clst == 0) { /* Is it a new chain? */ + obj->stat = 2; /* Set status 'contiguous chain' */ + } else { /* This is a stretched chain */ + if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */ + obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */ + obj->stat = 3; /* Change status 'just fragmented' */ + } + } + } else +#endif + { /* At the FAT12/16/32 */ + ncl = scl; /* Start cluster */ + for (;;) { + ncl++; /* Next cluster */ + if (ncl >= fs->n_fatent) { /* Check wrap-around */ + ncl = 2; + if (ncl > scl) return 0; /* No free cluster */ + } + cs = get_fat(obj, ncl); /* Get the cluster status */ + if (cs == 0) break; /* Found a free cluster */ + if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* An error occurred */ + if (ncl == scl) return 0; /* No free cluster */ } - cs = get_fat(fs, ncl); /* Get the cluster status */ - if (cs == 0) break; /* Found a free cluster */ - if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */ - return cs; - if (ncl == scl) return 0; /* No free cluster */ } - res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */ - if (res == FR_OK && clst != 0) { - res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */ - } - if (res == FR_OK) { - fs->last_clust = ncl; /* Update FSINFO */ - if (fs->free_clust != 0xFFFFFFFF) { - fs->free_clust--; - fs->fsi_flag |= 1; + if (_FS_EXFAT && fs->fs_type == FS_EXFAT && obj->stat == 2) { /* Is it a contiguous chain? */ + res = FR_OK; /* FAT does not need to be written */ + } else { + res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ + if (res == FR_OK && clst) { + res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ } + } + + if (res == FR_OK) { /* Update FSINFO if function succeeded. */ + fs->last_clst = ncl; + if (fs->free_clst < fs->n_fatent - 2) fs->free_clst--; + fs->fsi_flag |= 1; } else { - ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Create error status */ } - return ncl; /* Return new cluster number or error code */ + return ncl; /* Return new cluster number or error status */ } #endif /* !_FS_READONLY */ @@ -1065,17 +1378,18 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err static DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ FIL* fp, /* Pointer to the file object */ - DWORD ofs /* File offset to be converted to cluster# */ + FSIZE_t ofs /* File offset to be converted to cluster# */ ) { DWORD cl, ncl, *tbl; + FATFS *fs = fp->obj.fs; tbl = fp->cltbl + 1; /* Top of CLMT */ - cl = ofs / SS(fp->fs) / fp->fs->csize; /* Cluster order from top of the file */ + cl = (DWORD)(ofs / SS(fs) / fs->csize); /* Cluster order from top of the file */ for (;;) { ncl = *tbl++; /* Number of cluters in the fragment */ - if (!ncl) return 0; /* End of table? (error) */ + if (ncl == 0) return 0; /* End of table? (error) */ if (cl < ncl) break; /* In this fragment? */ cl -= ncl; tbl++; /* Next fragment */ } @@ -1085,48 +1399,48 @@ DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ - /*-----------------------------------------------------------------------*/ /* Directory handling - Set directory index */ /*-----------------------------------------------------------------------*/ static -FRESULT dir_sdi ( +FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp, /* Pointer to directory object */ - UINT idx /* Index of directory table */ + DWORD ofs /* Offset of directory table */ ) { - DWORD clst, sect; - UINT ic; + DWORD csz, clst; + FATFS *fs = dp->obj.fs; - dp->index = (WORD)idx; /* Current index */ - clst = dp->sclust; /* Table start cluster (0:root) */ - if (clst == 1 || clst >= dp->fs->n_fatent) /* Check start cluster range */ + if (ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */ return FR_INT_ERR; - if (!clst && dp->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */ - clst = dp->fs->dirbase; + } + dp->dptr = ofs; /* Set current offset */ + clst = dp->obj.sclust; /* Table start cluster (0:root) */ + if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */ + clst = fs->dirbase; + if (_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ + } if (clst == 0) { /* Static table (root-directory in FAT12/16) */ - if (idx >= dp->fs->n_rootdir) /* Is index out of range? */ - return FR_INT_ERR; - sect = dp->fs->dirbase; - } - else { /* Dynamic table (root-directory in FAT32 or sub-directory) */ - ic = SS(dp->fs) / SZ_DIRE * dp->fs->csize; /* Entries per cluster */ - while (idx >= ic) { /* Follow cluster chain */ - clst = get_fat(dp->fs, clst); /* Get next cluster */ + if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */ + dp->sect = fs->dirbase; + + } else { /* Dynamic table (sub-directory or root-directory in FAT32+) */ + csz = (DWORD)fs->csize * SS(fs); /* Bytes per cluster */ + while (ofs >= csz) { /* Follow cluster chain */ + clst = get_fat(&dp->obj, clst); /* Get next cluster */ if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ - if (clst < 2 || clst >= dp->fs->n_fatent) /* Reached to end of table or internal error */ - return FR_INT_ERR; - idx -= ic; + if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Reached to end of table or internal error */ + ofs -= csz; } - sect = clust2sect(dp->fs, clst); + dp->sect = clust2sect(fs, clst); } - dp->clust = clst; /* Current cluster# */ - if (!sect) return FR_INT_ERR; - dp->sect = sect + idx / (SS(dp->fs) / SZ_DIRE); /* Sector# of the directory entry */ - dp->dir = dp->fs->win + (idx % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Ptr to the entry in the sector */ + dp->clust = clst; /* Current cluster# */ + if (!dp->sect) return FR_INT_ERR; + dp->sect += ofs / SS(fs); /* Sector# of the directory entry */ + dp->dir = fs->win + (ofs % SS(fs)); /* Pointer to the entry in the win[] */ return FR_OK; } @@ -1139,64 +1453,63 @@ FRESULT dir_sdi ( /*-----------------------------------------------------------------------*/ static -FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ +FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ DIR* dp, /* Pointer to the directory object */ int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ ) { - DWORD clst; - UINT i; + DWORD ofs, clst; + FATFS *fs = dp->obj.fs; #if !_FS_READONLY - UINT c; + UINT n; #endif + ofs = dp->dptr + SZDIRE; /* Next entry */ + if (!dp->sect || ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) return FR_NO_FILE; /* Report EOT when offset has reached max value */ - i = dp->index + 1; - if (!(i & 0xFFFF) || !dp->sect) /* Report EOT when index has reached 65535 */ - return FR_NO_FILE; - - if (!(i % (SS(dp->fs) / SZ_DIRE))) { /* Sector changed? */ - dp->sect++; /* Next sector */ + if (ofs % SS(fs) == 0) { /* Sector changed? */ + dp->sect++; /* Next sector */ if (!dp->clust) { /* Static table */ - if (i >= dp->fs->n_rootdir) /* Report EOT if it reached end of static table */ - return FR_NO_FILE; + if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */ + dp->sect = 0; return FR_NO_FILE; + } } else { /* Dynamic table */ - if (((i / (SS(dp->fs) / SZ_DIRE)) & (dp->fs->csize - 1)) == 0) { /* Cluster changed? */ - clst = get_fat(dp->fs, dp->clust); /* Get next cluster */ - if (clst <= 1) return FR_INT_ERR; - if (clst == 0xFFFFFFFF) return FR_DISK_ERR; - if (clst >= dp->fs->n_fatent) { /* If it reached end of dynamic table, */ + if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ + clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ + if (clst <= 1) return FR_INT_ERR; /* Internal error */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst >= fs->n_fatent) { /* Reached end of dynamic table */ #if !_FS_READONLY - if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT */ - clst = create_chain(dp->fs, dp->clust); /* Stretch cluster chain */ + if (!stretch) { /* If no stretch, report EOT */ + dp->sect = 0; return FR_NO_FILE; + } + clst = create_chain(&dp->obj, dp->clust); /* Allocate a cluster */ if (clst == 0) return FR_DENIED; /* No free cluster */ - if (clst == 1) return FR_INT_ERR; - if (clst == 0xFFFFFFFF) return FR_DISK_ERR; - /* Clean-up stretched table */ - if (sync_window(dp->fs)) return FR_DISK_ERR;/* Flush disk access window */ - mem_set(dp->fs->win, 0, SS(dp->fs)); /* Clear window buffer */ - dp->fs->winsect = clust2sect(dp->fs, clst); /* Cluster start sector */ - for (c = 0; c < dp->fs->csize; c++) { /* Fill the new cluster with 0 */ - dp->fs->wflag = 1; - if (sync_window(dp->fs)) return FR_DISK_ERR; - dp->fs->winsect++; + if (clst == 1) return FR_INT_ERR; /* Internal error */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + /* Clean-up the stretched table */ + if (_FS_EXFAT) dp->obj.stat |= 4; /* The directory needs to be updated */ + if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ + mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */ + for (n = 0, fs->winsect = clust2sect(fs, clst); n < fs->csize; n++, fs->winsect++) { /* Fill the new cluster with 0 */ + fs->wflag = 1; + if (sync_window(fs) != FR_OK) return FR_DISK_ERR; } - dp->fs->winsect -= c; /* Rewind window offset */ + fs->winsect -= n; /* Restore window offset */ #else - if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT (this is to suppress warning) */ - return FR_NO_FILE; /* Report EOT */ + if (!stretch) dp->sect = 0; /* If no stretch, report EOT (this is to suppress warning) */ + dp->sect = 0; return FR_NO_FILE; /* Report EOT */ #endif } - dp->clust = clst; /* Initialize data for new cluster */ - dp->sect = clust2sect(dp->fs, clst); + dp->clust = clst; /* Initialize data for new cluster */ + dp->sect = clust2sect(fs, clst); } } } - - dp->index = (WORD)i; /* Current index */ - dp->dir = dp->fs->win + (i % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Current entry in the window */ + dp->dptr = ofs; /* Current entry */ + dp->dir = &fs->win[ofs % SS(fs)]; /* Pointer to the entry in the win[] */ return FR_OK; } @@ -1205,34 +1518,40 @@ FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could /*-----------------------------------------------------------------------*/ -/* Directory handling - Reserve directory entry */ +/* Directory handling - Reserve a block of directory entries */ /*-----------------------------------------------------------------------*/ #if !_FS_READONLY static -FRESULT dir_alloc ( - DIR* dp, /* Pointer to the directory object */ - UINT nent /* Number of contiguous entries to allocate (1-21) */ +FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp, /* Pointer to the directory object */ + UINT nent /* Number of contiguous entries to allocate */ ) { FRESULT res; UINT n; + FATFS *fs = dp->obj.fs; res = dir_sdi(dp, 0); if (res == FR_OK) { n = 0; do { - res = move_window(dp->fs, dp->sect); + res = move_window(fs, dp->sect); if (res != FR_OK) break; - if (dp->dir[0] == DDEM || dp->dir[0] == 0) { /* Is it a free entry? */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { +#else + if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) { +#endif if (++n == nent) break; /* A block of contiguous free entries is found */ } else { n = 0; /* Not a blank entry. Restart to search */ } - res = dir_next(dp, 1); /* Next entry with table stretch enabled */ - } while (res == FR_OK); + res = dir_next(dp, 1); + } while (res == FR_OK); /* Next entry with table stretch enabled */ } + if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ return res; } @@ -1242,20 +1561,21 @@ FRESULT dir_alloc ( /*-----------------------------------------------------------------------*/ -/* Directory handling - Load/Store start cluster number */ +/* FAT: Directory handling - Load/Store start cluster number */ /*-----------------------------------------------------------------------*/ static -DWORD ld_clust ( - FATFS* fs, /* Pointer to the fs object */ - BYTE* dir /* Pointer to the directory entry */ +DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ + FATFS* fs, /* Pointer to the fs object */ + const BYTE* dir /* Pointer to the key entry */ ) { DWORD cl; - cl = LD_WORD(dir + DIR_FstClusLO); - if (fs->fs_type == FS_FAT32) - cl |= (DWORD)LD_WORD(dir + DIR_FstClusHI) << 16; + cl = ld_word(dir + DIR_FstClusLO); + if (fs->fs_type == FS_FAT32) { + cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16; + } return cl; } @@ -1264,115 +1584,130 @@ DWORD ld_clust ( #if !_FS_READONLY static void st_clust ( - BYTE* dir, /* Pointer to the directory entry */ + FATFS* fs, /* Pointer to the fs object */ + BYTE* dir, /* Pointer to the key entry */ DWORD cl /* Value to be set */ ) { - ST_WORD(dir + DIR_FstClusLO, cl); - ST_WORD(dir + DIR_FstClusHI, cl >> 16); + st_word(dir + DIR_FstClusLO, (WORD)cl); + if (fs->fs_type == FS_FAT32) { + st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16)); + } } #endif -/*-----------------------------------------------------------------------*/ -/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */ -/*-----------------------------------------------------------------------*/ -#if _USE_LFN +/*------------------------------------------------------------------------*/ +/* FAT-LFN: LFN handling */ +/*------------------------------------------------------------------------*/ +#if _USE_LFN != 0 static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN characters in the directory entry */ - +/*--------------------------------------------------------*/ +/* FAT-LFN: Compare a part of file name with an LFN entry */ +/*--------------------------------------------------------*/ static -int cmp_lfn ( /* 1:Matched, 0:Not matched */ - WCHAR* lfnbuf, /* Pointer to the LFN to be compared */ - BYTE* dir /* Pointer to the directory entry containing a part of LFN */ +int cmp_lfn ( /* 1:matched, 0:not matched */ + const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ + BYTE* dir /* Pointer to the directory entry containing the part of LFN */ ) { UINT i, s; WCHAR wc, uc; - i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Get offset in the LFN buffer */ - s = 0; wc = 1; - do { - uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */ - if (wc) { /* Last character has not been processed */ - wc = ff_wtoupper(uc); /* Convert it to upper case */ - if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */ - return 0; /* Not matched */ + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + + i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + + for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ + uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ + if (wc) { + if (i >= _MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ + return 0; /* Not matched */ + } + wc = uc; } else { - if (uc != 0xFFFF) return 0; /* Check filler */ + if (uc != 0xFFFF) return 0; /* Check filler */ } - } while (++s < 13); /* Repeat until all characters in the entry are checked */ + } - if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) /* Last segment matched but different length */ - return 0; + if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0; /* Last segment matched but different length */ - return 1; /* The part of LFN matched */ + return 1; /* The part of LFN matched */ } +#if _FS_MINIMIZE <= 1 || _FS_EXFAT +/*-----------------------------------------------------*/ +/* FAT-LFN: Pick a part of file name from an LFN entry */ +/*-----------------------------------------------------*/ static -int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */ - WCHAR* lfnbuf, /* Pointer to the Unicode-LFN buffer */ - BYTE* dir /* Pointer to the directory entry */ +int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ + WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ + BYTE* dir /* Pointer to the LFN entry */ ) { UINT i, s; WCHAR wc, uc; + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ - s = 0; wc = 1; - do { - uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */ - if (wc) { /* Last character has not been processed */ + for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ + uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ + if (wc) { if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ lfnbuf[i++] = wc = uc; /* Store it */ } else { if (uc != 0xFFFF) return 0; /* Check filler */ } - } while (++s < 13); /* Read all character in the entry */ + } if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ lfnbuf[i] = 0; } - return 1; + return 1; /* The part of LFN is valid */ } - +#endif #if !_FS_READONLY +/*-----------------------------------------*/ +/* FAT-LFN: Create an entry of LFN entries */ +/*-----------------------------------------*/ static -void fit_lfn ( - const WCHAR* lfnbuf, /* Pointer to the LFN buffer */ - BYTE* dir, /* Pointer to the directory entry */ - BYTE ord, /* LFN order (1-20) */ - BYTE sum /* SFN sum */ +void put_lfn ( + const WCHAR* lfn, /* Pointer to the LFN */ + BYTE* dir, /* Pointer to the LFN entry to be created */ + BYTE ord, /* LFN order (1-20) */ + BYTE sum /* Checksum of the corresponding SFN */ ) { UINT i, s; WCHAR wc; - dir[LDIR_Chksum] = sum; /* Set check sum */ + dir[LDIR_Chksum] = sum; /* Set checksum */ dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ dir[LDIR_Type] = 0; - ST_WORD(dir + LDIR_FstClusLO, 0); + st_word(dir + LDIR_FstClusLO, 0); - i = (ord - 1) * 13; /* Get offset in the LFN buffer */ + i = (ord - 1) * 13; /* Get offset in the LFN working buffer */ s = wc = 0; do { - if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */ - ST_WORD(dir+LfnOfs[s], wc); /* Put it */ - if (!wc) wc = 0xFFFF; /* Padding characters following last character */ + if (wc != 0xFFFF) wc = lfn[i++]; /* Get an effective character */ + st_word(dir + LfnOfs[s], wc); /* Put it */ + if (wc == 0) wc = 0xFFFF; /* Padding characters for left locations */ } while (++s < 13); - if (wc == 0xFFFF || !lfnbuf[i]) ord |= LLEF; /* Bottom LFN part is the start of LFN sequence */ + if (wc == 0xFFFF || !lfn[i]) ord |= LLEF; /* Last LFN part is the start of LFN sequence */ dir[LDIR_Ord] = ord; /* Set the LFN order */ } @@ -1381,11 +1716,10 @@ void fit_lfn ( - /*-----------------------------------------------------------------------*/ -/* Create numbered name */ +/* FAT-LFN: Create a Numbered SFN */ /*-----------------------------------------------------------------------*/ -#if _USE_LFN +#if _USE_LFN != 0 && !_FS_READONLY static void gen_numname ( BYTE* dst, /* Pointer to the buffer to store numbered SFN */ @@ -1402,7 +1736,7 @@ void gen_numname ( mem_cpy(dst, src, 11); - if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */ + if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ sr = seq; while (*lfn) { /* Create a CRC */ wc = *lfn++; @@ -1440,11 +1774,10 @@ void gen_numname ( - /*-----------------------------------------------------------------------*/ -/* Calculate sum of an SFN */ +/* FAT-LFN: Calculate checksum of an SFN entry */ /*-----------------------------------------------------------------------*/ -#if _USE_LFN +#if _USE_LFN != 0 static BYTE sum_sfn ( const BYTE* dir /* Pointer to the SFN entry */ @@ -1461,122 +1794,396 @@ BYTE sum_sfn ( +#if _FS_EXFAT /*-----------------------------------------------------------------------*/ -/* Directory handling - Find an object in the directory */ +/* exFAT: Directory handling - Load/Store a block of directory entries */ /*-----------------------------------------------------------------------*/ static -FRESULT dir_find ( - DIR* dp /* Pointer to the directory object linked to the file name */ +WORD xdir_sum ( /* Get checksum of the directoly block */ + const BYTE* dir /* Directory entry block to be calculated */ ) { - FRESULT res; - BYTE c, *dir; -#if _USE_LFN - BYTE a, ord, sum; -#endif + UINT i, szblk; + WORD sum; - res = dir_sdi(dp, 0); /* Rewind directory object */ - if (res != FR_OK) return res; -#if _USE_LFN - ord = sum = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ -#endif - do { - res = move_window(dp->fs, dp->sect); - if (res != FR_OK) break; - dir = dp->dir; /* Ptr to the directory entry of current index */ - c = dir[DIR_Name]; - if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ -#if _USE_LFN /* LFN configuration */ - a = dir[DIR_Attr] & AM_MASK; - if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ - ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ + szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; + for (i = sum = 0; i < szblk; i++) { + if (i == XDIR_SetSum) { /* Skip sum field */ + i++; } else { - if (a == AM_LFN) { /* An LFN entry is found */ - if (dp->lfn) { - if (c & LLEF) { /* Is it start of LFN sequence? */ - sum = dir[LDIR_Chksum]; - c &= ~LLEF; ord = c; /* LFN start order */ - dp->lfn_idx = dp->index; /* Start index of LFN */ - } - /* Check validity of the LFN entry and compare it with given name */ - ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF; - } - } else { /* An SFN entry is found */ - if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */ - if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dir, dp->fn, 11)) break; /* SFN matched? */ - ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ - } + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i]; } -#else /* Non LFN configuration */ - if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dp->fn, 11)) /* Is it a valid entry? */ - break; + } + return sum; +} + + + +static +WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ + const WCHAR* name /* File name to be calculated */ +) +{ + WCHAR chr; + WORD sum = 0; + + + while ((chr = *name++) != 0) { + chr = ff_wtoupper(chr); /* File name needs to be ignored case */ + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF); + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8); + } + return sum; +} + + +/*------------------------------------------------------*/ +/* exFAT: Get object information from a directory block */ +/*------------------------------------------------------*/ +static +void get_xdir_info ( + BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ + FILINFO* fno /* Buffer to store the extracted file information */ +) +{ + UINT di, si, nc; + WCHAR w; + + /* Get file name */ +#if _LFN_UNICODE + if (dirb[XDIR_NumName] <= _MAX_LFN) { + for (si = SZDIRE * 2, di = 0; di < dirb[XDIR_NumName]; si += 2, di++) { + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + w = ld_word(dirb + si); /* Get a character */ + fno->fname[di] = w; /* Store it */ + } + } else { + di = 0; /* Buffer overflow and inaccessible object */ + } +#else + for (si = SZDIRE * 2, di = nc = 0; nc < dirb[XDIR_NumName]; si += 2, nc++) { + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + w = ld_word(dirb + si); /* Get a character */ + w = ff_convert(w, 0); /* Unicode -> OEM */ + if (w == 0) { di = 0; break; } /* Could not be converted and inaccessible object */ + if (_DF1S && w >= 0x100) { /* Put 1st byte if it is a DBC (always false at SBCS cfg) */ + fno->fname[di++] = (char)(w >> 8); + } + if (di >= _MAX_LFN) { di = 0; break; } /* Buffer overflow and inaccessible object */ + fno->fname[di++] = (char)w; + } #endif - res = dir_next(dp, 0); /* Next entry */ - } while (res == FR_OK); + if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object? */ + fno->fname[di] = 0; /* Terminate file name */ + + fno->altname[0] = 0; /* No SFN */ + fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ + fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize); /* Size */ + fno->ftime = ld_word(dirb + XDIR_ModTime + 0); /* Time */ + fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */ +} + + +/*-----------------------------------*/ +/* exFAT: Get a directry entry block */ +/*-----------------------------------*/ +static +FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ + DIR* dp /* Pointer to the reading direcotry object pointing the 85 entry */ +) +{ + FRESULT res; + UINT i, nent; + BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ + + /* Load 85 entry */ + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; + mem_cpy(&dirb[0], dp->dir, SZDIRE); + nent = dirb[XDIR_NumSec] + 1; + + /* Load C0 entry */ + res = dir_next(dp, 0); + if (res != FR_OK) return res; + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; + mem_cpy(dirb + SZDIRE, dp->dir, SZDIRE); + + /* Load C1 entries */ + if (nent < 3 || nent > 19) return FR_NO_FILE; + i = SZDIRE * 2; nent *= SZDIRE; + do { + res = dir_next(dp, 0); + if (res != FR_OK) return res; + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; + mem_cpy(dirb + i, dp->dir, SZDIRE); + i += SZDIRE; + } while (i < nent); + + /* Sanity check */ + if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + + return FR_OK; +} + + +#if !_FS_READONLY || _FS_RPATH != 0 +/*------------------------------------------------*/ +/* exFAT: Load the object's directory entry block */ +/*------------------------------------------------*/ +static +FRESULT load_obj_dir ( + DIR* dp, /* Blank directory object to be used to access containing direcotry */ + const _FDID* obj /* Object with containing directory information */ +) +{ + FRESULT res; + + + /* Open object containing directory */ + dp->obj.fs = obj->fs; + dp->obj.sclust = obj->c_scl; + dp->obj.stat = (BYTE)obj->c_size; + dp->obj.objsize = obj->c_size & 0xFFFFFF00; + dp->blk_ofs = obj->c_ofs; + + res = dir_sdi(dp, dp->blk_ofs); /* Goto the block location */ + if (res == FR_OK) { + res = load_xdir(dp); /* Load the object's entry block */ + } return res; } +#endif +#if !_FS_READONLY +/*-----------------------------------------------*/ +/* exFAT: Store the directory block to the media */ +/*-----------------------------------------------*/ +static +FRESULT store_xdir ( + DIR* dp /* Pointer to the direcotry object */ +) +{ + FRESULT res; + UINT nent; + WORD sum; + BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ + + /* Create set sum */ + sum = xdir_sum(dirb); + st_word(dirb + XDIR_SetSum, sum); + nent = dirb[XDIR_NumSec] + 1; + + res = dir_sdi(dp, dp->blk_ofs); + while (res == FR_OK && (res = move_window(dp->obj.fs, dp->sect)) == FR_OK) { + mem_cpy(dp->dir, dirb, SZDIRE); + dp->obj.fs->wflag = 1; + if (--nent == 0) break; + dirb += SZDIRE; + res = dir_next(dp, 0); + } + return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR; +} + + +/*-------------------------------------------*/ +/* exFAT: Create a new directory enrty block */ +/*-------------------------------------------*/ +static +void create_xdir ( + BYTE* dirb, /* Pointer to the direcotry entry block buffer */ + const WCHAR* lfn /* Pointer to the nul terminated file name */ +) +{ + UINT i; + BYTE nb, nc; + WCHAR chr; + WORD hash; + + + mem_set(dirb, 0, 2 * SZDIRE); /* Initialize 85+C0 entry */ + dirb[XDIR_Type] = 0x85; + dirb[XDIR_Type + SZDIRE] = 0xC0; + hash = xname_sum(lfn); + st_word(dirb + XDIR_NameHash, hash); /* Set name hash */ + + i = SZDIRE * 2; /* C1 offset */ + nc = 0; nb = 1; chr = 1; + do { + dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ + do { /* Fill name field */ + if (chr && (chr = lfn[nc]) != 0) nc++; /* Get a character if exist */ + st_word(dirb + i, chr); i += 2; /* Store it */ + } while (i % SZDIRE); + nb++; + } while (lfn[nc]); /* Fill next entry if any char follows */ + + dirb[XDIR_NumName] = nc; /* Set name length */ + dirb[XDIR_NumSec] = nb; /* Set number of C0+C1s */ +} +#endif +#endif + /*-----------------------------------------------------------------------*/ /* Read an object from the directory */ /*-----------------------------------------------------------------------*/ -#if _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT static FRESULT dir_read ( DIR* dp, /* Pointer to the directory object */ int vol /* Filtered by 0:file/directory or 1:volume label */ ) { - FRESULT res; - BYTE a, c, *dir; -#if _USE_LFN + FRESULT res = FR_NO_FILE; + FATFS *fs = dp->obj.fs; + BYTE a, c; +#if _USE_LFN != 0 BYTE ord = 0xFF, sum = 0xFF; #endif - res = FR_NO_FILE; while (dp->sect) { - res = move_window(dp->fs, dp->sect); + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + c = dp->dir[DIR_Name]; /* Test for the entry type */ + if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of the directory */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (_USE_LABEL && vol) { + if (c == 0x83) break; /* Volume label entry? */ + } else { + if (c == 0x85) { /* Start of the entry block? */ + dp->blk_ofs = dp->dptr; /* Set location of block */ + res = load_xdir(dp); /* Load the entry block */ + if (res == FR_OK) { + dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */ + } + break; + } + } + } else +#endif + { /* At the FAT12/16/32 */ + dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ +#if _USE_LFN != 0 /* LFN configuration */ + if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ + ord = 0xFF; + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (c & LLEF) { /* Is it start of an LFN sequence? */ + sum = dp->dir[LDIR_Chksum]; + c &= ~LLEF; ord = c; + dp->blk_ofs = dp->dptr; + } + /* Check LFN validity and capture it */ + ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(dp->lfn, dp->dir)) ? ord - 1 : 0xFF; + } else { /* An SFN entry is found */ + if (ord || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ + dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ + } + break; + } + } +#else /* Non LFN configuration */ + if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ + break; + } +#endif + } + res = dir_next(dp, 0); /* Next entry */ + if (res != FR_OK) break; + } + + if (res != FR_OK) dp->sect = 0; /* Terminate the read operation on error or EOT */ + return res; +} +#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */ + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Find an object in the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp /* Pointer to the directory object with the file name */ +) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; + BYTE c; +#if _USE_LFN != 0 + BYTE a, ord, sum; +#endif + + res = dir_sdi(dp, 0); /* Rewind directory object */ + if (res != FR_OK) return res; +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + BYTE nc; + UINT di, ni; + WORD hash = xname_sum(dp->lfn); /* Hash value of the name to find */ + + while ((res = dir_read(dp, 0)) == FR_OK) { /* Read an item */ + if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip the comparison if hash value mismatched */ + for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ + if ((di % SZDIRE) == 0) di += 2; + if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(dp->lfn[ni])) break; + } + if (nc == 0 && !dp->lfn[ni]) break; /* Name matched? */ + } + return res; + } +#endif + /* At the FAT12/16/32 */ +#if _USE_LFN != 0 + ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ +#endif + do { + res = move_window(fs, dp->sect); if (res != FR_OK) break; - dir = dp->dir; /* Ptr to the directory entry of current index */ - c = dir[DIR_Name]; + c = dp->dir[DIR_Name]; if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ - a = dir[DIR_Attr] & AM_MASK; -#if _USE_LFN /* LFN configuration */ - if (c == DDEM || (!_FS_RPATH && c == '.') || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ - ord = 0xFF; +#if _USE_LFN != 0 /* LFN configuration */ + dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; + if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ + ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } else { if (a == AM_LFN) { /* An LFN entry is found */ - if (c & LLEF) { /* Is it start of LFN sequence? */ - sum = dir[LDIR_Chksum]; - c &= ~LLEF; ord = c; - dp->lfn_idx = dp->index; + if (dp->lfn) { + if (c & LLEF) { /* Is it start of LFN sequence? */ + sum = dp->dir[LDIR_Chksum]; + c &= ~LLEF; ord = c; /* LFN start order */ + dp->blk_ofs = dp->dptr; /* Start offset of LFN */ + } + /* Check validity of the LFN entry and compare it with given name */ + ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(dp->lfn, dp->dir)) ? ord - 1 : 0xFF; } - /* Check LFN validity and capture it */ - ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF; } else { /* An SFN entry is found */ - if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */ - dp->lfn_idx = 0xFFFF; /* It has no LFN. */ - break; + if (!ord && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ + if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ + ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } } #else /* Non LFN configuration */ - if (c != DDEM && (_FS_RPATH || c != '.') && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) /* Is it a valid entry? */ - break; + dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK; + if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */ #endif - res = dir_next(dp, 0); /* Next entry */ - if (res != FR_OK) break; - } - - if (res != FR_OK) dp->sect = 0; + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK); return res; } -#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */ @@ -1586,25 +2193,53 @@ FRESULT dir_read ( /*-----------------------------------------------------------------------*/ #if !_FS_READONLY static -FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */ +FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ DIR* dp /* Target directory with object name to be created */ ) { FRESULT res; -#if _USE_LFN /* LFN configuration */ - UINT n, nent; + FATFS *fs = dp->obj.fs; +#if _USE_LFN != 0 /* LFN configuration */ + UINT n, nlen, nent; BYTE sn[12], *fn, sum; WCHAR *lfn; fn = dp->fn; lfn = dp->lfn; - mem_cpy(sn, fn, 12); - - if (_FS_RPATH && (sn[NSFLAG] & NS_DOT)) /* Cannot create dot entry */ - return FR_INVALID_NAME; + if (fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ + for (nlen = 0; lfn[nlen]; nlen++) ; /* Get lfn length */ + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + DIR dj; + + nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ + res = dir_alloc(dp, nent); /* Allocate entries */ + if (res != FR_OK) return res; + dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set block position */ + + if (dp->obj.stat & 4) { /* Has the sub-directory been stretched? */ + dp->obj.stat &= 3; + dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase object size by cluster size */ + res = fill_fat_chain(&dp->obj); /* Complement FAT chain if needed */ + if (res != FR_OK) return res; + res = load_obj_dir(&dj, &dp->obj); + if (res != FR_OK) return res; /* Load the object status */ + st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ + st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); + fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; + res = store_xdir(&dj); /* Store the object status */ + if (res != FR_OK) return res; + } + create_xdir(fs->dirbuf, lfn); /* Create on-memory directory block to be written later */ + return FR_OK; + } +#endif + /* At the FAT12/16/32 */ + mem_cpy(sn, fn, 12); if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ - fn[NSFLAG] = 0; dp->lfn = 0; /* Find only SFN */ + fn[NSFLAG] = 0; dp->lfn = 0; /* Find only SFN */ for (n = 1; n < 100; n++) { gen_numname(fn, sn, lfn, n); /* Generate a numbered name */ res = dir_find(dp); /* Check if the name collides with existing SFN */ @@ -1615,40 +2250,38 @@ FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many fn[NSFLAG] = sn[NSFLAG]; dp->lfn = lfn; } - if (sn[NSFLAG] & NS_LFN) { /* When LFN is to be created, allocate entries for an SFN + LFNs. */ - for (n = 0; lfn[n]; n++) ; - nent = (n + 25) / 13; - } else { /* Otherwise allocate an entry for an SFN */ - nent = 1; - } + /* Create an SFN with/without LFNs. */ + nent = (sn[NSFLAG] & NS_LFN) ? (nlen + 12) / 13 + 1 : 1; /* Number of entries to allocate */ res = dir_alloc(dp, nent); /* Allocate entries */ - if (res == FR_OK && --nent) { /* Set LFN entry if needed */ - res = dir_sdi(dp, dp->index - nent); + res = dir_sdi(dp, dp->dptr - nent * SZDIRE); if (res == FR_OK) { - sum = sum_sfn(dp->fn); /* Sum value of the SFN tied to the LFN */ + sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ do { /* Store LFN entries in bottom first */ - res = move_window(dp->fs, dp->sect); + res = move_window(fs, dp->sect); if (res != FR_OK) break; - fit_lfn(dp->lfn, dp->dir, (BYTE)nent, sum); - dp->fs->wflag = 1; + put_lfn(dp->lfn, dp->dir, (BYTE)nent, sum); + fs->wflag = 1; res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK && --nent); } } + #else /* Non LFN configuration */ res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ + #endif - if (res == FR_OK) { /* Set SFN entry */ - res = move_window(dp->fs, dp->sect); + /* Set SFN entry */ + if (res == FR_OK) { + res = move_window(fs, dp->sect); if (res == FR_OK) { - mem_set(dp->dir, 0, SZ_DIRE); /* Clean the entry */ - mem_cpy(dp->dir, dp->fn, 11); /* Put SFN */ -#if _USE_LFN + mem_set(dp->dir, 0, SZDIRE); /* Clean the entry */ + mem_cpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ +#if _USE_LFN != 0 dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ #endif - dp->fs->wflag = 1; + fs->wflag = 1; } } @@ -1664,38 +2297,38 @@ FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many /*-----------------------------------------------------------------------*/ #if !_FS_READONLY && !_FS_MINIMIZE static -FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */ +FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ DIR* dp /* Directory object pointing the entry to be removed */ ) { FRESULT res; -#if _USE_LFN /* LFN configuration */ - UINT i; + FATFS *fs = dp->obj.fs; +#if _USE_LFN != 0 /* LFN configuration */ + DWORD last = dp->dptr; - i = dp->index; /* SFN index */ - res = dir_sdi(dp, (dp->lfn_idx == 0xFFFF) ? i : dp->lfn_idx); /* Goto the SFN or top of the LFN entries */ + res = dp->blk_ofs == 0xFFFFFFFF ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ if (res == FR_OK) { do { - res = move_window(dp->fs, dp->sect); + res = move_window(fs, dp->sect); if (res != FR_OK) break; - mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */ - *dp->dir = DDEM; - dp->fs->wflag = 1; - if (dp->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */ - res = dir_next(dp, 0); /* Next entry */ + /* Mark an entry 'deleted' */ + if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* At the exFAT */ + dp->dir[XDIR_Type] &= 0x7F; + } else { /* At the FAT12/16/32 */ + dp->dir[DIR_Name] = DDEM; + } + fs->wflag = 1; + if (dp->dptr >= last) break; /* If reached last entry then all entries of the object has been deleted. */ + res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK); if (res == FR_NO_FILE) res = FR_INT_ERR; } - #else /* Non LFN configuration */ - res = dir_sdi(dp, dp->index); + + res = move_window(fs, dp->sect); if (res == FR_OK) { - res = move_window(dp->fs, dp->sect); - if (res == FR_OK) { - mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */ - *dp->dir = DDEM; - dp->fs->wflag = 1; - } + dp->dir[DIR_Name] = DDEM; + fs->wflag = 1; } #endif @@ -1716,60 +2349,90 @@ void get_fileinfo ( /* No return code */ FILINFO* fno /* Pointer to the file information to be filled */ ) { - UINT i; - TCHAR *p, c; - BYTE *dir; -#if _USE_LFN + UINT i, j; + TCHAR c; +#if _USE_LFN != 0 WCHAR w, *lfn; + WCHAR lfv; #endif - p = fno->fname; - if (dp->sect) { /* Get SFN */ - dir = dp->dir; - i = 0; - while (i < 11) { /* Copy name body and extension */ - c = (TCHAR)dir[i++]; - if (c == ' ') continue; /* Skip padding spaces */ - if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ - if (i == 9) *p++ = '.'; /* Insert a . if extension is exist */ -#if _USE_LFN - if (IsUpper(c) && (dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) - c += 0x20; /* To lower */ -#if _LFN_UNICODE - if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dir[i])) - c = c << 8 | dir[i++]; - c = ff_convert(c, 1); /* OEM -> Unicode */ - if (!c) c = '?'; + + fno->fname[0] = 0; /* Invaidate file info */ + if (!dp->sect) return; /* Exit if read pointer has reached end of directory */ + +#if _USE_LFN != 0 /* LFN configuration */ +#if _FS_EXFAT + if (dp->obj.fs->fs_type == FS_EXFAT) { /* At the exFAT */ + get_xdir_info(dp->obj.fs->dirbuf, fno); + return; + } else #endif + { /* At the FAT12/16/32 */ + if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ + i = 0; lfn = dp->lfn; + while ((w = *lfn++) != 0) { /* Get an LFN character */ +#if !_LFN_UNICODE + w = ff_convert(w, 0); /* Unicode -> OEM */ + if (w == 0) { i = 0; break; } /* No LFN if it could not be converted */ + if (_DF1S && w >= 0x100) { /* Put 1st byte if it is a DBC (always false at SBCS cfg) */ + fno->fname[i++] = (char)(w >> 8); + } #endif - *p++ = c; + if (i >= _MAX_LFN) { i = 0; break; } /* No LFN if buffer overflow */ + fno->fname[i++] = (char)w; + } + fno->fname[i] = 0; /* Terminate the LFN */ } - fno->fattrib = dir[DIR_Attr]; /* Attribute */ - fno->fsize = LD_DWORD(dir + DIR_FileSize); /* Size */ - fno->fdate = LD_WORD(dir + DIR_WrtDate); /* Date */ - fno->ftime = LD_WORD(dir + DIR_WrtTime); /* Time */ } - *p = 0; /* Terminate SFN string by a \0 */ -#if _USE_LFN - if (fno->lfname) { - i = 0; p = fno->lfname; - if (dp->sect && fno->lfsize && dp->lfn_idx != 0xFFFF) { /* Get LFN if available */ - lfn = dp->lfn; - while ((w = *lfn++) != 0) { /* Get an LFN character */ -#if !_LFN_UNICODE - w = ff_convert(w, 0); /* Unicode -> OEM */ - if (!w) { i = 0; break; } /* No LFN if it could not be converted */ - if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */ - p[i++] = (TCHAR)(w >> 8); + i = j = 0; + lfv = fno->fname[i]; /* LFN is exist if non-zero */ + while (i < 11) { /* Copy name body and extension */ + c = (TCHAR)dp->dir[i++]; + if (c == ' ') continue; /* Skip padding spaces */ + if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ + if (i == 9) { /* Insert a . if extension is exist */ + if (!lfv) fno->fname[j] = '.'; + fno->altname[j++] = '.'; + } +#if _LFN_UNICODE + if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dp->dir[i])) { + c = c << 8 | dp->dir[i++]; + } + c = ff_convert(c, 1); /* OEM -> Unicode */ + if (!c) c = '?'; #endif - if (i >= fno->lfsize - 1) { i = 0; break; } /* No LFN if buffer overflow */ - p[i++] = (TCHAR)w; + fno->altname[j] = c; + if (!lfv) { + if (IsUpper(c) && (dp->dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) { + c += 0x20; /* To lower */ } + fno->fname[j] = c; } - p[i] = 0; /* Terminate LFN string by a \0 */ + j++; } + if (!lfv) { + fno->fname[j] = 0; + if (!dp->dir[DIR_NTres]) j = 0; /* Altname is no longer needed if neither LFN nor case info is exist. */ + } + fno->altname[j] = 0; /* Terminate the SFN */ + +#else /* Non-LFN configuration */ + i = j = 0; + while (i < 11) { /* Copy name body and extension */ + c = (TCHAR)dp->dir[i++]; + if (c == ' ') continue; /* Skip padding spaces */ + if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ + if (i == 9) fno->fname[j++] = '.'; /* Insert a . if extension is exist */ + fno->fname[j++] = c; + } + fno->fname[j] = 0; #endif + + fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ + fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ + fno->fdate = ld_word(dp->dir + DIR_WrtDate); /* Date */ + fno->ftime = ld_word(dp->dir + DIR_WrtTime); /* Time */ } #endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ @@ -1785,25 +2448,27 @@ WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */ const TCHAR** ptr /* Pointer to pointer to the SBCS/DBCS/Unicode string */ ) { +#if !_LFN_UNICODE WCHAR chr; -#if !_LFN_UNICODE chr = (BYTE)*(*ptr)++; /* Get a byte */ if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ - if (IsDBCS1(chr) && IsDBCS2(**ptr)) /* Get DBC 2nd byte if needed */ - chr = chr << 8 | (BYTE)*(*ptr)++; #ifdef _EXCVT if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ -#endif #else - chr = ff_wtoupper(*(*ptr)++); /* Get a word and to upper */ + if (IsDBCS1(chr) && IsDBCS2(**ptr)) { /* Get DBC 2nd byte if needed */ + chr = chr << 8 | (BYTE)*(*ptr)++; + } #endif return chr; +#else + return ff_wtoupper(*(*ptr)++); /* Get a word and to upper */ +#endif } static -int pattern_matching ( /* Return value: 0:mismatched, 1:matched */ +int pattern_matching ( /* 0:not matched, 1:matched */ const TCHAR* pat, /* Matching pattern */ const TCHAR* nam, /* String to be tested */ int skip, /* Number of pre-skip chars (number of ?s) */ @@ -1828,13 +2493,13 @@ int pattern_matching ( /* Return value: 0:mismatched, 1:matched */ do { /* Analyze the wildcard chars */ if (*pp++ == '?') nm++; else nx = 1; } while (*pp == '?' || *pp == '*'); - if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ + if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recursions upto number of wildcard blocks in the pattern) */ nc = *np; break; /* Branch mismatched */ } pc = get_achar(&pp); /* Get a pattern char */ nc = get_achar(&np); /* Get a name char */ if (pc != nc) break; /* Branch mismatched? */ - if (!pc) return 1; /* Branch matched? (matched at end of both strings) */ + if (pc == 0) return 1; /* Branch matched? (matched at end of both strings) */ } get_achar(&nam); /* nam++ */ } while (inf && nc); /* Retry until end of name if infinite search is specified */ @@ -1847,65 +2512,62 @@ int pattern_matching ( /* Return value: 0:mismatched, 1:matched */ /*-----------------------------------------------------------------------*/ -/* Pick a segment and create the object name in directory form */ +/* Pick a top segment and create the object name in directory form */ /*-----------------------------------------------------------------------*/ static -FRESULT create_name ( +FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ DIR* dp, /* Pointer to the directory object */ const TCHAR** path /* Pointer to pointer to the segment in the path string */ ) { -#if _USE_LFN /* LFN configuration */ +#if _USE_LFN != 0 /* LFN configuration */ BYTE b, cf; WCHAR w, *lfn; UINT i, ni, si, di; const TCHAR *p; /* Create LFN in Unicode */ - for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ - lfn = dp->lfn; - si = di = 0; + p = *path; lfn = dp->lfn; si = di = 0; for (;;) { w = p[si++]; /* Get a character */ - if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */ - if (di >= _MAX_LFN) /* Reject too long name */ - return FR_INVALID_NAME; + if (w < ' ' || w == '/' || w == '\\') { /* Break on end of segment */ + while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator */ + break; + } + if (di >= _MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ #if !_LFN_UNICODE w &= 0xFF; if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ b = (BYTE)p[si++]; /* Get 2nd byte */ w = (w << 8) + b; /* Create a DBC */ - if (!IsDBCS2(b)) - return FR_INVALID_NAME; /* Reject invalid sequence */ + if (!IsDBCS2(b)) return FR_INVALID_NAME; /* Reject invalid sequence */ } w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */ if (!w) return FR_INVALID_NAME; /* Reject invalid code */ #endif - if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal characters for LFN */ - return FR_INVALID_NAME; + if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ lfn[di++] = w; /* Store the Unicode character */ } *path = &p[si]; /* Return pointer to the next segment */ cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ -#if _FS_RPATH - if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */ - (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { +#if _FS_RPATH != 0 + if ((di == 1 && lfn[di - 1] == '.') || + (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ lfn[di] = 0; - for (i = 0; i < 11; i++) + for (i = 0; i < 11; i++) /* Create dot name for SFN entry */ dp->fn[i] = (i < di) ? '.' : ' '; dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ return FR_OK; } #endif - while (di) { /* Strip trailing spaces and dots */ + while (di) { /* Snip off trailing spaces and dots if exist */ w = lfn[di - 1]; if (w != ' ' && w != '.') break; di--; } - if (!di) return FR_INVALID_NAME; /* Reject nul string */ - lfn[di] = 0; /* LFN is created */ + if (di == 0) return FR_INVALID_NAME; /* Reject nul name */ /* Create SFN in directory form */ mem_set(dp->fn, ' ', 11); @@ -1941,7 +2603,7 @@ FRESULT create_name ( cf |= NS_LFN; /* Force create LFN entry */ } - if (_DF1S && w >= 0x100) { /* DBC (always false at SBCS cfg) */ + if (_DF1S && w >= 0x100) { /* Is this DBC? (always false at SBCS cfg) */ if (i >= ni - 1) { cf |= NS_LOSS | NS_LFN; i = ni; continue; } @@ -1962,11 +2624,10 @@ FRESULT create_name ( dp->fn[i++] = (BYTE)w; } - if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with deleted mark, replace it with RDDEM */ + if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ if (ni == 8) b <<= 2; - if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */ - cf |= NS_LFN; + if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* Create LFN entry when there are composite capitals */ if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */ if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */ @@ -1983,11 +2644,10 @@ FRESULT create_name ( const char *p; /* Create file name in directory form */ - for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ - sfn = dp->fn; + p = *path; sfn = dp->fn; mem_set(sfn, ' ', 11); si = i = b = 0; ni = 8; -#if _FS_RPATH +#if _FS_RPATH != 0 if (p[si] == '.') { /* Is this a dot entry? */ for (;;) { c = (BYTE)p[si++]; @@ -2002,7 +2662,10 @@ FRESULT create_name ( #endif for (;;) { c = (BYTE)p[si++]; - if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */ + if (c <= ' ' || c == '/' || c == '\\') { /* Break on end of segment */ + while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator */ + break; + } if (c == '.' || i >= ni) { if (ni != 8 || c != '.') return FR_INVALID_NAME; i = 8; ni = 11; @@ -2018,15 +2681,13 @@ FRESULT create_name ( #endif #endif } - if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ + if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false at SBCS cfg.) */ d = (BYTE)p[si++]; /* Get 2nd byte */ - if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */ - return FR_INVALID_NAME; + if (!IsDBCS2(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ sfn[i++] = c; sfn[i++] = d; } else { /* SBC */ - if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */ - return FR_INVALID_NAME; + if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */ if (IsUpper(c)) { /* ASCII large capital? */ b |= 2; } else { @@ -2040,7 +2701,7 @@ FRESULT create_name ( *path = &p[si]; /* Return pointer to the next segment */ c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ - if (!i) return FR_INVALID_NAME; /* Reject nul string */ + if (i == 0) return FR_INVALID_NAME; /* Reject nul string */ if (sfn[0] == DDEM) sfn[0] = RDDEM; /* When first character collides with DDEM, replace it with RDDEM */ if (ni == 8) b <<= 2; @@ -2067,36 +2728,50 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ ) { FRESULT res; - BYTE *dir, ns; + BYTE ns; + _FDID *obj = &dp->obj; + FATFS *fs = obj->fs; -#if _FS_RPATH - if (*path == '/' || *path == '\\') { /* There is a heading separator */ - path++; dp->sclust = 0; /* Strip it and start from the root directory */ - } else { /* No heading separator */ - dp->sclust = dp->fs->cdir; /* Start from the current directory */ +#if _FS_RPATH != 0 + if (*path != '/' && *path != '\\') { /* Without heading separator */ + obj->sclust = fs->cdir; /* Start from the current directory */ + } else +#endif + { /* With heading separator */ + while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ + obj->sclust = 0; /* Start from the root directory */ + } +#if _FS_EXFAT && _FS_RPATH != 0 + if (fs->fs_type == FS_EXFAT && obj->sclust) { /* Retrieve the sub-directory status if needed */ + DIR dj; + + obj->c_scl = fs->cdc_scl; + obj->c_size = fs->cdc_size; + obj->c_ofs = fs->cdc_ofs; + res = load_obj_dir(&dj, obj); + if (res != FR_OK) return res; + obj->objsize = ld_dword(fs->dirbuf + XDIR_FileSize); + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; } -#else - if (*path == '/' || *path == '\\') /* Strip heading separator if exist */ - path++; - dp->sclust = 0; /* Always start from the root directory */ #endif if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ + dp->fn[NSFLAG] = NS_NONAME; res = dir_sdi(dp, 0); - dp->dir = 0; + } else { /* Follow path */ for (;;) { res = create_name(dp, &path); /* Get a segment name of the path */ if (res != FR_OK) break; - res = dir_find(dp); /* Find an object with the sagment name */ + res = dir_find(dp); /* Find an object with the segment name */ ns = dp->fn[NSFLAG]; if (res != FR_OK) { /* Failed to find the object */ if (res == FR_NO_FILE) { /* Object is not found */ - if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, */ - dp->sclust = 0; dp->dir = 0; /* it is the root directory and stay there */ + if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ - res = FR_OK; /* Ended at the root directroy. Function completed. */ + dp->fn[NSFLAG] = NS_NONAME; + res = FR_OK; } else { /* Could not find the object */ if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ } @@ -2104,11 +2779,23 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ break; } if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ - dir = dp->dir; /* Follow the sub-directory */ - if (!(dir[DIR_Attr] & AM_DIR)) { /* It is not a sub-directory and cannot follow */ + /* Get into the sub-directory */ + if (!(obj->attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ res = FR_NO_PATH; break; } - dp->sclust = ld_clust(dp->fs, dir); +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + obj->c_scl = obj->sclust; /* Save containing directory information for next dir */ + obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; + obj->c_ofs = dp->blk_ofs; + obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Open next directory */ + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; + obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + } else +#endif + { + obj->sclust = ld_clust(fs, &fs->win[dp->dptr % SS(fs)]); /* Open next directory */ + } } } @@ -2167,7 +2854,7 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ #endif return vol; } -#if _FS_RPATH && _VOLUMES >= 2 +#if _FS_RPATH != 0 && _VOLUMES >= 2 vol = CurrVol; /* Current drive */ #else vol = 0; /* Drive 0 */ @@ -2184,24 +2871,22 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ /*-----------------------------------------------------------------------*/ static -BYTE check_fs ( /* 0:FAT boor sector, 1:Valid boor sector but not FAT, 2:Not a boot sector, 3:Disk error */ +BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ FATFS* fs, /* File system object */ DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */ ) { - fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ - if (move_window(fs, sect) != FR_OK) /* Load boot record */ - return 3; - - if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */ - return 2; + fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ + if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */ - if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */ - return 0; - if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */ - return 0; + if (ld_word(&fs->win[BS_55AA]) != 0xAA55) return 3; /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */ - return 1; + if ((ld_dword(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */ + if ((ld_dword(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */ +#if _FS_EXFAT + if (!mem_cmp(&fs->win[BS_OEMName], "EXFAT ", 8)) return 1; +#endif + return 2; } @@ -2213,9 +2898,9 @@ BYTE check_fs ( /* 0:FAT boor sector, 1:Valid boor sector but not FAT, 2:Not a b static FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ - FATFS** rfs, /* Pointer to pointer to the found file system object */ const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ - BYTE wmode /* !=0: Check write protection for write access */ + FATFS** rfs, /* Pointer to pointer to the found file system object */ + BYTE mode /* !=0: Check write protection for write access */ ) { BYTE fmt, *pt; @@ -2239,11 +2924,13 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ ENTER_FF(fs); /* Lock the volume */ *rfs = fs; /* Return pointer to the file system object */ + mode &= ~FA_READ; /* Desired access mode, write access or not */ if (fs->fs_type) { /* If the volume has been mounted */ stat = disk_status(fs->drv); if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ - if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check write protection if needed */ + if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ return FR_WRITE_PROTECTED; + } return FR_OK; /* The file system object is valid */ } } @@ -2254,122 +2941,171 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ fs->fs_type = 0; /* Clear the file system object */ fs->drv = LD2PD(vol); /* Bind the logical drive and a physical drive */ stat = disk_initialize(fs->drv); /* Initialize the physical drive */ - if (stat & STA_NOINIT) /* Check if the initialization succeeded */ + if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ - if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check disk write protection if needed */ + } + if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ return FR_WRITE_PROTECTED; + } #if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) < _MIN_SS || SS(fs) > _MAX_SS) return FR_DISK_ERR; #endif /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */ bsect = 0; - fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT boot sector as SFD */ - if (fmt == 1 || (!fmt && (LD2PT(vol)))) { /* Not an FAT boot sector or forced partition number */ + fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT boot sector as SFD */ + if (fmt == 2 || (fmt < 2 && LD2PT(vol))) { /* Not an FAT boot sector or forced partition number */ for (i = 0; i < 4; i++) { /* Get partition offset */ pt = fs->win + MBR_Table + i * SZ_PTE; - br[i] = pt[4] ? LD_DWORD(&pt[8]) : 0; + br[i] = pt[4] ? ld_dword(&pt[8]) : 0; } i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ if (i) i--; do { /* Find an FAT volume */ bsect = br[i]; - fmt = bsect ? check_fs(fs, bsect) : 2; /* Check the partition */ - } while (!LD2PT(vol) && fmt && ++i < 4); + fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ + } while (!LD2PT(vol) && fmt >= 2 && ++i < 4); } - if (fmt == 3) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ - if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */ + if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ + if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ /* An FAT volume is found. Following code initializes the file system object */ - if (LD_WORD(fs->win + BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */ - return FR_NO_FILESYSTEM; +#if _FS_EXFAT + if (fmt == 1) { + QWORD maxlba; - fasize = LD_WORD(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ - if (!fasize) fasize = LD_DWORD(fs->win + BPB_FATSz32); - fs->fsize = fasize; + for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && !fs->win[i]; i++) ; /* Check zero filler */ + if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; - fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */ - if (fs->n_fats != 1 && fs->n_fats != 2) /* (Must be 1 or 2) */ - return FR_NO_FILESYSTEM; - fasize *= fs->n_fats; /* Number of sectors for FAT area */ + if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT revision (Must be 1.0) */ - fs->csize = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ - if (!fs->csize || (fs->csize & (fs->csize - 1))) /* (Must be power of 2) */ - return FR_NO_FILESYSTEM; + if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ + return FR_NO_FILESYSTEM; - fs->n_rootdir = LD_WORD(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ - if (fs->n_rootdir % (SS(fs) / SZ_DIRE)) /* (Must be sector aligned) */ - return FR_NO_FILESYSTEM; + maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Number of sectors on the volume */ + if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ - tsect = LD_WORD(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ - if (!tsect) tsect = LD_DWORD(fs->win + BPB_TotSec32); + fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ - nrsv = LD_WORD(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ - if (!nrsv) return FR_NO_FILESYSTEM; /* (Must not be 0) */ + fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ + if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Must be 1) */ - /* Determine the FAT sub type */ - sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIRE); /* RSV + FAT + DIR */ - if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ - if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - fmt = FS_FAT12; - if (nclst >= MIN_FAT16) fmt = FS_FAT16; - if (nclst >= MIN_FAT32) fmt = FS_FAT32; - - /* Boundaries and Limits */ - fs->n_fatent = nclst + 2; /* Number of FAT entries */ - fs->volbase = bsect; /* Volume start sector */ - fs->fatbase = bsect + nrsv; /* FAT start sector */ - fs->database = bsect + sysect; /* Data start sector */ - if (fmt == FS_FAT32) { - if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ - fs->dirbase = LD_DWORD(fs->win + BPB_RootClus); /* Root directory start cluster */ - szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ - } else { - if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ - fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ - szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ - fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); - } - if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (BPB_FATSz must not be less than the size needed) */ - return FR_NO_FILESYSTEM; + fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ + if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */ + + nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ + fs->n_fatent = nclst + 2; + if (fs->n_fatent >= 0x80000000) return FR_NO_FILESYSTEM; /* (Must be <= 0x7FFFFFFF) */ + + /* Boundaries and Limits */ + fs->volbase = bsect; + fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); + fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); + if (maxlba < fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ + fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); + /* Check if bitmap location is in assumption (at the first cluster) */ + if (move_window(fs, clust2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR; + for (i = 0; i < SS(fs); i += SZDIRE) { + if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */ + } + if (i == SS(fs)) return FR_NO_FILESYSTEM; #if !_FS_READONLY - /* Initialize cluster allocation information */ - fs->last_clust = fs->free_clust = 0xFFFFFFFF; + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ +#endif +#if _USE_LFN == 1 + fs->dirbuf = DirBuf; /* Static directory block working buuffer */ +#endif + fmt = FS_EXFAT; /* FAT sub-type */ + } else +#endif + { + if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ + + fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ + if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); + fs->fsize = fasize; + + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ + if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ + fasize *= fs->n_fats; /* Number of sectors for FAT area */ + + fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ + if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ + + fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ + if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ + + tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ + if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); + + nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ + if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ + + /* Determine the FAT sub type */ + sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ + if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ + if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + fmt = FS_FAT12; + if (nclst >= MIN_FAT16) fmt = FS_FAT16; + if (nclst >= MIN_FAT32) fmt = FS_FAT32; + + /* Boundaries and Limits */ + fs->n_fatent = nclst + 2; /* Number of FAT entries */ + fs->volbase = bsect; /* Volume start sector */ + fs->fatbase = bsect + nrsv; /* FAT start sector */ + fs->database = bsect + sysect; /* Data start sector */ + if (fmt == FS_FAT32) { + if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ + if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ + fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ + szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ + } else { + if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM;/* (BPB_RootEntCnt must not be 0) */ + fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ + szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ + fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); + } + if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ - /* Get fsinfo if available */ - fs->fsi_flag = 0x80; +#if !_FS_READONLY + /* Initialize cluster allocation information */ + fs->last_clst = fs->free_clst = 0xFFFFFFFF; + + /* Get FSINFO if available */ + fs->fsi_flag = 0x80; #if (_FS_NOFSINFO & 3) != 3 - if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo is 1 */ - && LD_WORD(fs->win + BPB_FSInfo) == 1 - && move_window(fs, bsect + 1) == FR_OK) - { - fs->fsi_flag = 0; - if (LD_WORD(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */ - && LD_DWORD(fs->win + FSI_LeadSig) == 0x41615252 - && LD_DWORD(fs->win + FSI_StrucSig) == 0x61417272) + if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo32 == 1 */ + && ld_word(fs->win + BPB_FSInfo32) == 1 + && move_window(fs, bsect + 1) == FR_OK) { + fs->fsi_flag = 0; + if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */ + && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 + && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) + { #if (_FS_NOFSINFO & 1) == 0 - fs->free_clust = LD_DWORD(fs->win + FSI_Free_Count); + fs->free_clst = ld_dword(fs->win + FSI_Free_Count); #endif #if (_FS_NOFSINFO & 2) == 0 - fs->last_clust = LD_DWORD(fs->win + FSI_Nxt_Free); + fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); #endif + } } - } #endif #endif + } + fs->fs_type = fmt; /* FAT sub-type */ fs->id = ++Fsid; /* File system mount ID */ -#if _FS_RPATH - fs->cdir = 0; /* Set current directory to root */ +#if _FS_RPATH != 0 + fs->cdir = 0; /* Initialize current directory */ #endif -#if _FS_LOCK /* Clear file lock semaphores */ +#if _FS_LOCK != 0 /* Clear file lock semaphores */ clear_lock(fs); #endif - return FR_OK; } @@ -2381,32 +3117,34 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ /*-----------------------------------------------------------------------*/ static -FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */ - void* obj /* Pointer to the object FIL/DIR to check validity */ +FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ + void* dfp, /* Pointer to the FIL/DIR object to check validity */ + FATFS** fs /* Pointer to pointer to the owner file system object to return */ ) { - FIL *fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/DIR structure is identical */ - - - if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id) - return FR_INVALID_OBJECT; - - ENTER_FF(fil->fs); /* Lock file system */ + _FDID *obj = (_FDID*)dfp; /* Assuming .obj in the FIL/DIR is the first member */ + FRESULT res; - if (disk_status(fil->fs->drv) & STA_NOINIT) - return FR_NOT_READY; - return FR_OK; + if (!dfp || !obj->fs || !obj->fs->fs_type || obj->fs->id != obj->id || (disk_status(obj->fs->drv) & STA_NOINIT)) { + *fs = 0; /* The object is invalid */ + res = FR_INVALID_OBJECT; + } else { + *fs = obj->fs; /* Owner file sytem object */ + ENTER_FF(obj->fs); /* Lock file system */ + res = FR_OK; + } + return res; } -/*-------------------------------------------------------------------------- +/*--------------------------------------------------------------------------- - Public Functions + Public Functions (FatFs API) ---------------------------------------------------------------------------*/ +----------------------------------------------------------------------------*/ @@ -2417,7 +3155,7 @@ FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */ FRESULT f_mount ( FATFS* fs, /* Pointer to the file system object (NULL:unmount)*/ const TCHAR* path, /* Logical drive number to be mounted/unmounted */ - BYTE opt /* 0:Do not mount (delayed mount), 1:Mount immediately */ + BYTE opt /* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */ ) { FATFS *cfs; @@ -2431,7 +3169,7 @@ FRESULT f_mount ( cfs = FatFs[vol]; /* Pointer to fs object */ if (cfs) { -#if _FS_LOCK +#if _FS_LOCK != 0 clear_lock(cfs); #endif #if _FS_REENTRANT /* Discard sync object of the current volume */ @@ -2450,7 +3188,7 @@ FRESULT f_mount ( if (!fs || opt != 1) return FR_OK; /* Do not mount now, it will be mounted later */ - res = find_volume(&fs, &path, 0); /* Force mounted the volume */ + res = find_volume(&path, &fs, 0); /* Force mounted the volume */ LEAVE_FF(fs, res); } @@ -2469,125 +3207,162 @@ FRESULT f_open ( { FRESULT res; DIR dj; - BYTE *dir; - DEFINE_NAMEBUF; + FATFS *fs; #if !_FS_READONLY DWORD dw, cl; #endif + DEF_NAMBUF; if (!fp) return FR_INVALID_OBJECT; - fp->fs = 0; /* Clear file object */ + fp->obj.fs = 0; /* Clear file object */ /* Get logical drive number */ -#if !_FS_READONLY - mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW; - res = find_volume(&dj.fs, &path, (BYTE)(mode & ~FA_READ)); -#else - mode &= FA_READ; - res = find_volume(&dj.fs, &path, 0); -#endif + mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW; + res = find_volume(&path, &fs, mode); if (res == FR_OK) { - INIT_BUF(dj); + dj.obj.fs = fs; + INIT_NAMBUF(dj); res = follow_path(&dj, path); /* Follow the file path */ - dir = dj.dir; #if !_FS_READONLY /* R/W configuration */ if (res == FR_OK) { - if (!dir) /* Default directory itself */ + if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ res = FR_INVALID_NAME; -#if _FS_LOCK - else + } +#if _FS_LOCK != 0 + else { res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); + } #endif } /* Create or Open a file */ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { if (res != FR_OK) { /* No file, create new */ if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ -#if _FS_LOCK +#if _FS_LOCK != 0 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else res = dir_register(&dj); #endif mode |= FA_CREATE_ALWAYS; /* File is created */ - dir = dj.dir; /* New entry */ } else { /* Any object is already existing */ - if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ + if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ res = FR_DENIED; } else { - if (mode & FA_CREATE_NEW) /* Cannot create as new file */ - res = FR_EXIST; + if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ } } if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ - dw = GET_FATTIME(); /* Created time */ - ST_DWORD(dir + DIR_CrtTime, dw); - dir[DIR_Attr] = 0; /* Reset attribute */ - ST_DWORD(dir + DIR_FileSize, 0);/* size = 0 */ - cl = ld_clust(dj.fs, dir); /* Get start cluster */ - st_clust(dir, 0); /* cluster = 0 */ - dj.fs->wflag = 1; - if (cl) { /* Remove the cluster chain if exist */ - dw = dj.fs->winsect; - res = remove_chain(dj.fs, cl); - if (res == FR_OK) { - dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */ - res = move_window(dj.fs, dw); + dw = GET_FATTIME(); +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + /* Get current allocation info */ + fp->obj.fs = fs; + fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); + fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + /* Initialize directory entry block */ + st_dword(fs->dirbuf + XDIR_CrtTime, dw); /* Set created time */ + fs->dirbuf[XDIR_CrtTime10] = 0; + st_dword(fs->dirbuf + XDIR_ModTime, dw); /* Set modified time */ + fs->dirbuf[XDIR_ModTime10] = 0; + fs->dirbuf[XDIR_Attr] = AM_ARC; /* Reset attribute */ + st_dword(fs->dirbuf + XDIR_FstClus, 0); /* Reset file allocation info */ + st_qword(fs->dirbuf + XDIR_FileSize, 0); + st_qword(fs->dirbuf + XDIR_ValidFileSize, 0); + fs->dirbuf[XDIR_GenFlags] = 1; + res = store_xdir(&dj); + if (res == FR_OK && fp->obj.sclust) { /* Remove the cluster chain if exist */ + res = remove_chain(&fp->obj, fp->obj.sclust, 0); + fs->last_clst = fp->obj.sclust - 1; /* Reuse the cluster hole */ + } + } else +#endif + { + /* Clean directory info */ + st_dword(dj.dir + DIR_CrtTime, dw); /* Set created time */ + st_dword(dj.dir + DIR_WrtTime, dw); /* Set modified time */ + dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ + cl = ld_clust(fs, dj.dir); /* Get cluster chain */ + st_clust(fs, dj.dir, 0); /* Reset file allocation info */ + st_dword(dj.dir + DIR_FileSize, 0); + fs->wflag = 1; + + if (cl) { /* Remove the cluster chain if exist */ + dw = fs->winsect; + res = remove_chain(&dj.obj, cl, 0); + if (res == FR_OK) { + res = move_window(fs, dw); + fs->last_clst = cl - 1; /* Reuse the cluster hole */ + } } } } } else { /* Open an existing file */ - if (res == FR_OK) { /* Follow succeeded */ - if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */ + if (res == FR_OK) { /* Following succeeded */ + if (dj.obj.attr & AM_DIR) { /* It is a directory */ res = FR_NO_FILE; } else { - if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ + if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* R/O violation */ res = FR_DENIED; + } } } } if (res == FR_OK) { if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ - mode |= FA__WRITTEN; - fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ - fp->dir_ptr = dir; -#if _FS_LOCK - fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); - if (!fp->lockid) res = FR_INT_ERR; + mode |= _FA_MODIFIED; + fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ + fp->dir_ptr = dj.dir; +#if _FS_LOCK != 0 + fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); + if (!fp->obj.lockid) res = FR_INT_ERR; #endif } - -#else /* R/O configuration */ - if (res == FR_OK) { /* Follow succeeded */ - dir = dj.dir; - if (!dir) { /* Current directory itself */ +#else /* R/O configuration */ + if (res == FR_OK) { + if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ res = FR_INVALID_NAME; } else { - if (dir[DIR_Attr] & AM_DIR) /* It is a directory */ + if (dj.obj.attr & AM_DIR) { /* It is a directory */ res = FR_NO_FILE; + } } } #endif - FREE_BUF(); if (res == FR_OK) { - fp->flag = mode; /* File access mode */ - fp->err = 0; /* Clear error flag */ - fp->sclust = ld_clust(dj.fs, dir); /* File start cluster */ - fp->fsize = LD_DWORD(dir + DIR_FileSize); /* File size */ - fp->fptr = 0; /* File pointer */ - fp->dsect = 0; -#if _USE_FASTSEEK - fp->cltbl = 0; /* Normal seek mode */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get allocation info */ + fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + fp->obj.c_scl = dj.obj.sclust; + fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; + fp->obj.c_ofs = dj.blk_ofs; + } else #endif - fp->fs = dj.fs; /* Validate file object */ - fp->id = fp->fs->id; + { + fp->obj.sclust = ld_clust(fs, dj.dir); /* Get allocation info */ + fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); + } +#if _USE_FASTSEEK + fp->cltbl = 0; /* Normal seek mode */ +#endif + fp->err = 0; /* Clear error flag */ + fp->fptr = 0; /* Set file pointer */ + fp->sect = 0; /* Invalidate current data sector */ + fp->flag = mode; /* File access mode */ + fp->obj.fs = fs; /* Validate the file object */ + fp->obj.id = fs->id; } + + FREE_NAMBUF(); } - LEAVE_FF(dj.fs, res); + LEAVE_FF(dj.obj.fs, res); } @@ -2598,96 +3373,103 @@ FRESULT f_open ( /*-----------------------------------------------------------------------*/ FRESULT f_read ( - FIL* fp, /* Pointer to the file object */ - void* buff, /* Pointer to data buffer */ - UINT btr, /* Number of bytes to read */ - UINT* br /* Pointer to number of bytes read */ + FIL* fp, /* Pointer to the file object */ + void* buff, /* Pointer to data buffer */ + UINT btr, /* Number of bytes to read */ + UINT* br /* Pointer to number of bytes read */ ) { FRESULT res; - DWORD clst, sect, remain; - UINT rcnt, cc; - BYTE csect, *rbuff = (BYTE*)buff; + FATFS *fs; + DWORD clst, sect; + FSIZE_t remain; + UINT rcnt, cc, csect; + BYTE *rbuff = (BYTE*)buff; *br = 0; /* Clear read byte counter */ - - res = validate(fp); /* Check validity */ - if (res != FR_OK) LEAVE_FF(fp->fs, res); - if (fp->err) /* Check error */ - LEAVE_FF(fp->fs, (FRESULT)fp->err); - if (!(fp->flag & FA_READ)) /* Check access mode */ - LEAVE_FF(fp->fs, FR_DENIED); - remain = fp->fsize - fp->fptr; + res = validate(fp, &fs); + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + remain = fp->obj.objsize - fp->fptr; if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ for ( ; btr; /* Repeat until all data read */ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { - if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ - csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ - if (!csect) { /* On the cluster boundary? */ + if ((fp->fptr % SS(fs)) == 0) { /* On the sector boundary? */ + csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ + if (csect == 0) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ - clst = fp->sclust; /* Follow from the origin */ + clst = fp->obj.sclust; /* Follow cluster chain from the origin */ } else { /* Middle or end of the file */ #if _USE_FASTSEEK - if (fp->cltbl) + if (fp->cltbl) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ - else + } else #endif - clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */ + { + clst = get_fat(&fp->obj, fp->clust); /* Follow cluster chain on the FAT */ + } } - if (clst < 2) ABORT(fp->fs, FR_INT_ERR); - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + if (clst < 2) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ } - sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ - if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect = clust2sect(fs, fp->clust); /* Get current sector */ + if (!sect) ABORT(fs, FR_INT_ERR); sect += csect; - cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */ + cc = btr / SS(fs); /* When remaining bytes >= sector size, */ if (cc) { /* Read maximum contiguous sectors directly */ - if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ - cc = fp->fs->csize - csect; - if (disk_read(fp->fs->drv, rbuff, sect, cc) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); + if (csect + cc > fs->csize) { /* Clip at cluster boundary */ + cc = fs->csize - csect; + } + if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) { + ABORT(fs, FR_DISK_ERR); + } #if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ #if _FS_TINY - if (fp->fs->wflag && fp->fs->winsect - sect < cc) - mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs)); + if (fs->wflag && fs->winsect - sect < cc) { + mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); + } #else - if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc) - mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs)); + if ((fp->flag & _FA_DIRTY) && fp->sect - sect < cc) { + mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); + } #endif #endif - rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ + rcnt = SS(fs) * cc; /* Number of bytes transferred */ continue; } #if !_FS_TINY - if (fp->dsect != sect) { /* Load data sector if not in cache */ + if (fp->sect != sect) { /* Load data sector if not in cache */ #if !_FS_READONLY - if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; + if (fp->flag & _FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { + ABORT(fs, FR_DISK_ERR); + } + fp->flag &= ~_FA_DIRTY; } #endif - if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */ - ABORT(fp->fs, FR_DISK_ERR); + if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { /* Fill sector cache */ + ABORT(fs, FR_DISK_ERR); + } } #endif - fp->dsect = sect; + fp->sect = sect; } - rcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */ + rcnt = SS(fs) - ((UINT)fp->fptr % SS(fs)); /* Get partial sector data from sector buffer */ if (rcnt > btr) rcnt = btr; #if _FS_TINY - if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */ - ABORT(fp->fs, FR_DISK_ERR); - mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ + if (move_window(fs, fp->sect) != FR_OK) { /* Move sector window */ + ABORT(fs, FR_DISK_ERR); + } + mem_cpy(rbuff, &fs->win[fp->fptr % SS(fs)], rcnt); /* Pick partial sector */ #else - mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ + mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fs)], rcnt); /* Pick partial sector */ #endif } - LEAVE_FF(fp->fs, FR_OK); + LEAVE_FF(fs, FR_OK); } @@ -2700,117 +3482,126 @@ FRESULT f_read ( FRESULT f_write ( FIL* fp, /* Pointer to the file object */ - const void *buff, /* Pointer to the data to be written */ + const void* buff, /* Pointer to the data to be written */ UINT btw, /* Number of bytes to write */ UINT* bw /* Pointer to number of bytes written */ ) { FRESULT res; + FATFS *fs; DWORD clst, sect; - UINT wcnt, cc; + UINT wcnt, cc, csect; const BYTE *wbuff = (const BYTE*)buff; - BYTE csect; *bw = 0; /* Clear write byte counter */ - - res = validate(fp); /* Check validity */ - if (res != FR_OK) LEAVE_FF(fp->fs, res); - if (fp->err) /* Check error */ - LEAVE_FF(fp->fs, (FRESULT)fp->err); - if (!(fp->flag & FA_WRITE)) /* Check access mode */ - LEAVE_FF(fp->fs, FR_DENIED); - if (fp->fptr + btw < fp->fptr) btw = 0; /* File size cannot reach 4GB */ + res = validate(fp, &fs); + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + /* Check fptr wrap-around (file size cannot exceed the limit on each FAT specs) */ + if ((_FS_EXFAT && fs->fs_type == FS_EXFAT && fp->fptr + btw < fp->fptr) + || (DWORD)fp->fptr + btw < (DWORD)fp->fptr) { + btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); + } for ( ; btw; /* Repeat until all data written */ - wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { - if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ - csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ - if (!csect) { /* On the cluster boundary? */ + wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize, *bw += wcnt, btw -= wcnt) { + if ((fp->fptr % SS(fs)) == 0) { /* On the sector boundary? */ + csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ + if (csect == 0) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ - clst = fp->sclust; /* Follow from the origin */ - if (clst == 0) /* When no cluster is allocated, */ - clst = create_chain(fp->fs, 0); /* Create a new cluster chain */ - } else { /* Middle or end of the file */ + clst = fp->obj.sclust; /* Follow from the origin */ + if (clst == 0) { /* If no cluster is allocated, */ + clst = create_chain(&fp->obj, 0); /* create a new cluster chain */ + } + } else { /* On the middle or end of the file */ #if _USE_FASTSEEK - if (fp->cltbl) + if (fp->cltbl) { clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ - else + } else #endif - clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */ + { + clst = create_chain(&fp->obj, fp->clust); /* Follow or stretch cluster chain on the FAT */ + } } if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ - if (clst == 1) ABORT(fp->fs, FR_INT_ERR); - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + if (clst == 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ - if (fp->sclust == 0) fp->sclust = clst; /* Set start cluster if the first write */ + if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */ } #if _FS_TINY - if (fp->fs->winsect == fp->dsect && sync_window(fp->fs)) /* Write-back sector cache */ - ABORT(fp->fs, FR_DISK_ERR); + if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) { /* Write-back sector cache */ + ABORT(fs, FR_DISK_ERR); + } #else - if (fp->flag & FA__DIRTY) { /* Write-back sector cache */ - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; + if (fp->flag & _FA_DIRTY) { /* Write-back sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { + ABORT(fs, FR_DISK_ERR); + } + fp->flag &= ~_FA_DIRTY; } #endif - sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ - if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect = clust2sect(fs, fp->clust); /* Get current sector */ + if (!sect) ABORT(fs, FR_INT_ERR); sect += csect; - cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */ + cc = btw / SS(fs); /* When remaining bytes >= sector size, */ if (cc) { /* Write maximum contiguous sectors directly */ - if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ - cc = fp->fs->csize - csect; - if (disk_write(fp->fs->drv, wbuff, sect, cc) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); + if (csect + cc > fs->csize) { /* Clip at cluster boundary */ + cc = fs->csize - csect; + } + if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) { + ABORT(fs, FR_DISK_ERR); + } #if _FS_MINIMIZE <= 2 #if _FS_TINY - if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ - mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs)); - fp->fs->wflag = 0; + if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); + fs->wflag = 0; } #else - if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ - mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs)); - fp->flag &= ~FA__DIRTY; + if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); + fp->flag &= ~_FA_DIRTY; } #endif #endif - wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ + wcnt = SS(fs) * cc; /* Number of bytes transferred */ continue; } #if _FS_TINY - if (fp->fptr >= fp->fsize) { /* Avoid silly cache filling at growing edge */ - if (sync_window(fp->fs)) ABORT(fp->fs, FR_DISK_ERR); - fp->fs->winsect = sect; + if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling at growing edge */ + if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); + fs->winsect = sect; } #else - if (fp->dsect != sect) { /* Fill sector cache with file data */ - if (fp->fptr < fp->fsize && - disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); + if (fp->sect != sect) { /* Fill sector cache with file data */ + if (fp->fptr < fp->obj.objsize && + disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { + ABORT(fs, FR_DISK_ERR); + } } #endif - fp->dsect = sect; + fp->sect = sect; } - wcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */ + wcnt = SS(fs) - ((UINT)fp->fptr % SS(fs)); /* Put partial sector into file I/O buffer */ if (wcnt > btw) wcnt = btw; #if _FS_TINY - if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */ - ABORT(fp->fs, FR_DISK_ERR); - mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ - fp->fs->wflag = 1; + if (move_window(fs, fp->sect) != FR_OK) { /* Move sector window */ + ABORT(fs, FR_DISK_ERR); + } + mem_cpy(&fs->win[fp->fptr % SS(fs)], wbuff, wcnt); /* Fit partial sector */ + fs->wflag = 1; #else - mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ - fp->flag |= FA__DIRTY; + mem_cpy(&fp->buf[fp->fptr % SS(fs)], wbuff, wcnt); /* Fit partial sector */ + fp->flag |= _FA_DIRTY; #endif } - if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */ - fp->flag |= FA__WRITTEN; /* Set file change flag */ + fp->flag |= _FA_MODIFIED; /* Set file change flag */ - LEAVE_FF(fp->fs, FR_OK); + LEAVE_FF(fs, FR_OK); } @@ -2825,39 +3616,70 @@ FRESULT f_sync ( ) { FRESULT res; + FATFS *fs; DWORD tm; BYTE *dir; + DEF_DIRBUF; - res = validate(fp); /* Check validity of the object */ + res = validate(fp, &fs); /* Check validity of the object */ if (res == FR_OK) { - if (fp->flag & FA__WRITTEN) { /* Has the file been written? */ - /* Write-back dirty buffer */ + if (fp->flag & _FA_MODIFIED) { /* Is there any change to the file? */ #if !_FS_TINY - if (fp->flag & FA__DIRTY) { - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - LEAVE_FF(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; + if (fp->flag & _FA_DIRTY) { /* Write-back cached data if needed */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { + LEAVE_FF(fs, FR_DISK_ERR); + } + fp->flag &= ~_FA_DIRTY; } #endif /* Update the directory entry */ - res = move_window(fp->fs, fp->dir_sect); - if (res == FR_OK) { - dir = fp->dir_ptr; - dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ - ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */ - st_clust(dir, fp->sclust); /* Update start cluster */ - tm = GET_FATTIME(); /* Update updated time */ - ST_DWORD(dir + DIR_WrtTime, tm); - ST_WORD(dir + DIR_LstAccDate, 0); - fp->flag &= ~FA__WRITTEN; - fp->fs->wflag = 1; - res = sync_fs(fp->fs); + tm = GET_FATTIME(); /* Modified time */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + res = fill_fat_chain(&fp->obj); /* Create FAT chain if needed */ + if (res == FR_OK) { + DIR dj; + + INIT_DIRBUF(fs); + res = load_obj_dir(&dj, &fp->obj); /* Load directory entry block */ + if (res == FR_OK) { + fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive bit */ + fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation info */ + st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); + st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); + st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); + st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */ + fs->dirbuf[XDIR_ModTime10] = 0; + st_dword(fs->dirbuf + XDIR_AccTime, 0); + res = store_xdir(&dj); /* Restore it to the directory */ + if (res == FR_OK) { + res = sync_fs(fs); + fp->flag &= ~_FA_MODIFIED; + } + } + FREE_DIRBUF(); + } + } else +#endif + { + res = move_window(fs, fp->dir_sect); + if (res == FR_OK) { + dir = fp->dir_ptr; + dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ + st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation info */ + st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ + st_dword(dir + DIR_WrtTime, tm); /* Update modified time */ + st_word(dir + DIR_LstAccDate, 0); + fs->wflag = 1; + res = sync_fs(fs); /* Restore it to the directory */ + fp->flag &= ~_FA_MODIFIED; + } } } } - LEAVE_FF(fp->fs, res); + LEAVE_FF(fs, res); } #endif /* !_FS_READONLY */ @@ -2870,27 +3692,26 @@ FRESULT f_sync ( /*-----------------------------------------------------------------------*/ FRESULT f_close ( - FIL *fp /* Pointer to the file object to be closed */ + FIL* fp /* Pointer to the file object to be closed */ ) { FRESULT res; - + FATFS *fs; #if !_FS_READONLY res = f_sync(fp); /* Flush cached data */ if (res == FR_OK) #endif { - res = validate(fp); /* Lock volume */ + res = validate(fp, &fs); /* Lock volume */ if (res == FR_OK) { -#if _FS_REENTRANT - FATFS *fs = fp->fs; -#endif -#if _FS_LOCK - res = dec_lock(fp->lockid); /* Decrement file open counter */ +#if _FS_LOCK != 0 + res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ if (res == FR_OK) #endif - fp->fs = 0; /* Invalidate file object */ + { + fp->obj.fs = 0; /* Invalidate file object */ + } #if _FS_REENTRANT unlock_fs(fs, FR_OK); /* Unlock volume */ #endif @@ -2931,29 +3752,48 @@ FRESULT f_chdir ( { FRESULT res; DIR dj; - DEFINE_NAMEBUF; - + FATFS *fs; + DEF_NAMBUF; /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 0); + res = find_volume(&path, &fs, 0); if (res == FR_OK) { - INIT_BUF(dj); + dj.obj.fs = fs; + INIT_NAMBUF(dj); res = follow_path(&dj, path); /* Follow the path */ - FREE_BUF(); if (res == FR_OK) { /* Follow completed */ - if (!dj.dir) { - dj.fs->cdir = dj.sclust; /* Start directory itself */ + if (dj.fn[NSFLAG] & NS_NONAME) { + fs->cdir = dj.obj.sclust; /* It is the start directory itself */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->cdc_scl = dj.obj.c_scl; + fs->cdc_size = dj.obj.c_size; + fs->cdc_ofs = dj.obj.c_ofs; + } +#endif } else { - if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */ - dj.fs->cdir = ld_clust(dj.fs, dj.dir); - else + if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ + fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ + fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; + fs->cdc_ofs = dj.blk_ofs; + } else +#endif + { + fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ + } + } else { res = FR_NO_PATH; /* Reached but a file */ + } } } + FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; } - LEAVE_FF(dj.fs, res); + LEAVE_FF(fs, res); } @@ -2965,51 +3805,47 @@ FRESULT f_getcwd ( { FRESULT res; DIR dj; + FATFS *fs; UINT i, n; DWORD ccl; TCHAR *tp; FILINFO fno; - DEFINE_NAMEBUF; + DEF_NAMBUF; *buff = 0; /* Get logical drive number */ - res = find_volume(&dj.fs, (const TCHAR**)&buff, 0); /* Get current volume */ + res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ if (res == FR_OK) { - INIT_BUF(dj); + dj.obj.fs = fs; + INIT_NAMBUF(dj); i = len; /* Bottom of buffer (directory stack base) */ - dj.sclust = dj.fs->cdir; /* Start to follow upper directory from current directory */ - while ((ccl = dj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ - res = dir_sdi(&dj, 1); /* Get parent directory */ - if (res != FR_OK) break; - res = dir_read(&dj, 0); - if (res != FR_OK) break; - dj.sclust = ld_clust(dj.fs, dj.dir); /* Goto parent directory */ - res = dir_sdi(&dj, 0); - if (res != FR_OK) break; - do { /* Find the entry links to the child directory */ - res = dir_read(&dj, 0); + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ + dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ + while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ + res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ if (res != FR_OK) break; - if (ccl == ld_clust(dj.fs, dj.dir)) break; /* Found the entry */ - res = dir_next(&dj, 0); - } while (res == FR_OK); - if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ - if (res != FR_OK) break; -#if _USE_LFN - fno.lfname = buff; - fno.lfsize = i; -#endif - get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ - tp = fno.fname; -#if _USE_LFN - if (*buff) tp = buff; -#endif - for (n = 0; tp[n]; n++) ; - if (i < n + 3) { - res = FR_NOT_ENOUGH_CORE; break; + res = move_window(fs, dj.sect); + if (res != FR_OK) break; + dj.obj.sclust = ld_clust(fs, dj.dir); /* Goto parent directory */ + res = dir_sdi(&dj, 0); + if (res != FR_OK) break; + do { /* Find the entry links to the child directory */ + res = dir_read(&dj, 0); + if (res != FR_OK) break; + if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ + res = dir_next(&dj, 0); + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ + if (res != FR_OK) break; + get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ + for (n = 0; fno.fname[n]; n++) ; + if (i < n + 3) { + res = FR_NOT_ENOUGH_CORE; break; + } + while (n) buff[--i] = fno.fname[--n]; + buff[--i] = '/'; } - while (n) buff[--i] = tp[--n]; - buff[--i] = '/'; } tp = buff; if (res == FR_OK) { @@ -3026,10 +3862,10 @@ FRESULT f_getcwd ( } } *tp = 0; - FREE_BUF(); + FREE_NAMBUF(); } - LEAVE_FF(dj.fs, res); + LEAVE_FF(fs, res); } #endif /* _FS_RPATH >= 2 */ #endif /* _FS_RPATH >= 1 */ @@ -3043,70 +3879,69 @@ FRESULT f_getcwd ( FRESULT f_lseek ( FIL* fp, /* Pointer to the file object */ - DWORD ofs /* File pointer from top of file */ + FSIZE_t ofs /* File pointer from top of file */ ) { FRESULT res; - DWORD clst, bcs, nsect, ifptr; + FATFS *fs; + DWORD clst, bcs, nsect; + FSIZE_t ifptr; #if _USE_FASTSEEK DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; #endif - - res = validate(fp); /* Check validity of the object */ - if (res != FR_OK) LEAVE_FF(fp->fs, res); - if (fp->err) /* Check error */ - LEAVE_FF(fp->fs, (FRESULT)fp->err); - + res = validate(fp, &fs); /* Check validity of the object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ #if _USE_FASTSEEK if (fp->cltbl) { /* Fast seek */ if (ofs == CREATE_LINKMAP) { /* Create CLMT */ tbl = fp->cltbl; tlen = *tbl++; ulen = 2; /* Given table size and required table size */ - cl = fp->sclust; /* Top of the chain */ + cl = fp->obj.sclust; /* Top of the chain */ if (cl) { do { /* Get a fragment */ tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ do { pcl = cl; ncl++; - cl = get_fat(fp->fs, cl); - if (cl <= 1) ABORT(fp->fs, FR_INT_ERR); - if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + cl = get_fat(&fp->obj, cl); + if (cl <= 1) ABORT(fs, FR_INT_ERR); + if (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); } while (cl == pcl + 1); if (ulen <= tlen) { /* Store the length and top of the fragment */ *tbl++ = ncl; *tbl++ = tcl; } - } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */ + } while (cl < fs->n_fatent); /* Repeat until end of chain */ } *fp->cltbl = ulen; /* Number of items used */ - if (ulen <= tlen) + if (ulen <= tlen) { *tbl = 0; /* Terminate table */ - else + } else { res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ - + } } else { /* Fast seek */ - if (ofs > fp->fsize) /* Clip offset at the file size */ - ofs = fp->fsize; + if (ofs > fp->obj.objsize) ofs = fp->obj.objsize; /* Clip offset at the file size */ fp->fptr = ofs; /* Set file pointer */ if (ofs) { fp->clust = clmt_clust(fp, ofs - 1); - dsc = clust2sect(fp->fs, fp->clust); - if (!dsc) ABORT(fp->fs, FR_INT_ERR); - dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1); - if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { /* Refill sector cache if needed */ + dsc = clust2sect(fs, fp->clust); + if (!dsc) ABORT(fs, FR_INT_ERR); + dsc += (ofs - 1) / SS(fs) & (fs->csize - 1); + if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */ #if !_FS_TINY #if !_FS_READONLY - if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; + if (fp->flag & _FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { + ABORT(fp, FR_DISK_ERR); + } + fp->flag &= ~_FA_DIRTY; } #endif - if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) /* Load current sector */ - ABORT(fp->fs, FR_DISK_ERR); + if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) { /* Load current sector */ + ABORT(fs, FR_DISK_ERR); + } #endif - fp->dsect = dsc; + fp->sect = dsc; } } } @@ -3115,29 +3950,29 @@ FRESULT f_lseek ( /* Normal Seek */ { - if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */ + if (ofs > fp->obj.objsize /* In read-only mode, clip offset with the file size */ #if !_FS_READONLY && !(fp->flag & FA_WRITE) #endif - ) ofs = fp->fsize; + ) ofs = fp->obj.objsize; ifptr = fp->fptr; fp->fptr = nsect = 0; if (ofs) { - bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */ + bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ if (ifptr > 0 && (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */ ofs -= fp->fptr; clst = fp->clust; } else { /* When seek to back cluster, */ - clst = fp->sclust; /* start from the first cluster */ + clst = fp->obj.sclust; /* start from the first cluster */ #if !_FS_READONLY if (clst == 0) { /* If no cluster chain, create a new chain */ - clst = create_chain(fp->fs, 0); - if (clst == 1) ABORT(fp->fs, FR_INT_ERR); - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); - fp->sclust = clst; + clst = create_chain(&fp->obj, 0); + if (clst == 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->obj.sclust = clst; } #endif fp->clust = clst; @@ -3146,50 +3981,52 @@ FRESULT f_lseek ( while (ofs > bcs) { /* Cluster following loop */ #if !_FS_READONLY if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ - clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */ + clst = create_chain(&fp->obj, clst); /* Force stretch if in write mode */ if (clst == 0) { /* When disk gets full, clip file size */ ofs = bcs; break; } } else #endif - clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */ - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); - if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR); + clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */ + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR); fp->clust = clst; fp->fptr += bcs; ofs -= bcs; } fp->fptr += ofs; - if (ofs % SS(fp->fs)) { - nsect = clust2sect(fp->fs, clst); /* Current sector */ - if (!nsect) ABORT(fp->fs, FR_INT_ERR); - nsect += ofs / SS(fp->fs); + if (ofs % SS(fs)) { + nsect = clust2sect(fs, clst); /* Current sector */ + if (!nsect) ABORT(fs, FR_INT_ERR); + nsect += (DWORD)(ofs / SS(fs)); } } } - if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */ + if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ #if !_FS_TINY #if !_FS_READONLY - if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; + if (fp->flag & _FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { + ABORT(fs, FR_DISK_ERR); + } + fp->flag &= ~_FA_DIRTY; } #endif - if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) /* Fill sector cache */ - ABORT(fp->fs, FR_DISK_ERR); + if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) { /* Fill sector cache */ + ABORT(fs, FR_DISK_ERR); + } #endif - fp->dsect = nsect; + fp->sect = nsect; } #if !_FS_READONLY - if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */ - fp->fsize = fp->fptr; - fp->flag |= FA__WRITTEN; + if (fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ + fp->obj.objsize = fp->fptr; + fp->flag |= _FA_MODIFIED; } #endif } - LEAVE_FF(fp->fs, res); + LEAVE_FF(fs, res); } @@ -3205,45 +4042,59 @@ FRESULT f_opendir ( ) { FRESULT res; - FATFS* fs; - DEFINE_NAMEBUF; + FATFS *fs; + _FDID *obj; + DEF_NAMBUF; if (!dp) return FR_INVALID_OBJECT; /* Get logical drive number */ - res = find_volume(&fs, &path, 0); + obj = &dp->obj; + res = find_volume(&path, &fs, 0); if (res == FR_OK) { - dp->fs = fs; - INIT_BUF(*dp); + obj->fs = fs; + INIT_NAMBUF(*dp); res = follow_path(dp, path); /* Follow the path to the directory */ - FREE_BUF(); if (res == FR_OK) { /* Follow completed */ - if (dp->dir) { /* It is not the origin directory itself */ - if (dp->dir[DIR_Attr] & AM_DIR) /* The object is a sub directory */ - dp->sclust = ld_clust(fs, dp->dir); - else /* The object is a file */ + if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ + if (obj->attr & AM_DIR) { /* This object is a sub-directory */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + obj->c_scl = obj->sclust; /* Save containing directory inforamation */ + obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; + obj->c_ofs = dp->blk_ofs; + obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object location and status */ + obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; + } else +#endif + { + obj->sclust = ld_clust(fs, dp->dir); /* Get object location */ + } + } else { /* This object is a file */ res = FR_NO_PATH; + } } if (res == FR_OK) { - dp->id = fs->id; + obj->id = fs->id; res = dir_sdi(dp, 0); /* Rewind directory */ -#if _FS_LOCK +#if _FS_LOCK != 0 if (res == FR_OK) { - if (dp->sclust) { - dp->lockid = inc_lock(dp, 0); /* Lock the sub directory */ - if (!dp->lockid) - res = FR_TOO_MANY_OPEN_FILES; + if (obj->sclust) { + obj->lockid = inc_lock(dp, 0); /* Lock the sub directory */ + if (!obj->lockid) res = FR_TOO_MANY_OPEN_FILES; } else { - dp->lockid = 0; /* Root directory need not to be locked */ + obj->lockid = 0; /* Root directory need not to be locked */ } } #endif } } + FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; } - if (res != FR_OK) dp->fs = 0; /* Invalidate the directory object if function faild */ + if (res != FR_OK) obj->fs = 0; /* Invalidate the directory object if function faild */ LEAVE_FF(fs, res); } @@ -3260,19 +4111,20 @@ FRESULT f_closedir ( ) { FRESULT res; + FATFS *fs; - res = validate(dp); + res = validate(dp, &fs); if (res == FR_OK) { -#if _FS_REENTRANT - FATFS *fs = dp->fs; -#endif -#if _FS_LOCK - if (dp->lockid) /* Decrement sub-directory open counter */ - res = dec_lock(dp->lockid); +#if _FS_LOCK != 0 + if (dp->obj.lockid) { /* Decrement sub-directory open counter */ + res = dec_lock(dp->obj.lockid); + } if (res == FR_OK) #endif - dp->fs = 0; /* Invalidate directory object */ + { + dp->obj.fs = 0; /* Invalidate directory object */ + } #if _FS_REENTRANT unlock_fs(fs, FR_OK); /* Unlock volume */ #endif @@ -3293,40 +4145,34 @@ FRESULT f_readdir ( ) { FRESULT res; - DEFINE_NAMEBUF; + FATFS *fs; + DEF_NAMBUF; - res = validate(dp); /* Check validity of the object */ + res = validate(dp, &fs); /* Check validity of the object */ if (res == FR_OK) { if (!fno) { res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { - INIT_BUF(*dp); + INIT_NAMBUF(*dp); res = dir_read(dp, 0); /* Read an item */ - if (res == FR_NO_FILE) { /* Reached end of directory */ - dp->sect = 0; - res = FR_OK; - } + if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ if (res == FR_OK) { /* A valid entry is found */ get_fileinfo(dp, fno); /* Get the object information */ res = dir_next(dp, 0); /* Increment index for next */ - if (res == FR_NO_FILE) { - dp->sect = 0; - res = FR_OK; - } + if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory now */ } - FREE_BUF(); + FREE_NAMBUF(); } } - - LEAVE_FF(dp->fs, res); + LEAVE_FF(fs, res); } #if _USE_FIND /*-----------------------------------------------------------------------*/ -/* Find next file */ +/* Find Next File */ /*-----------------------------------------------------------------------*/ FRESULT f_findnext ( @@ -3340,19 +4186,18 @@ FRESULT f_findnext ( for (;;) { res = f_readdir(dp, fno); /* Get a directory item */ if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ -#if _USE_LFN - if (fno->lfname && pattern_matching(dp->pat, fno->lfname, 0, 0)) break; /* Test for LFN if exist */ + if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for the file name */ +#if _USE_LFN != 0 && _USE_FIND == 2 + if (pattern_matching(dp->pat, fno->altname, 0, 0)) break; /* Test for alternative name if exist */ #endif - if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for SFN */ } return res; - } /*-----------------------------------------------------------------------*/ -/* Find first file */ +/* Find First File */ /*-----------------------------------------------------------------------*/ FRESULT f_findfirst ( @@ -3367,8 +4212,9 @@ FRESULT f_findfirst ( dp->pat = pattern; /* Save pointer to pattern string */ res = f_opendir(dp, path); /* Open the target directory */ - if (res == FR_OK) + if (res == FR_OK) { res = f_findnext(dp, fno); /* Find the first item */ + } return res; } @@ -3388,25 +4234,25 @@ FRESULT f_stat ( { FRESULT res; DIR dj; - DEFINE_NAMEBUF; + DEF_NAMBUF; /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 0); + res = find_volume(&path, &dj.obj.fs, 0); if (res == FR_OK) { - INIT_BUF(dj); + INIT_NAMBUF(dj); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK) { /* Follow completed */ - if (dj.dir) { /* Found an object */ - if (fno) get_fileinfo(&dj, fno); - } else { /* It is root directory */ + if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */ res = FR_INVALID_NAME; + } else { /* Found an object */ + if (fno) get_fileinfo(&dj, fno); } } - FREE_BUF(); + FREE_NAMBUF(); } - LEAVE_FF(dj.fs, res); + LEAVE_FF(dj.obj.fs, res); } @@ -3424,55 +4270,75 @@ FRESULT f_getfree ( { FRESULT res; FATFS *fs; - DWORD n, clst, sect, stat; + DWORD nfree, clst, sect, stat; UINT i; - BYTE fat, *p; + BYTE *p; + _FDID obj; /* Get logical drive number */ - res = find_volume(fatfs, &path, 0); - fs = *fatfs; + res = find_volume(&path, &fs, 0); if (res == FR_OK) { - /* If free_clust is valid, return it without full cluster scan */ - if (fs->free_clust <= fs->n_fatent - 2) { - *nclst = fs->free_clust; + *fatfs = fs; /* Return ptr to the fs object */ + /* If free_clst is valid, return it without full cluster scan */ + if (fs->free_clst <= fs->n_fatent - 2) { + *nclst = fs->free_clst; } else { /* Get number of free clusters */ - fat = fs->fs_type; - n = 0; - if (fat == FS_FAT12) { - clst = 2; + nfree = 0; + if (fs->fs_type == FS_FAT12) { /* FAT12: Sector unalighed FAT entries */ + clst = 2; obj.fs = fs; do { - stat = get_fat(fs, clst); + stat = get_fat(&obj, clst); if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } if (stat == 1) { res = FR_INT_ERR; break; } - if (stat == 0) n++; + if (stat == 0) nfree++; } while (++clst < fs->n_fatent); } else { - clst = fs->n_fatent; - sect = fs->fatbase; - i = 0; p = 0; - do { - if (!i) { - res = move_window(fs, sect++); - if (res != FR_OK) break; - p = fs->win; - i = SS(fs); - } - if (fat == FS_FAT16) { - if (LD_WORD(p) == 0) n++; - p += 2; i -= 2; - } else { - if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++; - p += 4; i -= 4; - } - } while (--clst); +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan bitmap table */ + BYTE bm; + UINT b; + + clst = fs->n_fatent - 2; + sect = fs->database; + i = 0; + do { + if (i == 0 && (res = move_window(fs, sect++)) != FR_OK) break; + for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { + if (!(bm & 1)) nfree++; + bm >>= 1; + } + i = (i + 1) & (SS(fs) - 1); + } while (clst); + } else +#endif + { /* FAT16/32: Sector alighed FAT entries */ + clst = fs->n_fatent; sect = fs->fatbase; + i = 0; p = 0; + do { + if (i == 0) { + res = move_window(fs, sect++); + if (res != FR_OK) break; + p = fs->win; + i = SS(fs); + } + if (fs->fs_type == FS_FAT16) { + if (ld_word(p) == 0) nfree++; + p += 2; i -= 2; + } else { + if ((ld_dword(p) & 0x0FFFFFFF) == 0) nfree++; + p += 4; i -= 4; + } + } while (--clst); + } } - fs->free_clust = n; - fs->fsi_flag |= 1; - *nclst = n; + *nclst = nfree; /* Return the free clusters */ + fs->free_clst = nfree; /* Now free_clst is valid */ + fs->fsi_flag |= 1; /* FSInfo is to be updated */ } } + LEAVE_FF(fs, res); } @@ -3488,55 +4354,49 @@ FRESULT f_truncate ( ) { FRESULT res; + FATFS *fs; DWORD ncl; - res = validate(fp); /* Check validity of the object */ - if (res == FR_OK) { - if (fp->err) { /* Check error */ - res = (FRESULT)fp->err; - } else { - if (!(fp->flag & FA_WRITE)) /* Check access mode */ - res = FR_DENIED; - } - } - if (res == FR_OK) { - if (fp->fsize > fp->fptr) { - fp->fsize = fp->fptr; /* Set file size to current R/W point */ - fp->flag |= FA__WRITTEN; - if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ - res = remove_chain(fp->fs, fp->sclust); - fp->sclust = 0; - } else { /* When truncate a part of the file, remove remaining clusters */ - ncl = get_fat(fp->fs, fp->clust); - res = FR_OK; - if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; - if (ncl == 1) res = FR_INT_ERR; - if (res == FR_OK && ncl < fp->fs->n_fatent) { - res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF); - if (res == FR_OK) res = remove_chain(fp->fs, ncl); - } + res = validate(fp, &fs); /* Check validity of the object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + if (fp->obj.objsize > fp->fptr) { + if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ + res = remove_chain(&fp->obj, fp->obj.sclust, 0); + fp->obj.sclust = 0; + } else { /* When truncate a part of the file, remove remaining clusters */ + ncl = get_fat(&fp->obj, fp->clust); + res = FR_OK; + if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (ncl == 1) res = FR_INT_ERR; + if (res == FR_OK && ncl < fs->n_fatent) { + res = remove_chain(&fp->obj, ncl, fp->clust); } + } + fp->obj.objsize = fp->fptr; /* Set file size to current R/W point */ + fp->flag |= _FA_MODIFIED; #if !_FS_TINY - if (res == FR_OK && (fp->flag & FA__DIRTY)) { - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - res = FR_DISK_ERR; - else - fp->flag &= ~FA__DIRTY; + if (res == FR_OK && (fp->flag & _FA_DIRTY)) { + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { + res = FR_DISK_ERR; + } else { + fp->flag &= ~_FA_DIRTY; } -#endif } - if (res != FR_OK) fp->err = (FRESULT)res; +#endif + if (res != FR_OK) ABORT(fs, res); } - LEAVE_FF(fp->fs, res); + LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ -/* Delete a File or Directory */ +/* Delete a File/Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_unlink ( @@ -3545,60 +4405,86 @@ FRESULT f_unlink ( { FRESULT res; DIR dj, sdj; - BYTE *dir; DWORD dclst = 0; - DEFINE_NAMEBUF; + FATFS *fs; +#if _FS_EXFAT + _FDID obj; +#endif + DEF_NAMBUF; /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 1); + res = find_volume(&path, &fs, FA_WRITE); + dj.obj.fs = fs; if (res == FR_OK) { - INIT_BUF(dj); + INIT_NAMBUF(dj); res = follow_path(&dj, path); /* Follow the file path */ - if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) + if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { res = FR_INVALID_NAME; /* Cannot remove dot entry */ -#if _FS_LOCK - if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open object */ + } +#if _FS_LOCK != 0 + if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ #endif if (res == FR_OK) { /* The object is accessible */ - dir = dj.dir; - if (!dir) { + if (dj.fn[NSFLAG] & NS_NONAME) { res = FR_INVALID_NAME; /* Cannot remove the origin directory */ } else { - if (dir[DIR_Attr] & AM_RDO) + if (dj.obj.attr & AM_RDO) { res = FR_DENIED; /* Cannot remove R/O object */ + } } if (res == FR_OK) { - dclst = ld_clust(dj.fs, dir); - if (dclst && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-directory ? */ -#if _FS_RPATH - if (dclst == dj.fs->cdir) { /* Is it the current directory? */ +#if _FS_EXFAT + obj.fs = fs; + if (fs->fs_type == FS_EXFAT) { + obj.sclust = dclst = ld_dword(fs->dirbuf + XDIR_FstClus); + obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + } else +#endif + { + dclst = ld_clust(fs, dj.dir); + } + if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory ? */ +#if _FS_RPATH != 0 + if (dclst == fs->cdir) { /* Is it the current directory? */ res = FR_DENIED; } else #endif { - mem_cpy(&sdj, &dj, sizeof (DIR)); /* Open the sub-directory */ - sdj.sclust = dclst; - res = dir_sdi(&sdj, 2); + sdj.obj.fs = fs; /* Open the sub-directory */ + sdj.obj.sclust = dclst; +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + sdj.obj.objsize = obj.objsize; + sdj.obj.stat = obj.stat; + } +#endif + res = dir_sdi(&sdj, 0); if (res == FR_OK) { - res = dir_read(&sdj, 0); /* Read an item (excluding dot entries) */ - if (res == FR_OK) res = FR_DENIED; /* Not empty? (cannot remove) */ - if (res == FR_NO_FILE) res = FR_OK; /* Empty? (can remove) */ + res = dir_read(&sdj, 0); /* Read an item */ + if (res == FR_OK) res = FR_DENIED; /* Not empty? */ + if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ } } } } if (res == FR_OK) { - res = dir_remove(&dj); /* Remove the directory entry */ - if (res == FR_OK && dclst) /* Remove the cluster chain if exist */ - res = remove_chain(dj.fs, dclst); - if (res == FR_OK) res = sync_fs(dj.fs); + res = dir_remove(&dj); /* Remove the directory entry */ + if (res == FR_OK && dclst) { /* Remove the cluster chain if exist */ +#if _FS_EXFAT + res = remove_chain(&obj, dclst, 0); +#else + res = remove_chain(&dj.obj, dclst, 0); +#endif + } + if (res == FR_OK) res = sync_fs(fs); } } - FREE_BUF(); + FREE_NAMBUF(); } - LEAVE_FF(dj.fs, res); + LEAVE_FF(fs, res); } @@ -3614,186 +4500,234 @@ FRESULT f_mkdir ( { FRESULT res; DIR dj; - BYTE *dir, n; - DWORD dsc, dcl, pcl, tm = GET_FATTIME(); - DEFINE_NAMEBUF; + FATFS *fs; + BYTE *dir; + UINT n; + DWORD dsc, dcl, pcl, tm; + DEF_NAMBUF; /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 1); + res = find_volume(&path, &fs, FA_WRITE); + dj.obj.fs = fs; if (res == FR_OK) { - INIT_BUF(dj); + INIT_NAMBUF(dj); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ - if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) + if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { res = FR_INVALID_NAME; + } if (res == FR_NO_FILE) { /* Can create a new directory */ - dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */ + dcl = create_chain(&dj.obj, 0); /* Allocate a cluster for the new directory table */ + dj.obj.objsize = (DWORD)fs->csize * SS(fs); res = FR_OK; if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ if (dcl == 1) res = FR_INT_ERR; if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; - if (res == FR_OK) /* Flush FAT */ - res = sync_window(dj.fs); + if (res == FR_OK) res = sync_window(fs); /* Flush FAT */ + tm = GET_FATTIME(); if (res == FR_OK) { /* Initialize the new directory table */ - dsc = clust2sect(dj.fs, dcl); - dir = dj.fs->win; - mem_set(dir, 0, SS(dj.fs)); - mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ - dir[DIR_Name] = '.'; - dir[DIR_Attr] = AM_DIR; - ST_DWORD(dir + DIR_WrtTime, tm); - st_clust(dir, dcl); - mem_cpy(dir + SZ_DIRE, dir, SZ_DIRE); /* Create ".." entry */ - dir[SZ_DIRE + 1] = '.'; pcl = dj.sclust; - if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase) - pcl = 0; - st_clust(dir + SZ_DIRE, pcl); - for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */ - dj.fs->winsect = dsc++; - dj.fs->wflag = 1; - res = sync_window(dj.fs); + dsc = clust2sect(fs, dcl); + dir = fs->win; + mem_set(dir, 0, SS(fs)); + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ + dir[DIR_Name] = '.'; + dir[DIR_Attr] = AM_DIR; + st_dword(dir + DIR_WrtTime, tm); + st_clust(fs, dir, dcl); + mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */ + dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; + if (fs->fs_type == FS_FAT32 && pcl == fs->dirbase) + pcl = 0; + st_clust(fs, dir + SZDIRE, pcl); + } + for (n = fs->csize; n; n--) { /* Write dot entries and clear following sectors */ + fs->winsect = dsc++; + fs->wflag = 1; + res = sync_window(fs); if (res != FR_OK) break; - mem_set(dir, 0, SS(dj.fs)); + mem_set(dir, 0, SS(fs)); } } if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */ - if (res != FR_OK) { - remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */ + if (res == FR_OK) { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + st_dword(fs->dirbuf + XDIR_ModTime, tm); + st_dword(fs->dirbuf + XDIR_FstClus, dcl); + st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); + st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize); + fs->dirbuf[XDIR_GenFlags] = 3; + fs->dirbuf[XDIR_Attr] = AM_DIR; + res = store_xdir(&dj); + } else +#endif + { + dir = dj.dir; + st_dword(dir + DIR_WrtTime, tm); /* Created time */ + st_clust(fs, dir, dcl); /* Table start cluster */ + dir[DIR_Attr] = AM_DIR; /* Attribute */ + fs->wflag = 1; + } + res = sync_fs(fs); } else { - dir = dj.dir; - dir[DIR_Attr] = AM_DIR; /* Attribute */ - ST_DWORD(dir + DIR_WrtTime, tm); /* Created time */ - st_clust(dir, dcl); /* Table start cluster */ - dj.fs->wflag = 1; - res = sync_fs(dj.fs); - } - } - FREE_BUF(); - } - - LEAVE_FF(dj.fs, res); -} - - - - -/*-----------------------------------------------------------------------*/ -/* Change Attribute */ -/*-----------------------------------------------------------------------*/ - -FRESULT f_chmod ( - const TCHAR* path, /* Pointer to the file path */ - BYTE attr, /* Attribute bits */ - BYTE mask /* Attribute mask to change */ -) -{ - FRESULT res; - DIR dj; - BYTE *dir; - DEFINE_NAMEBUF; - - - /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 1); - if (res == FR_OK) { - INIT_BUF(dj); - res = follow_path(&dj, path); /* Follow the file path */ - FREE_BUF(); - if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) - res = FR_INVALID_NAME; - if (res == FR_OK) { - dir = dj.dir; - if (!dir) { /* Is it a root directory? */ - res = FR_INVALID_NAME; - } else { /* File or sub directory */ - mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ - dir[DIR_Attr] = (attr & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ - dj.fs->wflag = 1; - res = sync_fs(dj.fs); + remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ } } + FREE_NAMBUF(); } - LEAVE_FF(dj.fs, res); + LEAVE_FF(fs, res); } /*-----------------------------------------------------------------------*/ -/* Rename File/Directory */ +/* Rename a File/Directory */ /*-----------------------------------------------------------------------*/ FRESULT f_rename ( - const TCHAR* path_old, /* Pointer to the object to be renamed */ + const TCHAR* path_old, /* Pointer to the object name to be renamed */ const TCHAR* path_new /* Pointer to the new name */ ) { FRESULT res; DIR djo, djn; - BYTE buf[21], *dir; + FATFS *fs; + BYTE buf[_FS_EXFAT ? SZDIRE * 2 : 24], *dir; DWORD dw; - DEFINE_NAMEBUF; + DEF_NAMBUF; - /* Get logical drive number of the source object */ - res = find_volume(&djo.fs, &path_old, 1); + get_ldnumber(&path_new); /* Ignore drive number of new name */ + res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive number of the old object */ if (res == FR_OK) { - djn.fs = djo.fs; - INIT_BUF(djo); + djo.obj.fs = fs; + INIT_NAMBUF(djo); res = follow_path(&djo, path_old); /* Check old object */ - if (_FS_RPATH && res == FR_OK && (djo.fn[NSFLAG] & NS_DOT)) - res = FR_INVALID_NAME; -#if _FS_LOCK + if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ +#if _FS_LOCK != 0 if (res == FR_OK) res = chk_lock(&djo, 2); #endif - if (res == FR_OK) { /* Old object is found */ - if (!djo.dir) { /* Is root dir? */ - res = FR_NO_FILE; - } else { - mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about object except name */ + if (res == FR_OK) { /* Object to be renamed is found */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At exFAT */ + BYTE nf, nn; + WORD nh; + + mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ + mem_cpy(&djn, &djo, sizeof djo); + res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ + if (res == FR_OK) res = FR_EXIST; /* Is new name already in use? */ + if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ + if (res == FR_OK) { + nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; + nh = ld_word(fs->dirbuf + XDIR_NameHash); + mem_cpy(fs->dirbuf, buf, SZDIRE * 2); + fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; + st_word(fs->dirbuf + XDIR_NameHash, nh); +/* Start of critical section where any interruption can cause a cross-link */ + res = store_xdir(&djn); + } + } + } else +#endif + { /* At FAT12/FAT16/FAT32 */ + mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about the object except name */ mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ - if (get_ldnumber(&path_new) >= 0) /* Snip drive number off and ignore it */ - res = follow_path(&djn, path_new); /* and make sure if new object name is not conflicting */ - else - res = FR_INVALID_DRIVE; - if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */ + res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ + if (res == FR_OK) res = FR_EXIST; /* Is new name already in use? */ if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { -/* Start of critical section where any interruption can cause a cross-link */ dir = djn.dir; /* Copy information about object except name */ mem_cpy(dir + 13, buf + 2, 19); dir[DIR_Attr] = buf[0] | AM_ARC; - djo.fs->wflag = 1; - if ((dir[DIR_Attr] & AM_DIR) && djo.sclust != djn.sclust) { /* Update .. entry in the sub-directory if needed */ - dw = clust2sect(djo.fs, ld_clust(djo.fs, dir)); + fs->wflag = 1; + if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */ + dw = clust2sect(fs, ld_clust(fs, dir)); if (!dw) { res = FR_INT_ERR; } else { - res = move_window(djo.fs, dw); - dir = djo.fs->win + SZ_DIRE * 1; /* Ptr to .. entry */ +/* Start of critical section where any interruption can cause a cross-link */ + res = move_window(fs, dw); + dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ if (res == FR_OK && dir[1] == '.') { - st_clust(dir, djn.sclust); - djo.fs->wflag = 1; + st_clust(fs, dir, djn.obj.sclust); + fs->wflag = 1; } } } - if (res == FR_OK) { - res = dir_remove(&djo); /* Remove old entry */ - if (res == FR_OK) - res = sync_fs(djo.fs); - } -/* End of critical section */ } } } + if (res == FR_OK) { + res = dir_remove(&djo); /* Remove old entry */ + if (res == FR_OK) { + res = sync_fs(fs); + } + } +/* End of critical section */ + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + + + +#endif /* !_FS_READONLY */ +#endif /* _FS_MINIMIZE == 0 */ +#endif /* _FS_MINIMIZE <= 1 */ +#endif /* _FS_MINIMIZE <= 2 */ + + + +#if _USE_CHMOD && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Change Attribute */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_chmod ( + const TCHAR* path, /* Pointer to the file path */ + BYTE attr, /* Attribute bits */ + BYTE mask /* Attribute mask to change */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + DEF_NAMBUF; + + + res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive number */ + dj.obj.fs = fs; + if (res == FR_OK) { + INIT_NAMBUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ + if (res == FR_OK) { + mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + res = store_xdir(&dj); + } else +#endif + { + dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + fs->wflag = 1; + } + res = sync_fs(fs); } - FREE_BUF(); + FREE_NAMBUF(); } - LEAVE_FF(djo.fs, res); + LEAVE_FF(fs, res); } @@ -3810,45 +4744,44 @@ FRESULT f_utime ( { FRESULT res; DIR dj; - BYTE *dir; - DEFINE_NAMEBUF; + FATFS *fs; + DEF_NAMBUF; - /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 1); + res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive number */ + dj.obj.fs = fs; if (res == FR_OK) { - INIT_BUF(dj); + INIT_NAMBUF(dj); res = follow_path(&dj, path); /* Follow the file path */ - FREE_BUF(); - if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) - res = FR_INVALID_NAME; + if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { - dir = dj.dir; - if (!dir) { /* Root directory */ - res = FR_INVALID_NAME; - } else { /* File or sub-directory */ - ST_WORD(dir + DIR_WrtTime, fno->ftime); - ST_WORD(dir + DIR_WrtDate, fno->fdate); - dj.fs->wflag = 1; - res = sync_fs(dj.fs); +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + st_word(fs->dirbuf + XDIR_ModTime, fno->ftime); + st_word(fs->dirbuf + XDIR_ModTime + 2, fno->fdate); + res = store_xdir(&dj); + } else +#endif + { + st_word(dj.dir + DIR_WrtTime, fno->ftime); + st_word(dj.dir + DIR_WrtDate, fno->fdate); + fs->wflag = 1; } + if (res == FR_OK) res = sync_fs(fs); } + FREE_NAMBUF(); } - LEAVE_FF(dj.fs, res); + LEAVE_FF(fs, res); } -#endif /* !_FS_READONLY */ -#endif /* _FS_MINIMIZE == 0 */ -#endif /* _FS_MINIMIZE <= 1 */ -#endif /* _FS_MINIMIZE <= 2 */ - +#endif /* _USE_CHMOD && !_FS_READONLY */ #if _USE_LABEL /*-----------------------------------------------------------------------*/ -/* Get volume label */ +/* Get Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_getlabel ( @@ -3859,63 +4792,85 @@ FRESULT f_getlabel ( { FRESULT res; DIR dj; - UINT i, j; -#if _USE_LFN && _LFN_UNICODE + FATFS *fs; + UINT si, di; +#if _LFN_UNICODE || _FS_EXFAT WCHAR w; #endif - /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 0); + res = find_volume(&path, &fs, 0); /* Get volume label */ if (res == FR_OK && label) { - dj.sclust = 0; /* Open root directory */ + dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { - res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ - if (res == FR_OK) { /* A volume label is exist */ -#if _USE_LFN && _LFN_UNICODE - i = j = 0; - do { - w = (i < 11) ? dj.dir[i++] : ' '; - if (IsDBCS1(w) && i < 11 && IsDBCS2(dj.dir[i])) - w = w << 8 | dj.dir[i++]; - label[j++] = ff_convert(w, 1); /* OEM -> Unicode */ - } while (j < 11); + res = dir_read(&dj, 1); /* Find a volume label entry */ + if (res == FR_OK) { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + for (si = di = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ + w = ld_word(dj.dir + XDIR_Label + si * 2); +#if _LFN_UNICODE + label[di++] = w; #else - mem_cpy(label, dj.dir, 11); + w = ff_convert(w, 0); /* Unicode -> OEM */ + if (w == 0) w = '?'; /* Replace wrong character */ + if (_DF1S && w >= 0x100) label[di++] = (char)(w >> 8); + label[di++] = (char)w; #endif - j = 11; - do { - label[j] = 0; - if (!j) break; - } while (label[--j] == ' '); - } - if (res == FR_NO_FILE) { /* No label, return nul string */ - label[0] = 0; - res = FR_OK; + } + label[di] = 0; + } else +#endif + { + si = di = 0; /* Extract volume label from AM_VOL entry with code comversion */ + do { +#if _LFN_UNICODE + w = (si < 11) ? dj.dir[si++] : ' '; + if (IsDBCS1(w) && si < 11 && IsDBCS2(dj.dir[si])) { + w = w << 8 | dj.dir[si++]; + } + label[di++] = ff_convert(w, 1); /* OEM -> Unicode */ +#else + label[di++] = dj.dir[si++]; +#endif + } while (di < 11); + do { /* Truncate trailing spaces */ + label[di] = 0; + if (di == 0) break; + } while (label[--di] == ' '); + } } } + if (res == FR_NO_FILE) { /* No label entry and return nul string */ + label[0] = 0; + res = FR_OK; + } } /* Get volume serial number */ if (res == FR_OK && vsn) { - res = move_window(dj.fs, dj.fs->volbase); + res = move_window(fs, fs->volbase); if (res == FR_OK) { - i = dj.fs->fs_type == FS_FAT32 ? BS_VolID32 : BS_VolID; - *vsn = LD_DWORD(&dj.fs->win[i]); + switch (fs->fs_type) { + case FS_EXFAT: di = BPB_VolIDEx; break; + case FS_FAT32: di = BS_VolID32; break; + default: di = BS_VolID; + } + *vsn = ld_dword(&fs->win[di]); } } - LEAVE_FF(dj.fs, res); + LEAVE_FF(fs, res); } #if !_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Set volume label */ +/* Set Volume Label */ /*-----------------------------------------------------------------------*/ FRESULT f_setlabel ( @@ -3924,84 +4879,115 @@ FRESULT f_setlabel ( { FRESULT res; DIR dj; - BYTE vn[11]; - UINT i, j, sl; + FATFS *fs; + BYTE dirvn[22]; + UINT i, j, slen; WCHAR w; - DWORD tm; + static const char badchr[] = "\"*+,.:;<=>\?[]|\x7F"; /* Get logical drive number */ - res = find_volume(&dj.fs, &label, 1); - if (res) LEAVE_FF(dj.fs, res); - - /* Create a volume label in directory form */ - vn[0] = 0; - for (sl = 0; label[sl]; sl++) ; /* Get name length */ - for ( ; sl && label[sl - 1] == ' '; sl--) ; /* Remove trailing spaces */ - if (sl) { /* Create volume label in directory form */ - i = j = 0; - do { -#if _USE_LFN && _LFN_UNICODE - w = ff_convert(ff_wtoupper(label[i++]), 0); + res = find_volume(&label, &fs, FA_WRITE); + if (res != FR_OK) LEAVE_FF(fs, res); + dj.obj.fs = fs; + + /* Get length of given volume label */ + for (slen = 0; (UINT)label[slen] >= ' '; slen++) ; /* Get name length */ + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + for (i = j = 0; i < slen; ) { /* Create volume label in directory form */ + w = label[i++]; +#if !_LFN_UNICODE + if (IsDBCS1(w)) { + w = (i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; + } + w = ff_convert(w, 1); +#endif + if (w == 0 || chk_chr(badchr, w) || j == 22) { /* Check validity check validity of the volume label */ + LEAVE_FF(fs, FR_INVALID_NAME); + } + st_word(dirvn + j, w); j += 2; + } + slen = j; + } else +#endif + { /* At the FAT12/16/32 */ + for ( ; slen && label[slen - 1] == ' '; slen--) ; /* Remove trailing spaces */ + if (slen) { /* Is there a volume label to be set? */ + dirvn[0] = 0; i = j = 0; /* Create volume label in directory form */ + do { +#if _LFN_UNICODE + w = ff_convert(ff_wtoupper(label[i++]), 0); #else - w = (BYTE)label[i++]; - if (IsDBCS1(w)) - w = (j < 10 && i < sl && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; -#if _USE_LFN - w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0); + w = (BYTE)label[i++]; + if (IsDBCS1(w)) { + w = (j < 10 && i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; + } +#if _USE_LFN != 0 + w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0); #else - if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */ + if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */ #ifdef _EXCVT - if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */ + if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */ #else - if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */ + if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */ #endif #endif #endif - if (!w || chk_chr("\"*+,.:;<=>\?[]|\x7F", w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) /* Reject invalid characters for volume label */ - LEAVE_FF(dj.fs, FR_INVALID_NAME); - if (w >= 0x100) vn[j++] = (BYTE)(w >> 8); - vn[j++] = (BYTE)w; - } while (i < sl); - while (j < 11) vn[j++] = ' '; /* Fill remaining name field */ - if (vn[0] == DDEM) LEAVE_FF(dj.fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ + if (w == 0 || chk_chr(badchr, w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ + LEAVE_FF(fs, FR_INVALID_NAME); + } + if (w >= 0x100) dirvn[j++] = (BYTE)(w >> 8); + dirvn[j++] = (BYTE)w; + } while (i < slen); + while (j < 11) dirvn[j++] = ' '; /* Fill remaining name field */ + if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ + } } /* Set volume label */ - dj.sclust = 0; /* Open root directory */ + dj.obj.sclust = 0; /* Open root directory */ res = dir_sdi(&dj, 0); if (res == FR_OK) { - res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ - if (res == FR_OK) { /* A volume label is found */ - if (vn[0]) { - mem_cpy(dj.dir, vn, 11); /* Change the volume label name */ - tm = GET_FATTIME(); - ST_DWORD(dj.dir + DIR_WrtTime, tm); + res = dir_read(&dj, 1); /* Get volume label entry */ + if (res == FR_OK) { + if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_NumLabel] = slen / 2; /* Change the volume label */ + mem_cpy(dj.dir + XDIR_Label, dirvn, slen); } else { - dj.dir[0] = DDEM; /* Remove the volume label */ + if (slen) { + mem_cpy(dj.dir, dirvn, 11); /* Change the volume label */ + } else { + dj.dir[DIR_Name] = DDEM; /* Remove the volume label */ + } } - dj.fs->wflag = 1; - res = sync_fs(dj.fs); - } else { /* No volume label is found or error */ + fs->wflag = 1; + res = sync_fs(fs); + } else { /* No volume label entry is found or error */ if (res == FR_NO_FILE) { res = FR_OK; - if (vn[0]) { /* Create volume label as new */ - res = dir_alloc(&dj, 1); /* Allocate an entry for volume label */ + if (slen) { /* Create a volume label entry */ + res = dir_alloc(&dj, 1); /* Allocate an entry */ if (res == FR_OK) { - mem_set(dj.dir, 0, SZ_DIRE); /* Set volume label */ - mem_cpy(dj.dir, vn, 11); - dj.dir[DIR_Attr] = AM_VOL; - tm = GET_FATTIME(); - ST_DWORD(dj.dir + DIR_WrtTime, tm); - dj.fs->wflag = 1; - res = sync_fs(dj.fs); + mem_set(dj.dir, 0, SZDIRE); /* Clear the entry */ + if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ + dj.dir[XDIR_NumLabel] = slen / 2; + mem_cpy(dj.dir + XDIR_Label, dirvn, slen); + } else { + dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ + mem_cpy(dj.dir, dirvn, 11); + } + fs->wflag = 1; + res = sync_fs(fs); } } } } } - LEAVE_FF(dj.fs, res); + LEAVE_FF(fs, res); } #endif /* !_FS_READONLY */ @@ -4009,10 +4995,95 @@ FRESULT f_setlabel ( +#if _USE_EXPAND && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Allocate a Contiguous Blocks to the File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_expand ( + FIL* fp, /* Pointer to the file object */ + FSIZE_t fsz, /* File size to be expanded to */ + BYTE opt /* Operation mode 0:Find and prepare or 1:Find and allocate */ +) +{ + FRESULT res; + FATFS *fs; + DWORD val, clst, csz, stcl, scl, ncl, tcl; + + + res = validate(fp, &fs); /* Check validity of the object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); +#if _FS_EXFAT + if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ +#endif + csz = (DWORD)fs->csize * SS(fs); /* Cluster size */ + tcl = (DWORD)(fsz / csz) + ((fsz & (csz - 1)) ? 1 : 0); /* Number of clusters required */ + stcl = fs->last_clst; + if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2; + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ + if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ + if (scl == 1) res = FR_INT_ERR; + if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (res == FR_OK) { + if (opt) { + res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ + fs->last_clst = scl + tcl - 1; + } else { + fs->last_clst = scl - 1; /* Set suggested cluster to start next */ + } + } + } else +#endif + { + scl = clst = stcl; ncl = 0; + for (;;) { /* Find a contiguous cluster block */ + val = get_fat(&fp->obj, clst); + if (++clst >= fs->n_fatent) clst = 2; + if (val == 1) { res = FR_INT_ERR; break; } + if (val == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (val == 0) { /* Is it a free cluster? */ + if (++ncl == tcl) break; /* Break if a contiguous cluster block was found */ + } else { + scl = clst; ncl = 0; /* Not a free cluster */ + } + if (clst == stcl) { res = FR_DENIED; break; } /* All cluster scanned? */ + } + if (res == FR_OK) { + if (opt) { + for (clst = scl; tcl; clst++, tcl--) { /* Create a cluster chain on the FAT */ + val = (tcl == 1) ? 0xFFFFFFFF : clst + 1; + res = put_fat(fs, clst, val); + if (res != FR_OK) break; + fs->last_clst = clst; + } + } else { + fs->last_clst = scl - 1; /* Set suggested cluster to start next */ + } + } + } + + if (opt && res == FR_OK) { + fp->obj.sclust = scl; /* Update allocation information */ + fp->obj.objsize = fsz; + if (_FS_EXFAT) fp->obj.stat = 2; + fp->flag |= _FA_MODIFIED; + } + + LEAVE_FF(fs, res); +} + +#endif /* _USE_EXPAND && !_FS_READONLY */ + + + /*-----------------------------------------------------------------------*/ -/* Forward data to the stream directly (available on only tiny cfg) */ +/* Forward data to the stream directly */ /*-----------------------------------------------------------------------*/ -#if _USE_FORWARD && _FS_TINY +#if _USE_FORWARD FRESULT f_forward ( FIL* fp, /* Pointer to the file object */ @@ -4022,48 +5093,59 @@ FRESULT f_forward ( ) { FRESULT res; - DWORD remain, clst, sect; - UINT rcnt; - BYTE csect; + FATFS *fs; + DWORD clst, sect; + FSIZE_t remain; + UINT rcnt, csect; + const BYTE *dbuf; *bf = 0; /* Clear transfer byte counter */ + res = validate(fp, &fs); /* Check validity of the object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ - res = validate(fp); /* Check validity of the object */ - if (res != FR_OK) LEAVE_FF(fp->fs, res); - if (fp->err) /* Check error */ - LEAVE_FF(fp->fs, (FRESULT)fp->err); - if (!(fp->flag & FA_READ)) /* Check access mode */ - LEAVE_FF(fp->fs, FR_DENIED); - - remain = fp->fsize - fp->fptr; + remain = fp->obj.objsize - fp->fptr; if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ - for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */ + for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream goes busy */ fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { - csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ - if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ - if (!csect) { /* On the cluster boundary? */ + csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + if (csect == 0) { /* On the cluster boundary? */ clst = (fp->fptr == 0) ? /* On the top of the file? */ - fp->sclust : get_fat(fp->fs, fp->clust); - if (clst <= 1) ABORT(fp->fs, FR_INT_ERR); - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + fp->obj.sclust : get_fat(&fp->obj, fp->clust); + if (clst <= 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); fp->clust = clst; /* Update current cluster */ } } - sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */ - if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect = clust2sect(fs, fp->clust); /* Get current data sector */ + if (!sect) ABORT(fs, FR_INT_ERR); sect += csect; - if (move_window(fp->fs, sect) != FR_OK) /* Move sector window */ - ABORT(fp->fs, FR_DISK_ERR); - fp->dsect = sect; - rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */ - if (rcnt > btf) rcnt = btf; - rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt); - if (!rcnt) ABORT(fp->fs, FR_INT_ERR); +#if _FS_TINY + if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window to the file data */ + dbuf = fs->win; +#else + if (fp->sect != sect) { /* Fill sector cache with file data */ +#if !_FS_READONLY + if (fp->flag & _FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= ~_FA_DIRTY; + } +#endif + if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + } + dbuf = fp->buf; +#endif + fp->sect = sect; + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (rcnt > btf) rcnt = btf; /* Clip it by btr if needed */ + rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */ + if (!rcnt) ABORT(fs, FR_INT_ERR); } - LEAVE_FF(fp->fs, FR_OK); + LEAVE_FF(fs, FR_OK); } #endif /* _USE_FORWARD */ @@ -4100,9 +5182,9 @@ FRESULT f_mkfs ( /* Check mounted drive and clear work area */ if (sfd > 1) return FR_INVALID_PARAMETER; - vol = get_ldnumber(&path); + vol = get_ldnumber(&path); /* Get target volume */ if (vol < 0) return FR_INVALID_DRIVE; - fs = FatFs[vol]; + fs = FatFs[vol]; /* Check if the volume has work area */ if (!fs) return FR_NOT_ENABLED; fs->fs_type = 0; pdrv = LD2PD(vol); /* Physical drive */ @@ -4113,21 +5195,23 @@ FRESULT f_mkfs ( if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; #if _MAX_SS != _MIN_SS /* Get disk sector size */ - if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS || SS(fs) < _MIN_SS) + if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS || SS(fs) < _MIN_SS) { return FR_DISK_ERR; + } #endif if (_MULTI_PARTITION && part) { /* Get partition information from partition table in the MBR */ if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR; - if (LD_WORD(fs->win + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; + if (ld_word(fs->win + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; if (!tbl[4]) return FR_MKFS_ABORTED; /* No partition? */ - b_vol = LD_DWORD(tbl + 8); /* Volume start sector */ - n_vol = LD_DWORD(tbl + 12); /* Volume size */ + b_vol = ld_dword(tbl + 8); /* Volume start sector */ + n_vol = ld_dword(tbl + 12); /* Volume size */ } else { - /* Create a partition in this function */ - if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128) + /* Create a single-partition in this function */ + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128) { return FR_DISK_ERR; + } b_vol = (sfd) ? 0 : 63; /* Volume start sector */ n_vol -= b_vol; /* Volume size */ } @@ -4157,7 +5241,7 @@ FRESULT f_mkfs ( n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4; n_fat = (n_fat + SS(fs) - 1) / SS(fs); n_rsv = 1; - n_dir = (DWORD)N_ROOTDIR * SZ_DIRE / SS(fs); + n_dir = (DWORD)N_ROOTDIR * SZDIRE / SS(fs); } b_fat = b_vol + n_rsv; /* FAT area start sector */ b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */ @@ -4178,8 +5262,9 @@ FRESULT f_mkfs ( /* Determine number of clusters and final check of validity of the FAT sub-type */ n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au; if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16) - || (fmt == FS_FAT32 && n_clst < MIN_FAT32)) + || (fmt == FS_FAT32 && n_clst < MIN_FAT32)) { return FR_MKFS_ABORTED; + } /* Determine system ID in the partition table */ if (fmt == FS_FAT32) { @@ -4196,8 +5281,9 @@ FRESULT f_mkfs ( /* Update system ID in the partition table */ tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; tbl[4] = sys; - if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to teh MBR */ + if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) { /* Write it to teh MBR */ return FR_DISK_ERR; + } md = 0xF8; } else { if (sfd) { /* No partition table (SFD) */ @@ -4213,11 +5299,12 @@ FRESULT f_mkfs ( n = (b_vol + n_vol) / 63 / 255; tbl[6] = (BYTE)(n >> 2 | 63); /* Partition end sector */ tbl[7] = (BYTE)n; /* End cylinder */ - ST_DWORD(tbl + 8, 63); /* Partition start in LBA */ - ST_DWORD(tbl + 12, n_vol); /* Partition size in LBA */ - ST_WORD(fs->win + BS_55AA, 0xAA55); /* MBR signature */ - if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to the MBR */ + st_dword(tbl + 8, 63); /* Partition start in LBA */ + st_dword(tbl + 12, n_vol); /* Partition size in LBA */ + st_word(fs->win + BS_55AA, 0xAA55); /* MBR signature */ + if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) { /* Write it to the MBR */ return FR_DISK_ERR; + } md = 0xF8; } } @@ -4227,43 +5314,45 @@ FRESULT f_mkfs ( mem_set(tbl, 0, SS(fs)); mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */ i = SS(fs); /* Sector size */ - ST_WORD(tbl + BPB_BytsPerSec, i); + st_word(tbl + BPB_BytsPerSec, (WORD)i); tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */ - ST_WORD(tbl + BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */ + st_word(tbl + BPB_RsvdSecCnt, (WORD)n_rsv); /* Reserved sectors */ tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */ i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of root directory entries */ - ST_WORD(tbl + BPB_RootEntCnt, i); + st_word(tbl + BPB_RootEntCnt, (WORD)i); if (n_vol < 0x10000) { /* Number of total sectors */ - ST_WORD(tbl + BPB_TotSec16, n_vol); + st_word(tbl + BPB_TotSec16, (WORD)n_vol); } else { - ST_DWORD(tbl + BPB_TotSec32, n_vol); + st_dword(tbl + BPB_TotSec32, (WORD)n_vol); } tbl[BPB_Media] = md; /* Media descriptor */ - ST_WORD(tbl + BPB_SecPerTrk, 63); /* Number of sectors per track */ - ST_WORD(tbl + BPB_NumHeads, 255); /* Number of heads */ - ST_DWORD(tbl + BPB_HiddSec, b_vol); /* Hidden sectors */ + st_word(tbl + BPB_SecPerTrk, 63); /* Number of sectors per track */ + st_word(tbl + BPB_NumHeads, 255); /* Number of heads */ + st_dword(tbl + BPB_HiddSec, b_vol); /* Volume offset */ n = GET_FATTIME(); /* Use current time as VSN */ if (fmt == FS_FAT32) { - ST_DWORD(tbl + BS_VolID32, n); /* VSN */ - ST_DWORD(tbl + BPB_FATSz32, n_fat); /* Number of sectors per FAT */ - ST_DWORD(tbl + BPB_RootClus, 2); /* Root directory start cluster (2) */ - ST_WORD(tbl + BPB_FSInfo, 1); /* FSINFO record offset (VBR + 1) */ - ST_WORD(tbl + BPB_BkBootSec, 6); /* Backup boot record offset (VBR + 6) */ + st_dword(tbl + BS_VolID32, n); /* VSN */ + st_dword(tbl + BPB_FATSz32, n_fat); /* Number of sectors per FAT */ + st_dword(tbl + BPB_RootClus32, 2); /* Root directory start cluster (2) */ + st_word(tbl + BPB_FSInfo32, 1); /* FSINFO record offset (VBR + 1) */ + st_word(tbl + BPB_BkBootSec32, 6); /* Backup boot record offset (VBR + 6) */ tbl[BS_DrvNum32] = 0x80; /* Drive number */ tbl[BS_BootSig32] = 0x29; /* Extended boot signature */ mem_cpy(tbl + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ } else { - ST_DWORD(tbl + BS_VolID, n); /* VSN */ - ST_WORD(tbl + BPB_FATSz16, n_fat); /* Number of sectors per FAT */ + st_dword(tbl + BS_VolID, n); /* VSN */ + st_word(tbl + BPB_FATSz16, (WORD)n_fat); /* Number of sectors per FAT */ tbl[BS_DrvNum] = 0x80; /* Drive number */ tbl[BS_BootSig] = 0x29; /* Extended boot signature */ mem_cpy(tbl + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ } - ST_WORD(tbl + BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ - if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */ + st_word(tbl + BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ + if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) { /* Write it to the VBR sector */ return FR_DISK_ERR; - if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR + 6) */ + } + if (fmt == FS_FAT32) { /* Write it to the backup VBR if needed (VBR + 6) */ disk_write(pdrv, tbl, b_vol + 6, 1); + } /* Initialize FAT area */ wsect = b_fat; @@ -4272,27 +5361,30 @@ FRESULT f_mkfs ( n = md; /* Media descriptor byte */ if (fmt != FS_FAT32) { n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00; - ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT12/16) */ + st_dword(tbl + 0, n); /* Reserve cluster #0-1 (FAT12/16) */ } else { n |= 0xFFFFFF00; - ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT32) */ - ST_DWORD(tbl + 4, 0xFFFFFFFF); - ST_DWORD(tbl + 8, 0x0FFFFFFF); /* Reserve cluster #2 for root directory */ + st_dword(tbl + 0, n); /* Reserve cluster #0-1 (FAT32) */ + st_dword(tbl + 4, 0xFFFFFFFF); + st_dword(tbl + 8, 0x0FFFFFFF); /* Reserve cluster #2 for root directory */ } - if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) + if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) { return FR_DISK_ERR; + } mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */ for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */ - if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) + if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) { return FR_DISK_ERR; + } } } /* Initialize root directory */ i = (fmt == FS_FAT32) ? au : (UINT)n_dir; do { - if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) + if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) { return FR_DISK_ERR; + } } while (--i); #if _USE_TRIM /* Erase data area if needed */ @@ -4304,11 +5396,11 @@ FRESULT f_mkfs ( /* Create FSINFO if needed */ if (fmt == FS_FAT32) { - ST_DWORD(tbl + FSI_LeadSig, 0x41615252); - ST_DWORD(tbl + FSI_StrucSig, 0x61417272); - ST_DWORD(tbl + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ - ST_DWORD(tbl + FSI_Nxt_Free, 2); /* Last allocated cluster# */ - ST_WORD(tbl + BS_55AA, 0xAA55); + st_dword(tbl + FSI_LeadSig, 0x41615252); + st_dword(tbl + FSI_StrucSig, 0x61417272); + st_dword(tbl + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ + st_dword(tbl + FSI_Nxt_Free, 2); /* Last allocated cluster# */ + st_word(tbl + BS_55AA, 0xAA55); disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR + 1) */ disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR + 7) */ } @@ -4372,13 +5464,13 @@ FRESULT f_fdisk ( p[5] = e_hd; /* End head */ p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ p[7] = (BYTE)e_cyl; /* End cylinder */ - ST_DWORD(p + 8, s_part); /* Start sector in LBA */ - ST_DWORD(p + 12, sz_part); /* Partition size */ + st_dword(p + 8, s_part); /* Start sector in LBA */ + st_dword(p + 12, sz_part); /* Partition size */ /* Next partition */ b_cyl += p_cyl; } - ST_WORD(p, 0xAA55); + st_word(p, 0xAA55); /* Write it to the MBR */ return (disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? FR_DISK_ERR : FR_OK; @@ -4409,7 +5501,7 @@ TCHAR* f_gets ( while (n < len - 1) { /* Read characters until buffer gets filled */ -#if _USE_LFN && _LFN_UNICODE +#if _LFN_UNICODE #if _STRF_ENCODE == 3 /* Read a character in UTF-8 */ f_read(fp, s, 1, &rc); if (rc != 1) break; @@ -4492,13 +5584,14 @@ void putc_bfd ( int i; - if (_USE_STRFUNC == 2 && c == '\n') /* LF -> CRLF conversion */ + if (_USE_STRFUNC == 2 && c == '\n') { /* LF -> CRLF conversion */ putc_bfd(pb, '\r'); + } i = pb->idx; /* Buffer write index (-1:error) */ if (i < 0) return; -#if _USE_LFN && _LFN_UNICODE +#if _LFN_UNICODE #if _STRF_ENCODE == 3 /* Write a character in UTF-8 */ if (c < 0x80) { /* 7-bit */ pb->buf[i++] = (BYTE)c; @@ -4603,7 +5696,7 @@ int f_printf ( BYTE f, r; UINT nw, i, j, w; DWORD v; - TCHAR c, d, s[16], *p; + TCHAR c, d, str[32], *p; putbuff pb; @@ -4673,12 +5766,12 @@ int f_printf ( do { d = (TCHAR)(v % r); v /= r; if (d > 9) d += (c == 'x') ? 0x27 : 0x07; - s[i++] = d + '0'; - } while (v && i < sizeof s / sizeof s[0]); - if (f & 8) s[i++] = '-'; + str[i++] = d + '0'; + } while (v && i < sizeof str / sizeof str[0]); + if (f & 8) str[i++] = '-'; j = i; d = (f & 1) ? '0' : ' '; while (!(f & 2) && j++ < w) putc_bfd(&pb, d); - do putc_bfd(&pb, s[--i]); while (i); + do putc_bfd(&pb, str[--i]); while (i); while (j++ < w) putc_bfd(&pb, d); } From 86cede457f86eba311be0ede1a96fa60a3704d5a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:25:58 +0200 Subject: [PATCH 040/259] Update diskio.c --- source/arm9/source/fatfs/diskio.c | 48 ++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/source/arm9/source/fatfs/diskio.c b/source/arm9/source/fatfs/diskio.c index 9e379e4..1b2b83c 100644 --- a/source/arm9/source/fatfs/diskio.c +++ b/source/arm9/source/fatfs/diskio.c @@ -10,6 +10,9 @@ #include "diskio.h" /* FatFs lower layer API */ #include "sdmmc/sdmmc.h" +/* Definitions of physical drive number for each media */ +#define SDCARD 0 +//#define CTRNAND 1 /*-----------------------------------------------------------------------*/ /* Get Drive Status */ @@ -30,11 +33,21 @@ DSTATUS disk_status ( /*-----------------------------------------------------------------------*/ DSTATUS disk_initialize ( - __attribute__((unused)) BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { - sdmmc_sdcard_init(); + switch(pdrv) + { + case SDCARD: + sdmmc_sdcard_init(); + break; + #ifdef CTRNAND + case CTRNAND: + ctrNandInit(); + break; + #endif + } + return RES_OK; } @@ -45,18 +58,27 @@ DSTATUS disk_initialize ( /*-----------------------------------------------------------------------*/ DRESULT disk_read ( - __attribute__((unused)) BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE *buff, /* Data buffer to store read data */ DWORD sector, /* Sector address in LBA */ UINT count /* Number of sectors to read */ ) { - if (sdmmc_sdcard_readsectors(sector, count, buff)) { - return RES_PARERR; - } - - return RES_OK; + switch(pdrv) + { + case SDCARD: + if(sdmmc_sdcard_readsectors(sector, count, (BYTE *)buff)) + return RES_PARERR; + break; + #ifdef CTRNAND + case CTRNAND: + if(ctrNandRead(sector, count, (BYTE *)buff)) + return RES_PARERR; + break; + #endif + } + + return RES_OK; } @@ -67,18 +89,16 @@ DRESULT disk_read ( #if _USE_WRITE DRESULT disk_write ( - __attribute__((unused)) BYTE pdrv, /* Physical drive nmuber to identify the drive */ - const BYTE *buff, /* Data to be written */ + const BYTE *buff, /* Data to be written */ DWORD sector, /* Sector address in LBA */ UINT count /* Number of sectors to write */ ) { - if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) { - return RES_PARERR; - } + if(pdrv == SDCARD && sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) + return RES_PARERR; - return RES_OK; + return RES_OK; } #endif From ca08e4c2e1a424f013fda03474513366a0f107d4 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:26:24 +0200 Subject: [PATCH 041/259] Update 00readme.txt --- source/arm9/source/fatfs/00readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/arm9/source/fatfs/00readme.txt b/source/arm9/source/fatfs/00readme.txt index c46ac5f..bd04d18 100644 --- a/source/arm9/source/fatfs/00readme.txt +++ b/source/arm9/source/fatfs/00readme.txt @@ -1,4 +1,4 @@ -FatFs Module Source Files R0.11 +FatFs Module Source Files R0.12 FILES From 7d93203edd28e4b4f02bdf862a70fb684614ebab Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:26:52 +0200 Subject: [PATCH 042/259] Update and rename history.txt to 00history.txt --- .../fatfs/{history.txt => 00history.txt} | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) rename source/arm9/source/fatfs/{history.txt => 00history.txt} (88%) diff --git a/source/arm9/source/fatfs/history.txt b/source/arm9/source/fatfs/00history.txt similarity index 88% rename from source/arm9/source/fatfs/history.txt rename to source/arm9/source/fatfs/00history.txt index b101820..464850b 100644 --- a/source/arm9/source/fatfs/history.txt +++ b/source/arm9/source/fatfs/00history.txt @@ -3,73 +3,98 @@ ---------------------------------------------------------------------------- R0.00 (February 26, 2006) + Prototype. + R0.01 (April 29, 2006) + First stable version. + R0.02 (June 01, 2006) + Added FAT12 support. Removed unbuffered mode. Fixed a problem on small (<32M) partition. + R0.02a (June 10, 2006) + Added a configuration option (_FS_MINIMUM). + R0.03 (September 22, 2006) + Added f_rename(). Changed option _FS_MINIMUM to _FS_MINIMIZE. + R0.03a (December 11, 2006) + Improved cluster scan algorithm to write files fast. Fixed f_mkdir() creates incorrect directory on FAT32. + R0.04 (February 04, 2007) + Added f_mkfs(). Supported multiple drive system. Changed some interfaces for multiple drive system. Changed f_mountdrv() to f_mount(). + R0.04a (April 01, 2007) + Supported multiple partitions on a physical drive. Added a capability of extending file size to f_lseek(). Added minimization level 3. Fixed an endian sensitive code in f_mkfs(). + R0.04b (May 05, 2007) + Added a configuration option _USE_NTFLAG. Added FSINFO support. Fixed DBCS name can result FR_INVALID_NAME. Fixed short seek (<= csize) collapses the file object. + R0.05 (August 25, 2007) + Changed arguments of f_read(), f_write() and f_mkfs(). Fixed f_mkfs() on FAT32 creates incorrect FSINFO. Fixed f_mkdir() on FAT32 creates incorrect directory. + R0.05a (February 03, 2008) + Added f_truncate() and f_utime(). Fixed off by one error at FAT sub-type determination. Fixed btr in f_read() can be mistruncated. Fixed cached sector is not flushed when create and close without write. + R0.06 (April 01, 2008) + Added fputc(), fputs(), fprintf() and fgets(). Improved performance of f_lseek() on moving to the same or following cluster. + R0.07 (April 01, 2009) + Merged Tiny-FatFs as a configuration option. (_FS_TINY) Added long file name feature. (_USE_LFN) Added multiple code page feature. (_CODE_PAGE) @@ -80,12 +105,16 @@ R0.07 (April 01, 2009) Renamed string functions to avoid name collision. + R0.07a (April 14, 2009) + Septemberarated out OS dependent code on reentrant cfg. Added multiple sector size feature. + R0.07c (June 21, 2009) + Fixed f_unlink() can return FR_OK on error. Fixed wrong cache control in f_lseek(). Added relative path feature. @@ -93,7 +122,9 @@ R0.07c (June 21, 2009) Added proper case conversion to extended character. + R0.07e (November 03, 2009) + Septemberarated out configuration options from ff.h to ffconf.h. Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH. Fixed name matching error on the 13 character boundary. @@ -101,7 +132,9 @@ R0.07e (November 03, 2009) Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. + R0.08 (May 15, 2010) + Added a memory configuration option. (_USE_LFN = 3) Added file lock feature. (_FS_SHARE) Added fast seek feature. (_USE_FASTSEEK) @@ -110,36 +143,48 @@ R0.08 (May 15, 2010) String functions support UTF-8 encoding files on Unicode cfg. + R0.08a (August 16, 2010) + Added f_getcwd(). (_FS_RPATH = 2) Added sector erase feature. (_USE_ERASE) Moved file lock semaphore table from fs object to the bss. Fixed f_mkfs() creates wrong FAT32 volume. + R0.08b (January 15, 2011) + Fast seek feature is also applied to f_read() and f_write(). f_lseek() reports required table size on creating CLMP. Extended format syntax of f_printf(). Ignores duplicated directory separators in given path name. + R0.09 (September 06, 2011) + f_mkfs() supports multiple partition to complete the multiple partition feature. Added f_fdisk(). + R0.09a (August 27, 2012) + Changed f_open() and f_opendir() reject null object pointer to avoid crash. Changed option name _FS_SHARE to _FS_LOCK. Fixed assertion failure due to OS/2 EA on FAT12/16 volume. + R0.09b (January 24, 2013) + Added f_setlabel() and f_getlabel(). + R0.10 (October 02, 2013) + Added selection of character encoding on the file. (_STRF_ENCODE) Added f_closedir(). Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO) @@ -148,10 +193,12 @@ R0.10 (October 02, 2013) Improved write throughput of f_puts() and f_printf(). Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write(). Fixed f_write() can be truncated when the file size is close to 4GB. - Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect error code. + Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error. + R0.10a (January 15, 2014) + Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID) Added a configuration option of minimum sector size. (_MIN_SS) 2nd argument of f_rename() can have a drive number and it will be ignored. @@ -161,12 +208,16 @@ R0.10a (January 15, 2014) Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07) + R0.10b (May 19, 2014) + Fixed a hard error in the disk I/O layer can collapse the directory entry. Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07) + R0.10c (November 09, 2014) + Added a configuration option for the platforms without RTC. (_FS_NORTC) Changed option name _USE_ERASE to _USE_TRIM. Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b) @@ -174,7 +225,30 @@ R0.10c (November 09, 2014) Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08) + R0.11 (February 09, 2015) + Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND) Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c) Fixed _FS_NORTC option does not work properly. (appeared at R0.10c) + + + +R0.11a (September 05, 2015) + + Fixed wrong media change can lead a deadlock at thread-safe configuration. + Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE) + Removed some code pages actually not exist on the standard systems. (_CODE_PAGE) + Fixed errors in the case conversion teble of code page 437 and 850 (ff.c). + Fixed errors in the case conversion teble of Unicode (cc*.c). + + + +R0.12 (April 12, 2016) + + Added support of exFAT file system. (_FS_EXFAT) + Added f_expand(). (_USE_EXPAND) + Changed some members in FINFO structure and behavior of f_readdir(). + Added an option _USE_CHMOD and removed an option _WORD_ACCESS. + Fixed errors in the case conversion teble of Unicode (cc*.c). + From 71f168168d3ac3dd31a67aa47d944028b3dafc67 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:27:34 +0200 Subject: [PATCH 043/259] Update delay.h --- source/arm9/source/fatfs/sdmmc/delay.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/arm9/source/fatfs/sdmmc/delay.h b/source/arm9/source/fatfs/sdmmc/delay.h index d08c0cc..afad438 100644 --- a/source/arm9/source/fatfs/sdmmc/delay.h +++ b/source/arm9/source/fatfs/sdmmc/delay.h @@ -6,4 +6,4 @@ #include "common.h" -void waitcycles(u32 us); +void ioDelay(u32 us); From 8aa1ddee4934db24c201fe663cbc81077ce39494 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:27:52 +0200 Subject: [PATCH 044/259] Update delay.s --- source/arm9/source/fatfs/sdmmc/delay.s | 28 ++++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/source/arm9/source/fatfs/sdmmc/delay.s b/source/arm9/source/fatfs/sdmmc/delay.s index 3a2cfdf..b3baccd 100644 --- a/source/arm9/source/fatfs/sdmmc/delay.s +++ b/source/arm9/source/fatfs/sdmmc/delay.s @@ -1,15 +1,17 @@ +// Copyright 2014 Normmatt +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + .arm -.global waitcycles -.type waitcycles STT_FUNC +.global ioDelay +.type ioDelay STT_FUNC -@waitcycles ( u32 us ) -waitcycles: - PUSH {R0-R2,LR} - STR R0, [SP,#4] - waitcycles_loop: - LDR R3, [SP,#4] - SUBS R2, R3, #1 - STR R2, [SP,#4] - CMP R3, #0 - BNE waitcycles_loop - POP {R0-R2,PC} +@ioDelay ( u32 us ) +ioDelay: + ldr r1, =0x18000000 @ VRAM +1: + @ Loop doing uncached reads from VRAM to make loop timing more reliable + ldr r2, [r1] + subs r0, #1 + bgt 1b + bx lr From c6077228cb6b5359ae45f5f4058206b78e07dabb Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:28:13 +0200 Subject: [PATCH 045/259] Update sdmmc.c --- source/arm9/source/fatfs/sdmmc/sdmmc.c | 69 +++++++++++++++++--------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/source/arm9/source/fatfs/sdmmc/sdmmc.c b/source/arm9/source/fatfs/sdmmc/sdmmc.c index 6d12848..a5b5043 100644 --- a/source/arm9/source/fatfs/sdmmc/sdmmc.c +++ b/source/arm9/source/fatfs/sdmmc/sdmmc.c @@ -2,8 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common.h" - #include "sdmmc.h" #include "delay.h" @@ -196,22 +194,6 @@ u32 __attribute__((noinline)) sdmmc_nand_readsectors(u32 sector_no, u32 numsecto return geterror(&handleNAND); } -u32 __attribute__((noinline)) sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, vu8 *in) //experimental -{ - if (handleNAND.isSDHC == 0) - sector_no <<= 9; - inittarget(&handleNAND); - sdmmc_write16(REG_SDSTOP,0x100); - - sdmmc_write16(REG_SDBLKCOUNT,numsectors); - - handleNAND.data = in; - handleNAND.size = numsectors << 9; - sdmmc_send_command(&handleNAND,0x52C19,sector_no); - inittarget(&handleSD); - return geterror(&handleNAND); -} - static u32 calcSDSize(u8* csd, int type) { u32 result = 0; @@ -286,7 +268,7 @@ static void InitSD() static int Nand_Init() { inittarget(&handleNAND); - waitcycles(0xF000); + ioDelay(0xF000); sdmmc_send_command(&handleNAND,0,0); @@ -337,7 +319,7 @@ static int SD_Init() { inittarget(&handleSD); - waitcycles(1u << 18); //Card needs a little bit of time to be detected, it seems + ioDelay(1u << 18); //Card needs a little bit of time to be detected, it seems //If not inserted if (!(*((vu16*)0x1000601c) & TMIO_STAT0_SIGSTATE)) return -1; @@ -397,10 +379,51 @@ static int SD_Init() return 0; } -int sdmmc_sdcard_init() +void sdmmc_sdcard_init() { InitSD(); - int result = Nand_Init(); - return result | SD_Init(); + Nand_Init(); + SD_Init(); } +int sdmmc_get_cid(int isNand, uint32_t *info) +{ + struct mmcdevice *device; + if(isNand) + device = &handleNAND; + else + device = &handleSD; + + inittarget(device); + // use cmd7 to put sd card in standby mode + // CMD7 + { + sdmmc_send_command(device,0x10507,0); + //if((device->error & 0x4)) return -1; + } + + // get sd card info + // use cmd10 to read CID + { + sdmmc_send_command(device,0x1060A,device->initarg << 0x10); + //if((device->error & 0x4)) return -2; + + for( int i = 0; i < 4; ++i ) { + info[i] = device->ret[i]; + } + } + + // put sd card back to transfer mode + // CMD7 + { + sdmmc_send_command(device,0x10507,device->initarg << 0x10); + //if((device->error & 0x4)) return -3; + } + + if(isNand) + { + inittarget(&handleSD); + } + + return 0; +} From 2a5b59b4347905dcb8ed30a1542bc5d77c56cd53 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:28:56 +0200 Subject: [PATCH 046/259] Update sdmmc.h --- source/arm9/source/fatfs/sdmmc/sdmmc.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/arm9/source/fatfs/sdmmc/sdmmc.h b/source/arm9/source/fatfs/sdmmc/sdmmc.h index 66cee62..9d58a22 100644 --- a/source/arm9/source/fatfs/sdmmc/sdmmc.h +++ b/source/arm9/source/fatfs/sdmmc/sdmmc.h @@ -118,11 +118,12 @@ typedef struct mmcdevice { u32 res; } mmcdevice; -int sdmmc_sdcard_init(); +mmcdevice *getMMCDevice(int drive); + +void sdmmc_sdcard_init(); u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out); u32 sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in); -mmcdevice *getMMCDevice(int drive); u32 sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out); -u32 sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, vu8 *in); +int sdmmc_get_cid( int isNand, uint32_t *info); From 91b8ba067b51b29c8533df04544c53518b4efb69 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 22 May 2016 14:29:51 +0200 Subject: [PATCH 047/259] Create ccsbcs.c --- source/arm9/source/fatfs/option/ccsbcs.c | 388 +++++++++++++++++++++++ 1 file changed, 388 insertions(+) create mode 100644 source/arm9/source/fatfs/option/ccsbcs.c diff --git a/source/arm9/source/fatfs/option/ccsbcs.c b/source/arm9/source/fatfs/option/ccsbcs.c new file mode 100644 index 0000000..e2762dc --- /dev/null +++ b/source/arm9/source/fatfs/option/ccsbcs.c @@ -0,0 +1,388 @@ +/*------------------------------------------------------------------------*/ +/* Unicode - Local code bidirectional converter (C)ChaN, 2015 */ +/* (SBCS code pages) */ +/*------------------------------------------------------------------------*/ +/* 437 U.S. +/ 720 Arabic +/ 737 Greek +/ 771 KBL +/ 775 Baltic +/ 850 Latin 1 +/ 852 Latin 2 +/ 855 Cyrillic +/ 857 Turkish +/ 860 Portuguese +/ 861 Icelandic +/ 862 Hebrew +/ 863 Canadian French +/ 864 Arabic +/ 865 Nordic +/ 866 Russian +/ 869 Greek 2 +*/ + +#include "../ff.h" + + +#if _CODE_PAGE == 437 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 720 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */ + 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, + 0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 737 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */ + 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, + 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, + 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E, + 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 771 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */ + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 775 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */ + 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, + 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D, + 0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019, + 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 850 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 852 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, + 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4, + 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 855 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */ + 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, + 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, + 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580, + 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116, + 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 857 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 860 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2, + 0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 861 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 862 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */ + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 863 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0, + 0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192, + 0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 864 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */ + 0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518, + 0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000, + 0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5, + 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F, + 0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9, + 0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9, + 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1, + 0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000 +}; + +#elif _CODE_PAGE == 865 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 866 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */ + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 869 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */ + 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, + 0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF, + 0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3, + 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580, + 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384, + 0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0 +}; + +#endif + + +#if !_TBLDEF || !_USE_LFN +#error This file is not needed at current configuration. Remove from the project. +#endif + + + + +WCHAR ff_convert ( /* Converted character, Returns zero on error */ + WCHAR chr, /* Character code to be converted */ + UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */ +) +{ + WCHAR c; + + + if (chr < 0x80) { /* ASCII */ + c = chr; + + } else { + if (dir) { /* OEM code to Unicode */ + c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80]; + + } else { /* Unicode to OEM code */ + for (c = 0; c < 0x80; c++) { + if (chr == Tbl[c]) break; + } + c = (c + 0x80) & 0xFF; + } + } + + return c; +} + + + +WCHAR ff_wtoupper ( /* Returns upper converted character */ + WCHAR chr /* Unicode character to be upper converted (BMP only) */ +) +{ + /* Compressed upper conversion table */ + static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */ + /* Basic Latin */ + 0x0061,0x031A, + /* Latin-1 Supplement */ + 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, + /* Latin Extended-A */ + 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, + /* Latin Extended-B */ + 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, + 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, + 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, + /* IPA Extensions */ + 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, + /* Greek, Coptic */ + 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, + 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, + 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, + /* Cyrillic */ + 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, + /* Armenian */ + 0x0561,0x0426, + + 0x0000 + }; + static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */ + /* Phonetic Extensions */ + 0x1D7D,0x0001,0x2C63, + /* Latin Extended Additional */ + 0x1E00,0x0196, 0x1EA0,0x015A, + /* Greek Extended */ + 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, + 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, + 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, + 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, + 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF2,0x0001,0x1FFC, + /* Letterlike Symbols */ + 0x214E,0x0001,0x2132, + /* Number forms */ + 0x2170,0x0210, 0x2184,0x0001,0x2183, + /* Enclosed Alphanumerics */ + 0x24D0,0x051A, 0x2C30,0x042F, + /* Latin Extended-C */ + 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, + /* Coptic */ + 0x2C80,0x0164, + /* Georgian Supplement */ + 0x2D00,0x0826, + /* Full-width */ + 0xFF41,0x031A, + + 0x0000 + }; + const WCHAR *p; + WCHAR bc, nc, cmd; + + + p = chr < 0x1000 ? cvt1 : cvt2; + for (;;) { + bc = *p++; /* Get block base */ + if (!bc || chr < bc) break; + nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ + if (chr < bc + nc) { /* In the block? */ + switch (cmd) { + case 0: chr = p[chr - bc]; break; /* Table conversion */ + case 1: chr -= (chr - bc) & 1; break; /* Case pairs */ + case 2: chr -= 16; break; /* Shift -16 */ + case 3: chr -= 32; break; /* Shift -32 */ + case 4: chr -= 48; break; /* Shift -48 */ + case 5: chr -= 26; break; /* Shift -26 */ + case 6: chr += 8; break; /* Shift +8 */ + case 7: chr -= 80; break; /* Shift -80 */ + case 8: chr -= 0x1C60; break; /* Shift -0x1C60 */ + } + break; + } + if (!cmd) p += nc; + } + + return chr; +} + From 9860b23c0c0549483f2f545a70f1913b26ee4a41 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 25 May 2016 00:23:22 +0200 Subject: [PATCH 048/259] Create anim.h --- source/anim.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 source/anim.h diff --git a/source/anim.h b/source/anim.h new file mode 100644 index 0000000..1c793e5 --- /dev/null +++ b/source/anim.h @@ -0,0 +1,33 @@ +#ifndef _anim_h_ +#define _anim_h_ + +#include "config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int timer; + int active; + + u8 bgTop1[3]; + u8 bgTop2[3]; + u8 bgBot[3]; + u8 highlight[4]; + u8 borders[4]; + u8 fntDef[4]; + u8 fntSel[4]; +} anim_state_s; + +anim_state_s* anim; + +void animInit(); +void animSetup(); +void incrementAnimTime(); + +#ifdef __cplusplus +} +#endif + +#endif From 3daabc7c077eb38811a2ff80e6212c9561175792 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 25 May 2016 00:23:45 +0200 Subject: [PATCH 049/259] Create anim.c --- source/anim.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 source/anim.c diff --git a/source/anim.c b/source/anim.c new file mode 100644 index 0000000..de3a521 --- /dev/null +++ b/source/anim.c @@ -0,0 +1,146 @@ +#include "anim.h" + +#ifdef ARM9 +#include "memory.h" +#endif + +void animInit() +{ +#ifdef ARM9 + anim = (anim_state_s*)PTR_ANIM; +#else + anim = malloc(sizeof(anim_state_s)); +#endif + + anim->timer = 0; + anim->active = 0; +} + +void animSetup() +{ + memcpy(anim->bgTop1, config->bgTop1, sizeof(u8[3])); + memcpy(anim->bgTop2, config->bgTop2, sizeof(u8[3])); + memcpy(anim->bgBot, config->bgBot, sizeof(u8[3])); + memcpy(anim->highlight, config->highlight, sizeof(u8[4])); + memcpy(anim->borders, config->borders, sizeof(u8[4])); + memcpy(anim->fntDef, config->fntDef, sizeof(u8[4])); + memcpy(anim->fntSel, config->fntSel, sizeof(u8[4])); + + if ( config->bgTop1AnimTime > 0 || config->bgTop2AnimTime > 0 || config->bgBotAnimTime > 0 + || config->highlightAnimTime > 0 || config->bordersAnimTime > 0 + || config->fntDefAnimTime > 0 || config->fntSelAnimTime > 0 + || config->globalFadeInTime > 0 || config->globalFadeInTimeStart != 0 ) + { + anim->active = 1; + incrementAnimTime(); + } +} + +float computeMerge(int elapsedTime, int animTime, int animStart) +{ + int curTime = (elapsedTime+animStart) % (2*animTime); + int animStep = (curTime/animTime == 0) ? (curTime%animTime) : (animTime-curTime%animTime-1); + return (float)animStep / (float)animTime; +} + +void setMergedColor(float mergeVal, u8 color1[3], u8 color2[3], u8 finalColor[3]) +{ + float oneMinusMerge = 1.0f - mergeVal; + finalColor[0] = (u8)(oneMinusMerge*color1[0]+mergeVal*color2[0]); + finalColor[1] = (u8)(oneMinusMerge*color1[1]+mergeVal*color2[1]); + finalColor[2] = (u8)(oneMinusMerge*color1[2]+mergeVal*color2[2]); +} + +void setMergedColorAlpha(float mergeVal, u8 color1[4], u8 color2[4], u8 finalColor[4]) +{ + float oneMinusMerge = 1.0f - mergeVal; + finalColor[0] = (u8)(oneMinusMerge*color1[0]+mergeVal*color2[0]); + finalColor[1] = (u8)(oneMinusMerge*color1[1]+mergeVal*color2[1]); + finalColor[2] = (u8)(oneMinusMerge*color1[2]+mergeVal*color2[2]); + finalColor[3] = (u8)(oneMinusMerge*color1[3]+mergeVal*color2[3]); +} + +void incrementAnimTime() +{ + if (!anim->active) + return; + + if ( config->bgTop1AnimTime > 0 ) + { + float merge = computeMerge(anim->timer, config->bgTop1AnimTime, config->bgTop1AnimTimeStart); + setMergedColor(merge, config->bgTop1, config->bgTop1AnimColor, anim->bgTop1); + } + + if ( config->bgTop2AnimTime > 0 ) + { + float merge = computeMerge(anim->timer, config->bgTop2AnimTime, config->bgTop2AnimTimeStart); + setMergedColor(merge, config->bgTop2, config->bgTop2AnimColor, anim->bgTop2); + } + + if ( config->bgBotAnimTime > 0 ) + { + float merge = computeMerge(anim->timer, config->bgBotAnimTime, config->bgBotAnimTimeStart); + setMergedColor(merge, config->bgBot, config->bgBotAnimColor, anim->bgBot); + } + + if ( config->highlightAnimTime > 0 ) + { + float merge = computeMerge(anim->timer, config->highlightAnimTime, config->highlightAnimTimeStart); + setMergedColorAlpha(merge, config->highlight, config->highlightAnimColor, anim->highlight); + } + else if ( anim->timer > config->globalFadeInTimeStart ) + memcpy(anim->highlight, config->highlight, sizeof(u8[4])); + + if ( config->bordersAnimTime > 0 ) + { + float merge = computeMerge(anim->timer, config->bordersAnimTime, config->bordersAnimTimeStart); + setMergedColorAlpha(merge, config->borders, config->bordersAnimColor, anim->borders); + } + else if ( anim->timer > config->globalFadeInTimeStart ) + memcpy(anim->borders, config->borders, sizeof(u8[4])); + + if ( config->fntDefAnimTime > 0 ) + { + float merge = computeMerge(anim->timer, config->fntDefAnimTime, config->fntDefAnimTimeStart); + setMergedColorAlpha(merge, config->fntDef, config->fntDefAnimColor, anim->fntDef); + } + else if ( anim->timer > config->globalFadeInTimeStart ) + memcpy(anim->fntDef, config->fntDef, sizeof(u8[4])); + + if ( config->fntSelAnimTime > 0 ) + { + float merge = computeMerge(anim->timer, config->fntSelAnimTime, config->fntSelAnimTimeStart); + setMergedColorAlpha(merge, config->fntSel, config->fntSelAnimColor, anim->fntSel); + } + else if ( anim->timer > config->globalFadeInTimeStart ) + memcpy(anim->fntSel, config->fntSel, sizeof(u8[4])); + + if ( anim->timer >= config->globalFadeInTimeStart ) + { + int fadeInTime = anim->timer - config->globalFadeInTimeStart; + if ( fadeInTime <= config->globalFadeInTime ) + { + float fadeIn = (config->globalFadeInTime > 0) ? (float)fadeInTime / (float)config->globalFadeInTime : 1.f; + + anim->highlight[3] = (u8)(fadeIn*(float)anim->highlight[3]); + anim->borders[3] = (u8)(fadeIn*(float)anim->borders[3]); + anim->fntDef[3] = (u8)(fadeIn*(float)anim->fntDef[3]); + anim->fntSel[3] = (u8)(fadeIn*(float)anim->fntSel[3]); + + if ( fadeInTime == config->globalFadeInTime && config->bgTop1AnimTime == 0 + && config->bgTop2AnimTime == 0 && config->bgBotAnimTime == 0 + && config->highlightAnimTime == 0 && config->bordersAnimTime == 0 + && config->fntDefAnimTime == 0 && config->fntSelAnimTime == 0 ) + anim->active = 0; + } + } + else + { + anim->highlight[3] = 0x00; + anim->borders[3] = 0x00; + anim->fntDef[3] = 0x00; + anim->fntSel[3] = 0x00; + } + + anim->timer++; +} From 25dc26b2d055f98c39bed69ba60e2c92ab490028 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 25 May 2016 00:24:29 +0200 Subject: [PATCH 050/259] Update config.c --- source/config.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 2 deletions(-) diff --git a/source/config.c b/source/config.c index 5f135c2..452a5fe 100644 --- a/source/config.c +++ b/source/config.c @@ -43,6 +43,49 @@ void setColorAlpha(u8 *cfgColor, const char *color) { } } +int setAnimTimes(int* animTime, int* animStart, char *item) +{ + int sep1Ind = 0; + while (item[sep1Ind] != ':') + { + if (item[sep1Ind] == '\0') + return -1; + sep1Ind++; + } + + item[sep1Ind] = '\0'; + *animTime = atoi(item); + + item = &item[sep1Ind+1]; + int sep2Ind = 0; + while (item[sep2Ind] != ':') + sep2Ind++; + + if ( item[sep2Ind] == '\0' ) + sep2Ind = -sep1Ind-3; + else + item[sep2Ind] = '\0'; + *animStart = atoi(item); + + return sep1Ind+sep2Ind+2; +} + +void setAnimWithColor(int* animTime, int* animStart, u8 *cfgColor, char *item) +{ + int colorInd = setAnimTimes(animTime, animStart, item); + if (colorInd < 2) + return; + setColor(cfgColor, &item[colorInd]); +} + +void setAnimWithColorAlpha(int* animTime, int* animStart, u8 *cfgColor, char *item) +{ + int colorInd = setAnimTimes(animTime, animStart, item); + if (colorInd < 2) + return; + setColorAlpha(cfgColor, &item[colorInd]); +} + void readStrAsHexData(const char *dataAsStr, char *data, int* dataSize) { *dataSize = strlen(dataAsStr)/2; for (int i = 0; i < *dataSize; i++) @@ -154,7 +197,26 @@ static int handler(void *user, const char *section, const char *name, } else if (MATCH("theme", "bgImgBot")) { strncpy(config->bgImgBot, item, 128); } - + + // theme animation + else if (MATCH("theme", "bgTop1Anim")) { + setAnimWithColor(&config->bgTop1AnimTime, &config->bgTop1AnimTimeStart, config->bgTop1AnimColor, item); + } else if (MATCH("theme", "bgTop2Anim")) { + setAnimWithColor(&config->bgTop2AnimTime, &config->bgTop2AnimTimeStart, config->bgTop2AnimColor, item); + } else if (MATCH("theme", "bgBottomAnim")) { + setAnimWithColor(&config->bgBotAnimTime, &config->bgBotAnimTimeStart, config->bgBotAnimColor, item); + } else if (MATCH("theme", "highlightAnim")) { + setAnimWithColorAlpha(&config->highlightAnimTime, &config->highlightAnimTimeStart, config->highlightAnimColor, item); + } else if (MATCH("theme", "bordersAnim")) { + setAnimWithColorAlpha(&config->bordersAnimTime, &config->bordersAnimTimeStart, config->bordersAnimColor, item); + } else if (MATCH("theme", "font1Anim")) { + setAnimWithColorAlpha(&config->fntDefAnimTime, &config->fntDefAnimTimeStart, config->fntDefAnimColor, item); + } else if (MATCH("theme", "font2Anim")) { + setAnimWithColorAlpha(&config->fntSelAnimTime, &config->fntSelAnimTimeStart, config->fntSelAnimColor, item); + } else if (MATCH("theme", "globalFadeIn")) { + setAnimTimes(&config->globalFadeInTime, &config->globalFadeInTimeStart, item); + } + // entries else if (MATCH("entry", "title")) { strncpy(config->entries[config->count].title, item, 64); @@ -213,6 +275,15 @@ void configThemeInit() { memcpy(config->borders, (u8[4]) {0xff, 0xff, 0xff, 0xff}, sizeof(u8[4])); memcpy(config->fntDef, (u8[4]) {0xff, 0xff, 0xff, 0xff}, sizeof(u8[4])); memcpy(config->fntSel, (u8[4]) {0x00, 0x00, 0x00, 0xff}, sizeof(u8[4])); + config->bgTop1AnimTime = 0; + config->bgTop2AnimTime = 0; + config->bgBotAnimTime = 0; + config->highlightAnimTime = 0; + config->bordersAnimTime = 0; + config->fntDefAnimTime = 0; + config->fntSelAnimTime = 0; + config->globalFadeInTime = 0; + config->globalFadeInTimeStart = 0; } int configInit() { @@ -256,7 +327,9 @@ int configInit() { } } - memcpy(fontDefault.color, config->fntDef, sizeof(u8[4])); + // Fix for fade in effect first frame + fontDefault.color[3] = 0x00; + loadBg(GFX_TOP); loadBg(GFX_BOTTOM); @@ -322,30 +395,103 @@ void configSave() { // theme section size += snprintf(cfg+size, 256, "[theme];\n"); + size += snprintf(cfg+size, 256, "bgTop1=%02X%02X%02X;\n", config->bgTop1[0], config->bgTop1[1], config->bgTop1[2]); + if ( config->bgTop1AnimTime > 0 ) + { + size += snprintf(cfg+size, 256, "bgTop1Anim=%i:%i:%02X%02X%02X;\n", config->bgTop1AnimTime, config->bgTop1AnimTimeStart, + config->bgTop1AnimColor[0], config->bgTop1AnimColor[1], config->bgTop1AnimColor[2]); + } + size += snprintf(cfg+size, 256, "bgTop2=%02X%02X%02X;\n", config->bgTop2[0], config->bgTop2[1], config->bgTop2[2]); + if ( config->bgTop2AnimTime > 0 ) + { + size += snprintf(cfg+size, 256, "bgTop2Anim=%i:%i:%02X%02X%02X;\n", config->bgTop2AnimTime, config->bgTop2AnimTimeStart, + config->bgTop2AnimColor[0], config->bgTop2AnimColor[1], config->bgTop2AnimColor[2]); + } + size += snprintf(cfg+size, 256, "bgBottom=%02X%02X%02X;\n", config->bgBot[0], config->bgBot[1], config->bgBot[2]); + if ( config->bgBotAnimTime > 0 ) + { + size += snprintf(cfg+size, 256, "bgBottomAnim=%i:%i:%02X%02X%02X;\n", config->bgBotAnimTime, config->bgBotAnimTimeStart, + config->bgBotAnimColor[0], config->bgBotAnimColor[1], config->bgBotAnimColor[2]); + } if ( config->highlight[3] < 0xFF ) size += snprintf(cfg+size, 256, "highlight=%02X%02X%02X%02X;\n", config->highlight[0], config->highlight[1], config->highlight[2], config->highlight[3]); else size += snprintf(cfg+size, 256, "highlight=%02X%02X%02X;\n", config->highlight[0], config->highlight[1], config->highlight[2]); + if ( config->highlightAnimTime > 0 ) + { + if ( config->highlightAnimColor[3] < 0xFF ) + { + size += snprintf(cfg+size, 256, "highlightAnim=%i:%i:%02X%02X%02X%02X;\n", config->highlightAnimTime, config->highlightAnimTimeStart, + config->highlightAnimColor[0], config->highlightAnimColor[1], config->highlightAnimColor[2], config->highlightAnimColor[3]); + } + else + { + size += snprintf(cfg+size, 256, "highlightAnim=%i:%i:%02X%02X%02X;\n", config->highlightAnimTime, config->highlightAnimTimeStart, + config->highlightAnimColor[0], config->highlightAnimColor[1], config->highlightAnimColor[2]); + } + } if ( config->borders[3] < 0xFF ) size += snprintf(cfg+size, 256, "borders=%02X%02X%02X%02X;\n", config->borders[0], config->borders[1], config->borders[2], config->borders[3]); else size += snprintf(cfg+size, 256, "borders=%02X%02X%02X;\n", config->borders[0], config->borders[1], config->borders[2]); + if ( config->bordersAnimTime > 0 ) + { + if ( config->highlightAnimColor[3] < 0xFF ) + { + size += snprintf(cfg+size, 256, "bordersAnim=%i:%i:%02X%02X%02X%02X;\n", config->bordersAnimTime, config->bordersAnimTimeStart, + config->bordersAnimColor[0], config->bordersAnimColor[1], config->bordersAnimColor[2], config->bordersAnimColor[3]); + } + else + { + size += snprintf(cfg+size, 256, "bordersAnim=%i:%i:%02X%02X%02X;\n", config->bordersAnimTime, config->bordersAnimTimeStart, + config->bordersAnimColor[0], config->bordersAnimColor[1], config->bordersAnimColor[2]); + } + } if ( config->fntDef[3] < 0xFF ) size += snprintf(cfg+size, 256, "font1=%02X%02X%02X%02X;\n", config->fntDef[0], config->fntDef[1], config->fntDef[2], config->fntDef[3]); else size += snprintf(cfg+size, 256, "font1=%02X%02X%02X;\n", config->fntDef[0], config->fntDef[1], config->fntDef[2]); + if ( config->fntDefAnimTime > 0 ) + { + if ( config->fntDefAnimColor[3] < 0xFF ) + { + size += snprintf(cfg+size, 256, "font1Anim=%i:%i:%02X%02X%02X%02X;\n", config->fntDefAnimTime, config->fntDefAnimTimeStart, + config->fntDefAnimColor[0], config->fntDefAnimColor[1], config->fntDefAnimColor[2], config->fntDefAnimColor[3]); + } + else + { + size += snprintf(cfg+size, 256, "font1Anim=%i:%i:%02X%02X%02X;\n", config->fntDefAnimTime, config->fntDefAnimTimeStart, + config->fntDefAnimColor[0], config->fntDefAnimColor[1], config->fntDefAnimColor[2]); + } + } if ( config->fntSel[3] < 0xFF ) size += snprintf(cfg+size, 256, "font2=%02X%02X%02X%02X;\n", config->fntSel[0], config->fntSel[1], config->fntSel[2], config->fntSel[3]); else size += snprintf(cfg+size, 256, "font2=%02X%02X%02X;\n", config->fntSel[0], config->fntSel[1], config->fntSel[2]); + if ( config->fntSelAnimTime > 0 ) + { + if ( config->fntDefAnimColor[3] < 0xFF ) + { + size += snprintf(cfg+size, 256, "font2Anim=%i:%i:%02X%02X%02X%02X;\n", config->fntSelAnimTime, config->fntSelAnimTimeStart, + config->fntSelAnimColor[0], config->fntSelAnimColor[1], config->fntSelAnimColor[2], config->fntSelAnimColor[3]); + } + else + { + size += snprintf(cfg+size, 256, "font2Anim=%i:%i:%02X%02X%02X;\n", config->fntDefAnimTime, config->fntSelAnimTimeStart, + config->fntSelAnimColor[0], config->fntSelAnimColor[1], config->fntSelAnimColor[2]); + } + } + if ( config->globalFadeInTime > 0 ) + size += snprintf(cfg+size, 256, "globalFadeIn=%i:%i;\n", config->globalFadeInTime, config->globalFadeInTimeStart); + size += snprintf(cfg+size, 256, "bgImgTop=%s;\n", config->bgImgTop); size += snprintf(cfg+size, 256, "bgImgBot=%s;\n\n", config->bgImgBot); From f4937a80d3fb0d10364f22240525b61b471eb674 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 25 May 2016 00:24:46 +0200 Subject: [PATCH 051/259] Update config.h --- source/config.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/source/config.h b/source/config.h index 081bbef..ce4404c 100644 --- a/source/config.h +++ b/source/config.h @@ -40,6 +40,7 @@ typedef struct { int recovery; int count; boot_entry_s entries[CONFIG_MAX_ENTRIES]; + u8 bgTop1[3]; u8 bgTop2[3]; u8 bgBot[3]; @@ -47,6 +48,34 @@ typedef struct { u8 borders[4]; u8 fntDef[4]; u8 fntSel[4]; + + u8 bgTop1AnimColor[3]; + u8 bgTop2AnimColor[3]; + u8 bgBotAnimColor[3]; + u8 highlightAnimColor[4]; + u8 bordersAnimColor[4]; + u8 fntDefAnimColor[4]; + u8 fntSelAnimColor[4]; + + int bgTop1AnimTime; + int bgTop2AnimTime; + int bgBotAnimTime; + int highlightAnimTime; + int bordersAnimTime; + int fntDefAnimTime; + int fntSelAnimTime; + + int bgTop1AnimTimeStart; + int bgTop2AnimTimeStart; + int bgBotAnimTimeStart; + int highlightAnimTimeStart; + int bordersAnimTimeStart; + int fntDefAnimTimeStart; + int fntSelAnimTimeStart; + + int globalFadeInTime; + int globalFadeInTimeStart; + char bgImgTop[128]; char bgImgBot[128]; bool imgError; From 0e660e57c502407614981d29f3daf3218186e20e Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 25 May 2016 00:26:00 +0200 Subject: [PATCH 052/259] Update gfx.c --- source/gfx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/gfx.c b/source/gfx.c index 410d2a3..d6b12df 100644 --- a/source/gfx.c +++ b/source/gfx.c @@ -13,12 +13,13 @@ #include #include "gfx.h" #include "text.h" +#include "anim.h" #ifdef ARM9 u8 *gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16 *width, u16 *height) { if (screen == GFX_TOP) { - if (width) *width = 240; + if (width) *width = 240; if (height) *height = 400; return PTR_TOP_SCREEN_BUF; } else { @@ -247,4 +248,5 @@ void gfxSwap() { gfxSwapBuffers(); gspWaitForVBlank(); #endif + incrementAnimTime(); } From 669cc6da5d60c09fa4071a2d26b13b3d82dce484 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 25 May 2016 00:26:42 +0200 Subject: [PATCH 053/259] Update main.c --- source/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/main.c b/source/main.c index 82a9770..f5b7043 100644 --- a/source/main.c +++ b/source/main.c @@ -2,6 +2,7 @@ #include #include #include "config.h" +#include "anim.h" #include "utility.h" #include "menu.h" @@ -77,12 +78,15 @@ int main() { if (!boot_app_enabled) { // fix SOC_Initialize #endif + animInit(); if (configInit() != 0 || config->count <= 0) { // recovery + animSetup(); while (aptMainLoop()) { if (menu_more() == 0) break; } } else { + animSetup(); while (aptMainLoop()) { if (menu_boot() == 0) break; From 7b83f41c1f791122f6cfbfc32f63d7100b721683 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 25 May 2016 00:27:12 +0200 Subject: [PATCH 054/259] Update memory.h --- source/memory.h | 1 + 1 file changed, 1 insertion(+) diff --git a/source/memory.h b/source/memory.h index 7ad68fc..d650169 100644 --- a/source/memory.h +++ b/source/memory.h @@ -13,6 +13,7 @@ #define PTR_BOT_BG (u8*)(0x25046500) #define PTR_CFG (u8*)(0x25200000) #define PTR_CFG_TMP (u8*)(0x25230000) +#define PTR_ANIM (u8*)(0x25240000) #define PTR_PICKER (u8*)(0x25210000) #define PTR_PICKER_FILE (u8*)(0x25220000) From c4eeed590df33983043d01abec27d93f43515e97 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 25 May 2016 00:27:45 +0200 Subject: [PATCH 055/259] Update menu.c --- source/menu.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/source/menu.c b/source/menu.c index 2125a5f..7784f15 100644 --- a/source/menu.c +++ b/source/menu.c @@ -7,6 +7,7 @@ #include #include #include "gfx.h" +#include "anim.h" #include "config.h" #include "menu.h" @@ -15,15 +16,15 @@ void drawBg() { memcpy(gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), config->bgImgTopBuff, (size_t) config->bgImgTopSize); } else { - gfxClearTop(config->bgTop1, config->bgTop2); + gfxClearTop(anim->bgTop1, anim->bgTop2); } if (!config->imgErrorBot) { memcpy(gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), config->bgImgBotBuff, (size_t) config->bgImgBotSize); } else { - gfxClearBot(config->bgBot); + gfxClearBot(anim->bgBot); } - drawRectColor(GFX_TOP, GFX_LEFT, MENU_MIN_X, MENU_MIN_Y - 20, MENU_MAX_X, MENU_MAX_Y, config->borders); + drawRectColor(GFX_TOP, GFX_LEFT, MENU_MIN_X, MENU_MIN_Y - 20, MENU_MAX_X, MENU_MAX_Y, anim->borders); } void drawTitle(const char *format, ...) { @@ -46,13 +47,13 @@ void drawItem(bool selected, int y, const char *format, ...) { va_end(argp); if (selected) { - gfxDrawRectangle(GFX_TOP, GFX_LEFT, config->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); + gfxDrawRectangle(GFX_TOP, GFX_LEFT, anim->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); } - memcpy(fontDefault.color, selected ? config->fntSel : config->fntDef, sizeof(u8[4])); + memcpy(fontDefault.color, selected ? anim->fntSel : anim->fntDef, sizeof(u8[4])); gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, msg, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); - memcpy(fontDefault.color, config->fntDef, sizeof(u8[4])); + memcpy(fontDefault.color, anim->fntDef, sizeof(u8[4])); } void drawItemN(bool selected, int maxChar, int y, const char *format, ...) { @@ -64,13 +65,13 @@ void drawItemN(bool selected, int maxChar, int y, const char *format, ...) { va_end(argp); if (selected) { - gfxDrawRectangle(GFX_TOP, GFX_LEFT, config->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); + gfxDrawRectangle(GFX_TOP, GFX_LEFT, anim->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); } - memcpy(fontDefault.color, selected ? config->fntSel : config->fntDef, sizeof(u8[4])); + memcpy(fontDefault.color, selected ? anim->fntSel : anim->fntDef, sizeof(u8[4])); gfxDrawTextN(GFX_TOP, GFX_LEFT, &fontDefault, msg, maxChar, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); - memcpy(fontDefault.color, config->fntDef, sizeof(u8[4])); + memcpy(fontDefault.color, anim->fntDef, sizeof(u8[4])); } void drawInfo(const char *format, ...) { From 5f0af1a00d76a9f466492c669dd4715ccf5896b0 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 1 Jun 2016 23:12:04 +0200 Subject: [PATCH 056/259] Update anim.c --- source/anim.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source/anim.c b/source/anim.c index de3a521..1e8949e 100644 --- a/source/anim.c +++ b/source/anim.c @@ -29,7 +29,7 @@ void animSetup() if ( config->bgTop1AnimTime > 0 || config->bgTop2AnimTime > 0 || config->bgBotAnimTime > 0 || config->highlightAnimTime > 0 || config->bordersAnimTime > 0 || config->fntDefAnimTime > 0 || config->fntSelAnimTime > 0 - || config->globalFadeInTime > 0 || config->globalFadeInTimeStart != 0 ) + || config->menuFadeInTime > 0 || config->menuFadeInTimeStart != 0 ) { anim->active = 1; incrementAnimTime(); @@ -88,7 +88,7 @@ void incrementAnimTime() float merge = computeMerge(anim->timer, config->highlightAnimTime, config->highlightAnimTimeStart); setMergedColorAlpha(merge, config->highlight, config->highlightAnimColor, anim->highlight); } - else if ( anim->timer > config->globalFadeInTimeStart ) + else if ( anim->timer > config->menuFadeInTimeStart ) memcpy(anim->highlight, config->highlight, sizeof(u8[4])); if ( config->bordersAnimTime > 0 ) @@ -96,7 +96,7 @@ void incrementAnimTime() float merge = computeMerge(anim->timer, config->bordersAnimTime, config->bordersAnimTimeStart); setMergedColorAlpha(merge, config->borders, config->bordersAnimColor, anim->borders); } - else if ( anim->timer > config->globalFadeInTimeStart ) + else if ( anim->timer > config->menuFadeInTimeStart ) memcpy(anim->borders, config->borders, sizeof(u8[4])); if ( config->fntDefAnimTime > 0 ) @@ -104,7 +104,7 @@ void incrementAnimTime() float merge = computeMerge(anim->timer, config->fntDefAnimTime, config->fntDefAnimTimeStart); setMergedColorAlpha(merge, config->fntDef, config->fntDefAnimColor, anim->fntDef); } - else if ( anim->timer > config->globalFadeInTimeStart ) + else if ( anim->timer > config->menuFadeInTimeStart ) memcpy(anim->fntDef, config->fntDef, sizeof(u8[4])); if ( config->fntSelAnimTime > 0 ) @@ -112,22 +112,22 @@ void incrementAnimTime() float merge = computeMerge(anim->timer, config->fntSelAnimTime, config->fntSelAnimTimeStart); setMergedColorAlpha(merge, config->fntSel, config->fntSelAnimColor, anim->fntSel); } - else if ( anim->timer > config->globalFadeInTimeStart ) + else if ( anim->timer > config->menuFadeInTimeStart ) memcpy(anim->fntSel, config->fntSel, sizeof(u8[4])); - if ( anim->timer >= config->globalFadeInTimeStart ) + if ( anim->timer >= config->menuFadeInTimeStart ) { - int fadeInTime = anim->timer - config->globalFadeInTimeStart; - if ( fadeInTime <= config->globalFadeInTime ) + int fadeInTime = anim->timer - config->menuFadeInTimeStart; + if ( fadeInTime <= config->menuFadeInTime ) { - float fadeIn = (config->globalFadeInTime > 0) ? (float)fadeInTime / (float)config->globalFadeInTime : 1.f; + float fadeIn = (config->menuFadeInTime > 0) ? (float)fadeInTime / (float)config->menuFadeInTime : 1.f; anim->highlight[3] = (u8)(fadeIn*(float)anim->highlight[3]); anim->borders[3] = (u8)(fadeIn*(float)anim->borders[3]); anim->fntDef[3] = (u8)(fadeIn*(float)anim->fntDef[3]); anim->fntSel[3] = (u8)(fadeIn*(float)anim->fntSel[3]); - if ( fadeInTime == config->globalFadeInTime && config->bgTop1AnimTime == 0 + if ( fadeInTime == config->menuFadeInTime && config->bgTop1AnimTime == 0 && config->bgTop2AnimTime == 0 && config->bgBotAnimTime == 0 && config->highlightAnimTime == 0 && config->bordersAnimTime == 0 && config->fntDefAnimTime == 0 && config->fntSelAnimTime == 0 ) From 163f99bd1032d764364aefb7fd449825e900bbea Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 1 Jun 2016 23:12:48 +0200 Subject: [PATCH 057/259] Update config.c --- source/config.c | 184 ++++++++++++++++++++++++++---------------------- 1 file changed, 98 insertions(+), 86 deletions(-) diff --git a/source/config.c b/source/config.c index 452a5fe..dbd6869 100644 --- a/source/config.c +++ b/source/config.c @@ -173,9 +173,12 @@ static int handler(void *user, const char *section, const char *name, config->recovery = atoi(item); } else if (MATCH("general", "default")) { config->index = atoi(item); - } else if (MATCH("general", "autobootfix")) { + } +#ifndef ARM9 + else if (MATCH("general", "autobootfix")) { config->autobootfix = atoi(item); } +#endif // theme else if (MATCH("theme", "bgTop1")) { @@ -198,69 +201,80 @@ static int handler(void *user, const char *section, const char *name, strncpy(config->bgImgBot, item, 128); } - // theme animation - else if (MATCH("theme", "bgTop1Anim")) { + // animation + else if (MATCH("animation", "bgTop1Anim")) { setAnimWithColor(&config->bgTop1AnimTime, &config->bgTop1AnimTimeStart, config->bgTop1AnimColor, item); - } else if (MATCH("theme", "bgTop2Anim")) { + } else if (MATCH("animation", "bgTop2Anim")) { setAnimWithColor(&config->bgTop2AnimTime, &config->bgTop2AnimTimeStart, config->bgTop2AnimColor, item); - } else if (MATCH("theme", "bgBottomAnim")) { + } else if (MATCH("animation", "bgBottomAnim")) { setAnimWithColor(&config->bgBotAnimTime, &config->bgBotAnimTimeStart, config->bgBotAnimColor, item); - } else if (MATCH("theme", "highlightAnim")) { + } else if (MATCH("animation", "highlightAnim")) { setAnimWithColorAlpha(&config->highlightAnimTime, &config->highlightAnimTimeStart, config->highlightAnimColor, item); - } else if (MATCH("theme", "bordersAnim")) { + } else if (MATCH("animation", "bordersAnim")) { setAnimWithColorAlpha(&config->bordersAnimTime, &config->bordersAnimTimeStart, config->bordersAnimColor, item); - } else if (MATCH("theme", "font1Anim")) { + } else if (MATCH("animation", "font1Anim")) { setAnimWithColorAlpha(&config->fntDefAnimTime, &config->fntDefAnimTimeStart, config->fntDefAnimColor, item); - } else if (MATCH("theme", "font2Anim")) { + } else if (MATCH("animation", "font2Anim")) { setAnimWithColorAlpha(&config->fntSelAnimTime, &config->fntSelAnimTimeStart, config->fntSelAnimColor, item); - } else if (MATCH("theme", "globalFadeIn")) { - setAnimTimes(&config->globalFadeInTime, &config->globalFadeInTimeStart, item); + } else if (MATCH("animation", "menuFadeIn")) { + setAnimTimes(&config->menuFadeInTime, &config->menuFadeInTimeStart, item); } // entries - else if (MATCH("entry", "title")) { - strncpy(config->entries[config->count].title, item, 64); - } else if (MATCH("entry", "path")) { - strncpy(config->entries[config->count].path, item, 128); - } else if (MATCH("entry", "offset")) { - config->entries[config->count].offset = strtoul(item, NULL, 16); - } - // Binary patches for current entry - else if (MATCH("entry", "patchMemSearch")) { - binary_patch* curPatch = &config->entries[config->count].patches[config->entries[config->count].patchesCount]; - readStrAsHexData(item, curPatch->memToSearch, &curPatch->memToSearchSize); - } else if (MATCH("entry", "patchMemOverwrite")) { - binary_patch* curPatch = &config->entries[config->count].patches[config->entries[config->count].patchesCount]; - readStrAsHexData(item, curPatch->memOverwrite, &curPatch->memOverwriteSize); - } else if (MATCH("entry", "patchMemOverwriteStr")) { - binary_patch* curPatch = &config->entries[config->count].patches[config->entries[config->count].patchesCount]; - curPatch->memOverwriteSize = strlen(item)+1; - memcpy(curPatch->memOverwrite, item, curPatch->memOverwriteSize); - } else if (MATCH("entry", "patchMemOverwriteWStr")) { - binary_patch* curPatch = &config->entries[config->count].patches[config->entries[config->count].patchesCount]; - int strSize = strlen(item)+1; - curPatch->memOverwriteSize = strSize*2; - for (int i = 0; i < strSize; i++) + else { + int entryInd = config->count; + if ( entryInd < CONFIG_MAX_ENTRIES ) { - curPatch->memOverwrite[2*i] = item[i]; - curPatch->memOverwrite[2*i+1] = '\0'; - } - } else if (MATCH("entry", "patchOccurence")) { - int prevPatchesCount = config->entries[config->count].patchesCount; - config->entries[config->count].patches[prevPatchesCount].occurence = atoi(item); - config->entries[config->count].patchesCount = (prevPatchesCount < PATCHES_MAX_PER_ENTRY) ? (prevPatchesCount+1) : prevPatchesCount; - } - // End current entry - else if (MATCH("entry", "key")) { - if(strlen(config->entries[config->count].title) > 0) { - config->entries[config->count].key = atoi(item); - config->count++; + if (MATCH("entry", "title")) { + strncpy(config->entries[entryInd].title, item, 64); + } else if (MATCH("entry", "path")) { + strncpy(config->entries[entryInd].path, item, 128); + } else if (MATCH("entry", "offset")) { + config->entries[entryInd].offset = strtoul(item, NULL, 16); + } + // End current entry + else if (MATCH("entry", "key")) { + if(strlen(config->entries[entryInd].title) > 0) { + config->entries[entryInd].key = atoi(item); + config->count++; + } + } + #ifdef ARM9 + else + { + int patchInd = config->entries[entryInd].patchesCount; + if ( patchInd < PATCHES_MAX_PER_ENTRY ) + { + // Binary patches for current entry + if (MATCH("entry", "patchMemSearch")) { + binary_patch* curPatch = &config->entries[entryInd].patches[patchInd]; + readStrAsHexData(item, curPatch->memToSearch, &curPatch->memToSearchSize); + } else if (MATCH("entry", "patchMemOverwrite")) { + binary_patch* curPatch = &config->entries[entryInd].patches[patchInd]; + readStrAsHexData(item, curPatch->memOverwrite, &curPatch->memOverwriteSize); + } else if (MATCH("entry", "patchMemOverwriteStr")) { + binary_patch* curPatch = &config->entries[entryInd].patches[patchInd]; + curPatch->memOverwriteSize = strlen(item)+1; + memcpy(curPatch->memOverwrite, item, curPatch->memOverwriteSize); + } else if (MATCH("entry", "patchMemOverwriteWStr")) { + binary_patch* curPatch = &config->entries[entryInd].patches[patchInd]; + int strSize = strlen(item)+1; + curPatch->memOverwriteSize = strSize*2; + for (int i = 0; i < strSize; i++) + { + curPatch->memOverwrite[2*i] = item[i]; + curPatch->memOverwrite[2*i+1] = '\0'; + } + } else if (MATCH("entry", "patchOccurence")) { + config->entries[entryInd].patches[patchInd].occurence = atoi(item); + config->entries[entryInd].patchesCount++; + } + } + } + #endif } } - else { - return 0; - } - return 1; + return 0; } void configThemeInit() { @@ -282,8 +296,8 @@ void configThemeInit() { config->bordersAnimTime = 0; config->fntDefAnimTime = 0; config->fntSelAnimTime = 0; - config->globalFadeInTime = 0; - config->globalFadeInTimeStart = 0; + config->menuFadeInTime = 0; + config->menuFadeInTimeStart = 0; } int configInit() { @@ -395,32 +409,46 @@ void configSave() { // theme section size += snprintf(cfg+size, 256, "[theme];\n"); - size += snprintf(cfg+size, 256, "bgTop1=%02X%02X%02X;\n", config->bgTop1[0], config->bgTop1[1], config->bgTop1[2]); + size += snprintf(cfg+size, 256, "bgTop2=%02X%02X%02X;\n", config->bgTop2[0], config->bgTop2[1], config->bgTop2[2]); + size += snprintf(cfg+size, 256, "bgBottom=%02X%02X%02X;\n", config->bgBot[0], config->bgBot[1], config->bgBot[2]); + if ( config->highlight[3] < 0xFF ) + size += snprintf(cfg+size, 256, "highlight=%02X%02X%02X%02X;\n", config->highlight[0], config->highlight[1], config->highlight[2], config->highlight[3]); + else + size += snprintf(cfg+size, 256, "highlight=%02X%02X%02X;\n", config->highlight[0], config->highlight[1], config->highlight[2]); + if ( config->borders[3] < 0xFF ) + size += snprintf(cfg+size, 256, "borders=%02X%02X%02X%02X;\n", config->borders[0], config->borders[1], config->borders[2], config->borders[3]); + else + size += snprintf(cfg+size, 256, "borders=%02X%02X%02X;\n", config->borders[0], config->borders[1], config->borders[2]); + if ( config->fntDef[3] < 0xFF ) + size += snprintf(cfg+size, 256, "font1=%02X%02X%02X%02X;\n", config->fntDef[0], config->fntDef[1], config->fntDef[2], config->fntDef[3]); + else + size += snprintf(cfg+size, 256, "font1=%02X%02X%02X;\n", config->fntDef[0], config->fntDef[1], config->fntDef[2]); + + if ( config->fntSel[3] < 0xFF ) + size += snprintf(cfg+size, 256, "font2=%02X%02X%02X%02X;\n", config->fntSel[0], config->fntSel[1], config->fntSel[2], config->fntSel[3]); + else + size += snprintf(cfg+size, 256, "font2=%02X%02X%02X;\n", config->fntSel[0], config->fntSel[1], config->fntSel[2]); + size += snprintf(cfg+size, 256, "bgImgTop=%s;\n", config->bgImgTop); + size += snprintf(cfg+size, 256, "bgImgBot=%s;\n\n", config->bgImgBot); + + // animation section + size += snprintf(cfg+size, 256, "[animation];\n"); if ( config->bgTop1AnimTime > 0 ) { size += snprintf(cfg+size, 256, "bgTop1Anim=%i:%i:%02X%02X%02X;\n", config->bgTop1AnimTime, config->bgTop1AnimTimeStart, config->bgTop1AnimColor[0], config->bgTop1AnimColor[1], config->bgTop1AnimColor[2]); } - - size += snprintf(cfg+size, 256, "bgTop2=%02X%02X%02X;\n", config->bgTop2[0], config->bgTop2[1], config->bgTop2[2]); if ( config->bgTop2AnimTime > 0 ) { size += snprintf(cfg+size, 256, "bgTop2Anim=%i:%i:%02X%02X%02X;\n", config->bgTop2AnimTime, config->bgTop2AnimTimeStart, config->bgTop2AnimColor[0], config->bgTop2AnimColor[1], config->bgTop2AnimColor[2]); } - - size += snprintf(cfg+size, 256, "bgBottom=%02X%02X%02X;\n", config->bgBot[0], config->bgBot[1], config->bgBot[2]); if ( config->bgBotAnimTime > 0 ) { size += snprintf(cfg+size, 256, "bgBottomAnim=%i:%i:%02X%02X%02X;\n", config->bgBotAnimTime, config->bgBotAnimTimeStart, config->bgBotAnimColor[0], config->bgBotAnimColor[1], config->bgBotAnimColor[2]); } - - if ( config->highlight[3] < 0xFF ) - size += snprintf(cfg+size, 256, "highlight=%02X%02X%02X%02X;\n", config->highlight[0], config->highlight[1], config->highlight[2], config->highlight[3]); - else - size += snprintf(cfg+size, 256, "highlight=%02X%02X%02X;\n", config->highlight[0], config->highlight[1], config->highlight[2]); if ( config->highlightAnimTime > 0 ) { if ( config->highlightAnimColor[3] < 0xFF ) @@ -434,11 +462,6 @@ void configSave() { config->highlightAnimColor[0], config->highlightAnimColor[1], config->highlightAnimColor[2]); } } - - if ( config->borders[3] < 0xFF ) - size += snprintf(cfg+size, 256, "borders=%02X%02X%02X%02X;\n", config->borders[0], config->borders[1], config->borders[2], config->borders[3]); - else - size += snprintf(cfg+size, 256, "borders=%02X%02X%02X;\n", config->borders[0], config->borders[1], config->borders[2]); if ( config->bordersAnimTime > 0 ) { if ( config->highlightAnimColor[3] < 0xFF ) @@ -452,11 +475,6 @@ void configSave() { config->bordersAnimColor[0], config->bordersAnimColor[1], config->bordersAnimColor[2]); } } - - if ( config->fntDef[3] < 0xFF ) - size += snprintf(cfg+size, 256, "font1=%02X%02X%02X%02X;\n", config->fntDef[0], config->fntDef[1], config->fntDef[2], config->fntDef[3]); - else - size += snprintf(cfg+size, 256, "font1=%02X%02X%02X;\n", config->fntDef[0], config->fntDef[1], config->fntDef[2]); if ( config->fntDefAnimTime > 0 ) { if ( config->fntDefAnimColor[3] < 0xFF ) @@ -470,11 +488,6 @@ void configSave() { config->fntDefAnimColor[0], config->fntDefAnimColor[1], config->fntDefAnimColor[2]); } } - - if ( config->fntSel[3] < 0xFF ) - size += snprintf(cfg+size, 256, "font2=%02X%02X%02X%02X;\n", config->fntSel[0], config->fntSel[1], config->fntSel[2], config->fntSel[3]); - else - size += snprintf(cfg+size, 256, "font2=%02X%02X%02X;\n", config->fntSel[0], config->fntSel[1], config->fntSel[2]); if ( config->fntSelAnimTime > 0 ) { if ( config->fntDefAnimColor[3] < 0xFF ) @@ -488,19 +501,17 @@ void configSave() { config->fntSelAnimColor[0], config->fntSelAnimColor[1], config->fntSelAnimColor[2]); } } + if ( config->menuFadeInTime > 0 ) + size += snprintf(cfg+size, 256, "menuFadeIn=%i:%i;\n", config->menuFadeInTime, config->menuFadeInTimeStart); - if ( config->globalFadeInTime > 0 ) - size += snprintf(cfg+size, 256, "globalFadeIn=%i:%i;\n", config->globalFadeInTime, config->globalFadeInTimeStart); - - size += snprintf(cfg+size, 256, "bgImgTop=%s;\n", config->bgImgTop); - size += snprintf(cfg+size, 256, "bgImgBot=%s;\n\n", config->bgImgBot); - + // entries section for(i=0; icount; i++) { - size += snprintf(cfg+size, 256, "[entry];\n"); + size += snprintf(cfg+size, 256, "\n[entry];\n"); size += snprintf(cfg+size, 256, "title=%s;\n", config->entries[i].title); size += snprintf(cfg+size, 256, "path=%s;\n", config->entries[i].path); size += snprintf(cfg+size, 256, "offset=%x;\n", (int)config->entries[i].offset); int patchesCount = config->entries[i].patchesCount; + #ifdef ARM9 for (int j = 0; j < patchesCount; j++) { binary_patch* curPatch = &config->entries[i].patches[j]; @@ -512,7 +523,8 @@ void configSave() { size += curPatch->memOverwriteSize*2; size += snprintf(cfg+size, 256, ";\npatchOccurence=%i;\n", curPatch->occurence); } - size += snprintf(cfg+size, 256, "key=%i;\n\n", config->entries[i].key); + #endif + size += snprintf(cfg+size, 256, "key=%i;\n", config->entries[i].key); } #ifdef ARM9 FIL file; From de04edbcb0a12e056cc1b8191c5ae664210e0276 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 1 Jun 2016 23:13:24 +0200 Subject: [PATCH 058/259] Update config.h --- source/config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/config.h b/source/config.h index ce4404c..b1ab582 100644 --- a/source/config.h +++ b/source/config.h @@ -73,8 +73,8 @@ typedef struct { int fntDefAnimTimeStart; int fntSelAnimTimeStart; - int globalFadeInTime; - int globalFadeInTimeStart; + int menuFadeInTime; + int menuFadeInTimeStart; char bgImgTop[128]; char bgImgBot[128]; From 6ed614182e78ab00dd2a7f922e99dada34ed239f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 1 Jun 2016 23:14:09 +0200 Subject: [PATCH 059/259] Update menu_boot.c --- source/menu_boot.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/menu_boot.c b/source/menu_boot.c index c5667f6..7028d33 100644 --- a/source/menu_boot.c +++ b/source/menu_boot.c @@ -106,6 +106,14 @@ int menu_boot() { if (boot_index < 0) boot_index = config->count; } + if (kDown & KEY_RIGHT) { + timer = false; + boot_index = (boot_index == config->count) ? 0 : config->count; + } + else if (kDown & KEY_LEFT) { + timer = false; + boot_index = (boot_index == 0) ? config->count : 0; + } else if (kDown & KEY_A) { timer = false; if (boot_index == config->count) { From 208227e6d6477f2e06e0a1d96ba082baec7f5184 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 1 Jun 2016 23:14:43 +0200 Subject: [PATCH 060/259] Update menu_more.c --- source/menu_more.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/menu_more.c b/source/menu_more.c index ab19711..d877854 100644 --- a/source/menu_more.c +++ b/source/menu_more.c @@ -60,6 +60,12 @@ int menu_more() { if (menu_index < 0) menu_index = MENU_COUNT - 1; } + else if (kDown & KEY_RIGHT) { + menu_index = (menu_index == MENU_COUNT - 1) ? 0 : (MENU_COUNT - 1); + } + else if (kDown & KEY_LEFT) { + menu_index = (menu_index == 0) ? (MENU_COUNT - 1) : 0; + } else if (kDown & KEY_A) { if (menu_index == 0 && menu_choose() == 0) { return 0; From 23b901d8436c76f09825b5ac06e04cdb863253bd Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 1 Jun 2016 23:15:15 +0200 Subject: [PATCH 061/259] Update menu_picker.c --- source/menu_picker.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/source/menu_picker.c b/source/menu_picker.c index 3e8b219..891ed79 100644 --- a/source/menu_picker.c +++ b/source/menu_picker.c @@ -184,42 +184,42 @@ void pick_file(file_s *picked, const char *path) { time(&t_start); // reset held timer } #endif - if (kDown & KEY_DOWN) { - picker->file_index++; + if (kDown & KEY_DOWN || kDown & KEY_RIGHT) { + picker->file_index += (kDown & KEY_DOWN) ? 1 : MAX_LINE; if (picker->file_index >= picker->file_count) - picker->file_index = 0; + picker->file_index = (kDown & KEY_DOWN || picker->file_index == picker->file_count - 1 + MAX_LINE) ? 0 : (picker->file_count - 1); #ifndef ARM9 time(&t_start); #endif - } else if (kHeld & KEY_DOWN) { + } else if (kHeld & KEY_DOWN || kHeld & KEY_RIGHT) { #ifndef ARM9 time(&t_end); #endif t_elapsed = t_end - t_start; if (t_elapsed > 0) { - picker->file_index++; + picker->file_index += (kDown & KEY_DOWN) ? 1 : MAX_LINE; if (picker->file_index >= picker->file_count) - picker->file_index = 0; + picker->file_index = (kDown & KEY_DOWN || picker->file_index == picker->file_count - 1 + MAX_LINE) ? 0 : (picker->file_count - 1); svcSleep(100); } } - if (kDown & KEY_UP) { - picker->file_index--; + if (kDown & KEY_UP || kDown & KEY_LEFT) { + picker->file_index -= (kDown & KEY_UP) ? 1 : MAX_LINE; if (picker->file_index < 0) - picker->file_index = picker->file_count - 1; + picker->file_index = (kDown & KEY_UP || picker->file_index == -MAX_LINE) ? (picker->file_count - 1) : 0; #ifndef ARM9 time(&t_start); #endif - } else if (kHeld & KEY_UP) { + } else if (kHeld & KEY_UP || kDown & KEY_LEFT) { #ifndef ARM9 time(&t_end); #endif t_elapsed = t_end - t_start; if (t_elapsed > 0) { - picker->file_index--; + picker->file_index -= (kDown & KEY_UP) ? 1 : MAX_LINE; if (picker->file_index < 0) - picker->file_index = picker->file_count - 1; + picker->file_index = (kDown & KEY_UP || picker->file_index == -MAX_LINE) ? (picker->file_count - 1) : 0; svcSleep(100); } } From fd1e2866e99bfd017cafe5507b20db7e5e7729dd Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 21:57:42 +0200 Subject: [PATCH 062/259] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e31ed1..eb9926c 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,6 @@ Binaries should now be in the `build` folder. * Fluto : graphics * Arkhandar : graphics * dotjasp : graphics (regionfree icon) - ###For screeninit: * Aurora Wright * dark_samus @@ -34,6 +33,9 @@ Binaries should now be in the `build` folder. * Normmatt * delebile * tiniVi +###For movies support: + * Wolfvak + * d0k3 : compressed movies ###Other credits: Readme by gemarcano From d3d3758046c1ae368973a351790777df5f2dc7e2 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 21:58:45 +0200 Subject: [PATCH 063/259] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index eb9926c..447b6ad 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ Binaries should now be in the `build` folder. * Fluto : graphics * Arkhandar : graphics * dotjasp : graphics (regionfree icon) + ###For screeninit: * Aurora Wright * dark_samus @@ -33,6 +34,7 @@ Binaries should now be in the `build` folder. * Normmatt * delebile * tiniVi + ###For movies support: * Wolfvak * d0k3 : compressed movies From 5962434f8b1efb49411805c0e2e581086bc934cb Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 22:01:27 +0200 Subject: [PATCH 064/259] Create movie.c --- source/movie.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 source/movie.c diff --git a/source/movie.c b/source/movie.c new file mode 100644 index 0000000..ba096b1 --- /dev/null +++ b/source/movie.c @@ -0,0 +1,77 @@ +#include "movie.h" + +#include "config.h" +#include "utility.h" + +int readMovieFrame(void* iFileHandlePtr, int* ioFileOffset, comp_manager_s* iCompMgr, char* oFrameBuffer, int iFrameBufferSize) +{ + if ( NULL == iCompMgr ) + { + int readBytes = fileHandleRead(iFileHandlePtr, oFrameBuffer, iFrameBufferSize, *ioFileOffset); + if ( readBytes < 0 ) + return -1; + *ioFileOffset += readBytes; + return 0; + } + else + { + int readBytes = fileHandleRead(iFileHandlePtr, iCompMgr->frame_comp, 9, *ioFileOffset); // Read top animations QuickLZ header + if (readBytes != 9) // If it couldn't read the header + return -1; // Disable the animation + *ioFileOffset += readBytes; + + size_t comp_size = qlz_size_compressed(iCompMgr->frame_comp); // Get compressed size + + readBytes = fileHandleRead(iFileHandlePtr, iCompMgr->frame_comp + 9, comp_size - 9, *ioFileOffset); // Read compressed buffer + + if (readBytes != (comp_size - 9) || qlz_size_decompressed(iCompMgr->frame_comp) != iFrameBufferSize) // Check if EOF + return -1; // Disable the animation + *ioFileOffset += readBytes; + + qlz_decompress(iCompMgr->frame_comp, iCompMgr->frame_curr, &iCompMgr->state); // Decompress the frame + + for (size_t i = 0; i < iFrameBufferSize; i++) // Perform delta decoding + iCompMgr->frame_curr[i] += iCompMgr->frame_prev[i]; + + memcpy(iCompMgr->frame_prev, iCompMgr->frame_curr, iFrameBufferSize); // Keep a copy of the fb + memcpy(oFrameBuffer, iCompMgr->frame_curr, iFrameBufferSize); // Display it on the screen + return 0; + } +} + +int getMovieFramesCount(void* iFileHandlePtr, int iFrameBufferSize, int iCompressed, int* ioFrameOffset) +{ + size_t fileSize = fileHandleSize(iFileHandlePtr); + if ( !iCompressed ) + { + int framesCount = fileSize / iFrameBufferSize; + if ( NULL != ioFrameOffset ) + *ioFrameOffset = ( *ioFrameOffset < framesCount && *ioFrameOffset >=0 ) ? (*ioFrameOffset * iFrameBufferSize) : -1; + return framesCount; + } + else + { + char compHeader[9]; + int framesCount = 0; + int fileOffset = 0; + + while ( 9 == fileHandleRead(iFileHandlePtr, compHeader, 9, fileOffset) ) + { + size_t comp_size = qlz_size_compressed(compHeader); // Get compressed size + if ( fileOffset + comp_size > fileSize ) + break; + if ( NULL != ioFrameOffset && *ioFrameOffset == framesCount ) + { + *ioFrameOffset = fileOffset; + ioFrameOffset = NULL; + } + fileOffset += comp_size; + framesCount++; + } + + if ( NULL != ioFrameOffset ) + *ioFrameOffset = -1; // We didn't find any valid frame + + return framesCount; + } +} From d8a1c1810ac1b98f5104bf511ad649ae04f7550a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 22:01:51 +0200 Subject: [PATCH 065/259] Create movie.h --- source/movie.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 source/movie.h diff --git a/source/movie.h b/source/movie.h new file mode 100644 index 0000000..bab36c3 --- /dev/null +++ b/source/movie.h @@ -0,0 +1,24 @@ +#ifndef _movie_h_ +#define _movie_h_ + +#include "quicklz.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + qlz_state_decompress state; + char* frame_prev; + char* frame_curr; + char* frame_comp; +} comp_manager_s; + +int readMovieFrame(void* iFileHandlePtr, int* ioFileOffset, comp_manager_s* iCompMgr, char* oFrameBuffer, int iFrameBufferSize); +int getMovieFramesCount(void* iFileHandlePtr, int iFrameBufferSize, int iCompressed, int* ioFrameOffset); + +#ifdef __cplusplus +} +#endif + +#endif From 140c76308def584a7113b0706cfc388f3804022a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 22:02:07 +0200 Subject: [PATCH 066/259] Create quicklz.c --- source/quicklz.c | 848 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 848 insertions(+) create mode 100644 source/quicklz.c diff --git a/source/quicklz.c b/source/quicklz.c new file mode 100644 index 0000000..3742129 --- /dev/null +++ b/source/quicklz.c @@ -0,0 +1,848 @@ +// Fast data compression library +// Copyright (C) 2006-2011 Lasse Mikkel Reinhold +// lar@quicklz.com +// +// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything +// released into public must be open source) or under a commercial license if such +// has been acquired (see http://www.quicklz.com/order.html). The commercial license +// does not cover derived or ported versions created by third parties under GPL. + +// 1.5.0 final + +#include "quicklz.h" + +#if QLZ_VERSION_MAJOR != 1 || QLZ_VERSION_MINOR != 5 || QLZ_VERSION_REVISION != 0 + #error quicklz.c and quicklz.h have different versions +#endif + +#if (defined(__X86__) || defined(__i386__) || defined(i386) || defined(_M_IX86) || defined(__386__) || defined(__x86_64__) || defined(_M_X64)) + #define X86X64 +#endif + +#define MINOFFSET 2 +#define UNCONDITIONAL_MATCHLEN 6 +#define UNCOMPRESSED_END 4 +#define CWORD_LEN 4 + +#if QLZ_COMPRESSION_LEVEL == 1 && defined QLZ_PTR_64 && QLZ_STREAMING_BUFFER == 0 + #define OFFSET_BASE source + #define CAST (ui32)(size_t) +#else + #define OFFSET_BASE 0 + #define CAST +#endif + +int qlz_get_setting(int setting) +{ + switch (setting) + { + case 0: return QLZ_COMPRESSION_LEVEL; + case 1: return sizeof(qlz_state_compress); + case 2: return sizeof(qlz_state_decompress); + case 3: return QLZ_STREAMING_BUFFER; +#ifdef QLZ_MEMORY_SAFE + case 6: return 1; +#else + case 6: return 0; +#endif + case 7: return QLZ_VERSION_MAJOR; + case 8: return QLZ_VERSION_MINOR; + case 9: return QLZ_VERSION_REVISION; + } + return -1; +} + +#if QLZ_COMPRESSION_LEVEL == 1 +static int same(const unsigned char *src, size_t n) +{ + while(n > 0 && *(src + n) == *src) + n--; + return n == 0 ? 1 : 0; +} +#endif + +static void reset_table_compress(qlz_state_compress *state) +{ + int i; + for(i = 0; i < QLZ_HASH_VALUES; i++) + { +#if QLZ_COMPRESSION_LEVEL == 1 + state->hash[i].offset = 0; +#else + state->hash_counter[i] = 0; +#endif + } +} + +static void reset_table_decompress(qlz_state_decompress *state) +{ + int i; + (void)state; + (void)i; +#if QLZ_COMPRESSION_LEVEL == 2 + for(i = 0; i < QLZ_HASH_VALUES; i++) + { + state->hash_counter[i] = 0; + } +#endif +} + +static __inline ui32 hash_func(ui32 i) +{ +#if QLZ_COMPRESSION_LEVEL == 2 + return ((i >> 9) ^ (i >> 13) ^ i) & (QLZ_HASH_VALUES - 1); +#else + return ((i >> 12) ^ i) & (QLZ_HASH_VALUES - 1); +#endif +} + +static __inline ui32 fast_read(void const *src, ui32 bytes) +{ +#ifndef X86X64 + unsigned char *p = (unsigned char*)src; + switch (bytes) + { + case 4: + return(*p | *(p + 1) << 8 | *(p + 2) << 16 | *(p + 3) << 24); + case 3: + return(*p | *(p + 1) << 8 | *(p + 2) << 16); + case 2: + return(*p | *(p + 1) << 8); + case 1: + return(*p); + } + return 0; +#else + if (bytes >= 1 && bytes <= 4) + return *((ui32*)src); + else + return 0; +#endif +} + +static __inline ui32 hashat(const unsigned char *src) +{ + ui32 fetch, hash; + fetch = fast_read(src, 3); + hash = hash_func(fetch); + return hash; +} + +static __inline void fast_write(ui32 f, void *dst, size_t bytes) +{ +#ifndef X86X64 + unsigned char *p = (unsigned char*)dst; + + switch (bytes) + { + case 4: + *p = (unsigned char)f; + *(p + 1) = (unsigned char)(f >> 8); + *(p + 2) = (unsigned char)(f >> 16); + *(p + 3) = (unsigned char)(f >> 24); + return; + case 3: + *p = (unsigned char)f; + *(p + 1) = (unsigned char)(f >> 8); + *(p + 2) = (unsigned char)(f >> 16); + return; + case 2: + *p = (unsigned char)f; + *(p + 1) = (unsigned char)(f >> 8); + return; + case 1: + *p = (unsigned char)f; + return; + } +#else + switch (bytes) + { + case 4: + *((ui32*)dst) = f; + return; + case 3: + *((ui32*)dst) = f; + return; + case 2: + *((ui16 *)dst) = (ui16)f; + return; + case 1: + *((unsigned char*)dst) = (unsigned char)f; + return; + } +#endif +} + + +size_t qlz_size_decompressed(const char *source) +{ + ui32 n, r; + n = (((*source) & 2) == 2) ? 4 : 1; + r = fast_read(source + 1 + n, n); + r = r & (0xffffffff >> ((4 - n)*8)); + return r; +} + +size_t qlz_size_compressed(const char *source) +{ + ui32 n, r; + n = (((*source) & 2) == 2) ? 4 : 1; + r = fast_read(source + 1, n); + r = r & (0xffffffff >> ((4 - n)*8)); + return r; +} + +size_t qlz_size_header(const char *source) +{ + size_t n = 2*((((*source) & 2) == 2) ? 4 : 1) + 1; + return n; +} + + +static __inline void memcpy_up(unsigned char *dst, const unsigned char *src, ui32 n) +{ + // Caution if modifying memcpy_up! Overlap of dst and src must be special handled. +#ifndef X86X64 + unsigned char *end = dst + n; + while(dst < end) + { + *dst = *src; + dst++; + src++; + } +#else + ui32 f = 0; + do + { + *(ui32 *)(dst + f) = *(ui32 *)(src + f); + f += MINOFFSET + 1; + } + while (f < n); +#endif +} + +static __inline void update_hash(qlz_state_decompress *state, const unsigned char *s) +{ +#if QLZ_COMPRESSION_LEVEL == 1 + ui32 hash; + hash = hashat(s); + state->hash[hash].offset = s; + state->hash_counter[hash] = 1; +#elif QLZ_COMPRESSION_LEVEL == 2 + ui32 hash; + unsigned char c; + hash = hashat(s); + c = state->hash_counter[hash]; + state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = s; + c++; + state->hash_counter[hash] = c; +#endif + (void)state; + (void)s; +} + +#if QLZ_COMPRESSION_LEVEL <= 2 +static void update_hash_upto(qlz_state_decompress *state, unsigned char **lh, const unsigned char *max) +{ + while(*lh < max) + { + (*lh)++; + update_hash(state, *lh); + } +} +#endif + +static size_t qlz_compress_core(const unsigned char *source, unsigned char *destination, size_t size, qlz_state_compress *state) +{ + const unsigned char *last_byte = source + size - 1; + const unsigned char *src = source; + unsigned char *cword_ptr = destination; + unsigned char *dst = destination + CWORD_LEN; + ui32 cword_val = 1U << 31; + const unsigned char *last_matchstart = last_byte - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END; + ui32 fetch = 0; + unsigned int lits = 0; + + (void) lits; + + if(src <= last_matchstart) + fetch = fast_read(src, 3); + + while(src <= last_matchstart) + { + if ((cword_val & 1) == 1) + { + // store uncompressed if compression ratio is too low + if (src > source + (size >> 1) && dst - destination > src - source - ((src - source) >> 5)) + return 0; + + fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN); + + cword_ptr = dst; + dst += CWORD_LEN; + cword_val = 1U << 31; + fetch = fast_read(src, 3); + } +#if QLZ_COMPRESSION_LEVEL == 1 + { + const unsigned char *o; + ui32 hash, cached; + + hash = hash_func(fetch); + cached = fetch ^ state->hash[hash].cache; + state->hash[hash].cache = fetch; + + o = state->hash[hash].offset + OFFSET_BASE; + state->hash[hash].offset = CAST(src - OFFSET_BASE); + +#ifdef X86X64 + if ((cached & 0xffffff) == 0 && o != OFFSET_BASE && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > source + 3 && same(src - 3, 6)))) + { + if(cached != 0) + { +#else + if (cached == 0 && o != OFFSET_BASE && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > source + 3 && same(src - 3, 6)))) + { + if (*(o + 3) != *(src + 3)) + { +#endif + hash <<= 4; + cword_val = (cword_val >> 1) | (1U << 31); + fast_write((3 - 2) | hash, dst, 2); + src += 3; + dst += 2; + } + else + { + const unsigned char *old_src = src; + size_t matchlen; + hash <<= 4; + + cword_val = (cword_val >> 1) | (1U << 31); + src += 4; + + if(*(o + (src - old_src)) == *src) + { + src++; + if(*(o + (src - old_src)) == *src) + { + size_t q = last_byte - UNCOMPRESSED_END - (src - 5) + 1; + size_t remaining = q > 255 ? 255 : q; + src++; + while(*(o + (src - old_src)) == *src && (size_t)(src - old_src) < remaining) + src++; + } + } + + matchlen = src - old_src; + if (matchlen < 18) + { + fast_write((ui32)(matchlen - 2) | hash, dst, 2); + dst += 2; + } + else + { + fast_write((ui32)(matchlen << 16) | hash, dst, 3); + dst += 3; + } + } + fetch = fast_read(src, 3); + lits = 0; + } + else + { + lits++; + *dst = *src; + src++; + dst++; + cword_val = (cword_val >> 1); +#ifdef X86X64 + fetch = fast_read(src, 3); +#else + fetch = (fetch >> 8 & 0xffff) | (*(src + 2) << 16); +#endif + } + } +#elif QLZ_COMPRESSION_LEVEL >= 2 + { + const unsigned char *o, *offset2; + ui32 hash, matchlen, k, m, best_k = 0; + unsigned char c; + size_t remaining = (last_byte - UNCOMPRESSED_END - src + 1) > 255 ? 255 : (last_byte - UNCOMPRESSED_END - src + 1); + (void)best_k; + + + //hash = hashat(src); + fetch = fast_read(src, 3); + hash = hash_func(fetch); + + c = state->hash_counter[hash]; + + offset2 = state->hash[hash].offset[0]; + if(offset2 < src - MINOFFSET && c > 0 && ((fast_read(offset2, 3) ^ fetch) & 0xffffff) == 0) + { + matchlen = 3; + if(*(offset2 + matchlen) == *(src + matchlen)) + { + matchlen = 4; + while(*(offset2 + matchlen) == *(src + matchlen) && matchlen < remaining) + matchlen++; + } + } + else + matchlen = 0; + for(k = 1; k < QLZ_POINTERS && c > k; k++) + { + o = state->hash[hash].offset[k]; +#if QLZ_COMPRESSION_LEVEL == 3 + if(((fast_read(o, 3) ^ fetch) & 0xffffff) == 0 && o < src - MINOFFSET) +#elif QLZ_COMPRESSION_LEVEL == 2 + if(*(src + matchlen) == *(o + matchlen) && ((fast_read(o, 3) ^ fetch) & 0xffffff) == 0 && o < src - MINOFFSET) +#endif + { + m = 3; + while(*(o + m) == *(src + m) && m < remaining) + m++; +#if QLZ_COMPRESSION_LEVEL == 3 + if ((m > matchlen) || (m == matchlen && o > offset2)) +#elif QLZ_COMPRESSION_LEVEL == 2 + if (m > matchlen) +#endif + { + offset2 = o; + matchlen = m; + best_k = k; + } + } + } + o = offset2; + state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src; + c++; + state->hash_counter[hash] = c; + +#if QLZ_COMPRESSION_LEVEL == 3 + if(matchlen > 2 && src - o < 131071) + { + ui32 u; + size_t offset = src - o; + + for(u = 1; u < matchlen; u++) + { + hash = hashat(src + u); + c = state->hash_counter[hash]++; + state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src + u; + } + + cword_val = (cword_val >> 1) | (1U << 31); + src += matchlen; + + if(matchlen == 3 && offset <= 63) + { + *dst = (unsigned char)(offset << 2); + dst++; + } + else if (matchlen == 3 && offset <= 16383) + { + ui32 f = (ui32)((offset << 2) | 1); + fast_write(f, dst, 2); + dst += 2; + } + else if (matchlen <= 18 && offset <= 1023) + { + ui32 f = ((matchlen - 3) << 2) | ((ui32)offset << 6) | 2; + fast_write(f, dst, 2); + dst += 2; + } + + else if(matchlen <= 33) + { + ui32 f = ((matchlen - 2) << 2) | ((ui32)offset << 7) | 3; + fast_write(f, dst, 3); + dst += 3; + } + else + { + ui32 f = ((matchlen - 3) << 7) | ((ui32)offset << 15) | 3; + fast_write(f, dst, 4); + dst += 4; + } + } + else + { + *dst = *src; + src++; + dst++; + cword_val = (cword_val >> 1); + } +#elif QLZ_COMPRESSION_LEVEL == 2 + + if(matchlen > 2) + { + cword_val = (cword_val >> 1) | (1U << 31); + src += matchlen; + + if (matchlen < 10) + { + ui32 f = best_k | ((matchlen - 2) << 2) | (hash << 5); + fast_write(f, dst, 2); + dst += 2; + } + else + { + ui32 f = best_k | (matchlen << 16) | (hash << 5); + fast_write(f, dst, 3); + dst += 3; + } + } + else + { + *dst = *src; + src++; + dst++; + cword_val = (cword_val >> 1); + } +#endif + } +#endif + } + while (src <= last_byte) + { + if ((cword_val & 1) == 1) + { + fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN); + cword_ptr = dst; + dst += CWORD_LEN; + cword_val = 1U << 31; + } +#if QLZ_COMPRESSION_LEVEL < 3 + if (src <= last_byte - 3) + { +#if QLZ_COMPRESSION_LEVEL == 1 + ui32 hash, fetch; + fetch = fast_read(src, 3); + hash = hash_func(fetch); + state->hash[hash].offset = CAST(src - OFFSET_BASE); + state->hash[hash].cache = fetch; +#elif QLZ_COMPRESSION_LEVEL == 2 + ui32 hash; + unsigned char c; + hash = hashat(src); + c = state->hash_counter[hash]; + state->hash[hash].offset[c & (QLZ_POINTERS - 1)] = src; + c++; + state->hash_counter[hash] = c; +#endif + } +#endif + *dst = *src; + src++; + dst++; + cword_val = (cword_val >> 1); + } + + while((cword_val & 1) != 1) + cword_val = (cword_val >> 1); + + fast_write((cword_val >> 1) | (1U << 31), cword_ptr, CWORD_LEN); + + // min. size must be 9 bytes so that the qlz_size functions can take 9 bytes as argument + return dst - destination < 9 ? 9 : dst - destination; +} + +static size_t qlz_decompress_core(const unsigned char *source, unsigned char *destination, size_t size, qlz_state_decompress *state, const unsigned char *history) +{ + const unsigned char *src = source + qlz_size_header((const char *)source); + unsigned char *dst = destination; + const unsigned char *last_destination_byte = destination + size - 1; + ui32 cword_val = 1; + const unsigned char *last_matchstart = last_destination_byte - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END; + unsigned char *last_hashed = destination - 1; + const unsigned char *last_source_byte = source + qlz_size_compressed((const char *)source) - 1; + static const ui32 bitlut[16] = {4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0}; + + (void) last_source_byte; + (void) last_hashed; + (void) state; + (void) history; + + for(;;) + { + ui32 fetch; + + if (cword_val == 1) + { +#ifdef QLZ_MEMORY_SAFE + if(src + CWORD_LEN - 1 > last_source_byte) + return 0; +#endif + cword_val = fast_read(src, CWORD_LEN); + src += CWORD_LEN; + } + +#ifdef QLZ_MEMORY_SAFE + if(src + 4 - 1 > last_source_byte) + return 0; +#endif + + fetch = fast_read(src, 4); + + if ((cword_val & 1) == 1) + { + ui32 matchlen; + const unsigned char *offset2; + +#if QLZ_COMPRESSION_LEVEL == 1 + ui32 hash; + cword_val = cword_val >> 1; + hash = (fetch >> 4) & 0xfff; + offset2 = (const unsigned char *)(size_t)state->hash[hash].offset; + + if((fetch & 0xf) != 0) + { + matchlen = (fetch & 0xf) + 2; + src += 2; + } + else + { + matchlen = *(src + 2); + src += 3; + } + +#elif QLZ_COMPRESSION_LEVEL == 2 + ui32 hash; + unsigned char c; + cword_val = cword_val >> 1; + hash = (fetch >> 5) & 0x7ff; + c = (unsigned char)(fetch & 0x3); + offset2 = state->hash[hash].offset[c]; + + if((fetch & (28)) != 0) + { + matchlen = ((fetch >> 2) & 0x7) + 2; + src += 2; + } + else + { + matchlen = *(src + 2); + src += 3; + } + +#elif QLZ_COMPRESSION_LEVEL == 3 + ui32 offset; + cword_val = cword_val >> 1; + if ((fetch & 3) == 0) + { + offset = (fetch & 0xff) >> 2; + matchlen = 3; + src++; + } + else if ((fetch & 2) == 0) + { + offset = (fetch & 0xffff) >> 2; + matchlen = 3; + src += 2; + } + else if ((fetch & 1) == 0) + { + offset = (fetch & 0xffff) >> 6; + matchlen = ((fetch >> 2) & 15) + 3; + src += 2; + } + else if ((fetch & 127) != 3) + { + offset = (fetch >> 7) & 0x1ffff; + matchlen = ((fetch >> 2) & 0x1f) + 2; + src += 3; + } + else + { + offset = (fetch >> 15); + matchlen = ((fetch >> 7) & 255) + 3; + src += 4; + } + + offset2 = dst - offset; +#endif + +#ifdef QLZ_MEMORY_SAFE + if(offset2 < history || offset2 > dst - MINOFFSET - 1) + return 0; + + if(matchlen > (ui32)(last_destination_byte - dst - UNCOMPRESSED_END + 1)) + return 0; +#endif + + memcpy_up(dst, offset2, matchlen); + dst += matchlen; + +#if QLZ_COMPRESSION_LEVEL <= 2 + update_hash_upto(state, &last_hashed, dst - matchlen); + last_hashed = dst - 1; +#endif + } + else + { + if (dst < last_matchstart) + { + unsigned int n = bitlut[cword_val & 0xf]; +#ifdef X86X64 + *(ui32 *)dst = *(ui32 *)src; +#else + memcpy_up(dst, src, 4); +#endif + cword_val = cword_val >> n; + dst += n; + src += n; +#if QLZ_COMPRESSION_LEVEL <= 2 + update_hash_upto(state, &last_hashed, dst - 3); +#endif + } + else + { + while(dst <= last_destination_byte) + { + if (cword_val == 1) + { + src += CWORD_LEN; + cword_val = 1U << 31; + } +#ifdef QLZ_MEMORY_SAFE + if(src >= last_source_byte + 1) + return 0; +#endif + *dst = *src; + dst++; + src++; + cword_val = cword_val >> 1; + } + +#if QLZ_COMPRESSION_LEVEL <= 2 + update_hash_upto(state, &last_hashed, last_destination_byte - 3); // todo, use constant +#endif + return size; + } + + } + } +} + +size_t qlz_compress(const void *source, char *destination, size_t size, qlz_state_compress *state) +{ + size_t r; + ui32 compressed; + size_t base; + + if(size == 0 || size > 0xffffffff - 400) + return 0; + + if(size < 216) + base = 3; + else + base = 9; + +#if QLZ_STREAMING_BUFFER > 0 + if (state->stream_counter + size - 1 >= QLZ_STREAMING_BUFFER) +#endif + { + reset_table_compress(state); + r = base + qlz_compress_core((const unsigned char *)source, (unsigned char*)destination + base, size, state); +#if QLZ_STREAMING_BUFFER > 0 + reset_table_compress(state); +#endif + if(r == base) + { + memcpy(destination + base, source, size); + r = size + base; + compressed = 0; + } + else + { + compressed = 1; + } + state->stream_counter = 0; + } +#if QLZ_STREAMING_BUFFER > 0 + else + { + unsigned char *src = state->stream_buffer + state->stream_counter; + + memcpy(src, source, size); + r = base + qlz_compress_core(src, (unsigned char*)destination + base, size, state); + + if(r == base) + { + memcpy(destination + base, src, size); + r = size + base; + compressed = 0; + reset_table_compress(state); + } + else + { + compressed = 1; + } + state->stream_counter += size; + } +#endif + if(base == 3) + { + *destination = (unsigned char)(0 | compressed); + *(destination + 1) = (unsigned char)r; + *(destination + 2) = (unsigned char)size; + } + else + { + *destination = (unsigned char)(2 | compressed); + fast_write((ui32)r, destination + 1, 4); + fast_write((ui32)size, destination + 5, 4); + } + + *destination |= (QLZ_COMPRESSION_LEVEL << 2); + *destination |= (1 << 6); + *destination |= ((QLZ_STREAMING_BUFFER == 0 ? 0 : (QLZ_STREAMING_BUFFER == 100000 ? 1 : (QLZ_STREAMING_BUFFER == 1000000 ? 2 : 3))) << 4); + +// 76543210 +// 01SSLLHC + + return r; +} + +size_t qlz_decompress(const char *source, void *destination, qlz_state_decompress *state) +{ + size_t dsiz = qlz_size_decompressed(source); + +#if QLZ_STREAMING_BUFFER > 0 + if (state->stream_counter + qlz_size_decompressed(source) - 1 >= QLZ_STREAMING_BUFFER) +#endif + { + if((*source & 1) == 1) + { + reset_table_decompress(state); + dsiz = qlz_decompress_core((const unsigned char *)source, (unsigned char *)destination, dsiz, state, (const unsigned char *)destination); + } + else + { + memcpy(destination, source + qlz_size_header(source), dsiz); + } + state->stream_counter = 0; + reset_table_decompress(state); + } +#if QLZ_STREAMING_BUFFER > 0 + else + { + unsigned char *dst = state->stream_buffer + state->stream_counter; + if((*source & 1) == 1) + { + dsiz = qlz_decompress_core((const unsigned char *)source, dst, dsiz, state, (const unsigned char *)state->stream_buffer); + } + else + { + memcpy(dst, source + qlz_size_header(source), dsiz); + reset_table_decompress(state); + } + memcpy(destination, dst, dsiz); + state->stream_counter += dsiz; + } +#endif + return dsiz; +} + From 71da5ac2de10b5c586cec8f89095b326787fb510 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 22:02:25 +0200 Subject: [PATCH 067/259] Create quicklz.h --- source/quicklz.h | 151 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 source/quicklz.h diff --git a/source/quicklz.h b/source/quicklz.h new file mode 100644 index 0000000..131a25b --- /dev/null +++ b/source/quicklz.h @@ -0,0 +1,151 @@ +#ifndef QLZ_HEADER +#define QLZ_HEADER + +// Fast data compression library +// Copyright (C) 2006-2011 Lasse Mikkel Reinhold +// lar@quicklz.com +// +// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything +// released into public must be open source) or under a commercial license if such +// has been acquired (see http://www.quicklz.com/order.html). The commercial license +// does not cover derived or ported versions created by third parties under GPL. + +// You can edit following user settings. Data must be decompressed with the same +// setting of QLZ_COMPRESSION_LEVEL and QLZ_STREAMING_BUFFER as it was compressed +// (see manual). If QLZ_STREAMING_BUFFER > 0, scratch buffers must be initially +// zeroed out (see manual). First #ifndef makes it possible to define settings from +// the outside like the compiler command line. + +// 1.5.0 final + +#ifndef QLZ_COMPRESSION_LEVEL + + // 1 gives fastest compression speed. 3 gives fastest decompression speed and best + // compression ratio. + //#define QLZ_COMPRESSION_LEVEL 1 + //#define QLZ_COMPRESSION_LEVEL 2 + #define QLZ_COMPRESSION_LEVEL 3 + + // If > 0, zero out both states prior to first call to qlz_compress() or qlz_decompress() + // and decompress packets in the same order as they were compressed + #define QLZ_STREAMING_BUFFER 0 + //#define QLZ_STREAMING_BUFFER 1000 + //#define QLZ_STREAMING_BUFFER 100000 + //#define QLZ_STREAMING_BUFFER 1000000 + + // Guarantees that decompression of corrupted data cannot crash. Decreases decompression + // speed 10-20%. Compression speed not affected. + //#define QLZ_MEMORY_SAFE +#endif + +#define QLZ_VERSION_MAJOR 1 +#define QLZ_VERSION_MINOR 5 +#define QLZ_VERSION_REVISION 0 + +// Using size_t, memset() and memcpy() +#include + +// Verify compression level +#if QLZ_COMPRESSION_LEVEL != 1 && QLZ_COMPRESSION_LEVEL != 2 && QLZ_COMPRESSION_LEVEL != 3 +#error QLZ_COMPRESSION_LEVEL must be 1, 2 or 3 +#endif + +typedef unsigned int ui32; +typedef unsigned short int ui16; + +// Decrease QLZ_POINTERS for level 3 to increase compression speed. Do not touch any other values! +#if QLZ_COMPRESSION_LEVEL == 1 +#define QLZ_POINTERS 1 +#define QLZ_HASH_VALUES 4096 +#elif QLZ_COMPRESSION_LEVEL == 2 +#define QLZ_POINTERS 4 +#define QLZ_HASH_VALUES 2048 +#elif QLZ_COMPRESSION_LEVEL == 3 +#define QLZ_POINTERS 16 +#define QLZ_HASH_VALUES 4096 +#endif + +// Detect if pointer size is 64-bit. It's not fatal if some 64-bit target is not detected because this is only for adding an optional 64-bit optimization. +#if defined _LP64 || defined __LP64__ || defined __64BIT__ || _ADDR64 || defined _WIN64 || defined __arch64__ || __WORDSIZE == 64 || (defined __sparc && defined __sparcv9) || defined __x86_64 || defined __amd64 || defined __x86_64__ || defined _M_X64 || defined _M_IA64 || defined __ia64 || defined __IA64__ + #define QLZ_PTR_64 +#endif + +// hash entry +typedef struct +{ +#if QLZ_COMPRESSION_LEVEL == 1 + ui32 cache; +#if defined QLZ_PTR_64 && QLZ_STREAMING_BUFFER == 0 + unsigned int offset; +#else + const unsigned char *offset; +#endif +#else + const unsigned char *offset[QLZ_POINTERS]; +#endif + +} qlz_hash_compress; + +typedef struct +{ +#if QLZ_COMPRESSION_LEVEL == 1 + const unsigned char *offset; +#else + const unsigned char *offset[QLZ_POINTERS]; +#endif +} qlz_hash_decompress; + + +// states +typedef struct +{ + #if QLZ_STREAMING_BUFFER > 0 + unsigned char stream_buffer[QLZ_STREAMING_BUFFER]; + #endif + size_t stream_counter; + qlz_hash_compress hash[QLZ_HASH_VALUES]; + unsigned char hash_counter[QLZ_HASH_VALUES]; +} qlz_state_compress; + + +#if QLZ_COMPRESSION_LEVEL == 1 || QLZ_COMPRESSION_LEVEL == 2 + typedef struct + { +#if QLZ_STREAMING_BUFFER > 0 + unsigned char stream_buffer[QLZ_STREAMING_BUFFER]; +#endif + qlz_hash_decompress hash[QLZ_HASH_VALUES]; + unsigned char hash_counter[QLZ_HASH_VALUES]; + size_t stream_counter; + } qlz_state_decompress; +#elif QLZ_COMPRESSION_LEVEL == 3 + typedef struct + { +#if QLZ_STREAMING_BUFFER > 0 + unsigned char stream_buffer[QLZ_STREAMING_BUFFER]; +#endif +#if QLZ_COMPRESSION_LEVEL <= 2 + qlz_hash_decompress hash[QLZ_HASH_VALUES]; +#endif + size_t stream_counter; + } qlz_state_decompress; +#endif + + +#if defined (__cplusplus) +extern "C" { +#endif + +// Public functions of QuickLZ +size_t qlz_size_decompressed(const char *source); +size_t qlz_size_compressed(const char *source); +size_t qlz_compress(const void *source, char *destination, size_t size, qlz_state_compress *state); +size_t qlz_decompress(const char *source, void *destination, qlz_state_decompress *state); +int qlz_get_setting(int setting); + +#if defined (__cplusplus) +} +#endif + +#endif + From 322e91a4e4fe6cee31e538b814e0a61f1a184211 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 22:03:07 +0200 Subject: [PATCH 068/259] Update anim.c --- source/anim.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) diff --git a/source/anim.c b/source/anim.c index 1e8949e..8333073 100644 --- a/source/anim.c +++ b/source/anim.c @@ -1,9 +1,40 @@ #include "anim.h" +#define TOP_SCREEN_SIZE (400*240*3) +#define BOT_SCREEN_SIZE (320*240*3) + #ifdef ARM9 #include "memory.h" + +// Top compression required memory: 864000+28809 = 892809 +#define TOP_COMP_PTR (char*)PTR_MOVIE_COMP +#define TOP_COMP_PREV_FRAME_PTR (TOP_COMP_PTR+sizeof(comp_manager_s)) +#define TOP_COMP_CURR_FRAME_PTR (TOP_COMP_PREV_FRAME_PTR+TOP_SCREEN_SIZE) +#define TOP_COMP_COMP_FRAME_PTR (TOP_COMP_CURR_FRAME_PTR+TOP_SCREEN_SIZE) + +// Bottom compression required memory: 691200+23049 = 714249 +#define BOT_COMP_PTR (TOP_COMP_COMP_FRAME_PTR+TOP_SCREEN_SIZE+(TOP_SCREEN_SIZE/10)+9) +#define BOT_COMP_PREV_FRAME_PTR (BOT_COMP_PTR+sizeof(comp_manager_s)) +#define BOT_COMP_CURR_FRAME_PTR (BOT_COMP_PREV_FRAME_PTR+BOT_SCREEN_SIZE) +#define BOT_COMP_COMP_FRAME_PTR (BOT_COMP_CURR_FRAME_PTR+BOT_SCREEN_SIZE) + +// Total compression required memory: 1607058 #endif +#include "utility.h" + +void movieInit(movie_state_s* movie) +{ + movie->file = NULL; + movie->fileOffset = 0; + movie->comp = NULL; + movie->loopStream = NULL; + movie->curLoop = 0; + movie->loopsToDo = 0; + movie->loopStartFrameStream = NULL; + movie->loopEndFrameStream = NULL; +} + void animInit() { #ifdef ARM9 @@ -14,6 +45,106 @@ void animInit() anim->timer = 0; anim->active = 0; + + anim->topMovie.frameSize = TOP_SCREEN_SIZE; + movieInit(&anim->topMovie); + + anim->botMovie.frameSize = BOT_SCREEN_SIZE; + movieInit(&anim->botMovie); +} + +void movieLoopSetup(movie_state_s* movie) +{ + movie->loopFramesCount = movie->loopEndFrame - movie->loopStartFrame + + movie->loopTimeOnStartFrame + movie->loopTimeOnEndFrame; + + if ( movie->loopTimeOnStartFrame > 0 ) + movie->loopStartFrameStream = movie->loopStream; + + if ( movie->loopTimeOnEndFrame > 0 ) + movie->loopEndFrameStream = movie->loopStream + movie->frameSize*(movie->loopEndFrame-movie->loopStartFrame); +} + +#ifdef ARM9 +void movieSetup(movie_config_s* mvConf, movie_state_s* movie, void* filePtr, comp_manager_s* compPtr, void* streamPtr) +#else +void movieSetup(movie_config_s* mvConf, movie_state_s* movie) +#endif +{ + if ( mvConf->path[0] == '\0' ) + return; + +#ifdef ARM9 + movie->file = (void*)(filePtr); +#else + int fileHandleSize = getFileHandleSize(); + movie->file = malloc(fileHandleSize); +#endif + if ( fileHandleOpen(movie->file, mvConf->path) < 0 ) + { + #ifndef ARM9 + free(movie->file); + #endif + movie->file = NULL; + return; + } + + if ( mvConf->compressed ) + { + #ifdef ARM9 + movie->comp = compPtr; + #else + movie->comp = (comp_manager_s*)malloc(sizeof(comp_manager_s)); + movie->comp->frame_prev = malloc(movie->frameSize); + movie->comp->frame_curr = malloc(movie->frameSize); + movie->comp->frame_comp = malloc(movie->frameSize + (movie->frameSize/10) + 9); + #endif + + memset(&movie->comp->state, 0, sizeof(qlz_state_decompress)); + memset(movie->comp->frame_prev, 0, movie->frameSize); + memset(movie->comp->frame_curr, 0, movie->frameSize); + memset(movie->comp->frame_comp, 0, movie->frameSize + (movie->frameSize/10) + 9); + } + + movie->framesCount = getMovieFramesCount(movie->file, movie->frameSize, (NULL != movie->comp), NULL); + if ( movie->framesCount <= 0 ) + { + fileHandleClose(movie->file); + #ifndef ARM9 + free(movie->file); + #endif + movie->file = NULL; + return; + } + + movie->curFrame = 0; + movie->curLoop = 0; + movie->loopsToDo = mvConf->loopCount; + if ( 0 == movie->loopsToDo ) + return; + + movie->loopReverse = mvConf->loopReverse; + + movie->loopTimeOnStartFrame = ( mvConf->loopTimeOnStartFrame > 0 ) ? mvConf->loopTimeOnStartFrame : 0; + movie->loopTimeOnEndFrame = ( mvConf->loopTimeOnEndFrame > 0 ) ? mvConf->loopTimeOnEndFrame : 0; + + movie->loopStartFrame = (mvConf->loopStartFrame < movie->framesCount) ? mvConf->loopStartFrame : (movie->framesCount-1); + if ( movie->loopStartFrame < 0 ) + movie->loopStartFrame = 0; + + movie->loopEndFrame = (mvConf->loopEndFrame < 0 || mvConf->loopEndFrame > movie->loopStartFrame) + ? mvConf->loopEndFrame : movie->loopStartFrame; + if ( movie->loopEndFrame < 0 || movie->loopEndFrame >= movie->framesCount ) + movie->loopEndFrame = movie->framesCount-1; + + movie->loopStreamSize = movie->frameSize * (movie->loopEndFrame-movie->loopStartFrame+1); +#ifdef ARM9 + movie->loopStream = streamPtr; +#else + movie->loopStream = malloc(movie->loopStreamSize); +#endif + + movieLoopSetup(movie); } void animSetup() @@ -25,6 +156,26 @@ void animSetup() memcpy(anim->borders, config->borders, sizeof(u8[4])); memcpy(anim->fntDef, config->fntDef, sizeof(u8[4])); memcpy(anim->fntSel, config->fntSel, sizeof(u8[4])); + +#ifdef ARM9 + comp_manager_s* topComp = (comp_manager_s*)PTR_MOVIE_COMP; + topComp->frame_prev = TOP_COMP_PREV_FRAME_PTR; + topComp->frame_curr = TOP_COMP_CURR_FRAME_PTR; + topComp->frame_comp = TOP_COMP_COMP_FRAME_PTR; + + comp_manager_s* botComp = (comp_manager_s*)BOT_COMP_PTR; + botComp->frame_prev = BOT_COMP_PREV_FRAME_PTR; + botComp->frame_curr = BOT_COMP_CURR_FRAME_PTR; + botComp->frame_comp = BOT_COMP_COMP_FRAME_PTR; + + int fileHandleSize = getFileHandleSize(); + movieSetup(&config->movieTop, &anim->topMovie, PTR_ANIM+sizeof(anim_state_s), topComp, PTR_MOVIE_LOOP); + movieSetup(&config->movieBot, &anim->botMovie, PTR_ANIM+sizeof(anim_state_s)+fileHandleSize, + botComp, PTR_MOVIE_LOOP+anim->topMovie.loopStreamSize); +#else + movieSetup(&config->movieTop, &anim->topMovie); + movieSetup(&config->movieBot, &anim->botMovie); +#endif if ( config->bgTop1AnimTime > 0 || config->bgTop2AnimTime > 0 || config->bgBotAnimTime > 0 || config->highlightAnimTime > 0 || config->bordersAnimTime > 0 @@ -144,3 +295,123 @@ void incrementAnimTime() anim->timer++; } + +int readMovie(u8* fb, movie_state_s* movie) +{ + if ( movie->curLoop == 0 ) + { + if ( NULL == movie->file ) + return -1; + int readMovieRes = readMovieFrame(movie->file, &movie->fileOffset, movie->comp, (char*)fb, movie->frameSize); + if ( readMovieRes < 0 || movie->curFrame >= movie->framesCount-1 + || ( movie->loopReverse && movie->curFrame >= movie->loopEndFrame ) ) + { + fileHandleClose(movie->file); + #ifndef ARM9 + free(movie->file); + #endif + movie->file = NULL; + movie->curLoop = 1; + + if ( 0 != movie->loopsToDo && movie->curFrame < movie->framesCount-1 ) + { + // Correction for corrupted compressed movies + movie->framesCount = movie->curFrame; + if ( movie->loopStartFrame >= movie->framesCount ) + movie->loopStartFrame = movie->framesCount-1; + if ( movie->loopEndFrame >= movie->framesCount ) + movie->loopEndFrame = movie->framesCount-1; + movieLoopSetup(movie); + } + } + + if ( 0 == readMovieRes && NULL != movie->loopStream && movie->curFrame >= movie->loopStartFrame && movie->curFrame <= movie->loopEndFrame ) + memcpy(movie->loopStream+(movie->curFrame-movie->loopStartFrame)*movie->frameSize, fb, movie->frameSize); + + movie->curFrame++; + if ( movie->curLoop > 0 ) + movie->curFrame = 0; + } + else if ( movie->loopsToDo < 0 || movie->curLoop <= movie->loopsToDo ) + { + if ( movie->loopReverse && movie->curLoop%2 == 1 ) + { + if ( movie->curFrame < movie->loopTimeOnEndFrame ) + memcpy(fb, movie->loopEndFrameStream, movie->frameSize); + else if ( movie->curFrame > movie->loopTimeOnEndFrame+movie->loopEndFrame-movie->loopStartFrame ) + memcpy(fb, movie->loopStartFrameStream, movie->frameSize); + else + { + memcpy(fb, movie->loopStream + movie->frameSize*((movie->loopEndFrame-movie->loopStartFrame) + -(movie->curFrame-movie->loopTimeOnEndFrame)), movie->frameSize); + } + } + else + { + if ( movie->curFrame < movie->loopTimeOnStartFrame ) + memcpy(fb, movie->loopStartFrameStream, movie->frameSize); + else if ( movie->curFrame > movie->loopTimeOnStartFrame+movie->loopEndFrame-movie->loopStartFrame ) + memcpy(fb, movie->loopEndFrameStream, movie->frameSize); + else + memcpy(fb, movie->loopStream+movie->frameSize*(movie->curFrame-movie->loopTimeOnStartFrame), movie->frameSize); + } + + movie->curFrame++; + if ( movie->curFrame > movie->loopFramesCount ) + { + movie->curFrame = 0; + movie->curLoop++; + } + } + else + return -1; + + return 0; +} + +int readTopMovie(u8* fb) +{ + return readMovie(fb, &anim->topMovie); +} + +int readBotMovie(u8* fb) +{ + return readMovie(fb, &anim->botMovie); +} + +void animExit() +{ + if (anim) { + if (anim->topMovie.file) + fileHandleClose(anim->topMovie.file); + if (anim->botMovie.file) + fileHandleClose(anim->botMovie.file); +#ifndef ARM9 + if (anim->topMovie.file) + free(anim->topMovie.file); + if (anim->topMovie.comp) + { + free(anim->topMovie.comp->frame_prev); + free(anim->topMovie.comp->frame_curr); + free(anim->topMovie.comp->frame_comp); + free(anim->topMovie.comp); + } + if (anim->topMovie.loopStream) + free(anim->topMovie.loopStream); + + if (anim->botMovie.file) + free(anim->botMovie.file); + if (anim->botMovie.comp) + { + free(anim->botMovie.comp->frame_prev); + free(anim->botMovie.comp->frame_curr); + free(anim->botMovie.comp->frame_comp); + free(anim->botMovie.comp); + } + if (anim->botMovie.loopStream) + free(anim->botMovie.loopStream); + free(anim); +#endif + anim = NULL; + } +} From 494446def91d002a41144f447020095fc78dd53f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 22:03:32 +0200 Subject: [PATCH 069/259] Update anim.h --- source/anim.h | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/source/anim.h b/source/anim.h index 1c793e5..4004a47 100644 --- a/source/anim.h +++ b/source/anim.h @@ -2,11 +2,40 @@ #define _anim_h_ #include "config.h" +#include "movie.h" #ifdef __cplusplus extern "C" { #endif +typedef struct { + int frameSize; + + void* file; + int fileOffset; + int curFrame; + int framesCount; + + comp_manager_s* comp; + + int curLoop; + int loopsToDo; + + int loopFramesCount; + + char* loopStream; + int loopStreamSize; + int loopReverse; + + char* loopStartFrameStream; + int loopStartFrame; + int loopTimeOnStartFrame; + + char* loopEndFrameStream; + int loopEndFrame; + int loopTimeOnEndFrame; +} movie_state_s; + typedef struct { int timer; int active; @@ -17,7 +46,10 @@ typedef struct { u8 highlight[4]; u8 borders[4]; u8 fntDef[4]; - u8 fntSel[4]; + u8 fntSel[4]; + + movie_state_s topMovie; + movie_state_s botMovie; } anim_state_s; anim_state_s* anim; @@ -25,6 +57,9 @@ anim_state_s* anim; void animInit(); void animSetup(); void incrementAnimTime(); +int readTopMovie(u8* fb); +int readBotMovie(u8* fb); +void animExit(); #ifdef __cplusplus } From fe1d5ff4024a023778197c780dfd7a2826601daf Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 22:04:06 +0200 Subject: [PATCH 070/259] Update config.c --- source/config.c | 222 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 166 insertions(+), 56 deletions(-) diff --git a/source/config.c b/source/config.c index dbd6869..2c76b55 100644 --- a/source/config.c +++ b/source/config.c @@ -13,7 +13,8 @@ #include "memory.h" #endif -#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 +#define SECTION_MATCH(s) strcmp(section, s) == 0 +#define NAME_MATCH(n) strcmp(name, n) == 0 typedef struct { const char *ptr; @@ -167,73 +168,121 @@ static int handler(void *user, const char *section, const char *name, } // general - if (MATCH("general", "timeout")) { - config->timeout = atoi(item); - } else if (MATCH("general", "recovery")) { - config->recovery = atoi(item); - } else if (MATCH("general", "default")) { - config->index = atoi(item); - } -#ifndef ARM9 - else if (MATCH("general", "autobootfix")) { - config->autobootfix = atoi(item); + if (SECTION_MATCH("general")) + { + if (NAME_MATCH("timeout")) { + config->timeout = atoi(item); + } else if (NAME_MATCH("recovery")) { + config->recovery = atoi(item); + } else if (NAME_MATCH("default")) { + config->index = atoi(item); + } + #ifndef ARM9 + else if (NAME_MATCH("autobootfix")) { + config->autobootfix = atoi(item); + } + #endif } -#endif // theme - else if (MATCH("theme", "bgTop1")) { - setColor(config->bgTop1, item); - } else if (MATCH("theme", "bgTop2")) { - setColor(config->bgTop2, item); - } else if (MATCH("theme", "bgBottom")) { - setColor(config->bgBot, item); - } else if (MATCH("theme", "highlight")) { - setColorAlpha(config->highlight, item); - } else if (MATCH("theme", "borders")) { - setColorAlpha(config->borders, item); - } else if (MATCH("theme", "font1")) { - setColorAlpha(config->fntDef, item); - } else if (MATCH("theme", "font2")) { - setColorAlpha(config->fntSel, item); - } else if (MATCH("theme", "bgImgTop")) { - strncpy(config->bgImgTop, item, 128); - } else if (MATCH("theme", "bgImgBot")) { - strncpy(config->bgImgBot, item, 128); + else if (SECTION_MATCH("theme")) + { + if (NAME_MATCH("bgTop1")) { + setColor(config->bgTop1, item); + } else if (NAME_MATCH("bgTop2")) { + setColor(config->bgTop2, item); + } else if (NAME_MATCH("bgBottom")) { + setColor(config->bgBot, item); + } else if (NAME_MATCH("highlight")) { + setColorAlpha(config->highlight, item); + } else if (NAME_MATCH("borders")) { + setColorAlpha(config->borders, item); + } else if (NAME_MATCH("font1")) { + setColorAlpha(config->fntDef, item); + } else if (NAME_MATCH("font2")) { + setColorAlpha(config->fntSel, item); + } else if (NAME_MATCH("bgImgTop")) { + strncpy(config->bgImgTop, item, 128); + } else if (NAME_MATCH("bgImgBot")) { + strncpy(config->bgImgBot, item, 128); + } } // animation - else if (MATCH("animation", "bgTop1Anim")) { - setAnimWithColor(&config->bgTop1AnimTime, &config->bgTop1AnimTimeStart, config->bgTop1AnimColor, item); - } else if (MATCH("animation", "bgTop2Anim")) { - setAnimWithColor(&config->bgTop2AnimTime, &config->bgTop2AnimTimeStart, config->bgTop2AnimColor, item); - } else if (MATCH("animation", "bgBottomAnim")) { - setAnimWithColor(&config->bgBotAnimTime, &config->bgBotAnimTimeStart, config->bgBotAnimColor, item); - } else if (MATCH("animation", "highlightAnim")) { - setAnimWithColorAlpha(&config->highlightAnimTime, &config->highlightAnimTimeStart, config->highlightAnimColor, item); - } else if (MATCH("animation", "bordersAnim")) { - setAnimWithColorAlpha(&config->bordersAnimTime, &config->bordersAnimTimeStart, config->bordersAnimColor, item); - } else if (MATCH("animation", "font1Anim")) { - setAnimWithColorAlpha(&config->fntDefAnimTime, &config->fntDefAnimTimeStart, config->fntDefAnimColor, item); - } else if (MATCH("animation", "font2Anim")) { - setAnimWithColorAlpha(&config->fntSelAnimTime, &config->fntSelAnimTimeStart, config->fntSelAnimColor, item); - } else if (MATCH("animation", "menuFadeIn")) { - setAnimTimes(&config->menuFadeInTime, &config->menuFadeInTimeStart, item); + else if (SECTION_MATCH("animation")) + { + if (NAME_MATCH("bgTop1Anim")) { + setAnimWithColor(&config->bgTop1AnimTime, &config->bgTop1AnimTimeStart, config->bgTop1AnimColor, item); + } else if (NAME_MATCH("bgTop2Anim")) { + setAnimWithColor(&config->bgTop2AnimTime, &config->bgTop2AnimTimeStart, config->bgTop2AnimColor, item); + } else if (NAME_MATCH("bgBottomAnim")) { + setAnimWithColor(&config->bgBotAnimTime, &config->bgBotAnimTimeStart, config->bgBotAnimColor, item); + } else if (NAME_MATCH("highlightAnim")) { + setAnimWithColorAlpha(&config->highlightAnimTime, &config->highlightAnimTimeStart, config->highlightAnimColor, item); + } else if (NAME_MATCH("bordersAnim")) { + setAnimWithColorAlpha(&config->bordersAnimTime, &config->bordersAnimTimeStart, config->bordersAnimColor, item); + } else if (NAME_MATCH("font1Anim")) { + setAnimWithColorAlpha(&config->fntDefAnimTime, &config->fntDefAnimTimeStart, config->fntDefAnimColor, item); + } else if (NAME_MATCH("font2Anim")) { + setAnimWithColorAlpha(&config->fntSelAnimTime, &config->fntSelAnimTimeStart, config->fntSelAnimColor, item); + } else if (NAME_MATCH("menuFadeIn")) { + setAnimTimes(&config->menuFadeInTime, &config->menuFadeInTimeStart, item); + } + } + + // movie + else if (SECTION_MATCH("movie")) + { + if (NAME_MATCH("movieTop")) { + strncpy(config->movieTop.path, item, 128); + } else if (NAME_MATCH("movieTopCompress")) { + config->movieTop.compressed = atoi(item); + } else if (NAME_MATCH("movieTopLoop")) { + config->movieTop.loopCount = atoi(item); + } else if (NAME_MATCH("movieTopLoopReverse")) { + config->movieTop.loopReverse = atoi(item); + } else if (NAME_MATCH("movieTopLoopStart")) { + config->movieTop.loopStartFrame = atoi(item); + } else if (NAME_MATCH("movieTopTimeOnLoopStart")) { + config->movieTop.loopTimeOnStartFrame = atoi(item); + } else if (NAME_MATCH("movieTopLoopEnd")) { + config->movieTop.loopEndFrame = atoi(item); + } else if (NAME_MATCH("movieTopTimeOnLoopEnd")) { + config->movieTop.loopTimeOnEndFrame = atoi(item); + } else if (NAME_MATCH("movieBot")) { + strncpy(config->movieBot.path, item, 128); + } else if (NAME_MATCH("movieBotCompress")) { + config->movieBot.compressed = atoi(item); + } else if (NAME_MATCH("movieBotLoop")) { + config->movieBot.loopCount = atoi(item); + } else if (NAME_MATCH("movieBotLoopReverse")) { + config->movieBot.loopReverse = atoi(item); + } else if (NAME_MATCH("movieBotLoopStart")) { + config->movieBot.loopStartFrame = atoi(item); + } else if (NAME_MATCH("movieBotTimeOnLoopStart")) { + config->movieBot.loopTimeOnStartFrame = atoi(item); + } else if (NAME_MATCH("movieBotLoopEnd")) { + config->movieBot.loopEndFrame = atoi(item); + } else if (NAME_MATCH("movieBotTimeOnLoopEnd")) { + config->movieBot.loopTimeOnEndFrame = atoi(item); + } } // entries - else { + else if (SECTION_MATCH("entry")) + { int entryInd = config->count; if ( entryInd < CONFIG_MAX_ENTRIES ) { - if (MATCH("entry", "title")) { + if (NAME_MATCH("title")) { strncpy(config->entries[entryInd].title, item, 64); - } else if (MATCH("entry", "path")) { + } else if (NAME_MATCH("path")) { strncpy(config->entries[entryInd].path, item, 128); - } else if (MATCH("entry", "offset")) { + } else if (NAME_MATCH("offset")) { config->entries[entryInd].offset = strtoul(item, NULL, 16); } // End current entry - else if (MATCH("entry", "key")) { + else if (NAME_MATCH("key")) { if(strlen(config->entries[entryInd].title) > 0) { config->entries[entryInd].key = atoi(item); config->count++; @@ -246,17 +295,17 @@ static int handler(void *user, const char *section, const char *name, if ( patchInd < PATCHES_MAX_PER_ENTRY ) { // Binary patches for current entry - if (MATCH("entry", "patchMemSearch")) { + if (NAME_MATCH("patchMemSearch")) { binary_patch* curPatch = &config->entries[entryInd].patches[patchInd]; readStrAsHexData(item, curPatch->memToSearch, &curPatch->memToSearchSize); - } else if (MATCH("entry", "patchMemOverwrite")) { + } else if (NAME_MATCH("patchMemOverwrite")) { binary_patch* curPatch = &config->entries[entryInd].patches[patchInd]; readStrAsHexData(item, curPatch->memOverwrite, &curPatch->memOverwriteSize); - } else if (MATCH("entry", "patchMemOverwriteStr")) { + } else if (NAME_MATCH("patchMemOverwriteStr")) { binary_patch* curPatch = &config->entries[entryInd].patches[patchInd]; curPatch->memOverwriteSize = strlen(item)+1; memcpy(curPatch->memOverwrite, item, curPatch->memOverwriteSize); - } else if (MATCH("entry", "patchMemOverwriteWStr")) { + } else if (NAME_MATCH("patchMemOverwriteWStr")) { binary_patch* curPatch = &config->entries[entryInd].patches[patchInd]; int strSize = strlen(item)+1; curPatch->memOverwriteSize = strSize*2; @@ -265,7 +314,7 @@ static int handler(void *user, const char *section, const char *name, curPatch->memOverwrite[2*i] = item[i]; curPatch->memOverwrite[2*i+1] = '\0'; } - } else if (MATCH("entry", "patchOccurence")) { + } else if (NAME_MATCH("patchOccurence")) { config->entries[entryInd].patches[patchInd].occurence = atoi(item); config->entries[entryInd].patchesCount++; } @@ -278,6 +327,8 @@ static int handler(void *user, const char *section, const char *name, } void configThemeInit() { + + // theme config->imgError = true; config->imgErrorBot = true; config->bgImgTop[0] = '\0'; @@ -289,6 +340,8 @@ void configThemeInit() { memcpy(config->borders, (u8[4]) {0xff, 0xff, 0xff, 0xff}, sizeof(u8[4])); memcpy(config->fntDef, (u8[4]) {0xff, 0xff, 0xff, 0xff}, sizeof(u8[4])); memcpy(config->fntSel, (u8[4]) {0x00, 0x00, 0x00, 0xff}, sizeof(u8[4])); + + // animation config->bgTop1AnimTime = 0; config->bgTop2AnimTime = 0; config->bgBotAnimTime = 0; @@ -298,6 +351,25 @@ void configThemeInit() { config->fntSelAnimTime = 0; config->menuFadeInTime = 0; config->menuFadeInTimeStart = 0; + + // movie + config->movieTop.path[0] = '\0'; + config->movieTop.compressed = 0; + config->movieTop.loopCount = 0; + config->movieTop.loopReverse = 0; + config->movieTop.loopStartFrame = 0; + config->movieTop.loopTimeOnStartFrame = 0; + config->movieTop.loopEndFrame = -1; + config->movieTop.loopTimeOnEndFrame = 0; + + config->movieBot.path[0] = '\0'; + config->movieBot.compressed = 0; + config->movieBot.loopCount = 0; + config->movieBot.loopReverse = 0; + config->movieBot.loopStartFrame = 0; + config->movieBot.loopTimeOnStartFrame = 0; + config->movieBot.loopEndFrame = -1; + config->movieBot.loopTimeOnEndFrame = 0; } int configInit() { @@ -504,6 +576,44 @@ void configSave() { if ( config->menuFadeInTime > 0 ) size += snprintf(cfg+size, 256, "menuFadeIn=%i:%i;\n", config->menuFadeInTime, config->menuFadeInTimeStart); + // movie section + size += snprintf(cfg+size, 256, "\n[movie];\n"); + size += snprintf(cfg+size, 256, "movieTop=%s;\n", config->movieTop.path); + if ( 0 != config->movieTop.compressed ) + size += snprintf(cfg+size, 256, "movieTopCompress=1;\n"); + if ( 0 != config->movieTop.loopCount ) + { + size += snprintf(cfg+size, 256, "movieTopLoop=%i;\n", config->movieTop.loopCount); + if ( 0 != config->movieTop.loopReverse ) + size += snprintf(cfg+size, 256, "movieTopLoopReverse=1;\n"); + if ( config->movieTop.loopStartFrame > 0 ) + size += snprintf(cfg+size, 256, "movieTopLoopStart=%i;\n", config->movieTop.loopStartFrame); + if ( config->movieTop.loopTimeOnStartFrame > 0 ) + size += snprintf(cfg+size, 256, "movieTopTimeOnLoopStart=%i;\n", config->movieTop.loopTimeOnStartFrame); + if ( config->movieTop.loopEndFrame >= 0 ) + size += snprintf(cfg+size, 256, "movieTopLoopEnd=%i;\n", config->movieTop.loopEndFrame); + if ( config->movieTop.loopTimeOnEndFrame > 0 ) + size += snprintf(cfg+size, 256, "movieTopTimeOnLoopEnd=%i;\n", config->movieTop.loopTimeOnEndFrame); + } + + size += snprintf(cfg+size, 256, "movieBot=%s;\n", config->movieBot.path); + if ( 0 != config->movieBot.compressed ) + size += snprintf(cfg+size, 256, "movieBotCompress=1;\n"); + if ( 0 != config->movieBot.loopCount ) + { + size += snprintf(cfg+size, 256, "movieBotLoop=%i;\n", config->movieTop.loopCount); + if ( 0 != config->movieBot.loopReverse ) + size += snprintf(cfg+size, 256, "movieBotLoopReverse=1;\n"); + if ( config->movieBot.loopStartFrame > 0 ) + size += snprintf(cfg+size, 256, "movieBotLoopStart=%i;\n", config->movieBot.loopStartFrame); + if ( config->movieBot.loopTimeOnStartFrame > 0 ) + size += snprintf(cfg+size, 256, "movieBotTimeOnLoopStart=%i;\n", config->movieBot.loopTimeOnStartFrame); + if ( config->movieBot.loopEndFrame >= 0 ) + size += snprintf(cfg+size, 256, "movieBotLoopEnd=%i;\n", config->movieBot.loopEndFrame); + if ( config->movieBot.loopTimeOnEndFrame > 0 ) + size += snprintf(cfg+size, 256, "movieBotTimeOnLoopEnd=%i;\n", config->movieBot.loopTimeOnEndFrame); + } + // entries section for(i=0; icount; i++) { size += snprintf(cfg+size, 256, "\n[entry];\n"); From 848ac19a996b3deafc5b231d9fcc29a9d710d9d0 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 22:04:35 +0200 Subject: [PATCH 071/259] Update config.h --- source/config.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/source/config.h b/source/config.h index b1ab582..109dfa7 100644 --- a/source/config.h +++ b/source/config.h @@ -8,7 +8,7 @@ extern "C" { #ifdef ARM9 #include "arm9/source/common.h" -#define CONFIG_PATH "/a9lh.cfg" +#define CONFIG_PATH "/a9lh.cfg\0Free space for binary patch to chainload another instance of CtrBootManager9... Space ends up now!" #else @@ -33,6 +33,17 @@ typedef struct { int patchesCount; } boot_entry_s; +typedef struct { + char path[128]; + int compressed; + int loopCount; + int loopReverse; + int loopStartFrame; + int loopTimeOnStartFrame; + int loopEndFrame; + int loopTimeOnEndFrame; +} movie_config_s; + typedef struct { int timeout; int autobootfix; @@ -84,6 +95,10 @@ typedef struct { u8 *bgImgBotBuff; off_t bgImgTopSize; off_t bgImgBotSize; + + movie_config_s movieTop; + movie_config_s movieBot; + } boot_config_s; boot_config_s *config; From 52956bf15175c9e638cc854cdd18e7ea563e305a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 22:05:04 +0200 Subject: [PATCH 072/259] Update main.c --- source/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/main.c b/source/main.c index f5b7043..6ce4c13 100644 --- a/source/main.c +++ b/source/main.c @@ -43,6 +43,7 @@ void __appExit() { gfxExit(); netloader_exit(); configExit(); + animExit(); amExit(); ptmuExit(); acExit(); From b5dc180f98d4068ca4d98c5c890c79bf8161cfd7 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 22:05:37 +0200 Subject: [PATCH 073/259] Update memory.h --- source/memory.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/memory.h b/source/memory.h index d650169..666a1e2 100644 --- a/source/memory.h +++ b/source/memory.h @@ -12,10 +12,12 @@ #define PTR_TOP_BG (u8*)(0x25000000) #define PTR_BOT_BG (u8*)(0x25046500) #define PTR_CFG (u8*)(0x25200000) -#define PTR_CFG_TMP (u8*)(0x25230000) -#define PTR_ANIM (u8*)(0x25240000) #define PTR_PICKER (u8*)(0x25210000) #define PTR_PICKER_FILE (u8*)(0x25220000) +#define PTR_CFG_TMP (u8*)(0x25230000) +#define PTR_ANIM (u8*)(0x25240000) +#define PTR_MOVIE_COMP (u8*)(0x25250000) +#define PTR_MOVIE_LOOP (u8*)(0x25450000) #define PTR_PAYLOAD_MAIN 0x23F00000 #define PTR_PAYLOAD_MAIN_DATA 0x26000000 From 5cff3c9b7027ec1a15df2c573760c969895f428e Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 22:06:29 +0200 Subject: [PATCH 074/259] Update menu.c --- source/menu.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/source/menu.c b/source/menu.c index 7784f15..eaab526 100644 --- a/source/menu.c +++ b/source/menu.c @@ -12,17 +12,23 @@ #include "menu.h" void drawBg() { - if (!config->imgError) { - memcpy(gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), config->bgImgTopBuff, - (size_t) config->bgImgTopSize); - } else { - gfxClearTop(anim->bgTop1, anim->bgTop2); + u8* fbTop = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); + if (readTopMovie(fbTop) < 0) + { + if (!config->imgError) { + memcpy(fbTop, config->bgImgTopBuff, (size_t) config->bgImgTopSize); + } else { + gfxClearTop(anim->bgTop1, anim->bgTop2); + } } - if (!config->imgErrorBot) { - memcpy(gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), config->bgImgBotBuff, - (size_t) config->bgImgBotSize); - } else { - gfxClearBot(anim->bgBot); + u8* fbBot = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); + if (readBotMovie(fbBot) < 0) + { + if (!config->imgErrorBot) { + memcpy(fbBot, config->bgImgBotBuff, (size_t) config->bgImgBotSize); + } else { + gfxClearBot(anim->bgBot); + } } drawRectColor(GFX_TOP, GFX_LEFT, MENU_MIN_X, MENU_MIN_Y - 20, MENU_MAX_X, MENU_MAX_Y, anim->borders); } From ab9b69e6d3e3a72feb2048cb73ba00d31a15981a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 22:07:09 +0200 Subject: [PATCH 075/259] Update utility.c --- source/utility.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/source/utility.c b/source/utility.c index 51ab4d2..4ea65f5 100644 --- a/source/utility.c +++ b/source/utility.c @@ -228,6 +228,59 @@ int fileRead(const char *path, void *data, size_t size) { return fileReadOffset(path, data, size, 0); } +int getFileHandleSize() +{ +#ifdef ARM9 + return sizeof(FIL); +#else + return sizeof(FILE*); +#endif +} + +int fileHandleOpen(void* handlePtr, const char *filePath) +{ +#ifdef ARM9 + return (f_open((FIL*)handlePtr, filePath, FA_READ | FA_OPEN_EXISTING) == FR_OK) ? 0 : -1; +#else + *(FILE**)handlePtr = fopen(filePath, "rt"); + return ( NULL != *(FILE**)handlePtr ) ? 0 : -1; +#endif +} + +size_t fileHandleSize(void* handlePtr) +{ +#ifdef ARM9 + return f_size((FIL*)handlePtr); +#else + *(FILE**)handlePtr(file, 0, SEEK_END); + return ftell(*(FILE**)handlePtr); +#endif +} + +int fileHandleRead(void* handlePtr, void *data, size_t size, u32 offset) +{ +#ifdef ARM9 + UINT bytes_read = 0; + f_lseek((FIL*)handlePtr, offset); + if (f_read((FIL*)handlePtr, data, size, &bytes_read) != FR_OK) + return -1; + return ( bytes_read > 0 ) ? bytes_read : -1; +#else + fseek(*(FILE**)handlePtr, offset, SEEK_SET ); + u32 bytes_read = fread(data, size, 1, *(FILE**)handlePtr); + return ( bytes_read > 0 ) ? bytes_read : -1; +#endif +} + +int fileHandleClose(void* handlePtr) +{ +#ifdef ARM9 + return f_close((FIL*)handlePtr); +#else + return fclose(*(FILE**)handlePtr); +#endif +} + int load_homemenu() { #ifdef ARM9 debug("load_homemenu not implemented"); From 353e9c2597a54d97117dc24884e372c00040ba9c Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 22:07:26 +0200 Subject: [PATCH 076/259] Update utility.h --- source/utility.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/utility.h b/source/utility.h index 9920713..11a9079 100644 --- a/source/utility.h +++ b/source/utility.h @@ -31,6 +31,16 @@ int fileReadOffset(const char *path, void *data, size_t size, u32 offset); int fileRead(const char *path, void *data, size_t size); +int getFileHandleSize(); + +int fileHandleOpen(void* handlePtr, const char *filePath); + +size_t fileHandleSize(void* handlePtr); + +int fileHandleRead(void* handlePtr, void *data, size_t size, u32 offset); + +int fileHandleClose(void* handlePtr); + void svcSleep(u32 millis); const char *get_filename_ext(const char *filename); From 1bf9198d33b336c1a9b77f5ec8624070775441cd Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 12 Jun 2016 22:20:36 +0200 Subject: [PATCH 077/259] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 447b6ad..1ded193 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Binaries should now be in the `build` folder. * Arkhandar : graphics * dotjasp : graphics (regionfree icon) -###For screeninit: +###For screeninit code: * Aurora Wright * dark_samus * bil1s @@ -35,7 +35,7 @@ Binaries should now be in the `build` folder. * delebile * tiniVi -###For movies support: +###For movies support code example: * Wolfvak * d0k3 : compressed movies From cab385460ee480b590c7ae2deafdb32c066c6ebb Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 17 Jun 2016 21:25:50 +0200 Subject: [PATCH 078/259] Update anim.c --- source/anim.c | 199 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 155 insertions(+), 44 deletions(-) diff --git a/source/anim.c b/source/anim.c index 8333073..401ee3d 100644 --- a/source/anim.c +++ b/source/anim.c @@ -6,19 +6,17 @@ #ifdef ARM9 #include "memory.h" -// Top compression required memory: 864000+28809 = 892809 +// Top compression required memory: 576000+28809 = 604809 #define TOP_COMP_PTR (char*)PTR_MOVIE_COMP #define TOP_COMP_PREV_FRAME_PTR (TOP_COMP_PTR+sizeof(comp_manager_s)) -#define TOP_COMP_CURR_FRAME_PTR (TOP_COMP_PREV_FRAME_PTR+TOP_SCREEN_SIZE) -#define TOP_COMP_COMP_FRAME_PTR (TOP_COMP_CURR_FRAME_PTR+TOP_SCREEN_SIZE) +#define TOP_COMP_COMP_FRAME_PTR (TOP_COMP_PREV_FRAME_PTR+TOP_SCREEN_SIZE) -// Bottom compression required memory: 691200+23049 = 714249 +// Bottom compression required memory: 460800+23049 = 483849 #define BOT_COMP_PTR (TOP_COMP_COMP_FRAME_PTR+TOP_SCREEN_SIZE+(TOP_SCREEN_SIZE/10)+9) #define BOT_COMP_PREV_FRAME_PTR (BOT_COMP_PTR+sizeof(comp_manager_s)) -#define BOT_COMP_CURR_FRAME_PTR (BOT_COMP_PREV_FRAME_PTR+BOT_SCREEN_SIZE) -#define BOT_COMP_COMP_FRAME_PTR (BOT_COMP_CURR_FRAME_PTR+BOT_SCREEN_SIZE) +#define BOT_COMP_COMP_FRAME_PTR (BOT_COMP_PREV_FRAME_PTR+BOT_SCREEN_SIZE) -// Total compression required memory: 1607058 +// Total compression required memory: 1088658 = 0x109C92 #endif #include "utility.h" @@ -58,11 +56,9 @@ void movieLoopSetup(movie_state_s* movie) movie->loopFramesCount = movie->loopEndFrame - movie->loopStartFrame + movie->loopTimeOnStartFrame + movie->loopTimeOnEndFrame; - if ( movie->loopTimeOnStartFrame > 0 ) - movie->loopStartFrameStream = movie->loopStream; - - if ( movie->loopTimeOnEndFrame > 0 ) - movie->loopEndFrameStream = movie->loopStream + movie->frameSize*(movie->loopEndFrame-movie->loopStartFrame); + movie->loopStartFrameStream = movie->loopStream; + movie->loopEndFrameStream = movie->loopStream + movie->frameSize + *( ( MEMORY_STREAM == movie->loopStreamType ) ? (movie->loopEndFrame-movie->loopStartFrame) : 1 ); } #ifdef ARM9 @@ -95,18 +91,18 @@ void movieSetup(movie_config_s* mvConf, movie_state_s* movie) movie->comp = compPtr; #else movie->comp = (comp_manager_s*)malloc(sizeof(comp_manager_s)); - movie->comp->frame_prev = malloc(movie->frameSize); - movie->comp->frame_curr = malloc(movie->frameSize); + movie->comp->frame_prev_read = malloc(movie->frameSize); movie->comp->frame_comp = malloc(movie->frameSize + (movie->frameSize/10) + 9); #endif + movie->comp->frame_prev_write = (char*)movie->comp->frame_prev_read; memset(&movie->comp->state, 0, sizeof(qlz_state_decompress)); - memset(movie->comp->frame_prev, 0, movie->frameSize); - memset(movie->comp->frame_curr, 0, movie->frameSize); + memset(movie->comp->frame_prev_write, 0, movie->frameSize); memset(movie->comp->frame_comp, 0, movie->frameSize + (movie->frameSize/10) + 9); + movie->comp->reverse = 0; } - movie->framesCount = getMovieFramesCount(movie->file, movie->frameSize, (NULL != movie->comp), NULL); + movie->framesCount = getMovieFramesCount(movie->file, movie->frameSize, (NULL != movie->comp)); if ( movie->framesCount <= 0 ) { fileHandleClose(movie->file); @@ -123,6 +119,15 @@ void movieSetup(movie_config_s* mvConf, movie_state_s* movie) if ( 0 == movie->loopsToDo ) return; + movie->loopStreamType = mvConf->loopStreamType; + if ( movie->loopStreamType == MEMORY_COMPRESSED_STREAM ) + { + if ( !mvConf->compressed ) + movie->loopStreamType = MEMORY_STREAM; + } + else if ( movie->loopStreamType != FILE_STREAM ) + movie->loopStreamType = MEMORY_STREAM; + movie->loopReverse = mvConf->loopReverse; movie->loopTimeOnStartFrame = ( mvConf->loopTimeOnStartFrame > 0 ) ? mvConf->loopTimeOnStartFrame : 0; @@ -137,13 +142,34 @@ void movieSetup(movie_config_s* mvConf, movie_state_s* movie) if ( movie->loopEndFrame < 0 || movie->loopEndFrame >= movie->framesCount ) movie->loopEndFrame = movie->framesCount-1; - movie->loopStreamSize = movie->frameSize * (movie->loopEndFrame-movie->loopStartFrame+1); + switch ( movie->loopStreamType ) + { + case FILE_STREAM: + // We will keep file opened to stream next loops content (slower but avoid memory issues). + // But we still keep at least uncompressed loop first and last frame in memory. + movie->loopStreamSize = movie->frameSize*2 + ((movie->loopEndFrame-movie->loopStartFrame+1)*sizeof(int)); + + case MEMORY_STREAM: + // Full uncompressed frames are kept in memory, file is closed. + movie->loopStreamSize = movie->frameSize * (movie->loopEndFrame-movie->loopStartFrame+1); + break; + + case MEMORY_COMPRESSED_STREAM: + // For compressed movie, we will keep compressed data in memory and close the file. + getMovieDataOffsetForFrames(movie->file, movie->frameSize, (NULL != movie->comp), + movie->loopStartFrame, movie->loopEndFrame, + NULL, &movie->loopStreamSize); + movie->loopStreamSize += movie->frameSize*2 + ((movie->loopEndFrame-movie->loopStartFrame+1)*sizeof(int)); + } + #ifdef ARM9 movie->loopStream = streamPtr; #else movie->loopStream = malloc(movie->loopStreamSize); #endif + if ( MEMORY_STREAM != movie->loopStreamType ) + *(int*)(movie->loopStream+movie->frameSize*2) = (movie->loopEndFrame-movie->loopStartFrame); movieLoopSetup(movie); } @@ -159,13 +185,11 @@ void animSetup() #ifdef ARM9 comp_manager_s* topComp = (comp_manager_s*)PTR_MOVIE_COMP; - topComp->frame_prev = TOP_COMP_PREV_FRAME_PTR; - topComp->frame_curr = TOP_COMP_CURR_FRAME_PTR; + topComp->frame_prev_read = TOP_COMP_PREV_FRAME_PTR; topComp->frame_comp = TOP_COMP_COMP_FRAME_PTR; comp_manager_s* botComp = (comp_manager_s*)BOT_COMP_PTR; - botComp->frame_prev = BOT_COMP_PREV_FRAME_PTR; - botComp->frame_curr = BOT_COMP_CURR_FRAME_PTR; + botComp->frame_prev_read = BOT_COMP_PREV_FRAME_PTR; botComp->frame_comp = BOT_COMP_COMP_FRAME_PTR; int fileHandleSize = getFileHandleSize(); @@ -302,18 +326,38 @@ int readMovie(u8* fb, movie_state_s* movie) { if ( NULL == movie->file ) return -1; - int readMovieRes = readMovieFrame(movie->file, &movie->fileOffset, movie->comp, (char*)fb, movie->frameSize); + + int prevOffset = movie->fileOffset; + + comp_manager_s* compPtr = movie->comp; + comp_manager_s compTmp; + if ( NULL != compPtr && MEMORY_COMPRESSED_STREAM == movie->loopStreamType && NULL != movie->loopStream + && movie->curFrame >= movie->loopStartFrame && movie->curFrame <= movie->loopEndFrame ) + { + int* loopFramesPtr = (int*)(movie->loopStream+movie->frameSize*2); + int* frameOffsets = loopFramesPtr+1; + compTmp = *movie->comp; + compTmp.frame_comp = (char*)loopFramesPtr + (*loopFramesPtr+1)*sizeof(int); + if ( movie->curFrame > movie->loopStartFrame ) + compTmp.frame_comp += prevOffset-frameOffsets[0]; + compPtr = &compTmp; + } + + int readMovieRes = readMovieFrame(movie->file, &movie->fileOffset, compPtr, (char*)fb, movie->frameSize); if ( readMovieRes < 0 || movie->curFrame >= movie->framesCount-1 || ( movie->loopReverse && movie->curFrame >= movie->loopEndFrame ) ) { - fileHandleClose(movie->file); - #ifndef ARM9 - free(movie->file); - #endif - movie->file = NULL; + if ( FILE_STREAM != movie->loopStreamType ) + { + fileHandleClose(movie->file); + #ifndef ARM9 + free(movie->file); + #endif + movie->file = NULL; + } movie->curLoop = 1; - - if ( 0 != movie->loopsToDo && movie->curFrame < movie->framesCount-1 ) + + /*if ( 0 != movie->loopsToDo && movie->curFrame < movie->framesCount-1 ) { // Correction for corrupted compressed movies movie->framesCount = movie->curFrame; @@ -322,11 +366,30 @@ int readMovie(u8* fb, movie_state_s* movie) if ( movie->loopEndFrame >= movie->framesCount ) movie->loopEndFrame = movie->framesCount-1; movieLoopSetup(movie); - } + }*/ } - if ( 0 == readMovieRes && NULL != movie->loopStream && movie->curFrame >= movie->loopStartFrame && movie->curFrame <= movie->loopEndFrame ) - memcpy(movie->loopStream+(movie->curFrame-movie->loopStartFrame)*movie->frameSize, fb, movie->frameSize); + if ( NULL != movie->loopStream && movie->curFrame >= movie->loopStartFrame && movie->curFrame <= movie->loopEndFrame ) + { + if ( MEMORY_STREAM != movie->loopStreamType ) + *(int*)(movie->loopStream+movie->frameSize*2+(movie->curFrame-movie->loopStartFrame+1)*sizeof(int)) = prevOffset; + + if ( MEMORY_COMPRESSED_STREAM == movie->loopStreamType && ( movie->curFrame == movie->loopEndFrame || readMovieRes < 0 ) ) + { + int* loopFramesPtr = (int*)(movie->loopStream+movie->frameSize*2); + int* frameOffsets = loopFramesPtr+1; + int remapOffset = (int)((char*)frameOffsets + (*loopFramesPtr)*sizeof(int) - frameOffsets[0]); + for ( int i = 0 ; i < *loopFramesPtr ; i++ ) + frameOffsets[i] += remapOffset; + } + + if ( movie->curFrame == movie->loopStartFrame ) + memcpy(movie->loopStartFrameStream, fb, movie->frameSize); + else if ( movie->curFrame == movie->loopEndFrame ) + memcpy(movie->loopEndFrameStream, fb, movie->frameSize); + else if ( MEMORY_STREAM == movie->loopStreamType ) + memcpy(movie->loopStream+(movie->curFrame-movie->loopStartFrame)*movie->frameSize, fb, movie->frameSize); + } movie->curFrame++; if ( movie->curLoop > 0 ) @@ -336,24 +399,74 @@ int readMovie(u8* fb, movie_state_s* movie) { if ( movie->loopReverse && movie->curLoop%2 == 1 ) { - if ( movie->curFrame < movie->loopTimeOnEndFrame ) + if ( movie->curFrame <= movie->loopTimeOnEndFrame ) memcpy(fb, movie->loopEndFrameStream, movie->frameSize); - else if ( movie->curFrame > movie->loopTimeOnEndFrame+movie->loopEndFrame-movie->loopStartFrame ) + else if ( movie->curFrame >= movie->loopTimeOnEndFrame+movie->loopEndFrame-movie->loopStartFrame ) memcpy(fb, movie->loopStartFrameStream, movie->frameSize); else { - memcpy(fb, movie->loopStream + movie->frameSize*((movie->loopEndFrame-movie->loopStartFrame) - -(movie->curFrame-movie->loopTimeOnEndFrame)), movie->frameSize); + int frameToGet = (movie->loopEndFrame-movie->loopStartFrame)-(movie->curFrame-movie->loopTimeOnEndFrame); + if ( MEMORY_STREAM == movie->loopStreamType ) + memcpy(fb, movie->loopStream + movie->frameSize*frameToGet, movie->frameSize); + else + { + if ( NULL != movie->comp ) + { + comp_manager_s compTmp = *movie->comp; + compTmp.reverse = 1; + if ( movie->curLoop == 1 ) // By-pass bug on first loop, ugly, no logic explanation found... + frameToGet++; + int offset = *(int*)(movie->loopStream + 2*movie->frameSize + (1+frameToGet)*sizeof(int)); + if ( MEMORY_COMPRESSED_STREAM == movie->loopStreamType ) + { + compTmp.frame_comp = (char*)offset; + readCompressedMovieFrameFromBuffer(&compTmp, (char*)fb, movie->frameSize ); + } + else + readMovieFrame(movie->file, &offset, &compTmp, (char*)fb, movie->frameSize); + } + else + { + int fileOffset = frameToGet*movie->frameSize; + readMovieFrame(movie->file, &fileOffset, NULL, (char*)fb, movie->frameSize); + } + } } } else { - if ( movie->curFrame < movie->loopTimeOnStartFrame ) + if ( movie->curFrame <= movie->loopTimeOnStartFrame ) memcpy(fb, movie->loopStartFrameStream, movie->frameSize); - else if ( movie->curFrame > movie->loopTimeOnStartFrame+movie->loopEndFrame-movie->loopStartFrame ) + else if ( movie->curFrame >= movie->loopTimeOnStartFrame+movie->loopEndFrame-movie->loopStartFrame ) memcpy(fb, movie->loopEndFrameStream, movie->frameSize); else - memcpy(fb, movie->loopStream+movie->frameSize*(movie->curFrame-movie->loopTimeOnStartFrame), movie->frameSize); + { + int frameToGet = movie->curFrame-movie->loopTimeOnStartFrame; + if ( MEMORY_STREAM == movie->loopStreamType ) + memcpy(fb, movie->loopStream+movie->frameSize*frameToGet, movie->frameSize); + else + { + if ( NULL != movie->comp ) + { + comp_manager_s compTmp = *movie->comp; + if ( frameToGet == 1 ) + compTmp.frame_prev_read = movie->loopStartFrameStream; + int offset = *(int*)(movie->loopStream + 2*movie->frameSize + (1+frameToGet)*sizeof(int)); + if ( MEMORY_COMPRESSED_STREAM == movie->loopStreamType ) + { + compTmp.frame_comp = (char*)offset; + readCompressedMovieFrameFromBuffer(&compTmp, (char*)fb, movie->frameSize ); + } + else + readMovieFrame(movie->file, &offset, &compTmp, (char*)fb, movie->frameSize); + } + else + { + int fileOffset = frameToGet*movie->frameSize; + readMovieFrame(movie->file, &fileOffset, NULL, (char*)fb, movie->frameSize); + } + } + } } movie->curFrame++; @@ -391,8 +504,7 @@ void animExit() free(anim->topMovie.file); if (anim->topMovie.comp) { - free(anim->topMovie.comp->frame_prev); - free(anim->topMovie.comp->frame_curr); + free(anim->topMovie.comp->frame_prev_read); // Same as frame_prev_write free(anim->topMovie.comp->frame_comp); free(anim->topMovie.comp); } @@ -403,8 +515,7 @@ void animExit() free(anim->botMovie.file); if (anim->botMovie.comp) { - free(anim->botMovie.comp->frame_prev); - free(anim->botMovie.comp->frame_curr); + free(anim->botMovie.comp->frame_prev_read); // Same as frame_prev_write free(anim->botMovie.comp->frame_comp); free(anim->botMovie.comp); } From 30efc3bbb24c6fca52b23f3576796070b0e3d35c Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 17 Jun 2016 21:26:09 +0200 Subject: [PATCH 079/259] Update anim.h --- source/anim.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/anim.h b/source/anim.h index 4004a47..1b9f3e3 100644 --- a/source/anim.h +++ b/source/anim.h @@ -22,7 +22,8 @@ typedef struct { int loopsToDo; int loopFramesCount; - + + int loopStreamType; char* loopStream; int loopStreamSize; int loopReverse; From 47a6a19efddcf73d1bab82ad06eddacca885fa65 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 17 Jun 2016 21:26:28 +0200 Subject: [PATCH 080/259] Update config.c --- source/config.c | 197 ++++++++++++++++++++++++++---------------------- 1 file changed, 107 insertions(+), 90 deletions(-) diff --git a/source/config.c b/source/config.c index 2c76b55..1c1f3dc 100644 --- a/source/config.c +++ b/source/config.c @@ -120,6 +120,78 @@ void writeHexDataAsStr(const char *data, int dataSize, char* dataAsStr) { } } +void readMovieProperty(movie_config_s* mvConf, const char *name, const char* value) { + + if (NAME_MATCH("path")) { + strncpy(mvConf->path, value, 128); + } else if (NAME_MATCH("compression")) { + if ( value[0] >= '0' && value[0] <= '9' ) + mvConf->compressed = atoi(value); + else if ( 0 == strcmp(value, "QuickLZ") ) + mvConf->compressed = 1; + } else if (NAME_MATCH("loopCount")) { + if ( value[0] == 'I' || value[0] <= 'i' ) // Value for "ININITE" or "infinite" + mvConf->loopCount = -1; + else + mvConf->loopCount = atoi(value); + } else if (NAME_MATCH("loopStreamType")) { + if ( value[0] >= '0' && value[0] <= '9' ) + mvConf->loopStreamType = atoi(value); + else if ( 0 == strcmp(value, "file") ) + mvConf->loopStreamType = FILE_STREAM; + else if ( 0 == strcmp(value, "memory") ) + mvConf->loopStreamType = MEMORY_STREAM; + else if ( 0 == strcmp(value, "compressed_memory") ) + mvConf->loopStreamType = MEMORY_COMPRESSED_STREAM; + } else if (NAME_MATCH("loopReverse")) { + if ( value[0] >= '0' && value[0] <= '9' ) + mvConf->loopReverse = atoi(value); + else if ( value[0] == 'Y' || value[0] == 'y' || value[0] == 'T' || value[0] == 't' ) + mvConf->loopReverse = 1; // Value for "YES", "yes", "TRUE" and "true" + else if ( value[0] == 'N' || value[0] == 'n' || value[0] == 'F' || value[0] == 'f' ) + mvConf->loopReverse = 0; // Value for "NO", "no", "FALSE" and "false" + } else if (NAME_MATCH("loopStartFrame")) { + mvConf->loopStartFrame = atoi(value); + } else if (NAME_MATCH("delayOnLoopStart")) { + mvConf->loopTimeOnStartFrame = atoi(value); + } else if (NAME_MATCH("loopEndFrame")) { + mvConf->loopEndFrame = atoi(value); + } else if (NAME_MATCH("delayOnLoopEnd")) { + mvConf->loopTimeOnEndFrame = atoi(value); + } +} + +void writeMovieProperty(movie_config_s* mvConf, char *cfg, int* sizePtr) { + + *sizePtr += snprintf(cfg+*sizePtr, 256, "path=%s;\n", mvConf->path); + if ( 0 != mvConf->compressed ) + *sizePtr += snprintf(cfg+*sizePtr, 256, "compression=QuickLZ;\n"); + if ( 0 != mvConf->loopCount ) + { + if ( mvConf->loopCount < 0 ) + *sizePtr += snprintf(cfg+*sizePtr, 256, "loopCount=infinite;\n"); + else + *sizePtr += snprintf(cfg+*sizePtr, 256, "loopCount=%i;\n", mvConf->loopCount); + if ( 0 != mvConf->loopStreamType ) + { + if ( MEMORY_COMPRESSED_STREAM == mvConf->loopStreamType ) + *sizePtr += snprintf(cfg+*sizePtr, 256, "loopStreamType=compressed_memory;\n"); + else + *sizePtr += snprintf(cfg+*sizePtr, 256, "loopStreamType=memory;\n"); + } + if ( 0 != mvConf->loopReverse ) + *sizePtr += snprintf(cfg+*sizePtr, 256, "loopReverse=yes;\n"); + if ( mvConf->loopStartFrame > 0 ) + *sizePtr += snprintf(cfg+*sizePtr, 256, "loopStartFrame=%i;\n", mvConf->loopStartFrame); + if ( mvConf->loopTimeOnStartFrame > 0 ) + *sizePtr += snprintf(cfg+*sizePtr, 256, "delayOnLoopStart=%i;\n", mvConf->loopTimeOnStartFrame); + if ( mvConf->loopEndFrame >= 0 ) + *sizePtr += snprintf(cfg+*sizePtr, 256, "loopEndFrame=%i;\n", mvConf->loopEndFrame); + if ( mvConf->loopTimeOnEndFrame > 0 ) + *sizePtr += snprintf(cfg+*sizePtr, 256, "delayOnLoopEnd=%i;\n", mvConf->loopTimeOnEndFrame); + } +} + static char *ini_buffer_reader(char *str, int num, void *stream) { buffer_ctx *ctx = (buffer_ctx *) stream; int idx = 0; @@ -211,61 +283,30 @@ static int handler(void *user, const char *section, const char *name, // animation else if (SECTION_MATCH("animation")) { - if (NAME_MATCH("bgTop1Anim")) { + if (NAME_MATCH("bgTop1")) { setAnimWithColor(&config->bgTop1AnimTime, &config->bgTop1AnimTimeStart, config->bgTop1AnimColor, item); - } else if (NAME_MATCH("bgTop2Anim")) { + } else if (NAME_MATCH("bgTop2")) { setAnimWithColor(&config->bgTop2AnimTime, &config->bgTop2AnimTimeStart, config->bgTop2AnimColor, item); - } else if (NAME_MATCH("bgBottomAnim")) { + } else if (NAME_MATCH("bgBottom")) { setAnimWithColor(&config->bgBotAnimTime, &config->bgBotAnimTimeStart, config->bgBotAnimColor, item); - } else if (NAME_MATCH("highlightAnim")) { + } else if (NAME_MATCH("highlight")) { setAnimWithColorAlpha(&config->highlightAnimTime, &config->highlightAnimTimeStart, config->highlightAnimColor, item); - } else if (NAME_MATCH("bordersAnim")) { + } else if (NAME_MATCH("borders")) { setAnimWithColorAlpha(&config->bordersAnimTime, &config->bordersAnimTimeStart, config->bordersAnimColor, item); - } else if (NAME_MATCH("font1Anim")) { + } else if (NAME_MATCH("font1")) { setAnimWithColorAlpha(&config->fntDefAnimTime, &config->fntDefAnimTimeStart, config->fntDefAnimColor, item); - } else if (NAME_MATCH("font2Anim")) { + } else if (NAME_MATCH("font2")) { setAnimWithColorAlpha(&config->fntSelAnimTime, &config->fntSelAnimTimeStart, config->fntSelAnimColor, item); } else if (NAME_MATCH("menuFadeIn")) { setAnimTimes(&config->menuFadeInTime, &config->menuFadeInTimeStart, item); } } - // movie - else if (SECTION_MATCH("movie")) - { - if (NAME_MATCH("movieTop")) { - strncpy(config->movieTop.path, item, 128); - } else if (NAME_MATCH("movieTopCompress")) { - config->movieTop.compressed = atoi(item); - } else if (NAME_MATCH("movieTopLoop")) { - config->movieTop.loopCount = atoi(item); - } else if (NAME_MATCH("movieTopLoopReverse")) { - config->movieTop.loopReverse = atoi(item); - } else if (NAME_MATCH("movieTopLoopStart")) { - config->movieTop.loopStartFrame = atoi(item); - } else if (NAME_MATCH("movieTopTimeOnLoopStart")) { - config->movieTop.loopTimeOnStartFrame = atoi(item); - } else if (NAME_MATCH("movieTopLoopEnd")) { - config->movieTop.loopEndFrame = atoi(item); - } else if (NAME_MATCH("movieTopTimeOnLoopEnd")) { - config->movieTop.loopTimeOnEndFrame = atoi(item); - } else if (NAME_MATCH("movieBot")) { - strncpy(config->movieBot.path, item, 128); - } else if (NAME_MATCH("movieBotCompress")) { - config->movieBot.compressed = atoi(item); - } else if (NAME_MATCH("movieBotLoop")) { - config->movieBot.loopCount = atoi(item); - } else if (NAME_MATCH("movieBotLoopReverse")) { - config->movieBot.loopReverse = atoi(item); - } else if (NAME_MATCH("movieBotLoopStart")) { - config->movieBot.loopStartFrame = atoi(item); - } else if (NAME_MATCH("movieBotTimeOnLoopStart")) { - config->movieBot.loopTimeOnStartFrame = atoi(item); - } else if (NAME_MATCH("movieBotLoopEnd")) { - config->movieBot.loopEndFrame = atoi(item); - } else if (NAME_MATCH("movieBotTimeOnLoopEnd")) { - config->movieBot.loopTimeOnEndFrame = atoi(item); - } + // movies + else if (SECTION_MATCH("topMovie")) { + readMovieProperty(&config->movieTop, name, item); + } else if (SECTION_MATCH("bottomMovie")) { + readMovieProperty(&config->movieBot, name, item); } // entries @@ -356,6 +397,7 @@ void configThemeInit() { config->movieTop.path[0] = '\0'; config->movieTop.compressed = 0; config->movieTop.loopCount = 0; + config->movieTop.loopStreamType = 0; config->movieTop.loopReverse = 0; config->movieTop.loopStartFrame = 0; config->movieTop.loopTimeOnStartFrame = 0; @@ -365,6 +407,7 @@ void configThemeInit() { config->movieBot.path[0] = '\0'; config->movieBot.compressed = 0; config->movieBot.loopCount = 0; + config->movieBot.loopStreamType = 0; config->movieBot.loopReverse = 0; config->movieBot.loopStartFrame = 0; config->movieBot.loopTimeOnStartFrame = 0; @@ -471,7 +514,7 @@ void configSave() { memset(cfg, 0, buffSize); // 256 lines * 256 char // general section - size += snprintf(cfg, 256, "[general];\n"); + size += snprintf(cfg, 256, "[general]\n"); #ifndef ARM9 size += snprintf(cfg+size, 256, "autobootfix=%i;\n", config->autobootfix); #endif @@ -480,7 +523,7 @@ void configSave() { size += snprintf(cfg+size, 256, "default=%i;\n\n", config->index); // theme section - size += snprintf(cfg+size, 256, "[theme];\n"); + size += snprintf(cfg+size, 256, "[theme]\n"); size += snprintf(cfg+size, 256, "bgTop1=%02X%02X%02X;\n", config->bgTop1[0], config->bgTop1[1], config->bgTop1[2]); size += snprintf(cfg+size, 256, "bgTop2=%02X%02X%02X;\n", config->bgTop2[0], config->bgTop2[1], config->bgTop2[2]); size += snprintf(cfg+size, 256, "bgBottom=%02X%02X%02X;\n", config->bgBot[0], config->bgBot[1], config->bgBot[2]); @@ -505,32 +548,32 @@ void configSave() { size += snprintf(cfg+size, 256, "bgImgBot=%s;\n\n", config->bgImgBot); // animation section - size += snprintf(cfg+size, 256, "[animation];\n"); + size += snprintf(cfg+size, 256, "[animation]\n"); if ( config->bgTop1AnimTime > 0 ) { - size += snprintf(cfg+size, 256, "bgTop1Anim=%i:%i:%02X%02X%02X;\n", config->bgTop1AnimTime, config->bgTop1AnimTimeStart, + size += snprintf(cfg+size, 256, "bgTop1=%i:%i:%02X%02X%02X;\n", config->bgTop1AnimTime, config->bgTop1AnimTimeStart, config->bgTop1AnimColor[0], config->bgTop1AnimColor[1], config->bgTop1AnimColor[2]); } if ( config->bgTop2AnimTime > 0 ) { - size += snprintf(cfg+size, 256, "bgTop2Anim=%i:%i:%02X%02X%02X;\n", config->bgTop2AnimTime, config->bgTop2AnimTimeStart, + size += snprintf(cfg+size, 256, "bgTop2=%i:%i:%02X%02X%02X;\n", config->bgTop2AnimTime, config->bgTop2AnimTimeStart, config->bgTop2AnimColor[0], config->bgTop2AnimColor[1], config->bgTop2AnimColor[2]); } if ( config->bgBotAnimTime > 0 ) { - size += snprintf(cfg+size, 256, "bgBottomAnim=%i:%i:%02X%02X%02X;\n", config->bgBotAnimTime, config->bgBotAnimTimeStart, + size += snprintf(cfg+size, 256, "bgBottom=%i:%i:%02X%02X%02X;\n", config->bgBotAnimTime, config->bgBotAnimTimeStart, config->bgBotAnimColor[0], config->bgBotAnimColor[1], config->bgBotAnimColor[2]); } if ( config->highlightAnimTime > 0 ) { if ( config->highlightAnimColor[3] < 0xFF ) { - size += snprintf(cfg+size, 256, "highlightAnim=%i:%i:%02X%02X%02X%02X;\n", config->highlightAnimTime, config->highlightAnimTimeStart, + size += snprintf(cfg+size, 256, "highlight=%i:%i:%02X%02X%02X%02X;\n", config->highlightAnimTime, config->highlightAnimTimeStart, config->highlightAnimColor[0], config->highlightAnimColor[1], config->highlightAnimColor[2], config->highlightAnimColor[3]); } else { - size += snprintf(cfg+size, 256, "highlightAnim=%i:%i:%02X%02X%02X;\n", config->highlightAnimTime, config->highlightAnimTimeStart, + size += snprintf(cfg+size, 256, "highlight=%i:%i:%02X%02X%02X;\n", config->highlightAnimTime, config->highlightAnimTimeStart, config->highlightAnimColor[0], config->highlightAnimColor[1], config->highlightAnimColor[2]); } } @@ -538,12 +581,12 @@ void configSave() { { if ( config->highlightAnimColor[3] < 0xFF ) { - size += snprintf(cfg+size, 256, "bordersAnim=%i:%i:%02X%02X%02X%02X;\n", config->bordersAnimTime, config->bordersAnimTimeStart, + size += snprintf(cfg+size, 256, "borders=%i:%i:%02X%02X%02X%02X;\n", config->bordersAnimTime, config->bordersAnimTimeStart, config->bordersAnimColor[0], config->bordersAnimColor[1], config->bordersAnimColor[2], config->bordersAnimColor[3]); } else { - size += snprintf(cfg+size, 256, "bordersAnim=%i:%i:%02X%02X%02X;\n", config->bordersAnimTime, config->bordersAnimTimeStart, + size += snprintf(cfg+size, 256, "borders=%i:%i:%02X%02X%02X;\n", config->bordersAnimTime, config->bordersAnimTimeStart, config->bordersAnimColor[0], config->bordersAnimColor[1], config->bordersAnimColor[2]); } } @@ -551,12 +594,12 @@ void configSave() { { if ( config->fntDefAnimColor[3] < 0xFF ) { - size += snprintf(cfg+size, 256, "font1Anim=%i:%i:%02X%02X%02X%02X;\n", config->fntDefAnimTime, config->fntDefAnimTimeStart, + size += snprintf(cfg+size, 256, "font1=%i:%i:%02X%02X%02X%02X;\n", config->fntDefAnimTime, config->fntDefAnimTimeStart, config->fntDefAnimColor[0], config->fntDefAnimColor[1], config->fntDefAnimColor[2], config->fntDefAnimColor[3]); } else { - size += snprintf(cfg+size, 256, "font1Anim=%i:%i:%02X%02X%02X;\n", config->fntDefAnimTime, config->fntDefAnimTimeStart, + size += snprintf(cfg+size, 256, "font1=%i:%i:%02X%02X%02X;\n", config->fntDefAnimTime, config->fntDefAnimTimeStart, config->fntDefAnimColor[0], config->fntDefAnimColor[1], config->fntDefAnimColor[2]); } } @@ -564,12 +607,12 @@ void configSave() { { if ( config->fntDefAnimColor[3] < 0xFF ) { - size += snprintf(cfg+size, 256, "font2Anim=%i:%i:%02X%02X%02X%02X;\n", config->fntSelAnimTime, config->fntSelAnimTimeStart, + size += snprintf(cfg+size, 256, "font2=%i:%i:%02X%02X%02X%02X;\n", config->fntSelAnimTime, config->fntSelAnimTimeStart, config->fntSelAnimColor[0], config->fntSelAnimColor[1], config->fntSelAnimColor[2], config->fntSelAnimColor[3]); } else { - size += snprintf(cfg+size, 256, "font2Anim=%i:%i:%02X%02X%02X;\n", config->fntDefAnimTime, config->fntSelAnimTimeStart, + size += snprintf(cfg+size, 256, "font2=%i:%i:%02X%02X%02X;\n", config->fntDefAnimTime, config->fntSelAnimTimeStart, config->fntSelAnimColor[0], config->fntSelAnimColor[1], config->fntSelAnimColor[2]); } } @@ -577,46 +620,20 @@ void configSave() { size += snprintf(cfg+size, 256, "menuFadeIn=%i:%i;\n", config->menuFadeInTime, config->menuFadeInTimeStart); // movie section - size += snprintf(cfg+size, 256, "\n[movie];\n"); - size += snprintf(cfg+size, 256, "movieTop=%s;\n", config->movieTop.path); - if ( 0 != config->movieTop.compressed ) - size += snprintf(cfg+size, 256, "movieTopCompress=1;\n"); - if ( 0 != config->movieTop.loopCount ) + if ( config->movieTop.path[0] != '\0' ) { - size += snprintf(cfg+size, 256, "movieTopLoop=%i;\n", config->movieTop.loopCount); - if ( 0 != config->movieTop.loopReverse ) - size += snprintf(cfg+size, 256, "movieTopLoopReverse=1;\n"); - if ( config->movieTop.loopStartFrame > 0 ) - size += snprintf(cfg+size, 256, "movieTopLoopStart=%i;\n", config->movieTop.loopStartFrame); - if ( config->movieTop.loopTimeOnStartFrame > 0 ) - size += snprintf(cfg+size, 256, "movieTopTimeOnLoopStart=%i;\n", config->movieTop.loopTimeOnStartFrame); - if ( config->movieTop.loopEndFrame >= 0 ) - size += snprintf(cfg+size, 256, "movieTopLoopEnd=%i;\n", config->movieTop.loopEndFrame); - if ( config->movieTop.loopTimeOnEndFrame > 0 ) - size += snprintf(cfg+size, 256, "movieTopTimeOnLoopEnd=%i;\n", config->movieTop.loopTimeOnEndFrame); + size += snprintf(cfg+size, 256, "\n[topMovie]\n"); + writeMovieProperty(&config->movieTop, cfg, &size); } - - size += snprintf(cfg+size, 256, "movieBot=%s;\n", config->movieBot.path); - if ( 0 != config->movieBot.compressed ) - size += snprintf(cfg+size, 256, "movieBotCompress=1;\n"); - if ( 0 != config->movieBot.loopCount ) + if ( config->movieBot.path[0] != '\0' ) { - size += snprintf(cfg+size, 256, "movieBotLoop=%i;\n", config->movieTop.loopCount); - if ( 0 != config->movieBot.loopReverse ) - size += snprintf(cfg+size, 256, "movieBotLoopReverse=1;\n"); - if ( config->movieBot.loopStartFrame > 0 ) - size += snprintf(cfg+size, 256, "movieBotLoopStart=%i;\n", config->movieBot.loopStartFrame); - if ( config->movieBot.loopTimeOnStartFrame > 0 ) - size += snprintf(cfg+size, 256, "movieBotTimeOnLoopStart=%i;\n", config->movieBot.loopTimeOnStartFrame); - if ( config->movieBot.loopEndFrame >= 0 ) - size += snprintf(cfg+size, 256, "movieBotLoopEnd=%i;\n", config->movieBot.loopEndFrame); - if ( config->movieBot.loopTimeOnEndFrame > 0 ) - size += snprintf(cfg+size, 256, "movieBotTimeOnLoopEnd=%i;\n", config->movieBot.loopTimeOnEndFrame); + size += snprintf(cfg+size, 256, "\n[bottomMovie]\n"); + writeMovieProperty(&config->movieBot, cfg, &size); } // entries section for(i=0; icount; i++) { - size += snprintf(cfg+size, 256, "\n[entry];\n"); + size += snprintf(cfg+size, 256, "\n[entry]\n"); size += snprintf(cfg+size, 256, "title=%s;\n", config->entries[i].title); size += snprintf(cfg+size, 256, "path=%s;\n", config->entries[i].path); size += snprintf(cfg+size, 256, "offset=%x;\n", (int)config->entries[i].offset); From b0f60fffd40b12075fe8663638c116c7c1198c62 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 17 Jun 2016 21:27:07 +0200 Subject: [PATCH 081/259] Update config.h --- source/config.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/config.h b/source/config.h index 109dfa7..3776a7f 100644 --- a/source/config.h +++ b/source/config.h @@ -24,6 +24,11 @@ extern "C" { #define CONFIG_MAX_ENTRIES 11 #define PATCHES_MAX_PER_ENTRY 4 +#define FILE_STREAM 0 +#define MEMORY_STREAM 1 +#define MEMORY_COMPRESSED_STREAM 2 + + typedef struct { char title[64]; char path[128]; @@ -38,6 +43,7 @@ typedef struct { int compressed; int loopCount; int loopReverse; + int loopStreamType; int loopStartFrame; int loopTimeOnStartFrame; int loopEndFrame; From 50a061a08d57ba5e4c1d8ae122bd63df9cb31990 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 17 Jun 2016 21:27:30 +0200 Subject: [PATCH 082/259] Update memory.h --- source/memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/memory.h b/source/memory.h index 666a1e2..22846bd 100644 --- a/source/memory.h +++ b/source/memory.h @@ -17,7 +17,7 @@ #define PTR_CFG_TMP (u8*)(0x25230000) #define PTR_ANIM (u8*)(0x25240000) #define PTR_MOVIE_COMP (u8*)(0x25250000) -#define PTR_MOVIE_LOOP (u8*)(0x25450000) +#define PTR_MOVIE_LOOP (u8*)(0x25360000) #define PTR_PAYLOAD_MAIN 0x23F00000 #define PTR_PAYLOAD_MAIN_DATA 0x26000000 From 3108b1103ff37e92a1195ad5b2a02ac8aa1c40b5 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 17 Jun 2016 21:28:04 +0200 Subject: [PATCH 083/259] Update menu_config.c --- source/menu_config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/menu_config.c b/source/menu_config.c index 3acb347..8469083 100644 --- a/source/menu_config.c +++ b/source/menu_config.c @@ -130,6 +130,8 @@ int menu_config() { #ifndef ARM9 drawItem(menu_index == 3, 48, "Bootfix: %i", config->autobootfix); #endif + + drawInfo("Unofficial version 10"); gfxSwap(); } return -1; From 2eeb3b556cff5957d0562aa6920667e33980745c Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 17 Jun 2016 21:28:42 +0200 Subject: [PATCH 084/259] Update movie.c --- source/movie.c | 85 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 23 deletions(-) diff --git a/source/movie.c b/source/movie.c index ba096b1..59ef513 100644 --- a/source/movie.c +++ b/source/movie.c @@ -24,31 +24,41 @@ int readMovieFrame(void* iFileHandlePtr, int* ioFileOffset, comp_manager_s* iCom readBytes = fileHandleRead(iFileHandlePtr, iCompMgr->frame_comp + 9, comp_size - 9, *ioFileOffset); // Read compressed buffer - if (readBytes != (comp_size - 9) || qlz_size_decompressed(iCompMgr->frame_comp) != iFrameBufferSize) // Check if EOF + if (readBytes != (comp_size - 9) || readCompressedMovieFrameFromBuffer(iCompMgr, oFrameBuffer, iFrameBufferSize)) // Check if EOF return -1; // Disable the animation + *ioFileOffset += readBytes; + return 0; + } +} - qlz_decompress(iCompMgr->frame_comp, iCompMgr->frame_curr, &iCompMgr->state); // Decompress the frame +int readCompressedMovieFrameFromBuffer(comp_manager_s* iCompMgr, char* oFrameBuffer, int iFrameBufferSize) +{ + if ( qlz_size_decompressed(iCompMgr->frame_comp) != iFrameBufferSize ) + return -1; + + qlz_decompress(iCompMgr->frame_comp, oFrameBuffer, &iCompMgr->state); // Decompress the frame + if ( iCompMgr->reverse ) + { for (size_t i = 0; i < iFrameBufferSize; i++) // Perform delta decoding - iCompMgr->frame_curr[i] += iCompMgr->frame_prev[i]; - - memcpy(iCompMgr->frame_prev, iCompMgr->frame_curr, iFrameBufferSize); // Keep a copy of the fb - memcpy(oFrameBuffer, iCompMgr->frame_curr, iFrameBufferSize); // Display it on the screen - return 0; + oFrameBuffer[i] = iCompMgr->frame_prev_read[i] - oFrameBuffer[i]; + } + else + { + for (size_t i = 0; i < iFrameBufferSize; i++) // Perform delta decoding + oFrameBuffer[i] += iCompMgr->frame_prev_read[i]; } + + memcpy(iCompMgr->frame_prev_write, oFrameBuffer, iFrameBufferSize); // Keep a copy of the fb + return 0; } -int getMovieFramesCount(void* iFileHandlePtr, int iFrameBufferSize, int iCompressed, int* ioFrameOffset) +int getMovieFramesCount(void* iFileHandlePtr, int iFrameBufferSize, int iCompressed) { size_t fileSize = fileHandleSize(iFileHandlePtr); if ( !iCompressed ) - { - int framesCount = fileSize / iFrameBufferSize; - if ( NULL != ioFrameOffset ) - *ioFrameOffset = ( *ioFrameOffset < framesCount && *ioFrameOffset >=0 ) ? (*ioFrameOffset * iFrameBufferSize) : -1; - return framesCount; - } + return fileSize / iFrameBufferSize; else { char compHeader[9]; @@ -60,18 +70,47 @@ int getMovieFramesCount(void* iFileHandlePtr, int iFrameBufferSize, int iCompres size_t comp_size = qlz_size_compressed(compHeader); // Get compressed size if ( fileOffset + comp_size > fileSize ) break; - if ( NULL != ioFrameOffset && *ioFrameOffset == framesCount ) - { - *ioFrameOffset = fileOffset; - ioFrameOffset = NULL; - } fileOffset += comp_size; framesCount++; } - - if ( NULL != ioFrameOffset ) - *ioFrameOffset = -1; // We didn't find any valid frame - + return framesCount; } } + +void getMovieDataOffsetForFrames(void* iFileHandlePtr, int iFrameBufferSize, int iCompressed, int iStartFrame, int iEndFrame, + int* oStartFrameOffset, int* oDataSizeToEndFrame) +{ + size_t fileSize = fileHandleSize(iFileHandlePtr); + if ( !iCompressed ) + { + int framesCount = fileSize / iFrameBufferSize; + if ( NULL != oStartFrameOffset ) + *oStartFrameOffset = iFrameBufferSize * ( ( iStartFrame < framesCount ) ? iStartFrame : (framesCount-1) ); + if ( NULL != oDataSizeToEndFrame ) + *oDataSizeToEndFrame = iFrameBufferSize * ( ( iEndFrame < framesCount ) ? iEndFrame : (framesCount-1) ); + } + else + { + char compHeader[9]; + int curFrame = 0; + int fileOffset = 0; + int firstFrameOffset = -1; + + while ( curFrame <= iEndFrame && 9 == fileHandleRead(iFileHandlePtr, compHeader, 9, fileOffset) ) + { + size_t comp_size = qlz_size_compressed(compHeader); // Get compressed size + if ( fileOffset + comp_size > fileSize ) + break; + if ( curFrame == iStartFrame ) + firstFrameOffset = fileOffset; + fileOffset += comp_size; + curFrame++; + } + + if ( NULL != oStartFrameOffset ) + *oStartFrameOffset = firstFrameOffset; + if ( NULL != oDataSizeToEndFrame ) + *oDataSizeToEndFrame = fileOffset; + } +} From 69274db697cc75d2d42a06b7c4e19cbdd359099b Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 17 Jun 2016 21:29:03 +0200 Subject: [PATCH 085/259] Update movie.h --- source/movie.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/source/movie.h b/source/movie.h index bab36c3..5d48414 100644 --- a/source/movie.h +++ b/source/movie.h @@ -9,13 +9,18 @@ extern "C" { typedef struct { qlz_state_decompress state; - char* frame_prev; - char* frame_curr; + const char* frame_prev_read; + char* frame_prev_write; char* frame_comp; + int reverse; } comp_manager_s; int readMovieFrame(void* iFileHandlePtr, int* ioFileOffset, comp_manager_s* iCompMgr, char* oFrameBuffer, int iFrameBufferSize); -int getMovieFramesCount(void* iFileHandlePtr, int iFrameBufferSize, int iCompressed, int* ioFrameOffset); +int readCompressedMovieFrameFromBuffer(comp_manager_s* iCompMgr, char* oFrameBuffer, int iFrameBufferSize); + +int getMovieFramesCount(void* iFileHandlePtr, int iFrameBufferSize, int iCompressed); +void getMovieDataOffsetForFrames(void* iFileHandlePtr, int iFrameBufferSize, int iCompressed, int iStartFrame, int iEndFrame, + int* oStartFrameOffset, int* oDataSizeToEndFrame); #ifdef __cplusplus } From 664a01042bb2fa49558bb73804a0980ef007fe61 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 18 Jun 2016 01:07:49 +0200 Subject: [PATCH 086/259] Update anim.c --- source/anim.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/anim.c b/source/anim.c index 401ee3d..a26e0c5 100644 --- a/source/anim.c +++ b/source/anim.c @@ -17,6 +17,8 @@ #define BOT_COMP_COMP_FRAME_PTR (BOT_COMP_PREV_FRAME_PTR+BOT_SCREEN_SIZE) // Total compression required memory: 1088658 = 0x109C92 +#else +#include #endif #include "utility.h" @@ -504,7 +506,7 @@ void animExit() free(anim->topMovie.file); if (anim->topMovie.comp) { - free(anim->topMovie.comp->frame_prev_read); // Same as frame_prev_write + free(anim->topMovie.comp->frame_prev_write); // Same as frame_prev_read free(anim->topMovie.comp->frame_comp); free(anim->topMovie.comp); } @@ -515,7 +517,7 @@ void animExit() free(anim->botMovie.file); if (anim->botMovie.comp) { - free(anim->botMovie.comp->frame_prev_read); // Same as frame_prev_write + free(anim->botMovie.comp->frame_prev_write); // Same as frame_prev_read free(anim->botMovie.comp->frame_comp); free(anim->botMovie.comp); } From f899db93f2e90bdefcb5081d9db37696d288f7f4 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 18 Jun 2016 01:08:17 +0200 Subject: [PATCH 087/259] Update loader.h --- source/loader.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/loader.h b/source/loader.h index 873c90c..7c3277d 100644 --- a/source/loader.h +++ b/source/loader.h @@ -11,4 +11,8 @@ typedef struct { int load(char *path, long offset, binary_patch* patches, int patchesCount); +#ifndef ARM9 +int load_3dsx(char *path); +#endif + #endif // _loader_h_ From bae8b6a73a5e865e511eada0bd5c43cc7d6ecd55 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 18 Jun 2016 01:08:43 +0200 Subject: [PATCH 088/259] Update screeninit.c --- source/screeninit.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/screeninit.c b/source/screeninit.c index bffbdd3..0e8f293 100644 --- a/source/screeninit.c +++ b/source/screeninit.c @@ -5,6 +5,8 @@ * Screen deinit code by tiniVi. */ +#ifdef ARM9 + #include "screeninit.h" #include @@ -62,3 +64,5 @@ void initScreens(void) //clearScreens(); } + +#endif From d80bfa2960ef3b196433ff411e9b7c40fa2b3aa2 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 18 Jun 2016 01:09:02 +0200 Subject: [PATCH 089/259] Update screeninit.h --- source/screeninit.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/screeninit.h b/source/screeninit.h index d6f0739..9808a58 100644 --- a/source/screeninit.h +++ b/source/screeninit.h @@ -7,9 +7,13 @@ #pragma once +#ifdef ARM9 + #include "arm9/source/common.h" #define PDN_GPU_CNT (*(vu8 *)0x10141200) void deinitScreens(void); void initScreens(void); + +#endif From 598e47d37877e68b98376a22ba68296e24ed6412 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 18 Jun 2016 01:09:34 +0200 Subject: [PATCH 090/259] Update utility.c --- source/utility.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/utility.c b/source/utility.c index 4ea65f5..55ac020 100644 --- a/source/utility.c +++ b/source/utility.c @@ -242,7 +242,7 @@ int fileHandleOpen(void* handlePtr, const char *filePath) #ifdef ARM9 return (f_open((FIL*)handlePtr, filePath, FA_READ | FA_OPEN_EXISTING) == FR_OK) ? 0 : -1; #else - *(FILE**)handlePtr = fopen(filePath, "rt"); + *(FILE**)handlePtr = fopen(filePath, "rb"); return ( NULL != *(FILE**)handlePtr ) ? 0 : -1; #endif } @@ -252,7 +252,7 @@ size_t fileHandleSize(void* handlePtr) #ifdef ARM9 return f_size((FIL*)handlePtr); #else - *(FILE**)handlePtr(file, 0, SEEK_END); + fseek(*(FILE**)handlePtr, 0, SEEK_END); return ftell(*(FILE**)handlePtr); #endif } @@ -266,8 +266,8 @@ int fileHandleRead(void* handlePtr, void *data, size_t size, u32 offset) return -1; return ( bytes_read > 0 ) ? bytes_read : -1; #else - fseek(*(FILE**)handlePtr, offset, SEEK_SET ); - u32 bytes_read = fread(data, size, 1, *(FILE**)handlePtr); + fseek(*(FILE**)handlePtr, offset, SEEK_SET); + u32 bytes_read = fread(data, 1, size, *(FILE**)handlePtr); return ( bytes_read > 0 ) ? bytes_read : -1; #endif } From bd4fd977ff4c57562cf8a7607bec4905b7ada930 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 18 Jun 2016 20:08:31 +0200 Subject: [PATCH 091/259] Update anim.c --- source/anim.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/source/anim.c b/source/anim.c index a26e0c5..dfc51da 100644 --- a/source/anim.c +++ b/source/anim.c @@ -63,6 +63,7 @@ void movieLoopSetup(movie_state_s* movie) *( ( MEMORY_STREAM == movie->loopStreamType ) ? (movie->loopEndFrame-movie->loopStartFrame) : 1 ); } + #ifdef ARM9 void movieSetup(movie_config_s* mvConf, movie_state_s* movie, void* filePtr, comp_manager_s* compPtr, void* streamPtr) #else @@ -93,8 +94,8 @@ void movieSetup(movie_config_s* mvConf, movie_state_s* movie) movie->comp = compPtr; #else movie->comp = (comp_manager_s*)malloc(sizeof(comp_manager_s)); - movie->comp->frame_prev_read = malloc(movie->frameSize); - movie->comp->frame_comp = malloc(movie->frameSize + (movie->frameSize/10) + 9); + movie->comp->frame_prev_read = (const char*)malloc(movie->frameSize); + movie->comp->frame_comp = (char*)malloc(movie->frameSize + (movie->frameSize/10) + 9); #endif movie->comp->frame_prev_write = (char*)movie->comp->frame_prev_read; @@ -149,7 +150,8 @@ void movieSetup(movie_config_s* mvConf, movie_state_s* movie) case FILE_STREAM: // We will keep file opened to stream next loops content (slower but avoid memory issues). // But we still keep at least uncompressed loop first and last frame in memory. - movie->loopStreamSize = movie->frameSize*2 + ((movie->loopEndFrame-movie->loopStartFrame+1)*sizeof(int)); + movie->loopStreamSize = movie->frameSize*2 + ((movie->loopEndFrame-movie->loopStartFrame+2)*sizeof(int)); + break; case MEMORY_STREAM: // Full uncompressed frames are kept in memory, file is closed. @@ -161,17 +163,18 @@ void movieSetup(movie_config_s* mvConf, movie_state_s* movie) getMovieDataOffsetForFrames(movie->file, movie->frameSize, (NULL != movie->comp), movie->loopStartFrame, movie->loopEndFrame, NULL, &movie->loopStreamSize); - movie->loopStreamSize += movie->frameSize*2 + ((movie->loopEndFrame-movie->loopStartFrame+1)*sizeof(int)); + movie->loopStreamSize += movie->frameSize*2 + ((movie->loopEndFrame-movie->loopStartFrame+2)*sizeof(int)); + break; } #ifdef ARM9 movie->loopStream = streamPtr; #else - movie->loopStream = malloc(movie->loopStreamSize); + movie->loopStream = (char*)malloc(movie->loopStreamSize); #endif if ( MEMORY_STREAM != movie->loopStreamType ) - *(int*)(movie->loopStream+movie->frameSize*2) = (movie->loopEndFrame-movie->loopStartFrame); + *(int*)(movie->loopStream+movie->frameSize*2) = (movie->loopEndFrame-movie->loopStartFrame+1); movieLoopSetup(movie); } @@ -358,17 +361,6 @@ int readMovie(u8* fb, movie_state_s* movie) movie->file = NULL; } movie->curLoop = 1; - - /*if ( 0 != movie->loopsToDo && movie->curFrame < movie->framesCount-1 ) - { - // Correction for corrupted compressed movies - movie->framesCount = movie->curFrame; - if ( movie->loopStartFrame >= movie->framesCount ) - movie->loopStartFrame = movie->framesCount-1; - if ( movie->loopEndFrame >= movie->framesCount ) - movie->loopEndFrame = movie->framesCount-1; - movieLoopSetup(movie); - }*/ } if ( NULL != movie->loopStream && movie->curFrame >= movie->loopStartFrame && movie->curFrame <= movie->loopEndFrame ) @@ -416,9 +408,9 @@ int readMovie(u8* fb, movie_state_s* movie) { comp_manager_s compTmp = *movie->comp; compTmp.reverse = 1; - if ( movie->curLoop == 1 ) // By-pass bug on first loop, ugly, no logic explanation found... - frameToGet++; - int offset = *(int*)(movie->loopStream + 2*movie->frameSize + (1+frameToGet)*sizeof(int)); + if ( frameToGet == movie->loopEndFrame-movie->loopStartFrame-1 ) + compTmp.frame_prev_read = movie->loopEndFrameStream; + int offset = *(int*)(movie->loopStream + 2*movie->frameSize + (2+frameToGet)*sizeof(int)); if ( MEMORY_COMPRESSED_STREAM == movie->loopStreamType ) { compTmp.frame_comp = (char*)offset; From cc2a6079f5c3c2dae0dbde2d7188fc162e6ae200 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 18 Jun 2016 20:09:19 +0200 Subject: [PATCH 092/259] Update movie.c --- source/movie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/movie.c b/source/movie.c index 59ef513..fe8c034 100644 --- a/source/movie.c +++ b/source/movie.c @@ -88,7 +88,7 @@ void getMovieDataOffsetForFrames(void* iFileHandlePtr, int iFrameBufferSize, int if ( NULL != oStartFrameOffset ) *oStartFrameOffset = iFrameBufferSize * ( ( iStartFrame < framesCount ) ? iStartFrame : (framesCount-1) ); if ( NULL != oDataSizeToEndFrame ) - *oDataSizeToEndFrame = iFrameBufferSize * ( ( iEndFrame < framesCount ) ? iEndFrame : (framesCount-1) ); + *oDataSizeToEndFrame = iFrameBufferSize * ( ( iEndFrame < framesCount ) ? (iEndFrame+1) : framesCount ); } else { From 7ad2b08cd184c11a4830f56d3fcc2cb91ea8b349 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 19 Jun 2016 00:37:48 +0200 Subject: [PATCH 093/259] Update menu_config.c --- source/menu_config.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/menu_config.c b/source/menu_config.c index 8469083..34c73fb 100644 --- a/source/menu_config.c +++ b/source/menu_config.c @@ -129,9 +129,11 @@ int menu_config() { drawItem(menu_index == 2, 32, "Recovery key: %s", get_button(config->recovery)); #ifndef ARM9 drawItem(menu_index == 3, 48, "Bootfix: %i", config->autobootfix); + drawInfo("CtrBootManager v2.0.0"); +#else + drawInfo("CtrBootManager9 v2.0.0"); #endif - drawInfo("Unofficial version 10"); gfxSwap(); } return -1; From dad060101f77690b872e8efdf337b43cf043c829 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 26 Jun 2016 16:58:03 +0200 Subject: [PATCH 094/259] Update anim.c --- source/anim.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/source/anim.c b/source/anim.c index dfc51da..dcad5f0 100644 --- a/source/anim.c +++ b/source/anim.c @@ -48,7 +48,10 @@ void animInit() anim->topMovie.frameSize = TOP_SCREEN_SIZE; movieInit(&anim->topMovie); - +#ifndef ARM9 + anim->top3DMovie.frameSize = TOP_SCREEN_SIZE; + movieInit(&anim->top3DMovie); +#endif anim->botMovie.frameSize = BOT_SCREEN_SIZE; movieInit(&anim->botMovie); } @@ -203,6 +206,9 @@ void animSetup() botComp, PTR_MOVIE_LOOP+anim->topMovie.loopStreamSize); #else movieSetup(&config->movieTop, &anim->topMovie); + movieSetup(&config->movieTop3D, &anim->top3DMovie); + if ( NULL != anim->top3DMovie.file && !gfxIs3D() ) + gfxSet3D(true); movieSetup(&config->movieBot, &anim->botMovie); #endif @@ -421,7 +427,7 @@ int readMovie(u8* fb, movie_state_s* movie) } else { - int fileOffset = frameToGet*movie->frameSize; + int fileOffset = (frameToGet+movie->loopStartFrame)*movie->frameSize; readMovieFrame(movie->file, &fileOffset, NULL, (char*)fb, movie->frameSize); } } @@ -456,7 +462,7 @@ int readMovie(u8* fb, movie_state_s* movie) } else { - int fileOffset = frameToGet*movie->frameSize; + int fileOffset = (frameToGet+movie->loopStartFrame)*movie->frameSize; readMovieFrame(movie->file, &fileOffset, NULL, (char*)fb, movie->frameSize); } } @@ -476,16 +482,6 @@ int readMovie(u8* fb, movie_state_s* movie) return 0; } -int readTopMovie(u8* fb) -{ - return readMovie(fb, &anim->topMovie); -} - -int readBotMovie(u8* fb) -{ - return readMovie(fb, &anim->botMovie); -} - void animExit() { if (anim) { @@ -494,6 +490,9 @@ void animExit() if (anim->botMovie.file) fileHandleClose(anim->botMovie.file); #ifndef ARM9 + if (anim->top3DMovie.file) + fileHandleClose(anim->top3DMovie.file); + if (anim->topMovie.file) free(anim->topMovie.file); if (anim->topMovie.comp) @@ -505,6 +504,17 @@ void animExit() if (anim->topMovie.loopStream) free(anim->topMovie.loopStream); + if (anim->top3DMovie.file) + free(anim->top3DMovie.file); + if (anim->top3DMovie.comp) + { + free(anim->top3DMovie.comp->frame_prev_write); // Same as frame_prev_read + free(anim->top3DMovie.comp->frame_comp); + free(anim->top3DMovie.comp); + } + if (anim->top3DMovie.loopStream) + free(anim->top3DMovie.loopStream); + if (anim->botMovie.file) free(anim->botMovie.file); if (anim->botMovie.comp) From 5fb042a75a57755da84f315e2c240988d4206098 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 26 Jun 2016 16:58:24 +0200 Subject: [PATCH 095/259] Update anim.h --- source/anim.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/anim.h b/source/anim.h index 1b9f3e3..d0f5880 100644 --- a/source/anim.h +++ b/source/anim.h @@ -37,6 +37,8 @@ typedef struct { int loopTimeOnEndFrame; } movie_state_s; +int readMovie(u8* fb, movie_state_s* movie); + typedef struct { int timer; int active; @@ -50,6 +52,7 @@ typedef struct { u8 fntSel[4]; movie_state_s topMovie; + movie_state_s top3DMovie; movie_state_s botMovie; } anim_state_s; @@ -58,8 +61,6 @@ anim_state_s* anim; void animInit(); void animSetup(); void incrementAnimTime(); -int readTopMovie(u8* fb); -int readBotMovie(u8* fb); void animExit(); #ifdef __cplusplus From 28a9c8de34a21698589f44e673442bba049a1984 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 26 Jun 2016 16:59:03 +0200 Subject: [PATCH 096/259] Update config.c --- source/config.c | 97 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 27 deletions(-) diff --git a/source/config.c b/source/config.c index 1c1f3dc..fd8d56a 100644 --- a/source/config.c +++ b/source/config.c @@ -130,7 +130,7 @@ void readMovieProperty(movie_config_s* mvConf, const char *name, const char* val else if ( 0 == strcmp(value, "QuickLZ") ) mvConf->compressed = 1; } else if (NAME_MATCH("loopCount")) { - if ( value[0] == 'I' || value[0] <= 'i' ) // Value for "ININITE" or "infinite" + if ( value[0] == 'I' || value[0] == 'i' ) // Value for "INFINITE" or "infinite" mvConf->loopCount = -1; else mvConf->loopCount = atoi(value); @@ -278,6 +278,11 @@ static int handler(void *user, const char *section, const char *name, } else if (NAME_MATCH("bgImgBot")) { strncpy(config->bgImgBot, item, 128); } + #ifndef ARM9 + else if (NAME_MATCH("bgImgTop3D")) { + strncpy(config->bgImgTop3D, item, 128); + } + #endif } // animation @@ -308,6 +313,11 @@ static int handler(void *user, const char *section, const char *name, } else if (SECTION_MATCH("bottomMovie")) { readMovieProperty(&config->movieBot, name, item); } +#ifndef ARM9 + else if (SECTION_MATCH("top3DMovie")) { + readMovieProperty(&config->movieTop3D, name, item); + } +#endif // entries else if (SECTION_MATCH("entry")) @@ -367,12 +377,27 @@ static int handler(void *user, const char *section, const char *name, return 0; } +void configMovieInit(movie_config_s* mvConf) +{ + mvConf->path[0] = '\0'; + mvConf->compressed = 0; + mvConf->loopCount = 0; + mvConf->loopStreamType = 0; + mvConf->loopReverse = 0; + mvConf->loopStartFrame = 0; + mvConf->loopTimeOnStartFrame = 0; + mvConf->loopEndFrame = -1; + mvConf->loopTimeOnEndFrame = 0; +} + void configThemeInit() { // theme config->imgError = true; + config->imgError3D = true; config->imgErrorBot = true; config->bgImgTop[0] = '\0'; + config->bgImgTop3D[0] = '\0'; config->bgImgBot[0] = '\0'; memcpy(config->bgTop1, (u8[3]) {0x4a, 0x00, 0x31}, sizeof(u8[3])); memcpy(config->bgTop2, (u8[3]) {0x6f, 0x01, 0x49}, sizeof(u8[3])); @@ -394,25 +419,9 @@ void configThemeInit() { config->menuFadeInTimeStart = 0; // movie - config->movieTop.path[0] = '\0'; - config->movieTop.compressed = 0; - config->movieTop.loopCount = 0; - config->movieTop.loopStreamType = 0; - config->movieTop.loopReverse = 0; - config->movieTop.loopStartFrame = 0; - config->movieTop.loopTimeOnStartFrame = 0; - config->movieTop.loopEndFrame = -1; - config->movieTop.loopTimeOnEndFrame = 0; - - config->movieBot.path[0] = '\0'; - config->movieBot.compressed = 0; - config->movieBot.loopCount = 0; - config->movieBot.loopStreamType = 0; - config->movieBot.loopReverse = 0; - config->movieBot.loopStartFrame = 0; - config->movieBot.loopTimeOnStartFrame = 0; - config->movieBot.loopEndFrame = -1; - config->movieBot.loopTimeOnEndFrame = 0; + configMovieInit(&config->movieTop); + configMovieInit(&config->movieTop3D); + configMovieInit(&config->movieBot); } int configInit() { @@ -459,8 +468,13 @@ int configInit() { // Fix for fade in effect first frame fontDefault.color[3] = 0x00; - loadBg(GFX_TOP); - loadBg(GFX_BOTTOM); + loadBg(GFX_TOP, GFX_LEFT); +#ifndef ARM9 + loadBg(GFX_TOP, GFX_RIGHT); + if (!config->imgError3D && !gfxIs3D()) + gfxSet3D(true); +#endif + loadBg(GFX_BOTTOM, GFX_LEFT); return 0; } @@ -545,6 +559,10 @@ void configSave() { else size += snprintf(cfg+size, 256, "font2=%02X%02X%02X;\n", config->fntSel[0], config->fntSel[1], config->fntSel[2]); size += snprintf(cfg+size, 256, "bgImgTop=%s;\n", config->bgImgTop); +#ifndef ARM9 + if (config->bgImgTop3D[0] != '\0') + size += snprintf(cfg+size, 256, "bgImgTop3D=%s;\n", config->bgImgTop3D); +#endif size += snprintf(cfg+size, 256, "bgImgBot=%s;\n\n", config->bgImgBot); // animation section @@ -625,6 +643,13 @@ void configSave() { size += snprintf(cfg+size, 256, "\n[topMovie]\n"); writeMovieProperty(&config->movieTop, cfg, &size); } +#ifndef ARM9 + if ( config->movieTop3D.path[0] != '\0' ) + { + size += snprintf(cfg+size, 256, "\n[top3DMovie]\n"); + writeMovieProperty(&config->movieTop3D, cfg, &size); + } +#endif if ( config->movieBot.path[0] != '\0' ) { size += snprintf(cfg+size, 256, "\n[bottomMovie]\n"); @@ -678,6 +703,9 @@ void configExit() { if (config->bgImgTopBuff) { free(config->bgImgTopBuff); } + if (config->bgImgTop3DBuff) { + free(config->bgImgTop3DBuff); + } if (config->bgImgBotBuff) { free(config->bgImgBotBuff); } @@ -686,9 +714,13 @@ void configExit() { #endif } -void loadBg(gfxScreen_t screen) { +void loadBg(gfxScreen_t screen, gfx3dSide_t side) { - const char *path = screen == GFX_TOP ? config->bgImgTop : config->bgImgBot; +#ifdef ARM9 + const char *path = (screen == GFX_TOP ? config->bgImgTop : config->bgImgBot); +#else + const char *path = (screen == GFX_TOP ? (side == GFX_RIGHT ? config->bgImgTop3D : config->bgImgTop) : config->bgImgBot); +#endif size_t size = fileSize(path); if ( size == -1 || size == 0 ) { return; @@ -704,9 +736,20 @@ void loadBg(gfxScreen_t screen) { } if (screen == GFX_TOP) { - config->bgImgTopSize = size; - config->bgImgTopBuff = bg; - config->imgError = false; + #ifndef ARM9 + if (side == GFX_RIGHT) { + config->bgImgTop3DSize = size; + config->bgImgTop3DBuff = bg; + config->imgError3D = false; + } else + { + #endif + config->bgImgTopSize = size; + config->bgImgTopBuff = bg; + config->imgError = false; + #ifndef ARM9 + } + #endif } else { config->bgImgBotSize = size; config->bgImgBotBuff = bg; From b39a29ea1a5d4952c03e5cca6bed8445387d6e56 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 26 Jun 2016 16:59:23 +0200 Subject: [PATCH 097/259] Update config.h --- source/config.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/config.h b/source/config.h index 3776a7f..f631a6e 100644 --- a/source/config.h +++ b/source/config.h @@ -94,15 +94,20 @@ typedef struct { int menuFadeInTimeStart; char bgImgTop[128]; + char bgImgTop3D[128]; char bgImgBot[128]; bool imgError; + bool imgError3D; bool imgErrorBot; u8 *bgImgTopBuff; + u8 *bgImgTop3DBuff; u8 *bgImgBotBuff; off_t bgImgTopSize; + off_t bgImgTop3DSize; off_t bgImgBotSize; movie_config_s movieTop; + movie_config_s movieTop3D; movie_config_s movieBot; } boot_config_s; @@ -119,7 +124,7 @@ void configSave(); void configExit(); -void loadBg(gfxScreen_t screen); +void loadBg(gfxScreen_t screen, gfx3dSide_t side); #ifdef __cplusplus } From fc7f0f477119774dd3c19d8e16cc9867b46b4bff Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 26 Jun 2016 16:59:58 +0200 Subject: [PATCH 098/259] Update gfx.c --- source/gfx.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/source/gfx.c b/source/gfx.c index d6b12df..a11fd9d 100644 --- a/source/gfx.c +++ b/source/gfx.c @@ -3,7 +3,6 @@ #include #ifdef ARM9 - #include "arm9/source/common.h" #include "memory.h" #else @@ -138,19 +137,17 @@ void gfxFillColor(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[3]) { void gfxFillColorGradient(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColorStart[3], u8 rgbColorEnd[3]) { u16 fbWidth, fbHeight; u8 *fbAdr = gfxGetFramebuffer(screen, side, &fbWidth, &fbHeight); - u8 colorLine[fbWidth * 3]; + u8 colorLine[1200]; // Avoid dynamic "fbWidth*3", illogical crash on 3DSX version with top right buffer //TODO : optimize; use GX command ? + // Avoid float operations, illogical crash on 3DSX version with top right buffer int i; - float n; - float total = (float) (fbWidth - 1); - // make slightly bigger to prevent gradients from blending around. SHould be removed and have the gradient color be better later. - total *= 1.5f; + int width = fbWidth; for (i = 0; i < fbWidth; i++) { - n = (float) i / total; - colorLine[i * 3 + 0] = (float) rgbColorStart[2] * (1.0f - n) + (float) rgbColorEnd[2] * n; - colorLine[i * 3 + 1] = (float) rgbColorStart[1] * (1.0f - n) + (float) rgbColorEnd[1] * n; - colorLine[i * 3 + 2] = (float) rgbColorStart[0] * (1.0f - n) + (float) rgbColorEnd[0] * n; + int minus = width-i-1; + colorLine[i * 3 + 0] = (minus*rgbColorStart[2] + i*rgbColorEnd[2]) / fbWidth; + colorLine[i * 3 + 1] = (minus*rgbColorStart[1] + i*rgbColorEnd[1]) / fbWidth; + colorLine[i * 3 + 2] = (minus*rgbColorStart[0] + i*rgbColorEnd[0]) / fbWidth; } for (i = 0; i < fbHeight; i++) { @@ -219,6 +216,8 @@ void gfxDrawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[4], s16 void gfxClearTop(u8 top1[3], u8 top2[3]) { gfxFillColorGradient(GFX_TOP, GFX_LEFT, top1, top2); + if( IS3DACTIVE ) + gfxFillColorGradient(GFX_TOP, GFX_RIGHT, top1, top2); } void gfxClearBot(u8 bot[8]) { @@ -235,6 +234,8 @@ void gfxClear() { memset(PTR_BOT_BG, 0, BOT_SCREEN_SIZE); #else gfxFillColor(GFX_TOP, GFX_LEFT, (u8[3]) {0x00, 0x00, 0x00}); + if( IS3DACTIVE ) + gfxFillColor(GFX_TOP, GFX_RIGHT, (u8[3]) {0x00, 0x00, 0x00}); gfxFillColor(GFX_BOTTOM, GFX_LEFT, (u8[3]) {0x00, 0x00, 0x00}); #endif } From 3e15ce556a8b499e9a2fcd64d4235c3c0b6be8c8 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 26 Jun 2016 17:00:20 +0200 Subject: [PATCH 099/259] Update gfx.h --- source/gfx.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/gfx.h b/source/gfx.h index bef3fb6..c19d937 100644 --- a/source/gfx.h +++ b/source/gfx.h @@ -8,8 +8,13 @@ u8 *gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16 *width, u16 *hei #define TOP_SCREEN_SIZE (400*240*3) #define BOT_SCREEN_SIZE (320*240*3) +#define IS3DACTIVE false + #else + #include <3ds.h> +#define IS3DACTIVE gfxIs3D() + #endif #include "font.h" From 6608f7364822f5367340c9e5ad4d7a7c190b55e2 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 26 Jun 2016 17:01:03 +0200 Subject: [PATCH 100/259] Update menu.c --- source/menu.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/source/menu.c b/source/menu.c index eaab526..d7b4121 100644 --- a/source/menu.c +++ b/source/menu.c @@ -13,7 +13,7 @@ void drawBg() { u8* fbTop = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); - if (readTopMovie(fbTop) < 0) + if (readMovie(fbTop, &anim->topMovie) < 0) { if (!config->imgError) { memcpy(fbTop, config->bgImgTopBuff, (size_t) config->bgImgTopSize); @@ -22,7 +22,7 @@ void drawBg() { } } u8* fbBot = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); - if (readBotMovie(fbBot) < 0) + if (readMovie(fbBot, &anim->botMovie) < 0) { if (!config->imgErrorBot) { memcpy(fbBot, config->bgImgBotBuff, (size_t) config->bgImgBotSize); @@ -31,6 +31,15 @@ void drawBg() { } } drawRectColor(GFX_TOP, GFX_LEFT, MENU_MIN_X, MENU_MIN_Y - 20, MENU_MAX_X, MENU_MAX_Y, anim->borders); + + u8* fbTop3D = IS3DACTIVE ? gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL) : NULL; + if (fbTop3D) + { + if (readMovie(fbTop3D, &anim->top3DMovie) < 0 && !config->imgError) + memcpy(fbTop3D, config->bgImgTop3DBuff, (size_t) config->bgImgTop3DSize); + + drawRectColor(GFX_TOP, GFX_RIGHT, MENU_MIN_X, MENU_MIN_Y - 20, MENU_MAX_X, MENU_MAX_Y, anim->borders); + } } void drawTitle(const char *format, ...) { @@ -42,6 +51,8 @@ void drawTitle(const char *format, ...) { va_end(argp); gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, msg, 140, 25); + if( IS3DACTIVE ) + gfxDrawText(GFX_TOP, GFX_RIGHT, &fontDefault, msg, 140, 25); } void drawItem(bool selected, int y, const char *format, ...) { @@ -54,10 +65,14 @@ void drawItem(bool selected, int y, const char *format, ...) { if (selected) { gfxDrawRectangle(GFX_TOP, GFX_LEFT, anim->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); + if( IS3DACTIVE ) + gfxDrawRectangle(GFX_TOP, GFX_RIGHT, anim->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); } memcpy(fontDefault.color, selected ? anim->fntSel : anim->fntDef, sizeof(u8[4])); - gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, msg, (s16) (MENU_MIN_X + 6), - (s16) y + (s16) MENU_MIN_Y); + + gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, msg, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); + if( IS3DACTIVE ) + gfxDrawText(GFX_TOP, GFX_RIGHT, &fontDefault, msg, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); memcpy(fontDefault.color, anim->fntDef, sizeof(u8[4])); } @@ -72,10 +87,13 @@ void drawItemN(bool selected, int maxChar, int y, const char *format, ...) { if (selected) { gfxDrawRectangle(GFX_TOP, GFX_LEFT, anim->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); + if( IS3DACTIVE ) + gfxDrawRectangle(GFX_TOP, GFX_RIGHT, anim->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); } memcpy(fontDefault.color, selected ? anim->fntSel : anim->fntDef, sizeof(u8[4])); - gfxDrawTextN(GFX_TOP, GFX_LEFT, &fontDefault, msg, maxChar, (s16) (MENU_MIN_X + 6), - (s16) y + (s16) MENU_MIN_Y); + gfxDrawTextN(GFX_TOP, GFX_LEFT, &fontDefault, msg, maxChar, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); + if( IS3DACTIVE ) + gfxDrawTextN(GFX_TOP, GFX_RIGHT, &fontDefault, msg, maxChar, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); memcpy(fontDefault.color, anim->fntDef, sizeof(u8[4])); } From 9c724e81cdedf146255b2bb441e48a941d3d8948 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 26 Jun 2016 17:01:30 +0200 Subject: [PATCH 101/259] Update menu_config.c --- source/menu_config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/menu_config.c b/source/menu_config.c index 34c73fb..8cff3da 100644 --- a/source/menu_config.c +++ b/source/menu_config.c @@ -129,9 +129,9 @@ int menu_config() { drawItem(menu_index == 2, 32, "Recovery key: %s", get_button(config->recovery)); #ifndef ARM9 drawItem(menu_index == 3, 48, "Bootfix: %i", config->autobootfix); - drawInfo("CtrBootManager v2.0.0"); + drawInfo("CtrBootManager v2.1.0"); #else - drawInfo("CtrBootManager9 v2.0.0"); + drawInfo("CtrBootManager9 v2.1.0"); #endif gfxSwap(); From 64e7c5475ed94f2fe580f680ae7c528900ec733d Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 26 Jun 2016 17:02:10 +0200 Subject: [PATCH 102/259] Update utility.c --- source/utility.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source/utility.c b/source/utility.c index 55ac020..ae3b50c 100644 --- a/source/utility.c +++ b/source/utility.c @@ -117,6 +117,11 @@ void debug(const char *fmt, ...) { drawBg(); gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, s, MENU_MIN_X + 16, MENU_MIN_Y + 16); gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, "Press (A) key to continue...", MENU_MIN_X + 16, MENU_MIN_Y + 64); + if ( IS3DACTIVE ) + { + gfxDrawText(GFX_TOP, GFX_RIGHT, &fontDefault, s, MENU_MIN_X + 16, MENU_MIN_Y + 16); + gfxDrawText(GFX_TOP, GFX_RIGHT, &fontDefault, "Press (A) key to continue...", MENU_MIN_X + 16, MENU_MIN_Y + 64); + } gfxSwap(); } } @@ -144,6 +149,13 @@ bool confirm(int confirmButton, const char *fmt, ...) { gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, "Press (B) key to cancel...", MENU_MIN_X + 16, MENU_MIN_Y + 64); gfxDrawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 84, "Press (%s) to confirm...", get_button(confirmButton)); + if ( IS3DACTIVE ) + { + gfxDrawText(GFX_TOP, GFX_RIGHT, &fontDefault, s, MENU_MIN_X + 16, MENU_MIN_Y + 16); + gfxDrawText(GFX_TOP, GFX_RIGHT, &fontDefault, "Press (B) key to cancel...", MENU_MIN_X + 16, MENU_MIN_Y + 64); + gfxDrawTextf(GFX_TOP, GFX_RIGHT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 84, "Press (%s) to confirm...", + get_button(confirmButton)); + } gfxSwap(); } return false; From 99d20abd6310f45ff79af139dd194cc7d1780c0f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 29 Jun 2016 18:03:54 +0200 Subject: [PATCH 103/259] Update config.h --- source/config.h | 1 + 1 file changed, 1 insertion(+) diff --git a/source/config.h b/source/config.h index f631a6e..fbf2eb5 100644 --- a/source/config.h +++ b/source/config.h @@ -18,6 +18,7 @@ extern "C" { #endif +#include "draw.h" #include "loader.h" // Binary patches define #define BIT(n) (1U<<(n)) From 61cdcaaeeb23063b7f318ac9be6e320c791d6d4b Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 29 Jun 2016 18:04:27 +0200 Subject: [PATCH 104/259] Update loader.c --- source/loader.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/loader.c b/source/loader.c index 45f04fe..94459a6 100644 --- a/source/loader.c +++ b/source/loader.c @@ -6,15 +6,16 @@ #else -#include "gfx.h" +#include "arm9/source/common.h" #include "arm9/source/fatfs/ff.h" #include "stage2_bin.h" +#include "memory.h" #endif +#include "draw.h" #include "loader.h" #include "utility.h" -#include "memory.h" #ifdef ARM9 @@ -79,7 +80,7 @@ int load_bin(char *path, long offset, binary_patch* patches, int patchesCount) { } // Start binary - gfxClear(); + clearFrameBuffers(); memcpy((void *) PTR_PAYLOAD_STAGE2, stage2_bin, stage2_bin_size); ((void (*)()) PTR_PAYLOAD_STAGE2)(); From 1eb22e929132472f32d73d4d71a7297fc6707a00 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 29 Jun 2016 18:04:59 +0200 Subject: [PATCH 105/259] Update menu.c --- source/menu.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/source/menu.c b/source/menu.c index d7b4121..a7cda52 100644 --- a/source/menu.c +++ b/source/menu.c @@ -6,7 +6,7 @@ #include #include #include -#include "gfx.h" +#include "draw.h" #include "anim.h" #include "config.h" #include "menu.h" @@ -18,7 +18,7 @@ void drawBg() { if (!config->imgError) { memcpy(fbTop, config->bgImgTopBuff, (size_t) config->bgImgTopSize); } else { - gfxClearTop(anim->bgTop1, anim->bgTop2); + clearTop(anim->bgTop1, anim->bgTop2); } } u8* fbBot = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); @@ -27,7 +27,7 @@ void drawBg() { if (!config->imgErrorBot) { memcpy(fbBot, config->bgImgBotBuff, (size_t) config->bgImgBotSize); } else { - gfxClearBot(anim->bgBot); + clearBot(anim->bgBot); } } drawRectColor(GFX_TOP, GFX_LEFT, MENU_MIN_X, MENU_MIN_Y - 20, MENU_MAX_X, MENU_MAX_Y, anim->borders); @@ -50,9 +50,9 @@ void drawTitle(const char *format, ...) { vsnprintf(msg, 512, format, argp); va_end(argp); - gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, msg, 140, 25); + drawText(GFX_TOP, GFX_LEFT, &fontDefault, msg, 140, 25); if( IS3DACTIVE ) - gfxDrawText(GFX_TOP, GFX_RIGHT, &fontDefault, msg, 140, 25); + drawText(GFX_TOP, GFX_RIGHT, &fontDefault, msg, 140, 25); } void drawItem(bool selected, int y, const char *format, ...) { @@ -64,15 +64,15 @@ void drawItem(bool selected, int y, const char *format, ...) { va_end(argp); if (selected) { - gfxDrawRectangle(GFX_TOP, GFX_LEFT, anim->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); + drawRectangle(GFX_TOP, GFX_LEFT, anim->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); if( IS3DACTIVE ) - gfxDrawRectangle(GFX_TOP, GFX_RIGHT, anim->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); + drawRectangle(GFX_TOP, GFX_RIGHT, anim->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); } memcpy(fontDefault.color, selected ? anim->fntSel : anim->fntDef, sizeof(u8[4])); - gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, msg, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); + drawText(GFX_TOP, GFX_LEFT, &fontDefault, msg, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); if( IS3DACTIVE ) - gfxDrawText(GFX_TOP, GFX_RIGHT, &fontDefault, msg, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); + drawText(GFX_TOP, GFX_RIGHT, &fontDefault, msg, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); memcpy(fontDefault.color, anim->fntDef, sizeof(u8[4])); } @@ -86,14 +86,14 @@ void drawItemN(bool selected, int maxChar, int y, const char *format, ...) { va_end(argp); if (selected) { - gfxDrawRectangle(GFX_TOP, GFX_LEFT, anim->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); + drawRectangle(GFX_TOP, GFX_LEFT, anim->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); if( IS3DACTIVE ) - gfxDrawRectangle(GFX_TOP, GFX_RIGHT, anim->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); + drawRectangle(GFX_TOP, GFX_RIGHT, anim->highlight, (s16) (MENU_MIN_X + 4), (s16) (y + MENU_MIN_Y), 361, 15); } memcpy(fontDefault.color, selected ? anim->fntSel : anim->fntDef, sizeof(u8[4])); - gfxDrawTextN(GFX_TOP, GFX_LEFT, &fontDefault, msg, maxChar, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); + drawTextN(GFX_TOP, GFX_LEFT, &fontDefault, msg, maxChar, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); if( IS3DACTIVE ) - gfxDrawTextN(GFX_TOP, GFX_RIGHT, &fontDefault, msg, maxChar, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); + drawTextN(GFX_TOP, GFX_RIGHT, &fontDefault, msg, maxChar, (s16) (MENU_MIN_X + 6), (s16) y + (s16) MENU_MIN_Y); memcpy(fontDefault.color, anim->fntDef, sizeof(u8[4])); } @@ -106,6 +106,6 @@ void drawInfo(const char *format, ...) { vsnprintf(msg, 512, format, argp); va_end(argp); - gfxDrawText(GFX_BOTTOM, GFX_LEFT, &fontDefault, "Informations", (s16) (MENU_MIN_X + 6), 40); - gfxDrawText(GFX_BOTTOM, GFX_LEFT, &fontDefault, msg, (s16) (MENU_MIN_X + 12), 80); + drawText(GFX_BOTTOM, GFX_LEFT, &fontDefault, "Informations", (s16) (MENU_MIN_X + 6), 40); + drawText(GFX_BOTTOM, GFX_LEFT, &fontDefault, msg, (s16) (MENU_MIN_X + 12), 80); } From 3c6675a3903cae32771178ff4904d67fa3fcca93 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 29 Jun 2016 18:05:46 +0200 Subject: [PATCH 106/259] Update and rename gfx.h to draw.h --- source/draw.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ source/gfx.h | 45 ---------------------------------------- 2 files changed, 57 insertions(+), 45 deletions(-) create mode 100644 source/draw.h delete mode 100644 source/gfx.h diff --git a/source/draw.h b/source/draw.h new file mode 100644 index 0000000..d6f1506 --- /dev/null +++ b/source/draw.h @@ -0,0 +1,57 @@ +#pragma once + +#ifdef ARM9 + +#include "arm9/source/common.h" + +typedef enum +{ + GFX_TOP = 0, ///< Top screen + GFX_BOTTOM = 1 ///< Bottom screen +}gfxScreen_t; + +typedef enum +{ + GFX_LEFT = 0, ///< Left eye framebuffer + GFX_RIGHT = 1,///< Right eye framebuffer +}gfx3dSide_t; + +u8 *gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16 *width, u16 *height); + +#define TOP_SCREEN_SIZE (400*240*3) +#define BOT_SCREEN_SIZE (320*240*3) +#define IS3DACTIVE false + +#else + +#include <3ds.h> +#define IS3DACTIVE gfxIs3D() + +#endif + +#include "font.h" + +//rendering stuff +void drawLine(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, char r, char g, char b, char a); + +void drawRectColor(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, u8 *rgbaColor); + +void drawText(gfxScreen_t screen, gfx3dSide_t side, font_s *f, char *str, s16 x, s16 y); + +void drawTextN(gfxScreen_t screen, gfx3dSide_t side, font_s *f, char *str, u16 length, s16 x, s16 y); + +void drawTextf(gfxScreen_t screen, gfx3dSide_t side, font_s *f, s16 x, s16 y, const char *fmt, ...); + +void fillColor(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[3]); + +void fillColorGradient(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColorStart[3], u8 rgbColorEnd[3]); + +void drawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbaColor[4], s16 x, s16 y, u16 width, u16 height); + +void clearTop(u8 top1[3], u8 top2[3]); + +void clearBot(u8 bot[8]); + +void clearFrameBuffers(); + +void swapFrameBuffers(); diff --git a/source/gfx.h b/source/gfx.h deleted file mode 100644 index c19d937..0000000 --- a/source/gfx.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#ifdef ARM9 - -#include "arm9/source/common.h" - -u8 *gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16 *width, u16 *height); - -#define TOP_SCREEN_SIZE (400*240*3) -#define BOT_SCREEN_SIZE (320*240*3) -#define IS3DACTIVE false - -#else - -#include <3ds.h> -#define IS3DACTIVE gfxIs3D() - -#endif - -#include "font.h" - -//rendering stuff -void drawLine(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, char r, char g, char b, char a); - -void drawRectColor(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, u8 *rgbaColor); - -void gfxDrawText(gfxScreen_t screen, gfx3dSide_t side, font_s *f, char *str, s16 x, s16 y); - -void gfxDrawTextN(gfxScreen_t screen, gfx3dSide_t side, font_s *f, char *str, u16 length, s16 x, s16 y); - -void gfxDrawTextf(gfxScreen_t screen, gfx3dSide_t side, font_s *f, s16 x, s16 y, const char *fmt, ...); - -void gfxFillColor(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[3]); - -void gfxFillColorGradient(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColorStart[3], u8 rgbColorEnd[3]); - -void gfxDrawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbaColor[4], s16 x, s16 y, u16 width, u16 height); - -void gfxClearTop(u8 top1[3], u8 top2[3]); - -void gfxClearBot(u8 bot[8]); - -void gfxClear(); - -void gfxSwap(); From 1c1c56bcb7fc4b0ae4287769902452e7562f98fd Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 29 Jun 2016 18:06:29 +0200 Subject: [PATCH 107/259] Update and rename gfx.c to draw.c --- source/{gfx.c => draw.c} | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) rename source/{gfx.c => draw.c} (83%) diff --git a/source/gfx.c b/source/draw.c similarity index 83% rename from source/gfx.c rename to source/draw.c index a11fd9d..8c3b14c 100644 --- a/source/gfx.c +++ b/source/draw.c @@ -10,7 +10,6 @@ #endif #include -#include "gfx.h" #include "text.h" #include "anim.h" @@ -90,7 +89,7 @@ void drawRectColor(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, drawRect(screen, side, x1, y1, x2, y2, rgbaColor[0], rgbaColor[1], rgbaColor[2], rgbaColor[3]); } -void gfxDrawTextf(gfxScreen_t screen, gfx3dSide_t side, font_s *f, s16 x, s16 y, const char *fmt, ...) { +void drawTextf(gfxScreen_t screen, gfx3dSide_t side, font_s *f, s16 x, s16 y, const char *fmt, ...) { char s[512]; memset(s, 0, 512); va_list args; @@ -98,10 +97,10 @@ void gfxDrawTextf(gfxScreen_t screen, gfx3dSide_t side, font_s *f, s16 x, s16 y, int len = vsprintf(s, fmt, args); va_end(args); if (len) - gfxDrawText(screen, side, f, s, x, y); + drawText(screen, side, f, s, x, y); } -void gfxDrawText(gfxScreen_t screen, gfx3dSide_t side, font_s *f, char *str, s16 x, s16 y) { +void drawText(gfxScreen_t screen, gfx3dSide_t side, font_s *f, char *str, s16 x, s16 y) { if (!str)return; if (!f)f = &fontDefault; @@ -111,7 +110,7 @@ void gfxDrawText(gfxScreen_t screen, gfx3dSide_t side, font_s *f, char *str, s16 drawString(fbAdr, f, str, x, 240 - y, fbHeight, fbWidth); } -void gfxDrawTextN(gfxScreen_t screen, gfx3dSide_t side, font_s *f, char *str, u16 length, s16 x, s16 y) { +void drawTextN(gfxScreen_t screen, gfx3dSide_t side, font_s *f, char *str, u16 length, s16 x, s16 y) { if (!str)return; if (!f)f = &fontDefault; @@ -121,7 +120,7 @@ void gfxDrawTextN(gfxScreen_t screen, gfx3dSide_t side, font_s *f, char *str, u1 drawStringN(fbAdr, f, str, length, x, 240 - y, fbHeight, fbWidth); } -void gfxFillColor(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[3]) { +void fillColor(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[3]) { u16 fbWidth, fbHeight; u8 *fbAdr = gfxGetFramebuffer(screen, side, &fbWidth, &fbHeight); @@ -134,7 +133,7 @@ void gfxFillColor(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[3]) { } } -void gfxFillColorGradient(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColorStart[3], u8 rgbColorEnd[3]) { +void fillColorGradient(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColorStart[3], u8 rgbColorEnd[3]) { u16 fbWidth, fbHeight; u8 *fbAdr = gfxGetFramebuffer(screen, side, &fbWidth, &fbHeight); u8 colorLine[1200]; // Avoid dynamic "fbWidth*3", illogical crash on 3DSX version with top right buffer @@ -156,7 +155,7 @@ void gfxFillColorGradient(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColorStart } } -void _gfxDrawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbaColor[4], s16 x, s16 y, u16 width, u16 height) { +void _drawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbaColor[4], s16 x, s16 y, u16 width, u16 height) { u16 fbWidth, fbHeight; u8 *fbAdr = gfxGetFramebuffer(screen, side, &fbWidth, &fbHeight); @@ -210,21 +209,21 @@ void _gfxDrawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbaColor[4], s1 } } -void gfxDrawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[4], s16 x, s16 y, u16 width, u16 height) { - _gfxDrawRectangle(screen, side, rgbColor, 240 - y, x, height, width); +void drawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[4], s16 x, s16 y, u16 width, u16 height) { + _drawRectangle(screen, side, rgbColor, 240 - y, x, height, width); } -void gfxClearTop(u8 top1[3], u8 top2[3]) { - gfxFillColorGradient(GFX_TOP, GFX_LEFT, top1, top2); +void clearTop(u8 top1[3], u8 top2[3]) { + fillColorGradient(GFX_TOP, GFX_LEFT, top1, top2); if( IS3DACTIVE ) - gfxFillColorGradient(GFX_TOP, GFX_RIGHT, top1, top2); + fillColorGradient(GFX_TOP, GFX_RIGHT, top1, top2); } -void gfxClearBot(u8 bot[8]) { - gfxFillColor(GFX_BOTTOM, GFX_LEFT, bot); +void clearBot(u8 bot[8]) { + fillColor(GFX_BOTTOM, GFX_LEFT, bot); } -void gfxClear() { +void clearFrameBuffers() { #ifdef ARM9 memset(PTR_TOP_SCREEN, 0, TOP_SCREEN_SIZE); memset(PTR_BOT_SCREEN, 0, BOT_SCREEN_SIZE); @@ -233,14 +232,14 @@ void gfxClear() { memset(PTR_TOP_BG, 0, TOP_SCREEN_SIZE); memset(PTR_BOT_BG, 0, BOT_SCREEN_SIZE); #else - gfxFillColor(GFX_TOP, GFX_LEFT, (u8[3]) {0x00, 0x00, 0x00}); + fillColor(GFX_TOP, GFX_LEFT, (u8[3]) {0x00, 0x00, 0x00}); if( IS3DACTIVE ) - gfxFillColor(GFX_TOP, GFX_RIGHT, (u8[3]) {0x00, 0x00, 0x00}); - gfxFillColor(GFX_BOTTOM, GFX_LEFT, (u8[3]) {0x00, 0x00, 0x00}); + fillColor(GFX_TOP, GFX_RIGHT, (u8[3]) {0x00, 0x00, 0x00}); + fillColor(GFX_BOTTOM, GFX_LEFT, (u8[3]) {0x00, 0x00, 0x00}); #endif } -void gfxSwap() { +void swapFrameBuffers() { #ifdef ARM9 memcpy(PTR_TOP_SCREEN, PTR_TOP_SCREEN_BUF, TOP_SCREEN_SIZE); memcpy(PTR_BOT_SCREEN, PTR_BOT_SCREEN_BUF, BOT_SCREEN_SIZE); From 3d6d72f9216d5d982dcfd17310d47a5a396c4328 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 29 Jun 2016 18:07:13 +0200 Subject: [PATCH 108/259] Update menu_boot.c --- source/menu_boot.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/menu_boot.c b/source/menu_boot.c index 7028d33..3829e0c 100644 --- a/source/menu_boot.c +++ b/source/menu_boot.c @@ -9,7 +9,7 @@ #endif #include "loader.h" -#include "gfx.h" +#include "draw.h" #include "utility.h" #include "menu.h" #include "config.h" @@ -43,7 +43,7 @@ int boot(int index) { #else int delay = config->autobootfix; while (aptMainLoop() && delay > 0) { - gfxSwap(); + swapFrameBuffers(); delay--; } return load(config->entries[index].path, @@ -179,5 +179,5 @@ static void draw(int boot_index, time_t elapsed) { drawInfo("Show more options ..."); } - gfxSwap(); + swapFrameBuffers(); } From 161e099ec173e50a1e32005584e4c5c6d1f7f143 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 29 Jun 2016 18:07:42 +0200 Subject: [PATCH 109/259] Update menu_config.c --- source/menu_config.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/menu_config.c b/source/menu_config.c index 8cff3da..cfd87de 100644 --- a/source/menu_config.c +++ b/source/menu_config.c @@ -7,7 +7,7 @@ #include #include "config.h" -#include "gfx.h" +#include "draw.h" #include "menu.h" #include "utility.h" @@ -129,12 +129,12 @@ int menu_config() { drawItem(menu_index == 2, 32, "Recovery key: %s", get_button(config->recovery)); #ifndef ARM9 drawItem(menu_index == 3, 48, "Bootfix: %i", config->autobootfix); - drawInfo("CtrBootManager v2.1.0"); + drawInfo("CtrBootManager v2.1.1"); #else - drawInfo("CtrBootManager9 v2.1.0"); + drawInfo("CtrBootManager9 v2.1.1"); #endif - gfxSwap(); + swapFrameBuffers(); } return -1; } From 104a5d4a9de7dbb5a74b1fad2cc54d7c85b37836 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 29 Jun 2016 18:08:10 +0200 Subject: [PATCH 110/259] Update menu_more.c --- source/menu_more.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/menu_more.c b/source/menu_more.c index d877854..d4133e5 100644 --- a/source/menu_more.c +++ b/source/menu_more.c @@ -4,11 +4,14 @@ #include "arm9/source/hid.h" #else + #include <3ds.h> #include #include "menu_netloaderarm9.h" + #endif -#include "gfx.h" + +#include "draw.h" #include "utility.h" #include "loader.h" #include "menu.h" @@ -150,5 +153,5 @@ static void draw() { break; } - gfxSwap(); + swapFrameBuffers(); } From 974f144cb1844bafe146a944639a49f731c8f4c6 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 29 Jun 2016 18:08:36 +0200 Subject: [PATCH 111/259] Update menu_netloader.c --- source/menu_netloader.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/menu_netloader.c b/source/menu_netloader.c index 4af7943..e9811c9 100644 --- a/source/menu_netloader.c +++ b/source/menu_netloader.c @@ -1,6 +1,6 @@ #include <3ds.h> #include -#include "gfx.h" +#include "draw.h" #include "netloader.h" #include "utility.h" #include "loader.h" @@ -22,8 +22,8 @@ int menu_netloader() { ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF, NETLOADER_PORT); drawBg(); - gfxDrawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 16, msg); - gfxSwap(); + drawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 16, msg); + swapFrameBuffers(); while (aptMainLoop()) { From fa5b903693d92e1dc277a74a823964614a00d141 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 29 Jun 2016 18:09:01 +0200 Subject: [PATCH 112/259] Update menu_netloaderarm9.c --- source/menu_netloaderarm9.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/menu_netloaderarm9.c b/source/menu_netloaderarm9.c index 616fb7b..2e97143 100644 --- a/source/menu_netloaderarm9.c +++ b/source/menu_netloaderarm9.c @@ -12,7 +12,7 @@ #include #include "utility.h" #include "menu.h" -#include "gfx.h" +#include "draw.h" int menu_netloaderarm9(void) { @@ -51,8 +51,8 @@ int menu_netloaderarm9(void) { "IP: %s, Port: %d\n\nPress B to cancel\n", inet_ntoa(sa.sin_addr), BRAHMA_NETWORK_PORT); drawBg(); - gfxDrawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 16, msg); - gfxSwap(); + drawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 16, msg); + swapFrameBuffers(); sflags = fcntl(sockfd, F_GETFL); if (sflags == -1) { @@ -84,8 +84,8 @@ int menu_netloaderarm9(void) { if (recvd != -1) { total += recvd; drawBg(); - gfxDrawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 16, "%i", total); - gfxSwap(); + drawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 16, "%i", total); + swapFrameBuffers(); } if (total >= ARM9_PAYLOAD_MAX_SIZE) { debug("Err: invalid payload size\n"); From a67ffc588ee5c5601f96c9fdf379d3f33c6d9d98 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 29 Jun 2016 18:09:23 +0200 Subject: [PATCH 113/259] Update menu_picker.c --- source/menu_picker.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/menu_picker.c b/source/menu_picker.c index 891ed79..d0a4d2f 100644 --- a/source/menu_picker.c +++ b/source/menu_picker.c @@ -13,7 +13,7 @@ #endif -#include "gfx.h" +#include "draw.h" #include "picker.h" #include "utility.h" #include "config.h" @@ -152,7 +152,7 @@ static void draw() { y++; } - gfxSwap(); + swapFrameBuffers(); } void pick_file(file_s *picked, const char *path) { From d52641bc9a711d3222358826c1b858c58b35a377 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 29 Jun 2016 18:10:16 +0200 Subject: [PATCH 114/259] Update utility.c --- source/utility.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/source/utility.c b/source/utility.c index ae3b50c..5f17456 100644 --- a/source/utility.c +++ b/source/utility.c @@ -8,16 +8,18 @@ #include "arm9/source/hid.h" #include "arm9/source/i2c.h" #include "arm9/source/fatfs/ff.h" +#include "memory.h" #else + #include <3ds.h> #include + #endif -#include "gfx.h" +#include "draw.h" #include "menu.h" #include "utility.h" -#include "memory.h" #ifdef ARM9 @@ -115,14 +117,14 @@ void debug(const char *fmt, ...) { break; drawBg(); - gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, s, MENU_MIN_X + 16, MENU_MIN_Y + 16); - gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, "Press (A) key to continue...", MENU_MIN_X + 16, MENU_MIN_Y + 64); + drawText(GFX_TOP, GFX_LEFT, &fontDefault, s, MENU_MIN_X + 16, MENU_MIN_Y + 16); + drawText(GFX_TOP, GFX_LEFT, &fontDefault, "Press (A) key to continue...", MENU_MIN_X + 16, MENU_MIN_Y + 64); if ( IS3DACTIVE ) { - gfxDrawText(GFX_TOP, GFX_RIGHT, &fontDefault, s, MENU_MIN_X + 16, MENU_MIN_Y + 16); - gfxDrawText(GFX_TOP, GFX_RIGHT, &fontDefault, "Press (A) key to continue...", MENU_MIN_X + 16, MENU_MIN_Y + 64); + drawText(GFX_TOP, GFX_RIGHT, &fontDefault, s, MENU_MIN_X + 16, MENU_MIN_Y + 16); + drawText(GFX_TOP, GFX_RIGHT, &fontDefault, "Press (A) key to continue...", MENU_MIN_X + 16, MENU_MIN_Y + 64); } - gfxSwap(); + swapFrameBuffers(); } } @@ -145,18 +147,18 @@ bool confirm(int confirmButton, const char *fmt, ...) { } drawBg(); - gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, s, MENU_MIN_X + 16, MENU_MIN_Y + 16); - gfxDrawText(GFX_TOP, GFX_LEFT, &fontDefault, "Press (B) key to cancel...", MENU_MIN_X + 16, MENU_MIN_Y + 64); - gfxDrawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 84, "Press (%s) to confirm...", + drawText(GFX_TOP, GFX_LEFT, &fontDefault, s, MENU_MIN_X + 16, MENU_MIN_Y + 16); + drawText(GFX_TOP, GFX_LEFT, &fontDefault, "Press (B) key to cancel...", MENU_MIN_X + 16, MENU_MIN_Y + 64); + drawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 84, "Press (%s) to confirm...", get_button(confirmButton)); if ( IS3DACTIVE ) { - gfxDrawText(GFX_TOP, GFX_RIGHT, &fontDefault, s, MENU_MIN_X + 16, MENU_MIN_Y + 16); - gfxDrawText(GFX_TOP, GFX_RIGHT, &fontDefault, "Press (B) key to cancel...", MENU_MIN_X + 16, MENU_MIN_Y + 64); - gfxDrawTextf(GFX_TOP, GFX_RIGHT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 84, "Press (%s) to confirm...", + drawText(GFX_TOP, GFX_RIGHT, &fontDefault, s, MENU_MIN_X + 16, MENU_MIN_Y + 16); + drawText(GFX_TOP, GFX_RIGHT, &fontDefault, "Press (B) key to cancel...", MENU_MIN_X + 16, MENU_MIN_Y + 64); + drawTextf(GFX_TOP, GFX_RIGHT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 84, "Press (%s) to confirm...", get_button(confirmButton)); } - gfxSwap(); + swapFrameBuffers(); } return false; } From 6b1b1a0e7d7cd94bf7f6c4c4f3ffa3c780a25a13 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 29 Jun 2016 18:10:56 +0200 Subject: [PATCH 115/259] Update common.h --- source/arm9/source/common.h | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/source/arm9/source/common.h b/source/arm9/source/common.h index 43dd670..7b86eff 100644 --- a/source/arm9/source/common.h +++ b/source/arm9/source/common.h @@ -38,16 +38,3 @@ #define getle64(d) (*((u64*) (d))) #define align(v,a) \ (((v) % (a)) ? ((v) + (a) - ((v) % (a))) : (v)) - -typedef enum -{ - GFX_TOP = 0, ///< Top screen - GFX_BOTTOM = 1 ///< Bottom screen -}gfxScreen_t; - - -typedef enum -{ - GFX_LEFT = 0, ///< Left eye framebuffer - GFX_RIGHT = 1,///< Right eye framebuffer -}gfx3dSide_t; From 979cb926bf7e5dd603e19eabd70115549f9181a8 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 29 Jun 2016 18:11:39 +0200 Subject: [PATCH 116/259] Update netloader.c --- source/hb_menu/netloader.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/hb_menu/netloader.c b/source/hb_menu/netloader.c index d3f77ec..6cb2552 100644 --- a/source/hb_menu/netloader.c +++ b/source/hb_menu/netloader.c @@ -14,7 +14,7 @@ #include #include #include -#include "gfx.h" +#include "draw.h" #define ZLIB_CHUNK (16 * 1024) @@ -55,9 +55,9 @@ static int netloader_draw_progress(void) { //gfxSwapBuffers(); //gspWaitForVBlank(); drawBg(); - gfxDrawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 16, + drawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 16, "%s: %s", netloadedPath, progress); - gfxSwap(); + swapFrameBuffers(); return 0; } From fe3b33bc2a9ac4fb91bc270bc8bc9a351f543df9 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:12:51 +0200 Subject: [PATCH 117/259] Update anim.c --- source/anim.c | 115 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 76 insertions(+), 39 deletions(-) diff --git a/source/anim.c b/source/anim.c index dcad5f0..b02ce36 100644 --- a/source/anim.c +++ b/source/anim.c @@ -68,7 +68,7 @@ void movieLoopSetup(movie_state_s* movie) #ifdef ARM9 -void movieSetup(movie_config_s* mvConf, movie_state_s* movie, void* filePtr, comp_manager_s* compPtr, void* streamPtr) +void movieSetup(movie_config_s* mvConf, movie_state_s* movie, void* filePtr, comp_manager_s* compPtr) #else void movieSetup(movie_config_s* mvConf, movie_state_s* movie) #endif @@ -171,7 +171,7 @@ void movieSetup(movie_config_s* mvConf, movie_state_s* movie) } #ifdef ARM9 - movie->loopStream = streamPtr; + movie->loopStream = (char*)memAlloc(movie->loopStreamSize); #else movie->loopStream = (char*)malloc(movie->loopStreamSize); #endif @@ -190,6 +190,10 @@ void animSetup() memcpy(anim->borders, config->borders, sizeof(u8[4])); memcpy(anim->fntDef, config->fntDef, sizeof(u8[4])); memcpy(anim->fntSel, config->fntSel, sizeof(u8[4])); + memcpy(anim->fntBot, config->fntBotActive ? config->fntBot : config->fntDef, sizeof(u8[4])); + anim->thumbFade = 0xFF; + anim->imgTopFade = 0xFF; + anim->imgBotFade = 0xFF; #ifdef ARM9 comp_manager_s* topComp = (comp_manager_s*)PTR_MOVIE_COMP; @@ -201,9 +205,8 @@ void animSetup() botComp->frame_comp = BOT_COMP_COMP_FRAME_PTR; int fileHandleSize = getFileHandleSize(); - movieSetup(&config->movieTop, &anim->topMovie, PTR_ANIM+sizeof(anim_state_s), topComp, PTR_MOVIE_LOOP); - movieSetup(&config->movieBot, &anim->botMovie, PTR_ANIM+sizeof(anim_state_s)+fileHandleSize, - botComp, PTR_MOVIE_LOOP+anim->topMovie.loopStreamSize); + movieSetup(&config->movieTop, &anim->topMovie, PTR_ANIM+sizeof(anim_state_s), topComp); + movieSetup(&config->movieBot, &anim->botMovie, PTR_ANIM+sizeof(anim_state_s)+fileHandleSize, botComp); #else movieSetup(&config->movieTop, &anim->topMovie); movieSetup(&config->movieTop3D, &anim->top3DMovie); @@ -214,8 +217,10 @@ void animSetup() if ( config->bgTop1AnimTime > 0 || config->bgTop2AnimTime > 0 || config->bgBotAnimTime > 0 || config->highlightAnimTime > 0 || config->bordersAnimTime > 0 - || config->fntDefAnimTime > 0 || config->fntSelAnimTime > 0 - || config->menuFadeInTime > 0 || config->menuFadeInTimeStart != 0 ) + || config->fntDefAnimTime > 0 || config->fntSelAnimTime > 0 || config->fntBotAnimTime > 0 + || config->menuFadeInTime > 0 || config->menuFadeInTimeStart != 0 + || config->bgImgTopFadeInTime > 0 || config->bgImgTopFadeInTimeStart != 0 + || config->bgImgBotFadeInTime > 0 || config->bgImgBotFadeInTimeStart != 0 ) { anim->active = 1; incrementAnimTime(); @@ -246,6 +251,17 @@ void setMergedColorAlpha(float mergeVal, u8 color1[4], u8 color2[4], u8 finalCol finalColor[3] = (u8)(oneMinusMerge*color1[3]+mergeVal*color2[3]); } +void computeMenuColor(u8 color[4], u8 colorAnim[4], int animTime, int animTimeStart, u8 finalColor[4]) +{ + if ( animTime > 0 ) + { + float merge = computeMerge(anim->timer, animTime, animTimeStart); + setMergedColorAlpha(merge, color, colorAnim, finalColor); + } + else if ( anim->timer > config->menuFadeInTimeStart ) + memcpy(finalColor, color, sizeof(u8[4])); +} + void incrementAnimTime() { if (!anim->active) @@ -269,38 +285,25 @@ void incrementAnimTime() setMergedColor(merge, config->bgBot, config->bgBotAnimColor, anim->bgBot); } - if ( config->highlightAnimTime > 0 ) - { - float merge = computeMerge(anim->timer, config->highlightAnimTime, config->highlightAnimTimeStart); - setMergedColorAlpha(merge, config->highlight, config->highlightAnimColor, anim->highlight); - } - else if ( anim->timer > config->menuFadeInTimeStart ) - memcpy(anim->highlight, config->highlight, sizeof(u8[4])); + computeMenuColor(config->highlight, config->highlightAnimColor, + config->highlightAnimTime, config->highlightAnimTimeStart, anim->highlight); - if ( config->bordersAnimTime > 0 ) - { - float merge = computeMerge(anim->timer, config->bordersAnimTime, config->bordersAnimTimeStart); - setMergedColorAlpha(merge, config->borders, config->bordersAnimColor, anim->borders); - } - else if ( anim->timer > config->menuFadeInTimeStart ) - memcpy(anim->borders, config->borders, sizeof(u8[4])); - - if ( config->fntDefAnimTime > 0 ) - { - float merge = computeMerge(anim->timer, config->fntDefAnimTime, config->fntDefAnimTimeStart); - setMergedColorAlpha(merge, config->fntDef, config->fntDefAnimColor, anim->fntDef); - } - else if ( anim->timer > config->menuFadeInTimeStart ) - memcpy(anim->fntDef, config->fntDef, sizeof(u8[4])); + computeMenuColor(config->borders, config->bordersAnimColor, + config->bordersAnimTime, config->bordersAnimTimeStart, anim->borders); - if ( config->fntSelAnimTime > 0 ) + computeMenuColor(config->fntDef, config->fntDefAnimColor, + config->fntDefAnimTime, config->fntDefAnimTimeStart, anim->fntDef); + + computeMenuColor(config->fntSel, config->fntSelAnimColor, + config->fntSelAnimTime, config->fntSelAnimTimeStart, anim->fntSel); + + if ( config->fntBotActive ) { - float merge = computeMerge(anim->timer, config->fntSelAnimTime, config->fntSelAnimTimeStart); - setMergedColorAlpha(merge, config->fntSel, config->fntSelAnimColor, anim->fntSel); + computeMenuColor(config->fntBot, config->fntBotAnimColor, + config->fntBotAnimTime, config->fntBotAnimTimeStart, anim->fntBot); } - else if ( anim->timer > config->menuFadeInTimeStart ) - memcpy(anim->fntSel, config->fntSel, sizeof(u8[4])); + bool checkStopAnim = false; if ( anim->timer >= config->menuFadeInTimeStart ) { int fadeInTime = anim->timer - config->menuFadeInTimeStart; @@ -312,12 +315,10 @@ void incrementAnimTime() anim->borders[3] = (u8)(fadeIn*(float)anim->borders[3]); anim->fntDef[3] = (u8)(fadeIn*(float)anim->fntDef[3]); anim->fntSel[3] = (u8)(fadeIn*(float)anim->fntSel[3]); + anim->fntBot[3] = (u8)(fadeIn*(float)anim->fntBot[3]); + anim->thumbFade = (u8)(fadeIn*255.f); - if ( fadeInTime == config->menuFadeInTime && config->bgTop1AnimTime == 0 - && config->bgTop2AnimTime == 0 && config->bgBotAnimTime == 0 - && config->highlightAnimTime == 0 && config->bordersAnimTime == 0 - && config->fntDefAnimTime == 0 && config->fntSelAnimTime == 0 ) - anim->active = 0; + checkStopAnim = ( fadeInTime == config->menuFadeInTime ); } } else @@ -326,7 +327,43 @@ void incrementAnimTime() anim->borders[3] = 0x00; anim->fntDef[3] = 0x00; anim->fntSel[3] = 0x00; + anim->fntBot[3] = 0x00; + anim->thumbFade = 0x00; + } + + if ( anim->timer >= config->bgImgTopFadeInTimeStart ) + { + int fadeInTime = anim->timer - config->bgImgTopFadeInTimeStart; + if ( fadeInTime <= config->bgImgTopFadeInTime ) + { + float fadeIn = (config->bgImgTopFadeInTime > 0) ? (float)fadeInTime / (float)config->bgImgTopFadeInTime : 1.f; + anim->imgTopFade = (u8)(fadeIn*255.f); + checkStopAnim = ( fadeInTime == config->bgImgTopFadeInTime ); + } } + else + anim->imgTopFade = 0x00; + + if ( anim->timer >= config->bgImgBotFadeInTimeStart ) + { + int fadeInTime = anim->timer - config->bgImgBotFadeInTimeStart; + if ( fadeInTime <= config->bgImgBotFadeInTime ) + { + float fadeIn = (config->bgImgBotFadeInTime > 0) ? (float)fadeInTime / (float)config->bgImgBotFadeInTime : 1.f; + anim->imgBotFade = (u8)(fadeIn*255.f); + checkStopAnim = ( fadeInTime == config->bgImgBotFadeInTime ); + } + } + else + anim->imgBotFade = 0x00; + + if ( checkStopAnim && config->bgTop2AnimTime == 0 && config->bgBotAnimTime == 0 + && config->highlightAnimTime == 0 && config->bordersAnimTime == 0 + && config->fntDefAnimTime == 0 && config->fntSelAnimTime == 0 && config->fntBotAnimTime == 0 + && anim->timer >= config->menuFadeInTimeStart+config->menuFadeInTime + && anim->timer >= config->bgImgTopFadeInTimeStart+config->bgImgTopFadeInTime + && anim->timer >= config->bgImgBotFadeInTimeStart+config->bgImgBotFadeInTime ) + anim->active = 0; anim->timer++; } From 933d8b901b79cdf9fe7d4eff300e7b0efc85f40f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:13:13 +0200 Subject: [PATCH 118/259] Update anim.h --- source/anim.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/anim.h b/source/anim.h index d0f5880..e00b92e 100644 --- a/source/anim.h +++ b/source/anim.h @@ -50,6 +50,10 @@ typedef struct { u8 borders[4]; u8 fntDef[4]; u8 fntSel[4]; + u8 fntBot[4]; + u8 thumbFade; + u8 imgTopFade; + u8 imgBotFade; movie_state_s topMovie; movie_state_s top3DMovie; From 6dc9fa587c556d5929646fe36cec20581313d35f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:13:36 +0200 Subject: [PATCH 119/259] Update config.c --- source/config.c | 390 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 319 insertions(+), 71 deletions(-) diff --git a/source/config.c b/source/config.c index fd8d56a..f368216 100644 --- a/source/config.c +++ b/source/config.c @@ -44,6 +44,15 @@ void setColorAlpha(u8 *cfgColor, const char *color) { } } +bool setBoolean(const char *item) +{ + if ( item[0] == 'Y' || item[0] == 'y' || item[0] == 'T' || item[0] == 't' ) + return true; // Value for "YES", "yes", "TRUE" and "true" + else if ( item[0] == '-' || (item[0] >= '0' && item[0] <= '9') ) + return ( 0 != atoi(item) ); + return false; +} + int setAnimTimes(int* animTime, int* animStart, char *item) { int sep1Ind = 0; @@ -87,6 +96,53 @@ void setAnimWithColorAlpha(int* animTime, int* animStart, u8 *cfgColor, char *it setColorAlpha(cfgColor, &item[colorInd]); } +int readIntValuesList(int* values, int maxValCount, char *item) +{ + int valCount = 0; + while ( valCount < maxValCount ) + { + int sepInd = 0; + while (item[sepInd] != ':' && item[sepInd] != ';' && item[sepInd] != '\0' && item[sepInd] != '\r' && item[sepInd] != '\n') + sepInd++; + bool lastVal = ( item[sepInd] != ':' ); + item[sepInd] = '\0'; + + if ( item[0] == '-' || (item[0] >= '0' && item[0] <= '9') ) + values[valCount] = atoi(item); + else if ( item[0] == 'T' || item[0] == 't' || item[0] == 'Y' || item[0] == 'y' ) // "true" or "yes" + values[valCount] = 1; + else if ( item[0] == 'I' || item[0] == 'i' ) // "infininte" + values[valCount] = 1; + else + values[valCount] = 0; + + item = &item[sepInd+1]; + valCount++; + if ( lastVal ) + break; + } + return valCount; +} + +void setThumbnailParams(thumbnail_s* thumbnail, char *item) +{ + int params[5]; + int pCount = readIntValuesList(params, 5, item); + switch(pCount) + { + case 5: + thumbnail->isRGBA = ( params[4] != 0 ); + case 4: + thumbnail->sizeY = params[3]; + case 3: + thumbnail->sizeX = params[2]; + case 2: + thumbnail->posY = params[1]; + case 1: + thumbnail->posX = params[0]; + } +} + void readStrAsHexData(const char *dataAsStr, char *data, int* dataSize) { *dataSize = strlen(dataAsStr)/2; for (int i = 0; i < *dataSize; i++) @@ -144,12 +200,7 @@ void readMovieProperty(movie_config_s* mvConf, const char *name, const char* val else if ( 0 == strcmp(value, "compressed_memory") ) mvConf->loopStreamType = MEMORY_COMPRESSED_STREAM; } else if (NAME_MATCH("loopReverse")) { - if ( value[0] >= '0' && value[0] <= '9' ) - mvConf->loopReverse = atoi(value); - else if ( value[0] == 'Y' || value[0] == 'y' || value[0] == 'T' || value[0] == 't' ) - mvConf->loopReverse = 1; // Value for "YES", "yes", "TRUE" and "true" - else if ( value[0] == 'N' || value[0] == 'n' || value[0] == 'F' || value[0] == 'f' ) - mvConf->loopReverse = 0; // Value for "NO", "no", "FALSE" and "false" + mvConf->loopReverse = setBoolean(value); } else if (NAME_MATCH("loopStartFrame")) { mvConf->loopStartFrame = atoi(value); } else if (NAME_MATCH("delayOnLoopStart")) { @@ -192,6 +243,46 @@ void writeMovieProperty(movie_config_s* mvConf, char *cfg, int* sizePtr) { } } +void thumbnailInit(thumbnail_s* thumbnail, int sizeX, int sizeY) +{ + thumbnail->path[0] = '\0'; + thumbnail->posX = 0; + thumbnail->posY = 0; + thumbnail->sizeX = sizeX; + thumbnail->sizeY = sizeY; + thumbnail->isRGBA = false; + thumbnail->imgBuff = NULL; + thumbnail->loaded = 0; +} + +void thumbnailAlloc(thumbnail_s* thumbnail, int maxSizeX, int maxSizeY) +{ + if ( thumbnail->sizeX > 0 && thumbnail->sizeY > 0 && thumbnail->sizeX <= maxSizeX && thumbnail->sizeY <= maxSizeY ) + { + int allocSize = thumbnail->sizeX * thumbnail->sizeY * (thumbnail->isRGBA?4:3); + #ifdef ARM9 + thumbnail->imgBuff = (u8*)memAlloc(allocSize); + #else + thumbnail->imgBuff = (u8*)malloc(allocSize); + #endif + } + else + thumbnail->loaded = -1; +} + +void entryInit(boot_entry_s* entry) +{ + entry->title[0] = '\0'; + entry->path[0] = '\0'; + entry->key = -1; + entry->offset = 0; + entry->patchesCount = 0; + + thumbnailInit(&entry->thumbTop, 400, 240); + thumbnailInit(&entry->thumbTop3D, 400, 240); + thumbnailInit(&entry->thumbBot, 320, 240); +} + static char *ini_buffer_reader(char *str, int num, void *stream) { buffer_ctx *ctx = (buffer_ctx *) stream; int idx = 0; @@ -249,7 +340,11 @@ static int handler(void *user, const char *section, const char *name, } else if (NAME_MATCH("default")) { config->index = atoi(item); } - #ifndef ARM9 + #ifdef ARM9 + else if (NAME_MATCH("brightness")) { + config->brightness = atoi(item); + } + #else else if (NAME_MATCH("autobootfix")) { config->autobootfix = atoi(item); } @@ -273,14 +368,23 @@ static int handler(void *user, const char *section, const char *name, setColorAlpha(config->fntDef, item); } else if (NAME_MATCH("font2")) { setColorAlpha(config->fntSel, item); + } else if (NAME_MATCH("font3")) { + setColorAlpha(config->fntBot, item); + config->fntBotActive = true; } else if (NAME_MATCH("bgImgTop")) { strncpy(config->bgImgTop, item, 128); + } else if (NAME_MATCH("bgImgTopAlpha")) { + config->imgTopIsRGBA = setBoolean(item); } else if (NAME_MATCH("bgImgBot")) { strncpy(config->bgImgBot, item, 128); + } else if (NAME_MATCH("bgImgBotAlpha")) { + config->imgBotIsRGBA = setBoolean(item); } #ifndef ARM9 else if (NAME_MATCH("bgImgTop3D")) { strncpy(config->bgImgTop3D, item, 128); + } else if (NAME_MATCH("bgImgTop3DAlpha")) { + config->imgTop3DIsRGBA = setBoolean(item); } #endif } @@ -302,8 +406,15 @@ static int handler(void *user, const char *section, const char *name, setAnimWithColorAlpha(&config->fntDefAnimTime, &config->fntDefAnimTimeStart, config->fntDefAnimColor, item); } else if (NAME_MATCH("font2")) { setAnimWithColorAlpha(&config->fntSelAnimTime, &config->fntSelAnimTimeStart, config->fntSelAnimColor, item); + } else if (NAME_MATCH("font3")) { + setAnimWithColorAlpha(&config->fntBotAnimTime, &config->fntBotAnimTimeStart, config->fntBotAnimColor, item); + config->fntBotActive = true; } else if (NAME_MATCH("menuFadeIn")) { setAnimTimes(&config->menuFadeInTime, &config->menuFadeInTimeStart, item); + } else if (NAME_MATCH("bgImgTopFadeIn")) { + setAnimTimes(&config->bgImgTopFadeInTime, &config->bgImgTopFadeInTimeStart, item); + } else if (NAME_MATCH("bgImgBotFadeIn")) { + setAnimTimes(&config->bgImgBotFadeInTime, &config->bgImgBotFadeInTimeStart, item); } } @@ -323,56 +434,78 @@ static int handler(void *user, const char *section, const char *name, else if (SECTION_MATCH("entry")) { int entryInd = config->count; - if ( entryInd < CONFIG_MAX_ENTRIES ) - { - if (NAME_MATCH("title")) { - strncpy(config->entries[entryInd].title, item, 64); - } else if (NAME_MATCH("path")) { - strncpy(config->entries[entryInd].path, item, 128); - } else if (NAME_MATCH("offset")) { - config->entries[entryInd].offset = strtoul(item, NULL, 16); - } - // End current entry - else if (NAME_MATCH("key")) { - if(strlen(config->entries[entryInd].title) > 0) { - config->entries[entryInd].key = atoi(item); - config->count++; + boot_entry_s* entry = &config->entries[entryInd]; + + if (NAME_MATCH("title")) { + strncpy(entry->title, item, 64); + } else if (NAME_MATCH("path")) { + strncpy(entry->path, item, 128); + } else if (NAME_MATCH("offset")) { + entry->offset = strtoul(item, NULL, 16); + } else if (NAME_MATCH("thumbTop")) { + strncpy(entry->thumbTop.path, item, 128); + } else if (NAME_MATCH("thumbTopParams")) { + setThumbnailParams(&entry->thumbTop, item); + } else if (NAME_MATCH("thumbTop3D")) { + strncpy(entry->thumbTop3D.path, item, 128); + } else if (NAME_MATCH("thumbTop3DParams")) { + setThumbnailParams(&entry->thumbTop3D, item); + } else if (NAME_MATCH("thumbBot")) { + strncpy(entry->thumbBot.path, item, 128); + } else if (NAME_MATCH("thumbBotParams")) { + setThumbnailParams(&entry->thumbBot, item); + } + // End current entry + else if (NAME_MATCH("key")) { + if(strlen(entry->title) > 0) { + entry->key = atoi(item); + config->count++; + if (config->count >= config->maxCount) + { + config->maxCount += ENTRIES_COUNT_INC; + #ifdef ARM9 + // Increase size of allocated space (nothing must be allocated since "config->entries" first allocation) + memAlloc(ENTRIES_COUNT_INC*sizeof(boot_entry_s)); + #else + config->entries = realloc(config->entries, config->maxCount*sizeof(boot_entry_s)); + #endif } + entryInit(&config->entries[config->count]); } - #ifdef ARM9 - else + } + #ifdef ARM9 + else + { + int patchInd = entry->patchesCount; + if ( patchInd < PATCHES_MAX_PER_ENTRY ) { - int patchInd = config->entries[entryInd].patchesCount; - if ( patchInd < PATCHES_MAX_PER_ENTRY ) - { - // Binary patches for current entry - if (NAME_MATCH("patchMemSearch")) { - binary_patch* curPatch = &config->entries[entryInd].patches[patchInd]; - readStrAsHexData(item, curPatch->memToSearch, &curPatch->memToSearchSize); - } else if (NAME_MATCH("patchMemOverwrite")) { - binary_patch* curPatch = &config->entries[entryInd].patches[patchInd]; - readStrAsHexData(item, curPatch->memOverwrite, &curPatch->memOverwriteSize); - } else if (NAME_MATCH("patchMemOverwriteStr")) { - binary_patch* curPatch = &config->entries[entryInd].patches[patchInd]; - curPatch->memOverwriteSize = strlen(item)+1; - memcpy(curPatch->memOverwrite, item, curPatch->memOverwriteSize); - } else if (NAME_MATCH("patchMemOverwriteWStr")) { - binary_patch* curPatch = &config->entries[entryInd].patches[patchInd]; - int strSize = strlen(item)+1; - curPatch->memOverwriteSize = strSize*2; - for (int i = 0; i < strSize; i++) - { - curPatch->memOverwrite[2*i] = item[i]; - curPatch->memOverwrite[2*i+1] = '\0'; - } - } else if (NAME_MATCH("patchOccurence")) { - config->entries[entryInd].patches[patchInd].occurence = atoi(item); - config->entries[entryInd].patchesCount++; + // Binary patches for current entry + if (NAME_MATCH("patchMemSearch")) { + binary_patch* curPatch = &entry->patches[patchInd]; + readStrAsHexData(item, curPatch->memToSearch, &curPatch->memToSearchSize); + } else if (NAME_MATCH("patchMemOverwrite")) { + binary_patch* curPatch = &entry->patches[patchInd]; + readStrAsHexData(item, curPatch->memOverwrite, &curPatch->memOverwriteSize); + } else if (NAME_MATCH("patchMemOverwriteStr")) { + binary_patch* curPatch = &entry->patches[patchInd]; + curPatch->memOverwriteSize = strlen(item)+1; + memcpy(curPatch->memOverwrite, item, curPatch->memOverwriteSize); + } else if (NAME_MATCH("patchMemOverwriteWStr")) { + binary_patch* curPatch = &entry->patches[patchInd]; + int strSize = strlen(item)+1; + curPatch->memOverwriteSize = strSize*2; + for (int i = 0; i < strSize; i++) + { + curPatch->memOverwrite[2*i] = item[i]; + curPatch->memOverwrite[2*i+1] = '\0'; } + } else if (NAME_MATCH("patchOccurence")) { + entry->patches[patchInd].occurence = atoi(item); + entry->patchesCount++; } } - #endif } + #endif } return 0; } @@ -399,6 +532,9 @@ void configThemeInit() { config->bgImgTop[0] = '\0'; config->bgImgTop3D[0] = '\0'; config->bgImgBot[0] = '\0'; + config->imgTopIsRGBA = false; + config->imgTop3DIsRGBA = false; + config->imgBotIsRGBA = false; memcpy(config->bgTop1, (u8[3]) {0x4a, 0x00, 0x31}, sizeof(u8[3])); memcpy(config->bgTop2, (u8[3]) {0x6f, 0x01, 0x49}, sizeof(u8[3])); memcpy(config->bgBot, (u8[3]) {0x6f, 0x01, 0x49}, sizeof(u8[3])); @@ -406,6 +542,8 @@ void configThemeInit() { memcpy(config->borders, (u8[4]) {0xff, 0xff, 0xff, 0xff}, sizeof(u8[4])); memcpy(config->fntDef, (u8[4]) {0xff, 0xff, 0xff, 0xff}, sizeof(u8[4])); memcpy(config->fntSel, (u8[4]) {0x00, 0x00, 0x00, 0xff}, sizeof(u8[4])); + memcpy(config->fntBot, (u8[4]) {0xff, 0xff, 0xff, 0xff}, sizeof(u8[4])); + config->fntBotActive = false; // animation config->bgTop1AnimTime = 0; @@ -415,9 +553,14 @@ void configThemeInit() { config->bordersAnimTime = 0; config->fntDefAnimTime = 0; config->fntSelAnimTime = 0; + config->fntBotAnimTime = 0; config->menuFadeInTime = 0; config->menuFadeInTimeStart = 0; - + config->bgImgTopFadeInTime = 0; + config->bgImgTopFadeInTimeStart = 0; + config->bgImgBotFadeInTime = 0; + config->bgImgBotFadeInTimeStart = 0; + // movie configMovieInit(&config->movieTop); configMovieInit(&config->movieTop3D); @@ -437,9 +580,19 @@ int configInit() { config->timeout = 3; config->autobootfix = 8; + config->brightness = 0; config->index = 0; config->recovery = 2; + +#ifdef ARM9 + config->entries = memAlloc(DEFAULT_ENTRIES_COUNT*sizeof(boot_entry_s)); +#else + config->entries = malloc(DEFAULT_ENTRIES_COUNT*sizeof(boot_entry_s)); +#endif config->count = 0; + config->maxCount = DEFAULT_ENTRIES_COUNT; + entryInit(&config->entries[0]); + configThemeInit(); // read config file to buffer @@ -476,19 +629,29 @@ int configInit() { #endif loadBg(GFX_BOTTOM, GFX_LEFT); + for (int i = 0 ; i < config->count ; i++) + { + boot_entry_s* entry = &config->entries[i]; + thumbnailAlloc(&entry->thumbTop, 400, 240); + #ifndef ARM9 + thumbnailAlloc(&entry->thumbTop3D, 400, 240); + #endif + thumbnailAlloc(&entry->thumbBot, 320, 240); + } + return 0; } int configAddEntry(char *title, char *path, long offset) { - if (config->count >= CONFIG_MAX_ENTRIES) + if (config->count >= config->maxCount) return 1; - strncpy(config->entries[config->count].title, title, 64); - strncpy(config->entries[config->count].path, path, 128); - config->entries[config->count].offset = offset; - config->entries[config->count].patchesCount = 0; - config->entries[config->count].key = -1; + boot_entry_s* entry = &config->entries[config->count]; + entryInit(entry); + strncpy(entry->title, title, 64); + strncpy(entry->path, path, 128); + entry->offset = offset; config->count++; configSave(); @@ -500,6 +663,16 @@ int configRemoveEntry(int index) { if ( index >= config->count ) return 1; +#ifndef ARM9 + boot_entry_s* entry = &config->entries[index]; + if ( NULL != entry->thumbTop.imgBuff ) + free(entry->thumbTop.imgBuff); + if ( NULL != entry->thumbTop3D.imgBuff ) + free(entry->thumbTop.imgBuff); + if ( NULL != entry->thumbBot.imgBuff ) + free(entry->thumbTop.imgBuff); +#endif + int i = 0; for(i=0; icount; i++) { if(i > index) { @@ -529,7 +702,10 @@ void configSave() { // general section size += snprintf(cfg, 256, "[general]\n"); -#ifndef ARM9 +#ifdef ARM9 + if (config->brightness > 0) + size += snprintf(cfg+size, 256, "brightness=%i;\n", config->brightness); +#else size += snprintf(cfg+size, 256, "autobootfix=%i;\n", config->autobootfix); #endif size += snprintf(cfg+size, 256, "timeout=%i;\n", config->timeout); @@ -553,20 +729,32 @@ void configSave() { size += snprintf(cfg+size, 256, "font1=%02X%02X%02X%02X;\n", config->fntDef[0], config->fntDef[1], config->fntDef[2], config->fntDef[3]); else size += snprintf(cfg+size, 256, "font1=%02X%02X%02X;\n", config->fntDef[0], config->fntDef[1], config->fntDef[2]); - if ( config->fntSel[3] < 0xFF ) size += snprintf(cfg+size, 256, "font2=%02X%02X%02X%02X;\n", config->fntSel[0], config->fntSel[1], config->fntSel[2], config->fntSel[3]); else size += snprintf(cfg+size, 256, "font2=%02X%02X%02X;\n", config->fntSel[0], config->fntSel[1], config->fntSel[2]); + if ( config->fntBotActive ) + { + if ( config->fntBot[3] < 0xFF ) + size += snprintf(cfg+size, 256, "font3=%02X%02X%02X%02X;\n", config->fntBot[0], config->fntBot[1], config->fntBot[2], config->fntBot[3]); + else + size += snprintf(cfg+size, 256, "font3=%02X%02X%02X;\n", config->fntBot[0], config->fntBot[1], config->fntBot[2]); + } size += snprintf(cfg+size, 256, "bgImgTop=%s;\n", config->bgImgTop); + if ( config->imgTopIsRGBA ) + size += snprintf(cfg+size, 256, "bgImgTopAlpha=yes;\n"); #ifndef ARM9 - if (config->bgImgTop3D[0] != '\0') + if ( config->bgImgTop3D[0] != '\0' ) size += snprintf(cfg+size, 256, "bgImgTop3D=%s;\n", config->bgImgTop3D); + if ( config->imgTop3DIsRGBA ) + size += snprintf(cfg+size, 256, "bgImgTop3DAlpha=yes;\n"); #endif - size += snprintf(cfg+size, 256, "bgImgBot=%s;\n\n", config->bgImgBot); + size += snprintf(cfg+size, 256, "bgImgBot=%s;\n", config->bgImgBot); + if ( config->imgBotIsRGBA ) + size += snprintf(cfg+size, 256, "bgImgBotAlpha=yes;\n"); // animation section - size += snprintf(cfg+size, 256, "[animation]\n"); + size += snprintf(cfg+size, 256, "\n[animation]\n"); if ( config->bgTop1AnimTime > 0 ) { size += snprintf(cfg+size, 256, "bgTop1=%i:%i:%02X%02X%02X;\n", config->bgTop1AnimTime, config->bgTop1AnimTimeStart, @@ -623,20 +811,37 @@ void configSave() { } if ( config->fntSelAnimTime > 0 ) { - if ( config->fntDefAnimColor[3] < 0xFF ) + if ( config->fntSelAnimColor[3] < 0xFF ) { size += snprintf(cfg+size, 256, "font2=%i:%i:%02X%02X%02X%02X;\n", config->fntSelAnimTime, config->fntSelAnimTimeStart, config->fntSelAnimColor[0], config->fntSelAnimColor[1], config->fntSelAnimColor[2], config->fntSelAnimColor[3]); } else { - size += snprintf(cfg+size, 256, "font2=%i:%i:%02X%02X%02X;\n", config->fntDefAnimTime, config->fntSelAnimTimeStart, + size += snprintf(cfg+size, 256, "font2=%i:%i:%02X%02X%02X;\n", config->fntSelAnimTime, config->fntSelAnimTimeStart, config->fntSelAnimColor[0], config->fntSelAnimColor[1], config->fntSelAnimColor[2]); } } + if ( config->fntBotActive && config->fntBotAnimTime > 0 ) + { + if ( config->fntBotAnimColor[3] < 0xFF ) + { + size += snprintf(cfg+size, 256, "font3=%i:%i:%02X%02X%02X%02X;\n", config->fntBotAnimTime, config->fntBotAnimTimeStart, + config->fntBotAnimColor[0], config->fntBotAnimColor[1], config->fntBotAnimColor[2], config->fntBotAnimColor[3]); + } + else + { + size += snprintf(cfg+size, 256, "font3=%i:%i:%02X%02X%02X;\n", config->fntBotAnimTime, config->fntBotAnimTimeStart, + config->fntBotAnimColor[0], config->fntBotAnimColor[1], config->fntBotAnimColor[2]); + } + } if ( config->menuFadeInTime > 0 ) size += snprintf(cfg+size, 256, "menuFadeIn=%i:%i;\n", config->menuFadeInTime, config->menuFadeInTimeStart); - + if ( config->bgImgTopFadeInTime > 0 ) + size += snprintf(cfg+size, 256, "bgImgTopFadeIn=%i:%i;\n", config->bgImgTopFadeInTime, config->bgImgTopFadeInTimeStart); + if ( config->bgImgBotFadeInTime > 0 ) + size += snprintf(cfg+size, 256, "bgImgBotFadeIn=%i:%i;\n", config->bgImgBotFadeInTime, config->bgImgBotFadeInTimeStart); + // movie section if ( config->movieTop.path[0] != '\0' ) { @@ -657,16 +862,20 @@ void configSave() { } // entries section - for(i=0; icount; i++) { + for(i=0; icount; i++) + { + boot_entry_s* entry = &config->entries[i]; + size += snprintf(cfg+size, 256, "\n[entry]\n"); - size += snprintf(cfg+size, 256, "title=%s;\n", config->entries[i].title); - size += snprintf(cfg+size, 256, "path=%s;\n", config->entries[i].path); - size += snprintf(cfg+size, 256, "offset=%x;\n", (int)config->entries[i].offset); + size += snprintf(cfg+size, 256, "title=%s;\n", entry->title); + size += snprintf(cfg+size, 256, "path=%s;\n", entry->path); + size += snprintf(cfg+size, 256, "offset=%x;\n", (int)entry->offset); + int patchesCount = config->entries[i].patchesCount; #ifdef ARM9 for (int j = 0; j < patchesCount; j++) { - binary_patch* curPatch = &config->entries[i].patches[j]; + binary_patch* curPatch = &entry->patches[j]; size += snprintf(cfg+size, 256, "patchMemSearch="); writeHexDataAsStr(curPatch->memToSearch, curPatch->memToSearchSize, cfg+size); size += curPatch->memToSearchSize*2; @@ -676,7 +885,29 @@ void configSave() { size += snprintf(cfg+size, 256, ";\npatchOccurence=%i;\n", curPatch->occurence); } #endif - size += snprintf(cfg+size, 256, "key=%i;\n", config->entries[i].key); + + if ( entry->thumbTop.path[0] != '\0' ) + { + thumbnail_s* thumb = &entry->thumbTop; + size += snprintf(cfg+size, 256, "thumbTop=%s;\n", thumb->path); + size += snprintf(cfg+size, 256, "thumbTopParams=%d:%d:%d:%d:%s;\n", thumb->posX, thumb->posY, thumb->sizeX, thumb->sizeY, thumb->isRGBA?"yes":"no"); + } + #ifndef ARM9 + if ( entry->thumbTop3D.path[0] != '\0' ) + { + thumbnail_s* thumb = &entry->thumbTop3D; + size += snprintf(cfg+size, 256, "thumbTop3D=%s;\n", thumb->path); + size += snprintf(cfg+size, 256, "thumbTop3DParams=%d:%d:%d:%d:%s;\n", thumb->posX, thumb->posY, thumb->sizeX, thumb->sizeY, thumb->isRGBA?"yes":"no"); + } + #endif + if ( entry->thumbBot.path[0] != '\0' ) + { + thumbnail_s* thumb = &entry->thumbBot; + size += snprintf(cfg+size, 256, "thumbBot=%s;\n", thumb->path); + size += snprintf(cfg+size, 256, "thumbBotParams=%d:%d:%d:%d:%s;\n", thumb->posX, thumb->posY, thumb->sizeX, thumb->sizeY, thumb->isRGBA?"yes":"no"); + } + + size += snprintf(cfg+size, 256, "key=%i;\n", entry->key); } #ifdef ARM9 FIL file; @@ -700,6 +931,18 @@ void configSave() { void configExit() { #ifndef ARM9 if (config) { + for (int i = 0 ; i < config->count ; i++) + { + boot_entry_s* entry = &config->entries[i]; + if ( NULL != entry->thumbTop.imgBuff ) + free(entry->thumbTop.imgBuff); + if ( NULL != entry->thumbTop3D.imgBuff ) + free(entry->thumbTop.imgBuff); + if ( NULL != entry->thumbBot.imgBuff ) + free(entry->thumbTop.imgBuff); + } + free(config->entries); + if (config->bgImgTopBuff) { free(config->bgImgTopBuff); } @@ -709,6 +952,7 @@ void configExit() { if (config->bgImgBotBuff) { free(config->bgImgBotBuff); } + free(config); } #endif @@ -726,6 +970,10 @@ void loadBg(gfxScreen_t screen, gfx3dSide_t side) { return; } + size_t maxsize = GFX_TOP ? (400*240*4) : (320*240*4); + if (size > maxsize) + size = maxsize; + #ifdef ARM9 u8 *bg = screen == GFX_TOP ? PTR_TOP_BG : PTR_BOT_BG; #else From d61d7e0f299a021ada15a610a5c8134550676a9e Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:13:57 +0200 Subject: [PATCH 120/259] Update config.h --- source/config.h | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/source/config.h b/source/config.h index fbf2eb5..57a07eb 100644 --- a/source/config.h +++ b/source/config.h @@ -22,13 +22,24 @@ extern "C" { #include "loader.h" // Binary patches define #define BIT(n) (1U<<(n)) -#define CONFIG_MAX_ENTRIES 11 +#define DEFAULT_ENTRIES_COUNT 11 +#define ENTRIES_COUNT_INC 12 #define PATCHES_MAX_PER_ENTRY 4 #define FILE_STREAM 0 #define MEMORY_STREAM 1 #define MEMORY_COMPRESSED_STREAM 2 +typedef struct { + char path[128]; + int posX; + int posY; + int sizeX; + int sizeY; + bool isRGBA; + u8 *imgBuff; + int loaded; +} thumbnail_s; typedef struct { char title[64]; @@ -37,6 +48,10 @@ typedef struct { long offset; binary_patch patches[PATCHES_MAX_PER_ENTRY]; int patchesCount; + + thumbnail_s thumbTop; + thumbnail_s thumbTop3D; + thumbnail_s thumbBot; } boot_entry_s; typedef struct { @@ -54,11 +69,13 @@ typedef struct { typedef struct { int timeout; int autobootfix; + int brightness; int index; int recovery; int count; - boot_entry_s entries[CONFIG_MAX_ENTRIES]; - + int maxCount; + boot_entry_s* entries; + u8 bgTop1[3]; u8 bgTop2[3]; u8 bgBot[3]; @@ -66,7 +83,9 @@ typedef struct { u8 borders[4]; u8 fntDef[4]; u8 fntSel[4]; - + u8 fntBot[4]; + bool fntBotActive; + u8 bgTop1AnimColor[3]; u8 bgTop2AnimColor[3]; u8 bgBotAnimColor[3]; @@ -74,7 +93,8 @@ typedef struct { u8 bordersAnimColor[4]; u8 fntDefAnimColor[4]; u8 fntSelAnimColor[4]; - + u8 fntBotAnimColor[4]; + int bgTop1AnimTime; int bgTop2AnimTime; int bgBotAnimTime; @@ -82,6 +102,7 @@ typedef struct { int bordersAnimTime; int fntDefAnimTime; int fntSelAnimTime; + int fntBotAnimTime; int bgTop1AnimTimeStart; int bgTop2AnimTimeStart; @@ -90,13 +111,21 @@ typedef struct { int bordersAnimTimeStart; int fntDefAnimTimeStart; int fntSelAnimTimeStart; - + int fntBotAnimTimeStart; + int menuFadeInTime; int menuFadeInTimeStart; + int bgImgTopFadeInTime; + int bgImgTopFadeInTimeStart; + int bgImgBotFadeInTime; + int bgImgBotFadeInTimeStart; char bgImgTop[128]; char bgImgTop3D[128]; char bgImgBot[128]; + bool imgTopIsRGBA; + bool imgTop3DIsRGBA; + bool imgBotIsRGBA; bool imgError; bool imgError3D; bool imgErrorBot; @@ -110,7 +139,6 @@ typedef struct { movie_config_s movieTop; movie_config_s movieTop3D; movie_config_s movieBot; - } boot_config_s; boot_config_s *config; From ee3ebe7437506a05d08542ea43ccab75daa43022 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:14:22 +0200 Subject: [PATCH 121/259] Update draw.c --- source/draw.c | 78 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/source/draw.c b/source/draw.c index 8c3b14c..b76008b 100644 --- a/source/draw.c +++ b/source/draw.c @@ -16,6 +16,7 @@ #ifdef ARM9 u8 *gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16 *width, u16 *height) { + //WARNING: width and height must stay inverted to simulate 3DSX version behavior! if (screen == GFX_TOP) { if (width) *width = 240; if (height) *height = 400; @@ -43,12 +44,12 @@ void drawPixelAlpha(int x, int y, char r, char g, char b, char a, u8 *screen) { u32 v = (height - 1 - y + x * height) * 3; - float alpha = (float)a / 255.f; - float one_minus_alpha = 1.f - alpha; - - screen[v + 0] = (u8)(alpha*b+one_minus_alpha*(float)screen[v + 0]); - screen[v + 1] = (u8)(alpha*g+one_minus_alpha*(float)screen[v + 1]); - screen[v + 2] = (u8)(alpha*r+one_minus_alpha*(float)screen[v + 2]); + int alpha = a; + int one_minus_alpha = 255-alpha; + + screen[v + 0] = (u8)((alpha*b+one_minus_alpha*screen[v + 0])/255); + screen[v + 1] = (u8)((alpha*g+one_minus_alpha*screen[v + 1])/255); + screen[v + 2] = (u8)((alpha*a+one_minus_alpha*screen[v + 2])/255); } void drawLine(gfxScreen_t screen, gfx3dSide_t side, int x1, int y1, int x2, int y2, char r, char g, char b, char a) { @@ -120,6 +121,58 @@ void drawTextN(gfxScreen_t screen, gfx3dSide_t side, font_s *f, char *str, u16 l drawStringN(fbAdr, f, str, length, x, 240 - y, fbHeight, fbWidth); } +void drawImage(gfxScreen_t screen, gfx3dSide_t side, u8* img, bool rgba, u16 w, u16 h, s16 x, s16 y, char a) +{ + u16 fbWidth, fbHeight; + u8 *fbAdr = gfxGetFramebuffer(screen, side, &fbWidth, &fbHeight); + + int imax = w; + if (imax+x > fbHeight) + imax = fbHeight-x; + + int jmax = h; + if (jmax+y > fbWidth) + jmax = fbWidth-y; + + int i, j; + if ( rgba ) + { + for (i = 0; i < imax; i++) + { + u8* imgAdr = img + 4*i*h; + u8* rowFbAdr = fbAdr + 3*((x+i)*fbWidth + y); + for (j = 0; j < jmax; j++) + { + int alpha = ((int)a*imgAdr[0]) / 255; + int one_minus_alpha = 255-alpha; + rowFbAdr[0] = (u8)((alpha*imgAdr[1]+one_minus_alpha*rowFbAdr[0])/255); + rowFbAdr[1] = (u8)((alpha*imgAdr[2]+one_minus_alpha*rowFbAdr[1])/255); + rowFbAdr[2] = (u8)((alpha*imgAdr[3]+one_minus_alpha*rowFbAdr[2])/255); + imgAdr += 4; + rowFbAdr += 3; + } + } + } + else + { + int alpha = a; + int one_minus_alpha = 255-a; + for (i = 0; i < imax; i++) + { + u8* imgAdr = img + 3*i*h; + u8* rowFbAdr = fbAdr + 3*((x+i)*fbWidth + y); + for (j = 0; j < jmax; j++) + { + rowFbAdr[0] = (u8)((alpha*imgAdr[0]+one_minus_alpha*rowFbAdr[0])/255); + rowFbAdr[1] = (u8)((alpha*imgAdr[1]+one_minus_alpha*rowFbAdr[1])/255); + rowFbAdr[2] = (u8)((alpha*imgAdr[2]+one_minus_alpha*rowFbAdr[2])/255); + imgAdr += 3; + rowFbAdr += 3; + } + } + } +} + void fillColor(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[3]) { u16 fbWidth, fbHeight; u8 *fbAdr = gfxGetFramebuffer(screen, side, &fbWidth, &fbHeight); @@ -136,7 +189,7 @@ void fillColor(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[3]) { void fillColorGradient(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColorStart[3], u8 rgbColorEnd[3]) { u16 fbWidth, fbHeight; u8 *fbAdr = gfxGetFramebuffer(screen, side, &fbWidth, &fbHeight); - u8 colorLine[1200]; // Avoid dynamic "fbWidth*3", illogical crash on 3DSX version with top right buffer + u8 colorLine[720]; // Avoid dynamic "fbWidth*3", illogical crash on 3DSX version with top right buffer //TODO : optimize; use GX command ? // Avoid float operations, illogical crash on 3DSX version with top right buffer @@ -192,17 +245,18 @@ void _drawRectangle(gfxScreen_t screen, gfx3dSide_t side, u8 rgbaColor[4], s16 x } else if ( rgbaColor[3] > 0 ) { - float alpha = (float)rgbaColor[3] / 255.f; - float one_minus_alpha = 1.f - alpha; + int alpha = rgbaColor[3]; + int one_minus_alpha = 255-alpha; + int i, j; fbAdr += fbWidth * 3 * y; for (j = 0; j < height; j++) { for (i = 0; i < width; i++) { - fbAdr[3*(i+x)+0] = (u8)(alpha*(float)rgbaColor[2]+one_minus_alpha*(float)fbAdr[3*(i+x)+0]); - fbAdr[3*(i+x)+1] = (u8)(alpha*(float)rgbaColor[1]+one_minus_alpha*(float)fbAdr[3*(i+x)+1]); - fbAdr[3*(i+x)+2] = (u8)(alpha*(float)rgbaColor[0]+one_minus_alpha*(float)fbAdr[3*(i+x)+2]); + fbAdr[3*(i+x)+0] = (u8)((alpha*rgbaColor[2]+one_minus_alpha*fbAdr[3*(i+x)+0])/255); + fbAdr[3*(i+x)+1] = (u8)((alpha*rgbaColor[1]+one_minus_alpha*fbAdr[3*(i+x)+1])/255); + fbAdr[3*(i+x)+2] = (u8)((alpha*rgbaColor[0]+one_minus_alpha*fbAdr[3*(i+x)+2])/255); } fbAdr += fbWidth * 3; } From e73d596c5c8a91d6531dfb74979db545f6240744 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:14:41 +0200 Subject: [PATCH 122/259] Update draw.h --- source/draw.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/draw.h b/source/draw.h index d6f1506..4a85414 100644 --- a/source/draw.h +++ b/source/draw.h @@ -42,6 +42,8 @@ void drawTextN(gfxScreen_t screen, gfx3dSide_t side, font_s *f, char *str, u16 l void drawTextf(gfxScreen_t screen, gfx3dSide_t side, font_s *f, s16 x, s16 y, const char *fmt, ...); +void drawImage(gfxScreen_t screen, gfx3dSide_t side, u8* img, bool rgba, u16 w, u16 h, s16 x, s16 y, char a); + void fillColor(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColor[3]); void fillColorGradient(gfxScreen_t screen, gfx3dSide_t side, u8 rgbColorStart[3], u8 rgbColorEnd[3]); From 7f807bc795cf0d3a6236f34576b0ec4c938178f8 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:15:12 +0200 Subject: [PATCH 123/259] Update main.c --- source/main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/main.c b/source/main.c index 6ce4c13..0bafac9 100644 --- a/source/main.c +++ b/source/main.c @@ -63,7 +63,6 @@ int main() { *(u32 *) 0x10000020 = 0x340; FATFS fs; f_mount(&fs, "0:", 0); - initScreens(); #else if (netloader_init() != 0) { // fix SOC_Initialize @@ -81,12 +80,18 @@ int main() { #endif animInit(); if (configInit() != 0 || config->count <= 0) { // recovery + #ifdef ARM9 + initScreens(config->brightness); + #endif animSetup(); while (aptMainLoop()) { if (menu_more() == 0) break; } } else { + #ifdef ARM9 + initScreens(config->brightness); + #endif animSetup(); while (aptMainLoop()) { if (menu_boot() == 0) From c31fc063770a2c56f8bf6000fc14fb1d2846a1e4 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:15:42 +0200 Subject: [PATCH 124/259] Update memory.h --- source/memory.h | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/source/memory.h b/source/memory.h index 22846bd..d5be655 100644 --- a/source/memory.h +++ b/source/memory.h @@ -7,17 +7,18 @@ #define PTR_TOP_SCREEN (u8*)(*(u32*)0x23FFFE00) #define PTR_BOT_SCREEN (u8*)(*(u32*)0x23FFFE08) -#define PTR_TOP_SCREEN_BUF (u8*)(0x2507E900) -#define PTR_BOT_SCREEN_BUF (u8*)(0x250C4E00) -#define PTR_TOP_BG (u8*)(0x25000000) -#define PTR_BOT_BG (u8*)(0x25046500) -#define PTR_CFG (u8*)(0x25200000) -#define PTR_PICKER (u8*)(0x25210000) -#define PTR_PICKER_FILE (u8*)(0x25220000) -#define PTR_CFG_TMP (u8*)(0x25230000) -#define PTR_ANIM (u8*)(0x25240000) -#define PTR_MOVIE_COMP (u8*)(0x25250000) -#define PTR_MOVIE_LOOP (u8*)(0x25360000) +#define PTR_TOP_SCREEN_BUF (u8*)(0x25000000) +#define PTR_BOT_SCREEN_BUF (u8*)(0x25046500) +#define PTR_TOP_BG (u8*)(0x2507E900) +#define PTR_BOT_BG (u8*)(0x250DC500) +#define PTR_CFG (u8*)(0x25130000) +#define PTR_PICKER (u8*)(0x25140000) +#define PTR_PICKER_FILE (u8*)(0x25150000) +#define PTR_CFG_TMP (u8*)(0x25160000) +#define PTR_ANIM (u8*)(0x25170000) +#define PTR_MOVIE_COMP (u8*)(0x25180000) +#define PTR_DYNAMIC_MEM_START (u8*)(0x25290000) + #define PTR_PAYLOAD_MAIN 0x23F00000 #define PTR_PAYLOAD_MAIN_DATA 0x26000000 From adeb5a433ccbac0c3d4cfe09465439c708abfb03 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:16:21 +0200 Subject: [PATCH 125/259] Update menu.c --- source/menu.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/source/menu.c b/source/menu.c index a7cda52..16497a6 100644 --- a/source/menu.c +++ b/source/menu.c @@ -12,31 +12,44 @@ #include "menu.h" void drawBg() { - u8* fbTop = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); + + u16 fbWidth, fbHeight; + u8* fbTop = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, &fbWidth, &fbHeight); if (readMovie(fbTop, &anim->topMovie) < 0) { - if (!config->imgError) { + if (!config->imgError && 0xFF == anim->imgTopFade && !config->imgTopIsRGBA) { memcpy(fbTop, config->bgImgTopBuff, (size_t) config->bgImgTopSize); } else { clearTop(anim->bgTop1, anim->bgTop2); + if (!config->imgError && anim->imgTopFade) + drawImage(GFX_TOP, GFX_LEFT, config->bgImgTopBuff, config->imgTopIsRGBA, fbHeight, fbWidth, 0, 0, anim->imgTopFade); } } - u8* fbBot = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); + u8* fbBot = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, &fbWidth, &fbHeight); if (readMovie(fbBot, &anim->botMovie) < 0) { - if (!config->imgErrorBot) { + if (!config->imgErrorBot && 0xFF == anim->imgBotFade && !config->imgBotIsRGBA) { memcpy(fbBot, config->bgImgBotBuff, (size_t) config->bgImgBotSize); } else { clearBot(anim->bgBot); + if (!config->imgErrorBot && anim->imgBotFade) + drawImage(GFX_BOTTOM, GFX_LEFT, config->bgImgBotBuff, config->imgBotIsRGBA, fbHeight, fbWidth, 0, 0, anim->imgBotFade); } } drawRectColor(GFX_TOP, GFX_LEFT, MENU_MIN_X, MENU_MIN_Y - 20, MENU_MAX_X, MENU_MAX_Y, anim->borders); - u8* fbTop3D = IS3DACTIVE ? gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL) : NULL; + u8* fbTop3D = IS3DACTIVE ? gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, &fbWidth, &fbHeight) : NULL; if (fbTop3D) { - if (readMovie(fbTop3D, &anim->top3DMovie) < 0 && !config->imgError) - memcpy(fbTop3D, config->bgImgTop3DBuff, (size_t) config->bgImgTop3DSize); + if (readMovie(fbTop3D, &anim->top3DMovie) < 0) + { + if (!config->imgError3D && 0xFF == anim->imgTopFade && !config->imgTop3DIsRGBA) { + memcpy(fbTop3D, config->bgImgTop3DBuff, (size_t) config->bgImgTop3DSize); + } else { + if (!config->imgError3D && anim->imgTopFade) + drawImage(GFX_TOP, GFX_RIGHT, config->bgImgTop3DBuff, config->imgTop3DIsRGBA, fbHeight, fbWidth, 0, 0, anim->imgTopFade); + } + } drawRectColor(GFX_TOP, GFX_RIGHT, MENU_MIN_X, MENU_MIN_Y - 20, MENU_MAX_X, MENU_MAX_Y, anim->borders); } @@ -106,6 +119,9 @@ void drawInfo(const char *format, ...) { vsnprintf(msg, 512, format, argp); va_end(argp); + memcpy(fontDefault.color, config->fntBotActive ? anim->fntBot : anim->fntDef, sizeof(u8[4])); drawText(GFX_BOTTOM, GFX_LEFT, &fontDefault, "Informations", (s16) (MENU_MIN_X + 6), 40); drawText(GFX_BOTTOM, GFX_LEFT, &fontDefault, msg, (s16) (MENU_MIN_X + 12), 80); + + memcpy(fontDefault.color, anim->fntDef, sizeof(u8[4])); } From 7954b3121775d06a3dd20d331041d444012e8d37 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:16:57 +0200 Subject: [PATCH 126/259] Update menu_boot.c --- source/menu_boot.c | 81 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/source/menu_boot.c b/source/menu_boot.c index 3829e0c..2e377b5 100644 --- a/source/menu_boot.c +++ b/source/menu_boot.c @@ -13,6 +13,7 @@ #include "utility.h" #include "menu.h" #include "config.h" +#include "anim.h" static bool timer = true; @@ -140,11 +141,50 @@ int menu_boot() { return 0; } +void drawThumbnail(gfxScreen_t screen, gfx3dSide_t side, thumbnail_s* thumbnail) +{ + if ( NULL == thumbnail->imgBuff ) + return; + if ( 0 == thumbnail->loaded ) + { + // Lazy image load + size_t size = fileSize(thumbnail->path); + if ( size == -1 || size == 0 ) { + thumbnail->loaded = -1; + return; + } + + size_t maxsize = thumbnail->sizeX * thumbnail->sizeY * (thumbnail->isRGBA?4:3); + if (size > maxsize) + size = maxsize; + + if (fileRead(thumbnail->path, thumbnail->imgBuff, size) != 0) { + thumbnail->loaded = -1; + return; + } + + thumbnail->loaded = 1; + } + if ( thumbnail->loaded <= 0 ) + return; + + drawImage(screen, side, thumbnail->imgBuff, thumbnail->isRGBA, thumbnail->sizeX, thumbnail->sizeY, thumbnail->posX, thumbnail->posY, anim->thumbFade); +} + static void draw(int boot_index, time_t elapsed) { int i = 0; drawBg(); + + if ( boot_index < config->count ) + { + boot_entry_s* selEntry = &config->entries[boot_index]; + drawThumbnail(GFX_TOP, GFX_LEFT, &selEntry->thumbTop); + if ( IS3DACTIVE ) + drawThumbnail(GFX_TOP, GFX_RIGHT, &selEntry->thumbTop3D); + drawThumbnail(GFX_BOTTOM, GFX_LEFT, &selEntry->thumbBot); + } if (!timer) { drawTitle("*** Select a boot entry ***"); @@ -152,31 +192,44 @@ static void draw(int boot_index, time_t elapsed) { drawTitle("*** Booting %s in %i ***", config->entries[boot_index].title, config->timeout - elapsed); } - for (i = 0; i < config->count; i++) { - drawItem(i == boot_index, 16 * i, config->entries[i].title); - if (i == boot_index) { + int entriesStart = ENTRIES_COUNT_INC * (boot_index / ENTRIES_COUNT_INC); + int entriesEnd = entriesStart + ENTRIES_COUNT_INC; + if ( entriesEnd > config->count ) + entriesEnd = config->count; + int displayedEntries = entriesEnd - entriesStart; + + for (i = 0; i < displayedEntries; i++) { + boot_entry_s* curEntry = &config->entries[entriesStart+i]; + bool selected = (entriesStart+i == boot_index); + drawItem(selected, 16 * i, curEntry->title); + if (selected) { #ifdef ARM9 - if ( config->entries[i].patchesCount > 0 ) + if ( curEntry->patchesCount > 0 ) { drawInfo("Name: %s\nPath: %s\nOffset: 0x%lx\nPatches count: %d\n\nPress (A) to launch\nPress (X) to remove entry\n", - config->entries[i].title, - config->entries[i].path, - config->entries[i].offset, - config->entries[i].patchesCount); + curEntry->title, + curEntry->path, + curEntry->offset, + curEntry->patchesCount); } else #endif { drawInfo("Name: %s\nPath: %s\nOffset: 0x%lx\n\n\nPress (A) to launch\nPress (X) to remove entry\n", - config->entries[i].title, - config->entries[i].path, - config->entries[i].offset); + curEntry->title, + curEntry->path, + curEntry->offset); } } } - drawItem(boot_index == config->count, 16 * i, "More..."); - if (boot_index == config->count) { - drawInfo("Show more options ..."); + + if ( i < ENTRIES_COUNT_INC ) + { + bool selected = (boot_index == config->count); + drawItem(selected, 16 * i, "More..."); + if (selected) { + drawInfo("Show more options ..."); + } } swapFrameBuffers(); From d13149ce9e9cee3386aa81f7a9fe5320fb918417 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:17:33 +0200 Subject: [PATCH 127/259] Update menu_config.c --- source/menu_config.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/source/menu_config.c b/source/menu_config.c index cfd87de..4f4892e 100644 --- a/source/menu_config.c +++ b/source/menu_config.c @@ -1,6 +1,7 @@ #ifdef ARM9 #include "arm9/source/common.h" #include "arm9/source/hid.h" +#include "screeninit.h" #else #include <3ds.h> #endif @@ -31,8 +32,13 @@ void keyLeft(int index) { config->recovery = 11; break; case 3: + #ifdef ARM9 + if (config->brightness < BRIGHTNESS_COUNT-1) + config->brightness++; + #else if (config->autobootfix > 0) config->autobootfix--; + #endif break; } } @@ -56,17 +62,20 @@ void keyRight(int index) { config->recovery = 0; break; case 3: + #ifdef ARM9 + if (config->brightness > 0) + config->brightness--; + #else config->autobootfix++; + #endif break; } } int menu_config() { -#ifdef ARM9 - int menu_count = 3, menu_index = 0; -#else + int menu_count = 4, menu_index = 0; -#endif + // key repeat timer time_t t_start = 0, t_end = 0, t_elapsed = 0; @@ -127,11 +136,12 @@ int menu_config() { drawItem(menu_index == 0, 0, "Timeout: %i", config->timeout); drawItem(menu_index == 1, 16, "Default: %s", config->entries[config->index].title); drawItem(menu_index == 2, 32, "Recovery key: %s", get_button(config->recovery)); -#ifndef ARM9 - drawItem(menu_index == 3, 48, "Bootfix: %i", config->autobootfix); - drawInfo("CtrBootManager v2.1.1"); +#ifdef ARM9 + drawItem(menu_index == 3, 48, "Screen initialization brightness: %i", BRIGHTNESS_COUNT-config->brightness); + drawInfo("CtrBootManager9 v2.2.0"); #else - drawInfo("CtrBootManager9 v2.1.1"); + drawItem(menu_index == 3, 48, "Bootfix: %i", config->autobootfix); + drawInfo("CtrBootManager v2.2.0"); #endif swapFrameBuffers(); From 294f3dc6e2929a2e355bdc17cfbb8a504a35e0af Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:18:02 +0200 Subject: [PATCH 128/259] Update menu_picker.c --- source/menu_picker.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/menu_picker.c b/source/menu_picker.c index d0a4d2f..dcb18c4 100644 --- a/source/menu_picker.c +++ b/source/menu_picker.c @@ -252,8 +252,8 @@ void pick_file(file_s *picked, const char *path) { if (strcasecmp(ext, "3dsx") == 0) { #endif if (confirm(3, "Add entry to boot menu: \"%s\" ?", picker->files[index].name)) { - if (config->count > CONFIG_MAX_ENTRIES - 1) { - debug("Maximum entries reached (%i)\n", CONFIG_MAX_ENTRIES); + if (config->count > config->maxCount - 1) { + debug("Maximum entries reached (%i)\n", config->maxCount); } else if (configAddEntry(picker->files[index].name, picker->files[index].path, noOffsetReq?0:0x12000) == 0) { debug("Added entry: %s\n", picker->files[index].name); } else { From a4ea5654171095612dd90e9c1c9080926d515e06 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:18:30 +0200 Subject: [PATCH 129/259] Update screeninit.c --- source/screeninit.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/source/screeninit.c b/source/screeninit.c index 0e8f293..5d71adb 100644 --- a/source/screeninit.c +++ b/source/screeninit.c @@ -44,25 +44,52 @@ void deinitScreens(void) } } -void initScreens(void) +const u32 brightness[BRIGHTNESS_COUNT] = {0x5F, 0x4C, 0x39, 0x26}; + +void initScreens(u8 brightnessLevel) { if(PDN_GPU_CNT == 1) { u32 *const screenInitAddress = (u32 *)0x24FFFC00; - memcpy(screenInitAddress, screeninit, screeninit_size); //Write brightness level for the stub to pick up - //screenInitAddress[2] = MULTICONFIG(0); - + screenInitAddress[2] = brightnessLevel%BRIGHTNESS_COUNT; + *arm11Entry = (u32)screenInitAddress; while(*arm11Entry); //Turn on backlight i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A); } - - //clearScreens(); } +/*void updateBrightness(u8 brightnessLevel) +{ + static int brightnessValue; + brightnessValue = brightness[brightnessLevel%BRIGHTNESS_COUNT]; + + void __attribute__((naked)) ARM11(void) + { + //Disable interrupts + __asm(".word 0xF10C01C0"); + + //Clear ARM11 entry offset + *arm11Entry = 0; + + //Change brightness + *(vu32 *)0x10202240 = brightnessValue; + *(vu32 *)0x10202A40 = brightnessValue; + + //Wait for the entry to be set + while(!*arm11Entry); + + //Jump to it + ((void (*)())*arm11Entry)(); + } + + *arm11Entry = (u32)ARM11; + while(*arm11Entry); +}*/ + #endif From 01ad83eec9cbe486df72bda992793253d3860827 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:18:53 +0200 Subject: [PATCH 130/259] Update screeninit.h --- source/screeninit.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/screeninit.h b/source/screeninit.h index 9808a58..590909e 100644 --- a/source/screeninit.h +++ b/source/screeninit.h @@ -11,9 +11,11 @@ #include "arm9/source/common.h" +#define BRIGHTNESS_COUNT 0x4 #define PDN_GPU_CNT (*(vu8 *)0x10141200) void deinitScreens(void); -void initScreens(void); +void initScreens(u8 brightnessLevel); +//void updateBrightness(u8 brightnessLevel); #endif From 850ce8b92398e857579ef3a4dbc790ebd2933af2 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:19:24 +0200 Subject: [PATCH 131/259] Update text.c --- source/text.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/text.c b/source/text.c index f61e6d6..2fe5642 100644 --- a/source/text.c +++ b/source/text.c @@ -52,8 +52,8 @@ int drawCharacter(u8 *fb, font_s *f, char c, s16 x, s16 y, u16 w, u16 h) { } else if ( a > 0 ) { - float alpha = (float)a / 255.f; - float one_minus_alpha = 1.f - alpha; + int alpha = a; + int one_minus_alpha = 255-alpha; for (i = 0; i < cd->w; i++) { charData += cyo; @@ -63,9 +63,9 @@ int drawCharacter(u8 *fb, font_s *f, char c, s16 x, s16 y, u16 w, u16 h) { u8 blend[3] = { (fb[0] * (0xFF - v) + (b * v)) >> 8, (fb[1] * (0xFF - v) + (g * v)) >> 8, (fb[2] * (0xFF - v) + (r * v)) >> 8 }; - fb[0] = (u8)(alpha*blend[0]+one_minus_alpha*(float)fb[0]); - fb[1] = (u8)(alpha*blend[1]+one_minus_alpha*(float)fb[1]); - fb[2] = (u8)(alpha*blend[2]+one_minus_alpha*(float)fb[2]); + fb[0] = (u8)((alpha*blend[0]+one_minus_alpha*fb[0])/255); + fb[1] = (u8)((alpha*blend[1]+one_minus_alpha*fb[1])/255); + fb[2] = (u8)((alpha*blend[2]+one_minus_alpha*fb[2])/255); } fb += 3; } From 5b292a96d2a929c82c07112fae4b478dd41b6971 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:19:53 +0200 Subject: [PATCH 132/259] Update utility.c --- source/utility.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/utility.c b/source/utility.c index 5f17456..0d3744b 100644 --- a/source/utility.c +++ b/source/utility.c @@ -26,6 +26,7 @@ void ioDelay(uint32_t val); #else + FS_Archive sdmcArchive; extern void __appExit(); @@ -37,6 +38,7 @@ void openSDArchive() { void closeSDArchive() { FSUSER_CloseArchive(&sdmcArchive); } + #endif void svcSleep(u32 millis) { @@ -362,4 +364,11 @@ bool aptMainLoop() { return true; } +void* memAlloc(unsigned int iSize) { + static u8* nextFreeMem = PTR_DYNAMIC_MEM_START; + void* retPtr = (void*)nextFreeMem; + nextFreeMem += iSize; + return retPtr; +} + #endif From e5d78114077d573c62886f312aba288c91bac9f5 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:20:12 +0200 Subject: [PATCH 133/259] Update utility.h --- source/utility.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/utility.h b/source/utility.h index 11a9079..f1a4753 100644 --- a/source/utility.h +++ b/source/utility.h @@ -9,7 +9,10 @@ extern "C" { bool aptMainLoop(); +void* memAlloc(unsigned int iSize); + #else + #include "descriptor.h" typedef struct menuEntry_s { @@ -21,6 +24,7 @@ typedef struct menuEntry_s { void openSDArchive(); void closeSDArchive(); + #endif bool fileExists(char *path); From fd0bc285384763dc11092a2ac84c874e6aa1d03f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 18 Aug 2016 23:21:30 +0200 Subject: [PATCH 134/259] Update changelog.txt --- changelog.txt | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/changelog.txt b/changelog.txt index 3f942f4..8f98ead 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,136 @@ +2.2.0 + +Add "brightness" property for screen-init (only used if CtrBootManager must initialize the screen) +The font used on bottom screen can have a different color ("font3" property in "[theme]" and "[animation]" categories. +Add support for transparent background images (the background color will be displayed on transparent zones) +- "bgImgTopAlpha", "bgImgTop3DAlpha" and "bgImgBotAlpha" keywords in "[theme]" category to set a background image as transparent +Add background images fade-in effect, activated by "bgImgTopFadeIn" and "bgImgBotFadeIn" properties in "[animation]" category +Add the possibility to have more than 11 boot entries (but "File browser" entry add feature cannot put more than the previous entries rounded up to a 12 multiplier) +Thumbnail support for each boot entry, new keywords in "[entry]" categories: +- "thumbTop", "thumbTop3D" and "thumbBot" for thumbnail path for each screen +- "thumbTopParams", "thumbTop3DParams" and "thumbBotParams" for thumbnail parameters, format "posX:posY:sizeX:sizeY:alpha" + +2.1.1 + +Some code refactoring to avoid confusion with "gfx" functions: fix 3DSX version crash on CFW start from MenuHax + +2.1.0 + +Fix loops count issue while reading the configuration file (always considered as infinite) +Fix uncompressed movie loops issue when the loop doesn't start from the begining and the stream type was file +3D movie/background image support for 3DSX version + +2.0.0 + +Fix some random issues with "compressed_memory" and "file" stream types with compressed movies +Documentation and Wiki: https://github.com/OperationNT414C/CtrBootManager/wiki/CtrBootManager-setup + +V10-3DSX + +Changes to support the 3DSX version with new animation and movie features +It seems 3DSX version has a bug with compressed movies when property "loopStreamType=compressed_memory" is active. + +V10 + +Remove "Anim" part from keywords in "[animation]" category (the category should be enough to avoid confusion) + +The "[movie]" category is removed, 2 new categories have been created to replace it: "[topMovie]" and "[bottomMovie]" +So keywords are renamed: +- "movieTop" and "movieBot" => "path" +- "movieTopCompress" and "movieBotCompress" => "compression" +- "movieTopLoop" and "movieBotLoop" => "loopCount" +- "movieTopLoopReverse" and "movieBotLoopReverse" => "loopReverse" +- "movieTopLoopStart" and "movieBotLoopStart" => "loopStartFrame" +- "movieTopTimeOnLoopStart" and "movieBotTimeOnLoopStart" => "delayOnLoopStart" +- "movieTopLoopEnd" and "movieBotLoopEnd" => "loopEndFrame" +- "movieTopTimeOnLoopEnd" and "movieBotTimeOnLoopEnd" => "delayOnLoopEnd" + +More explicit values has been added for some properties: +- For "compression" property: "QuickLZ" +- For "loopCount" property: "infinite" and "INFINITE" (set a negative value) +- For "loopReverse" property: "yes" and "YES" set a not null value, "no" and "NO" set a null value + +A new property "loopStreamType" has been added to manage how the loop is stored: +- "loopStreamType=file" (or "loopStreamType=0"): the movie file stays opened and loop will be permanently read from file +- "loopStreamType=memory" (or "loopStreamType=1"): the movie file is close and all frames required for loop are kept in memory +- "loopStreamType=compressed_memory" (or "loopStreamType=2"): only for compressed movies, the file content for loop is kept in memory and decompressed again on each loop +Now, the default loop stream mode is "file" to prevent any crash due memory usage. + +Add the CtrBootManager current version display in "Settings" menu + +V9 + +Movies support, new category "movie" and new keywords: +- "movieTop" and "movieBot": movie pathes +- "movieTopCompress" and "movieBotCompress": declare a movie as compressed (QuickLZ compression) +- "movieTopLoop" and "movieBotLoop": set the number of loops to do (negative means infinite) +- "movieTopLoopReverse" and "movieBotLoopReverse": if active, the loop will be played in reverse to ensure movie continuity +- "movieTopLoopStart" and "movieBotLoopStart": set up the first movie frame for loop +- "movieTopTimeOnLoopStart" and "movieBotTimeOnLoopStart": set up the "freeze time" on loop first frame +- "movieTopLoopEnd" and "movieBotLoopEnd": set up the last movie frame for loop (negative means the movie end frame) +- "movieTopTimeOnLoopEnd" and "movieBotTimeOnLoopEnd": set up the "freeze time" on loop last frame +WARNING: Loop is fully stored in memory as an uncompressed movie. So if one loop contains too much frames, you WILL crash. +To avoid this issue, please control carefully the loop number of frames particularly with compressed videos. +You can clamp your loop size with "movieXxxLoopStart" and "movieXxxLoopEnd" to avoid any issue. By default, the whole movie is put in loop. +For the top movie, the loop size will cost {(movieTopLoopEnd-movieTopLoopStart) * 288000} bytes. +For the bottom movie, the loop size will cost {(movieBotLoopEnd-movieBotLoopStart) * 230400} bytes. +Crashes occurs beyond 24MB, so do the maths! + +Add some space for CtrBootManager9 chainloading with binary patch: +<< patchMemSearch=2F61396C682E63666700; + patchMemOverwriteStr=/directory/other_a9lh.cfg; + patchOccurence=1; >> + +V8 +Rename "globalFadeIn" to "menuFadeIn" +Move all animations keywords under a new category "animation" +Add security checks to avoid configuration corruption if there are more than 11 entries or more than 4 patches for one entry +Add key left and right to speed up selection move in menus (particularly useful for File Browser) + +V7 +Add animation system for colors and fade in setup +New keywords added to support animations and fade in effect: +- "bgTop1Anim", "bgTop2Anim", "bgBottomAnim" (syntax example: "1:-1:FFFFFF") +- "highlightAnim", "bordersAnim", "font1Anim", "font2Anim" (syntax example: "1:-1:FFFFFF" or "1:-1:FFFFFF7F") +- "globalFadeIn" (syntax example: "1:-1" +Syntax for "*object*Anim" keyword is "objectAnim=X:Y:Z;" where: +- X as positive integer: the animation time in frame for one way (consider 2X for animation round-trip) +- Y as integer: the animation offset (if 2 animations has the same X value, this Y value will allow a shift between them) +- Z as a color in hexadecimal (3 bytes for color without transparency, mandatory for background; 4 bytes with transparency) +Syntax for fade in effect is "globalFadeIn=X:Y;" where: +- X as positive integer: the fade-in effect duration in frame +- Y as an integer: the time to wait before starting the fade-in effect (can be negative to start directly in the middle of the effect) + +V6 +Minor fix for background load +Default offset 0x12000 is also added if the binary is directly started for File Browser + +V5 +Update fatfs to fix File Browser illogical crashes (for example, if the background was not set to black) +Add a default offset at 0x12000 if a ".dat" file is added to entries through File Browser + +V4 +Displays the number of binary patches for current entry (if there is at least one patch) +Add the possibility to set transparency for borders and fonts +Fix a crash on start if no config file exists + +V3 +Add the possibility of binary patching, limited to 4 for each entry +New keywords for config file to support binary patching: +- "patchMemSearch" represents the searched pattern in hexadecimal values (730064006D0063003A002F00 => sdmc:/ with null value between each letter) +- "patchMemOverwrite" represents the values which will overwrite the found pattern (in hexadecimal values) +- "patchMemOverwriteStr" represents a string which will overwrite the pattern (it replaces "patchMemOverwrite" usage) +- "patchMemOverwriteWStr" represents a string with wide characters (null value between each character) which will overwrite the pattern (it replaces "patchMemOverwrite" usage) +- "patchOccurence" represents the occurence to modify: if the pattern can be found multiple times in the loaded binary file, only the indicated occurence will be overwritten (0 means all occurences will be overwritten) +A patch of an entry MUST always end with "patchOccurence" (it is like an entry which must always end with "key"). + +V2 +Add screen-init support + +V1 +Fix offset write issue and crash when a background was added +Add the possibility to set transparency for highlight + 1.0: add boot menu entry from the file manager (X) 1.0: remove boot menu entry from boot menu (X) 1.0: add a few more help/information to the bottom screen From f184426feb73b9fdb3359ec95ddaa17b2350a19e Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 19 Aug 2016 00:02:21 +0200 Subject: [PATCH 135/259] Update changelog.txt --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 8f98ead..2e7a31a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,7 +1,7 @@ 2.2.0 Add "brightness" property for screen-init (only used if CtrBootManager must initialize the screen) -The font used on bottom screen can have a different color ("font3" property in "[theme]" and "[animation]" categories. +The font used on bottom screen can have a different color ("font3" property in "[theme]" and "[animation]" categories). Add support for transparent background images (the background color will be displayed on transparent zones) - "bgImgTopAlpha", "bgImgTop3DAlpha" and "bgImgBotAlpha" keywords in "[theme]" category to set a background image as transparent Add background images fade-in effect, activated by "bgImgTopFadeIn" and "bgImgBotFadeIn" properties in "[animation]" category From 95620148ec5eb55e08755b5c8847ab0c79622369 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 19:53:56 +0200 Subject: [PATCH 136/259] Create menu_password.c --- source/menu_password.c | 117 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 source/menu_password.c diff --git a/source/menu_password.c b/source/menu_password.c new file mode 100644 index 0000000..453d8a6 --- /dev/null +++ b/source/menu_password.c @@ -0,0 +1,117 @@ +#include + +#ifdef ARM9 + +#include "arm9/source/common.h" +#include "arm9/source/hid.h" + +#else + +#include <3ds.h> +#include "menu_netloaderarm9.h" + +#endif + +#include "anim.h" +#include "config.h" +#include "draw.h" +#include "utility.h" +#include "loader.h" +#include "menu.h" + +static bool passSuccess = false; +static int attempt = 0; +static int keyIndex = 0; + +static void draw(); + +static u32 kDownPrev = 0; +static u32 kDown = 0; + +int menu_password() { + + if ( passSuccess ) + return 0; + + if ( config->passSize <= 0 ) + { + passSuccess = true; + return 0; + } + + static const u32 checkedKeys = 0x0FFF; + + hidScanInput(); + kDownPrev = (hidKeysDown() & checkedKeys); + int validCount = 0; + + while (aptMainLoop()) { + + hidScanInput(); + kDown = (hidKeysDown() & checkedKeys); + + if ( 0 == kDownPrev && 0 != kDown ) + { + if ( kDown & BIT(config->password[keyIndex]) ) + validCount++; + keyIndex++; + + if ( keyIndex >= config->passSize ) + { + if ( validCount >= config->passSize ) + { + passSuccess = true; + break; + } + + keyIndex = 0; + validCount = 0; + attempt++; + + if ( config->passMaxAttempt > 0 && attempt >= config->passMaxAttempt ) + { + // Fail! + char* splashTop = splashScreen(config->failSplashTop, config->splashTopDef); + char* splashBot = splashScreen(config->failSplashBot, config->splashBotDef); + load(config->failPath, config->failOffset, NULL, 0, splashTop, splashBot); + while (aptMainLoop()) // Loop of death + screensBehavior(splashTop, splashBot); + return -1; + } + } + } + kDownPrev = kDown; + + draw(); + } + return 1; +} + +static void draw() { + + drawBg(); + drawTitle("*** Password required ***", kDownPrev, kDown); + + char passStars[PASSWORD_MAX_SIZE+1]; + int i = 0; + for ( ; i < keyIndex ; i++ ) + passStars[i] = 'X'; + for ( ; i < config->passSize ; i++ ) + passStars[i] = '_'; + passStars[i] = '\0'; + + char* invalidMsg = ( 0 == keyIndex && attempt > 0 ) ? "\nInvalid password, try again!\n" : ""; + char msg[256]; + if ( config->passMaxAttempt > 0 ) + sprintf(msg, "Password: %s\n\nAttempt %d on %d\n%s", passStars, attempt+1, config->passMaxAttempt, invalidMsg); + else + sprintf(msg, "Password: %s\n%s", passStars, invalidMsg); + + drawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 96, MENU_MIN_Y + 48, msg); + if ( IS3DACTIVE ) + drawTextf(GFX_TOP, GFX_RIGHT, &fontDefault, MENU_MIN_X + 96, MENU_MIN_Y + 48, msg); + + drawInfo("Please enter the password for menu access...\n"); + + swapFrameBuffers(); +} From 42862efda383939bffae5ebe5326eca8cb7136d9 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 19:54:27 +0200 Subject: [PATCH 137/259] Update config.c --- source/config.c | 93 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 87 insertions(+), 6 deletions(-) diff --git a/source/config.c b/source/config.c index f368216..d12ae59 100644 --- a/source/config.c +++ b/source/config.c @@ -7,6 +7,7 @@ #include "ini.h" #include "config.h" #include "font.h" + #ifdef ARM9 #include "arm9/source/fatfs/ff.h" #include "utility.h" @@ -277,6 +278,9 @@ void entryInit(boot_entry_s* entry) entry->key = -1; entry->offset = 0; entry->patchesCount = 0; + + entry->splashTop[0] = '\0'; + entry->splashBot[0] = '\0'; thumbnailInit(&entry->thumbTop, 400, 240); thumbnailInit(&entry->thumbTop3D, 400, 240); @@ -339,6 +343,10 @@ static int handler(void *user, const char *section, const char *name, config->recovery = atoi(item); } else if (NAME_MATCH("default")) { config->index = atoi(item); + } else if (NAME_MATCH("splashTop")) { + strncpy(config->splashTopDef, item, 128); + } else if (NAME_MATCH("splashBot")) { + strncpy(config->splashBotDef, item, 128); } #ifdef ARM9 else if (NAME_MATCH("brightness")) { @@ -351,6 +359,24 @@ static int handler(void *user, const char *section, const char *name, #endif } + // password + if (SECTION_MATCH("password")) + { + if (NAME_MATCH("keys")) { + config->passSize = readIntValuesList(config->password, PASSWORD_MAX_SIZE, item); + } else if (NAME_MATCH("attempts")) { + config->passMaxAttempt = atoi(item); + } else if (NAME_MATCH("failPath")) { + strncpy(config->failPath, item, 128); + } else if (NAME_MATCH("failOffset")) { + config->failOffset = strtoul(item, NULL, 16); + } else if (NAME_MATCH("failImgTop")) { + strncpy(config->failSplashTop, item, 128); + } else if (NAME_MATCH("failImgBot")) { + strncpy(config->failSplashBot, item, 128); + } + } + // theme else if (SECTION_MATCH("theme")) { @@ -442,6 +468,10 @@ static int handler(void *user, const char *section, const char *name, strncpy(entry->path, item, 128); } else if (NAME_MATCH("offset")) { entry->offset = strtoul(item, NULL, 16); + } else if (NAME_MATCH("splashTop")) { + strncpy(entry->splashTop, item, 128); + } else if (NAME_MATCH("splashBot")) { + strncpy(entry->splashBot, item, 128); } else if (NAME_MATCH("thumbTop")) { strncpy(entry->thumbTop.path, item, 128); } else if (NAME_MATCH("thumbTopParams")) { @@ -583,7 +613,18 @@ int configInit() { config->brightness = 0; config->index = 0; config->recovery = 2; - + + config->splashTopDef[0] = '\0'; + config->splashBotDef[0] = '\0'; + + config->password[0] = -1; + config->passSize = 0; + config->passMaxAttempt = 0; + config->failPath[0] = '\0'; + config->failOffset = 0; + config->failSplashTop[0] = '\0'; + config->failSplashBot[0] = '\0'; + #ifdef ARM9 config->entries = memAlloc(DEFAULT_ENTRIES_COUNT*sizeof(boot_entry_s)); #else @@ -618,8 +659,12 @@ int configInit() { } } - // Fix for fade in effect first frame - fontDefault.color[3] = 0x00; + int i = 0; + while ( i < config->passSize && config->password[i] >= 0 && config->password[i] <= MAX_KEY ) + i++; + if ( i < PASSWORD_MAX_SIZE ) + config->password[i] = -1; + config->passSize = i; loadBg(GFX_TOP, GFX_LEFT); #ifndef ARM9 @@ -652,6 +697,12 @@ int configAddEntry(char *title, char *path, long offset) { strncpy(entry->title, title, 64); strncpy(entry->path, path, 128); entry->offset = offset; + entry->patchesCount = 0; + entry->splashTop[0] = '\0'; + entry->splashBot[0] = '\0'; + thumbnailInit(&entry->thumbTop, 400, 240); + thumbnailInit(&entry->thumbTop3D, 400, 240); + thumbnailInit(&entry->thumbBot, 320, 240); config->count++; configSave(); @@ -710,10 +761,35 @@ void configSave() { #endif size += snprintf(cfg+size, 256, "timeout=%i;\n", config->timeout); size += snprintf(cfg+size, 256, "recovery=%i;\n", config->recovery); - size += snprintf(cfg+size, 256, "default=%i;\n\n", config->index); + size += snprintf(cfg+size, 256, "default=%i;\n", config->index); + if (config->splashTopDef[0] != '\0') + size += snprintf(cfg+size, 256, "splashTop=%s;\n", config->splashTopDef); + if (config->splashBotDef[0] != '\0') + size += snprintf(cfg+size, 256, "splashBot=%s;\n", config->splashBotDef); + + // password section + if ( config->passSize > 0 ) + { + size += snprintf(cfg+size, 256, "\n[password]\n"); + size += snprintf(cfg+size, 256, "keys="); + for ( int i = 0 ; i < config->passSize-1 ; i++ ) + size += snprintf(cfg+size, 256, "%i:", config->password[i]); + size += snprintf(cfg+size, 256, "%i;\n", config->password[config->passSize-1]); + if ( config->passMaxAttempt > 0 ) + size += snprintf(cfg+size, 256, "attempts=%d;\n", config->passMaxAttempt); + if ( config->failPath[0] != '\0' ) + { + size += snprintf(cfg+size, 256, "failPath=%s;\n", config->failPath); + size += snprintf(cfg+size, 256, "failOffset=%x;\n", (int)config->failOffset); + } + if (config->failSplashTop[0] != '\0') + size += snprintf(cfg+size, 256, "failImgTop=%s;\n", config->failSplashTop); + if (config->failSplashBot[0] != '\0') + size += snprintf(cfg+size, 256, "failImgBot=%s;\n", config->failSplashBot); + } // theme section - size += snprintf(cfg+size, 256, "[theme]\n"); + size += snprintf(cfg+size, 256, "\n[theme]\n"); size += snprintf(cfg+size, 256, "bgTop1=%02X%02X%02X;\n", config->bgTop1[0], config->bgTop1[1], config->bgTop1[2]); size += snprintf(cfg+size, 256, "bgTop2=%02X%02X%02X;\n", config->bgTop2[0], config->bgTop2[1], config->bgTop2[2]); size += snprintf(cfg+size, 256, "bgBottom=%02X%02X%02X;\n", config->bgBot[0], config->bgBot[1], config->bgBot[2]); @@ -871,7 +947,7 @@ void configSave() { size += snprintf(cfg+size, 256, "path=%s;\n", entry->path); size += snprintf(cfg+size, 256, "offset=%x;\n", (int)entry->offset); - int patchesCount = config->entries[i].patchesCount; + int patchesCount = entry->patchesCount; #ifdef ARM9 for (int j = 0; j < patchesCount; j++) { @@ -886,6 +962,11 @@ void configSave() { } #endif + if (entry->splashTop[0] != '\0') + size += snprintf(cfg+size, 256, "splashTop=%s;\n", entry->splashTop); + if (entry->splashBot[0] != '\0') + size += snprintf(cfg+size, 256, "splashBot=%s;\n", entry->splashBot); + if ( entry->thumbTop.path[0] != '\0' ) { thumbnail_s* thumb = &entry->thumbTop; From 896d0cda6c548420f61a7c42cb1f7d9fbf4f88b7 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 19:54:43 +0200 Subject: [PATCH 138/259] Update config.h --- source/config.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/source/config.h b/source/config.h index 57a07eb..f69cacf 100644 --- a/source/config.h +++ b/source/config.h @@ -22,6 +22,10 @@ extern "C" { #include "loader.h" // Binary patches define #define BIT(n) (1U<<(n)) + +#define PASSWORD_MAX_SIZE 16 +#define MAX_KEY 11 + #define DEFAULT_ENTRIES_COUNT 11 #define ENTRIES_COUNT_INC 12 #define PATCHES_MAX_PER_ENTRY 4 @@ -49,6 +53,9 @@ typedef struct { binary_patch patches[PATCHES_MAX_PER_ENTRY]; int patchesCount; + char splashTop[128]; + char splashBot[128]; + thumbnail_s thumbTop; thumbnail_s thumbTop3D; thumbnail_s thumbBot; @@ -72,10 +79,22 @@ typedef struct { int brightness; int index; int recovery; + + int password[PASSWORD_MAX_SIZE]; + int passSize; + int passMaxAttempt; + char failPath[128]; + long failOffset; + char failSplashTop[128]; + char failSplashBot[128]; + int count; int maxCount; boot_entry_s* entries; + char splashTopDef[128]; + char splashBotDef[128]; + u8 bgTop1[3]; u8 bgTop2[3]; u8 bgBot[3]; From 5fe4adf66670a8e264b59fb4823a73be5d8c841a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 19:55:08 +0200 Subject: [PATCH 139/259] Update draw.c --- source/draw.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/source/draw.c b/source/draw.c index b76008b..1e5b46e 100644 --- a/source/draw.c +++ b/source/draw.c @@ -277,22 +277,6 @@ void clearBot(u8 bot[8]) { fillColor(GFX_BOTTOM, GFX_LEFT, bot); } -void clearFrameBuffers() { -#ifdef ARM9 - memset(PTR_TOP_SCREEN, 0, TOP_SCREEN_SIZE); - memset(PTR_BOT_SCREEN, 0, BOT_SCREEN_SIZE); - memset(PTR_TOP_SCREEN_BUF, 0, TOP_SCREEN_SIZE); - memset(PTR_BOT_SCREEN_BUF, 0, BOT_SCREEN_SIZE); - memset(PTR_TOP_BG, 0, TOP_SCREEN_SIZE); - memset(PTR_BOT_BG, 0, BOT_SCREEN_SIZE); -#else - fillColor(GFX_TOP, GFX_LEFT, (u8[3]) {0x00, 0x00, 0x00}); - if( IS3DACTIVE ) - fillColor(GFX_TOP, GFX_RIGHT, (u8[3]) {0x00, 0x00, 0x00}); - fillColor(GFX_BOTTOM, GFX_LEFT, (u8[3]) {0x00, 0x00, 0x00}); -#endif -} - void swapFrameBuffers() { #ifdef ARM9 memcpy(PTR_TOP_SCREEN, PTR_TOP_SCREEN_BUF, TOP_SCREEN_SIZE); From 16f670a2e11187a6e27dd6515b652b39f8b9dddc Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 19:55:27 +0200 Subject: [PATCH 140/259] Update draw.h --- source/draw.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/source/draw.h b/source/draw.h index 4a85414..39178c5 100644 --- a/source/draw.h +++ b/source/draw.h @@ -18,8 +18,6 @@ typedef enum u8 *gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16 *width, u16 *height); -#define TOP_SCREEN_SIZE (400*240*3) -#define BOT_SCREEN_SIZE (320*240*3) #define IS3DACTIVE false #else @@ -29,6 +27,9 @@ u8 *gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16 *width, u16 *hei #endif +#define TOP_SCREEN_SIZE (400*240*3) +#define BOT_SCREEN_SIZE (320*240*3) + #include "font.h" //rendering stuff @@ -54,6 +55,4 @@ void clearTop(u8 top1[3], u8 top2[3]); void clearBot(u8 bot[8]); -void clearFrameBuffers(); - void swapFrameBuffers(); From d2d16a7752a3d90ac9c535d6fe9ed1c1f77abccb Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 19:55:55 +0200 Subject: [PATCH 141/259] Update loader.c --- source/loader.c | 50 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/source/loader.c b/source/loader.c index 94459a6..8faec3e 100644 --- a/source/loader.c +++ b/source/loader.c @@ -10,6 +10,7 @@ #include "arm9/source/fatfs/ff.h" #include "stage2_bin.h" #include "memory.h" +#include "screeninit.h" #endif @@ -17,6 +18,29 @@ #include "loader.h" #include "utility.h" +void screenBehavior(gfxScreen_t screen, int screenSize, char* splash) +{ + if ( NULL == splash || splash[0] == '\0' ) + return; + + u8* fb = gfxGetFramebuffer(screen, GFX_LEFT, NULL, NULL); + if ( splash[0] == '/' ) + fileRead(splash, fb, screenSize); + else if ( strcasecmp(splash, "clear") == 0 ) + memset(fb, 0, screenSize); +} + +void screensBehavior(char* splashTop, char* splashBot) +{ +#ifndef ARM9 + gfxSet3D(false); +#endif + + screenBehavior(GFX_TOP, TOP_SCREEN_SIZE, splashTop); + screenBehavior(GFX_BOTTOM, BOT_SCREEN_SIZE, splashBot); + swapFrameBuffers(); +} + #ifdef ARM9 unsigned char *memsearch(unsigned char *startPos, const void *pattern, int size, int patternSize) // From Luma3DS' pathchanger.c @@ -45,7 +69,7 @@ unsigned char *memsearch(unsigned char *startPos, const void *pattern, int size, return NULL; } -int load_bin(char *path, long offset, binary_patch* patches, int patchesCount) { +int load_bin(char *path, long offset, binary_patch* patches, int patchesCount, char* splashTop, char* splashBot) { // Load binary size_t size = fileSize(path); @@ -78,9 +102,8 @@ int load_bin(char *path, long offset, binary_patch* patches, int patchesCount) { binFound += patches[i].memToSearchSize; } } - - // Start binary - clearFrameBuffers(); + + screensBehavior(splashTop, splashBot); memcpy((void *) PTR_PAYLOAD_STAGE2, stage2_bin, stage2_bin_size); ((void (*)()) PTR_PAYLOAD_STAGE2)(); @@ -92,15 +115,18 @@ int load_bin(char *path, long offset, binary_patch* patches, int patchesCount) { char boot_app[512]; bool boot_app_enabled; -int load_3dsx(char *path) { +int load_3dsx(char *path, char* splashTop, char* splashBot) { + + screensBehavior(splashTop, splashBot); memset(boot_app, 0, 512); strncpy(boot_app, path, 512); boot_app_enabled = true; return 0; } -int load_bin(char *path, long offset, binary_patch* patches, int patchesCount) { +int load_bin(char *path, long offset, binary_patch* patches, int patchesCount, char* splashTop, char* splashBot) { + screensBehavior(splashTop, splashBot); gfxExit(); if (brahma_init()) { @@ -121,7 +147,7 @@ int load_bin(char *path, long offset, binary_patch* patches, int patchesCount) { #endif -int load(char *path, long offset, binary_patch* patches, int patchesCount) { +int load(char *path, long offset, binary_patch* patches, int patchesCount, char* splashTop, char* splashBot) { // check for reboot/poweroff if (strcasecmp(path, "reboot") == 0) { reboot(); @@ -131,14 +157,14 @@ int load(char *path, long offset, binary_patch* patches, int patchesCount) { } else if (strcasecmp(path, "homemenu") == 0) { return load_homemenu(); #endif - } else { + } else if (NULL != path && path[0] != '\0') { + const char *ext = get_filename_ext(path); - if (strcasecmp(ext, "bin") == 0 - || strcasecmp(ext, "dat") == 0) { - return load_bin(path, offset, patches, patchesCount); + if (strcasecmp(ext, "bin") == 0 || strcasecmp(ext, "dat") == 0) { + return load_bin(path, offset, patches, patchesCount, splashTop, splashBot); #ifndef ARM9 } else if (strcasecmp(ext, "3dsx") == 0) { - return load_3dsx(path); + return load_3dsx(path, splashTop, splashBot); #endif } else { debug("Invalid file: %s\n", path); From 576ffa5a8b90fc964504d1e1f1e1d9bd117ba69a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 19:56:12 +0200 Subject: [PATCH 142/259] Update loader.h --- source/loader.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/loader.h b/source/loader.h index 7c3277d..36d690f 100644 --- a/source/loader.h +++ b/source/loader.h @@ -9,10 +9,12 @@ typedef struct { int occurence; } binary_patch; -int load(char *path, long offset, binary_patch* patches, int patchesCount); +int load(char *path, long offset, binary_patch* patches, int patchesCount, char* splashTop, char* splashBot); + +void screensBehavior(char* splashTop, char* splashBot); #ifndef ARM9 -int load_3dsx(char *path); +int load_3dsx(char *path, char* splashTop, char* splashBot); #endif #endif // _loader_h_ From 0ef1c666044b7e90fdff4e83f7cc7c6ff490d18c Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 19:56:41 +0200 Subject: [PATCH 143/259] Update menu.c --- source/menu.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/menu.c b/source/menu.c index 16497a6..c565ee9 100644 --- a/source/menu.c +++ b/source/menu.c @@ -63,6 +63,7 @@ void drawTitle(const char *format, ...) { vsnprintf(msg, 512, format, argp); va_end(argp); + memcpy(fontDefault.color, anim->fntDef, sizeof(u8[4])); drawText(GFX_TOP, GFX_LEFT, &fontDefault, msg, 140, 25); if( IS3DACTIVE ) drawText(GFX_TOP, GFX_RIGHT, &fontDefault, msg, 140, 25); @@ -125,3 +126,12 @@ void drawInfo(const char *format, ...) { memcpy(fontDefault.color, anim->fntDef, sizeof(u8[4])); } + +char* splashScreen(char* splash, char* defSplash) +{ + if ( NULL != splash && splash[0] != '\0') + return splash; + if ( NULL != defSplash && defSplash[0] != '\0') + return defSplash; + return NULL; +} From a1928a72bed8f1e585a7812efb5f4c91299cc904 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 19:57:02 +0200 Subject: [PATCH 144/259] Update menu.h --- source/menu.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/menu.h b/source/menu.h index e0e73a3..0aaa3ab 100644 --- a/source/menu.h +++ b/source/menu.h @@ -16,12 +16,16 @@ void drawItemN(bool selected, int maxChar, int y, const char *format, ...); void drawInfo(const char *format, ...); +char* splashScreen(char* splash, char* defSplash); + int menu_more(); int menu_boot(); +int menu_password(); + int menu_config(); int menu_netloader(); -#endif \ No newline at end of file +#endif From a7f047ceb36271420306cea975a5985593b2518e Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 19:57:37 +0200 Subject: [PATCH 145/259] Update menu_boot.c --- source/menu_boot.c | 94 ++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/source/menu_boot.c b/source/menu_boot.c index 2e377b5..bb7db7c 100644 --- a/source/menu_boot.c +++ b/source/menu_boot.c @@ -36,22 +36,17 @@ int key_override(int index) { int boot(int index) { -#ifdef ARM9 - return load(config->entries[index].path, - config->entries[index].offset, - config->entries[index].patches, - config->entries[index].patchesCount); -#else +#ifndef ARM9 int delay = config->autobootfix; while (aptMainLoop() && delay > 0) { swapFrameBuffers(); delay--; } - return load(config->entries[index].path, - config->entries[index].offset, - config->entries[index].patches, - config->entries[index].patchesCount); #endif + boot_entry_s* entry = &config->entries[index]; + return load(entry->path, entry->offset, entry->patches, entry->patchesCount, + splashScreen(entry->splashTop, config->splashTopDef), + splashScreen(entry->splashBot, config->splashBotDef)); } int menu_boot() { @@ -76,8 +71,17 @@ int menu_boot() { time(&start); #endif + static const u32 checkedKeys = 0x0FFF; + + // Trash first key + hidScanInput(); + hidKeysDown(); + while (aptMainLoop()) { + hidScanInput(); + u32 kDown = hidKeysDown(); + if (timer) { #ifdef ARM9 now++; @@ -90,47 +94,47 @@ int menu_boot() { int index = key_override(boot_index); return boot(index); } + + if (kDown & checkedKeys) + timer = false; } - hidScanInput(); - u32 kDown = hidKeysDown(); + if (!timer) + { + if ( menu_password() ) + kDown = 0; - if (kDown & KEY_DOWN) { - timer = false; - boot_index++; - if (boot_index > config->count) - boot_index = 0; - } - else if (kDown & KEY_UP) { - timer = false; - boot_index--; - if (boot_index < 0) - boot_index = config->count; - } - if (kDown & KEY_RIGHT) { - timer = false; - boot_index = (boot_index == config->count) ? 0 : config->count; - } - else if (kDown & KEY_LEFT) { - timer = false; - boot_index = (boot_index == 0) ? config->count : 0; - } - else if (kDown & KEY_A) { - timer = false; - if (boot_index == config->count) { - if(menu_more() == 0) { + if (kDown & KEY_DOWN) { + boot_index++; + if (boot_index > config->count) + boot_index = 0; + } + else if (kDown & KEY_UP) { + boot_index--; + if (boot_index < 0) + boot_index = config->count; + } + if (kDown & KEY_RIGHT) { + boot_index = (boot_index == config->count) ? 0 : config->count; + } + else if (kDown & KEY_LEFT) { + boot_index = (boot_index == 0) ? config->count : 0; + } + else if (kDown & KEY_A) { + if (boot_index == config->count) { + if(menu_more() == 0) { + break; + } + } else if (boot(boot_index) == 0) { break; } - } else if (boot(boot_index) == 0) { - break; } - } - else if (kDown & KEY_X) { - timer = false; - if (boot_index != config->count) { - if (confirm(3, "Delete boot entry: \"%s\" ?\n", config->entries[boot_index].title)) { - configRemoveEntry(boot_index); - boot_index = config->index; + else if (kDown & KEY_X) { + if (boot_index != config->count) { + if (confirm(3, "Delete boot entry: \"%s\" ?\n", config->entries[boot_index].title)) { + configRemoveEntry(boot_index); + boot_index = config->index; + } } } } From cb065197ec34db2a55d95cbdd93d57bd7d7021f1 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 19:57:59 +0200 Subject: [PATCH 146/259] Update menu_config.c --- source/menu_config.c | 209 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 202 insertions(+), 7 deletions(-) diff --git a/source/menu_config.c b/source/menu_config.c index 4f4892e..ff93bd5 100644 --- a/source/menu_config.c +++ b/source/menu_config.c @@ -1,3 +1,7 @@ +#include +#include +#include + #ifdef ARM9 #include "arm9/source/common.h" #include "arm9/source/hid.h" @@ -5,13 +9,16 @@ #else #include <3ds.h> #endif -#include #include "config.h" #include "draw.h" #include "menu.h" #include "utility.h" + +static int pass_size = 0; +static int pass_fail = -1; + void keyLeft(int index) { switch (index) { @@ -29,7 +36,7 @@ void keyLeft(int index) { if (config->recovery > 0) config->recovery--; else - config->recovery = 11; + config->recovery = MAX_KEY; break; case 3: #ifdef ARM9 @@ -40,6 +47,18 @@ void keyLeft(int index) { config->autobootfix--; #endif break; + case 4: + if ( config->passMaxAttempt > 0 ) + config->passMaxAttempt--; + break; + case 5: + if (pass_fail > -1) + pass_fail--; + break; + case 6: + if (pass_size > 0) + pass_size--; + break; } } @@ -56,7 +75,7 @@ void keyRight(int index) { config->index = 0; break; case 2: - if (config->recovery < 11) + if (config->recovery < MAX_KEY) config->recovery++; else config->recovery = 0; @@ -69,12 +88,104 @@ void keyRight(int index) { config->autobootfix++; #endif break; + case 4: + config->passMaxAttempt++; + break; + case 5: + #ifdef ARM9 + if (pass_fail < config->count+1) + #else + if (pass_fail < config->count+2) + #endif + pass_fail++; + break; + case 6: + if (pass_size < PASSWORD_MAX_SIZE) + pass_size++; + break; + } +} + +void keyIn(int index) { + + if ( index != 7 ) + return; // Currently, only password is managed + + static const u32 checkedKeys = 0x0FFF; + config->passSize = pass_size; + + hidScanInput(); + u32 kDownPrev = (hidKeysDown() & checkedKeys); + int curKey = 0; + + while (aptMainLoop() && curKey < pass_size) + { + hidScanInput(); + u32 kDown = (hidKeysDown() & checkedKeys); + + if ( 0 == kDownPrev && 0 != kDown ) + { + kDownPrev = kDown; + int value = 0; + while ( (kDown >> (value+1)) != 0 ) + value++; + + config->password[curKey] = value; + curKey++; + } + kDownPrev = kDown; + + drawBg(); + drawTitle("*** Password setup ***"); + + char msg[256]; + int size = 0; + size += snprintf(msg, 256, "Enter the new password (%i keys):\n", pass_size); + for ( int i = 0 ; i < curKey ; i++ ) + { + size += snprintf(msg+size, 256, get_button(config->password[i])); + if ( i < curKey-1 ) + size += snprintf(msg+size, 256, (i%4 == 3) ? "\n" : ", "); + } + msg[size] = '\0'; + + drawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 64, MENU_MIN_Y + 64, msg); + if ( IS3DACTIVE ) + drawTextf(GFX_TOP, GFX_RIGHT, &fontDefault, MENU_MIN_X + 64, MENU_MIN_Y + 64, msg); + + swapFrameBuffers(); } } int menu_config() { - int menu_count = 4, menu_index = 0; + pass_size = config->passSize; + pass_fail = -1; + + if ( strcasecmp(config->failPath, "reboot") == 0 ) + pass_fail = config->count; + else if (strcasecmp(config->failPath, "shutdown") == 0) + pass_fail = config->count+1; +#ifndef ARM9 + else if (strcasecmp(config->failPath, "homemenu") == 0) + pass_fail = config->count+2; +#endif + else + { + for ( int i = 0 ; i < config->count ; i++ ) + { + boot_entry_s* entry = &config->entries[i]; + if ( 0 == entry->patchesCount && strcasecmp(config->failPath, entry->path) == 0 + && config->failOffset == entry->offset ) + { + pass_fail = i; + break; + } + } + } + + bool pass_fail_found = ( pass_fail >= 0 ); + int menu_count = 8, menu_index = 0; // key repeat timer time_t t_start = 0, t_end = 0, t_elapsed = 0; @@ -124,8 +235,32 @@ int menu_config() { svcSleep(100); } } + + if (kDown & KEY_A) { + keyIn(menu_index); + } if (kDown & KEY_B) { + + // Apply password failed behavior + int size = 0; + if ( pass_fail == config->count ) + size = snprintf(config->failPath, 256, "reboot"); + else if ( pass_fail == config->count+1 ) + size = snprintf(config->failPath, 256, "shutdown"); + #ifndef ARM9 + else if ( pass_fail == config->count+2 ) + size = snprintf(config->failPath, 256, "homemenu"); + #endif + else if ( pass_fail >= 0 ) + { + boot_entry_s* entry = &config->entries[pass_fail]; + size = snprintf(config->failPath, 256, entry->path); + config->failOffset = entry->offset; + } + if ( pass_fail >= 0 || pass_fail_found ) + config->failPath[size] = '\0'; + configSave(); return 0; } @@ -133,15 +268,75 @@ int menu_config() { drawBg(); drawTitle("*** Boot configuration ***"); - drawItem(menu_index == 0, 0, "Timeout: %i", config->timeout); + if ( config->timeout >= 0 ) + drawItem(menu_index == 0, 0, "Timeout: %i", config->timeout); + else + drawItem(menu_index == 0, 0, "Timeout: Disabled"); + drawItem(menu_index == 1, 16, "Default: %s", config->entries[config->index].title); drawItem(menu_index == 2, 32, "Recovery key: %s", get_button(config->recovery)); + + if ( config->passMaxAttempt > 0 ) + drawItem(menu_index == 4, 80, "Password allowed attempts: %i", config->passMaxAttempt); + else + drawItem(menu_index == 4, 80, "Password allowed attempts: Infinite"); + + char msg[256]; + int size = 0; + if ( pass_fail < 0 ) + { + if (config->failPath[0] == '\0' || pass_fail_found) + { + if (config->failSplashTop[0] != '\0' || config->failSplashBot[0] != '\0') + size = snprintf(msg, 256, "Freeze on failure images"); + else if (config->splashTopDef[0] != '\0' || config->splashBotDef[0] != '\0') + size = snprintf(msg, 256, "Freeze on default splash screen"); + else + size = snprintf(msg, 256, "Freeze on last rendered image"); + } + else + size = snprintf(msg, 256, "Load \"%s\"", config->failPath); + } + else if ( pass_fail == config->count ) + size = snprintf(msg, 256, "Reboot"); + else if ( pass_fail == config->count+1 ) + size = snprintf(msg, 256, "Power off"); +#ifndef ARM9 + else if ( pass_fail == config->count+2 ) + size = snprintf(msg, 256, "Return to home menu"); +#endif + else + size = snprintf(msg, 256, "Load %s", config->entries[pass_fail].title); + msg[size] = '\0'; + + drawItem(menu_index == 5, 96, "Password fail behavior: %s", msg); + drawItem(menu_index == 6, 112, "Password size: %i", pass_size); + drawItem(menu_index == 7, 128, "Password:"); + + size = 0; + if ( config->passSize > 0 ) + { + for ( int i = 0 ; i < config->passSize ; i++ ) + { + size += snprintf(msg+size, 256, get_button(config->password[i])); + if ( i < config->passSize-1 ) + size += snprintf(msg+size, 256, (i%4 == 3) ? "\n" : ", "); + } + } + else + size = snprintf(msg, 256, "None"); + msg[size] = '\0'; + + drawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 64, MENU_MIN_Y + 128, msg); + if ( IS3DACTIVE ) + drawTextf(GFX_TOP, GFX_RIGHT, &fontDefault, MENU_MIN_X + 64, MENU_MIN_Y + 128, msg); + #ifdef ARM9 drawItem(menu_index == 3, 48, "Screen initialization brightness: %i", BRIGHTNESS_COUNT-config->brightness); - drawInfo("CtrBootManager9 v2.2.0"); + drawInfo("CtrBootManager9 v2.3.0"); #else drawItem(menu_index == 3, 48, "Bootfix: %i", config->autobootfix); - drawInfo("CtrBootManager v2.2.0"); + drawInfo("CtrBootManager v2.3.0"); #endif swapFrameBuffers(); From c5928b2b31121e46c8abd26596e9d8a8a4001c24 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 19:58:20 +0200 Subject: [PATCH 147/259] Update menu_more.c --- source/menu_more.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/menu_more.c b/source/menu_more.c index d4133e5..ee9184a 100644 --- a/source/menu_more.c +++ b/source/menu_more.c @@ -11,6 +11,7 @@ #endif +#include "config.h" #include "draw.h" #include "utility.h" #include "loader.h" @@ -38,7 +39,7 @@ int menu_choose() { int pathLength = 0; if ((pathLength = strlen(picked.path)) > 0) { int offset = ( pathLength > 3 && strcasecmp(&picked.path[pathLength-3], "dat") == 0 ) ? 0x12000 : 0; - return load(picked.path, offset, NULL, 0); + return load(picked.path, offset, NULL, 0, config->splashTopDef, config->splashBotDef); } return -1; @@ -46,6 +47,7 @@ int menu_choose() { int menu_more() { + menu_password(); menu_index = 0; while (aptMainLoop()) { From 3fa5ccfd73292d87e62a6a580005ac2bc641401f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 19:58:44 +0200 Subject: [PATCH 148/259] Update menu_netloader.c --- source/menu_netloader.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/menu_netloader.c b/source/menu_netloader.c index e9811c9..43a1b2b 100644 --- a/source/menu_netloader.c +++ b/source/menu_netloader.c @@ -1,5 +1,6 @@ #include <3ds.h> #include +#include "config.h" #include "draw.h" #include "netloader.h" #include "utility.h" @@ -23,6 +24,8 @@ int menu_netloader() { drawBg(); drawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 16, msg); + if ( IS3DACTIVE ) + drawTextf(GFX_TOP, GFX_RIGHT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 16, msg); swapFrameBuffers(); while (aptMainLoop()) { @@ -38,7 +41,7 @@ int menu_netloader() { int rc = netloader_loop(); if (rc > 0) { netloader_boot = true; - return load_3dsx(netloadedPath); + return load_3dsx(netloadedPath, config->splashTopDef, config->splashBotDef); } else if (rc < 0) { netloader_draw_error(); break; From 7e048da6da1a4fb76a39d1ebb7d0c40f83631187 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 19:59:06 +0200 Subject: [PATCH 149/259] Update menu_netloaderarm9.c --- source/menu_netloaderarm9.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/menu_netloaderarm9.c b/source/menu_netloaderarm9.c index 2e97143..590b4e6 100644 --- a/source/menu_netloaderarm9.c +++ b/source/menu_netloaderarm9.c @@ -52,6 +52,8 @@ int menu_netloaderarm9(void) { inet_ntoa(sa.sin_addr), BRAHMA_NETWORK_PORT); drawBg(); drawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 16, msg); + if ( IS3DACTIVE ) + drawTextf(GFX_TOP, GFX_RIGHT, &fontDefault, MENU_MIN_X + 16, MENU_MIN_Y + 16, msg); swapFrameBuffers(); sflags = fcntl(sockfd, F_GETFL); From 9448b2f60e87dc76088110d31c8adf1265fdfca2 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 4 Sep 2016 20:01:27 +0200 Subject: [PATCH 150/259] Update changelog.txt --- changelog.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/changelog.txt b/changelog.txt index 2e7a31a..1b6e794 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,11 +1,31 @@ +2.3.0 + +Add splash screen support, keywords "splashTop" and "splashBot" +- In "[general]" category for default behavior +- In "[entry]" categories for per-entry behavior (which override the default behavior) + +Add password feature, it can be configured from "Settings" menu (maximum of 16 keys supported) + +Password can be set through the new "[password]" category with the following properties: +- "keys": the password itself (integers list separated with ":") +- "attempts": the allowed attempts before considering that the password check is failed (0 means infinite) +- "failPath": loaded element if the password check has failed +- "failOffset": offset for loaded element if the password check has failed +- "failImgTop" and "failImgBot": splash screen when password check has failed (it could be the freeze scren if "failPath" is invalid/empty) + 2.2.0 Add "brightness" property for screen-init (only used if CtrBootManager must initialize the screen) + The font used on bottom screen can have a different color ("font3" property in "[theme]" and "[animation]" categories). + Add support for transparent background images (the background color will be displayed on transparent zones) - "bgImgTopAlpha", "bgImgTop3DAlpha" and "bgImgBotAlpha" keywords in "[theme]" category to set a background image as transparent + Add background images fade-in effect, activated by "bgImgTopFadeIn" and "bgImgBotFadeIn" properties in "[animation]" category + Add the possibility to have more than 11 boot entries (but "File browser" entry add feature cannot put more than the previous entries rounded up to a 12 multiplier) + Thumbnail support for each boot entry, new keywords in "[entry]" categories: - "thumbTop", "thumbTop3D" and "thumbBot" for thumbnail path for each screen - "thumbTopParams", "thumbTop3DParams" and "thumbBotParams" for thumbnail parameters, format "posX:posY:sizeX:sizeY:alpha" From 04c13d8d5f48868101e94a5d3377a2cdeefd1c25 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 7 Oct 2016 20:10:01 +0200 Subject: [PATCH 151/259] Update config.c --- source/config.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/config.c b/source/config.c index d12ae59..705d8c0 100644 --- a/source/config.c +++ b/source/config.c @@ -349,7 +349,9 @@ static int handler(void *user, const char *section, const char *name, strncpy(config->splashBotDef, item, 128); } #ifdef ARM9 - else if (NAME_MATCH("brightness")) { + else if (NAME_MATCH("screeninit")) { + config->directBootScreenInit = atoi(item); + } else if (NAME_MATCH("brightness")) { config->brightness = atoi(item); } #else @@ -613,6 +615,7 @@ int configInit() { config->brightness = 0; config->index = 0; config->recovery = 2; + config->directBootScreenInit = 1; config->splashTopDef[0] = '\0'; config->splashBotDef[0] = '\0'; @@ -754,6 +757,8 @@ void configSave() { // general section size += snprintf(cfg, 256, "[general]\n"); #ifdef ARM9 + if (config->directBootScreenInit != 1) + size += snprintf(cfg+size, 256, "screeninit=%i;\n", config->directBootScreenInit); if (config->brightness > 0) size += snprintf(cfg+size, 256, "brightness=%i;\n", config->brightness); #else From 4fc4fce2387a15f6e9249a73d1b7b5b15bab9a8f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 7 Oct 2016 20:10:17 +0200 Subject: [PATCH 152/259] Update config.h --- source/config.h | 1 + 1 file changed, 1 insertion(+) diff --git a/source/config.h b/source/config.h index f69cacf..5ece679 100644 --- a/source/config.h +++ b/source/config.h @@ -79,6 +79,7 @@ typedef struct { int brightness; int index; int recovery; + int directBootScreenInit; int password[PASSWORD_MAX_SIZE]; int passSize; From 2475d0f2cffcd763c008d0eb364effc810743ed2 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 7 Oct 2016 20:10:40 +0200 Subject: [PATCH 153/259] Update main.c --- source/main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/source/main.c b/source/main.c index 0bafac9..bcef4fa 100644 --- a/source/main.c +++ b/source/main.c @@ -89,9 +89,6 @@ int main() { break; } } else { - #ifdef ARM9 - initScreens(config->brightness); - #endif animSetup(); while (aptMainLoop()) { if (menu_boot() == 0) From 97ebc80536f9032a5eedccd0806b912100d894af Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 7 Oct 2016 20:11:10 +0200 Subject: [PATCH 154/259] Update menu_boot.c --- source/menu_boot.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/source/menu_boot.c b/source/menu_boot.c index bb7db7c..4c9face 100644 --- a/source/menu_boot.c +++ b/source/menu_boot.c @@ -2,6 +2,7 @@ #include "arm9/source/common.h" #include "arm9/source/hid.h" +#include "screeninit.h" #else #include <3ds.h> @@ -64,11 +65,26 @@ int menu_boot() { if (key & BIT(config->recovery) || config->timeout < 0) { // disable autoboot timer = false; } else if (config->timeout == 0 || key_override(boot_index) != boot_index) { // autoboot + #ifdef ARM9 + if (config->directBootScreenInit) + initScreens(config->brightness); + else + { + // Screen was not initialize, we must absolutly avoid any splash screen! + boot_entry_s* entry = &config->entries[key_override(boot_index)]; + entry->splashTop[0] = '\0'; + entry->splashBot[0] = '\0'; + config->splashTopDef[0] = '\0'; + config->splashBotDef[0] = '\0'; + } + #endif return boot(key_override(boot_index)); } #ifndef ARM9 time(&start); +#else + initScreens(config->brightness); #endif static const u32 checkedKeys = 0x0FFF; From c2d1cbec890135b31781f5905a9a73c78fc169c2 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 7 Oct 2016 20:11:30 +0200 Subject: [PATCH 155/259] Update menu_config.c --- source/menu_config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/menu_config.c b/source/menu_config.c index ff93bd5..6200734 100644 --- a/source/menu_config.c +++ b/source/menu_config.c @@ -333,10 +333,10 @@ int menu_config() { #ifdef ARM9 drawItem(menu_index == 3, 48, "Screen initialization brightness: %i", BRIGHTNESS_COUNT-config->brightness); - drawInfo("CtrBootManager9 v2.3.0"); + drawInfo("CtrBootManager9 v2.3.1"); #else drawItem(menu_index == 3, 48, "Bootfix: %i", config->autobootfix); - drawInfo("CtrBootManager v2.3.0"); + drawInfo("CtrBootManager v2.3.1"); #endif swapFrameBuffers(); From 9fb626e22ba0368e99379bedb6f23d2b43e307e0 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Fri, 7 Oct 2016 20:12:38 +0200 Subject: [PATCH 156/259] Update changelog.txt --- changelog.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/changelog.txt b/changelog.txt index 1b6e794..56a02c3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,10 @@ +2.3.1 + +Add the possibility to disable screen initialization for direct boot (timeout of "0" and no recovery key pressed) +- In "[general]" category, write "screeninit=0;" + +Don't forget that if the chainloaded binary doesn't do any screen initalization, enabling this feature will make it crash! + 2.3.0 Add splash screen support, keywords "splashTop" and "splashBot" From b288e0e548a414dff0dee9ce2234601f6e08531e Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 9 Oct 2016 20:06:58 +0200 Subject: [PATCH 157/259] Update loader.c --- source/loader.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/source/loader.c b/source/loader.c index 8faec3e..f6117b0 100644 --- a/source/loader.c +++ b/source/loader.c @@ -18,16 +18,18 @@ #include "loader.h" #include "utility.h" -void screenBehavior(gfxScreen_t screen, int screenSize, char* splash) +int screenBehavior(gfxScreen_t screen, int screenSize, char* splash) { if ( NULL == splash || splash[0] == '\0' ) - return; + return 0; u8* fb = gfxGetFramebuffer(screen, GFX_LEFT, NULL, NULL); if ( splash[0] == '/' ) fileRead(splash, fb, screenSize); else if ( strcasecmp(splash, "clear") == 0 ) memset(fb, 0, screenSize); + + return 1; } void screensBehavior(char* splashTop, char* splashBot) @@ -36,9 +38,11 @@ void screensBehavior(char* splashTop, char* splashBot) gfxSet3D(false); #endif - screenBehavior(GFX_TOP, TOP_SCREEN_SIZE, splashTop); - screenBehavior(GFX_BOTTOM, BOT_SCREEN_SIZE, splashBot); - swapFrameBuffers(); + int needSwap = screenBehavior(GFX_TOP, TOP_SCREEN_SIZE, splashTop); + needSwap += screenBehavior(GFX_BOTTOM, BOT_SCREEN_SIZE, splashBot); + + if (needSwap) + swapFrameBuffers(); } #ifdef ARM9 From 5da4559a2febce69c0d5d02fc322602202c4ddb3 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 9 Oct 2016 20:07:31 +0200 Subject: [PATCH 158/259] Update menu_config.c --- source/menu_config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/menu_config.c b/source/menu_config.c index 6200734..4dcd5b9 100644 --- a/source/menu_config.c +++ b/source/menu_config.c @@ -333,10 +333,10 @@ int menu_config() { #ifdef ARM9 drawItem(menu_index == 3, 48, "Screen initialization brightness: %i", BRIGHTNESS_COUNT-config->brightness); - drawInfo("CtrBootManager9 v2.3.1"); + drawInfo("CtrBootManager9 v2.3.2"); #else drawItem(menu_index == 3, 48, "Bootfix: %i", config->autobootfix); - drawInfo("CtrBootManager v2.3.1"); + drawInfo("CtrBootManager v2.3.2"); #endif swapFrameBuffers(); From 65b825518481e97267cda0125a5a32535c67fd4a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 9 Oct 2016 20:08:30 +0200 Subject: [PATCH 159/259] Update changelog.txt --- changelog.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.txt b/changelog.txt index 56a02c3..4361c05 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +2.3.2 + +Fix crash in the recently added feature to disable screen initialization for direct boot (due to swapbuffer for splash screen) + 2.3.1 Add the possibility to disable screen initialization for direct boot (timeout of "0" and no recovery key pressed) From e73f3c7bfb9ca0755ec7138f325d3645f736cd2e Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 9 Oct 2016 20:09:01 +0200 Subject: [PATCH 160/259] Update changelog.txt --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 4361c05..a37df35 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,6 @@ 2.3.2 -Fix crash in the recently added feature to disable screen initialization for direct boot (due to swapbuffer for splash screen) +Fix crash in the recently added feature to disable screen initialization for direct boot (due to swapbuffer call for splash screen) 2.3.1 From 7763fa1d32e98be5616dc909d5293af8f7bd7687 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:20:26 +0200 Subject: [PATCH 161/259] Update changelog.txt --- changelog.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/changelog.txt b/changelog.txt index a37df35..f667aaf 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,11 @@ +2.4.0 + +Include B9S version named "CtrBootManager9.firm" +Support ".firm" files in A9LH/B9S versions +- Binary patches are supported for this new file type +- Offset is not supported for this new file type +- Remove useless 3DSX file detection for those versions + 2.3.2 Fix crash in the recently added feature to disable screen initialization for direct boot (due to swapbuffer call for splash screen) From b8b7446d69c8d92f4ec87b7648f61f68b24cc336 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:23:41 +0200 Subject: [PATCH 162/259] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ded193..72be248 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,9 @@ CtrBootManager is a boot manager for some 3DS homebrew applications, like HBL an 3. `cmake -DCMAKE_TOOLCHAIN_FILE=../DevkitArm3DS.cmake ../` 4. `cmake --build . --target screeninit_a9lh` 5. `bin2h -c screeninit < screeninit.bin > screeninit.h` - 6. `cmake --build . --target CtrBootManager_a9lh` + 6. `cmake --build . --target loader_a9lh` + 7. `bin2h -c loader < loader.bin > loader.h` + 8. `cmake --build . --target CtrBootManager_a9lh` Binaries should now be in the `build` folder. From 68594d1dbe31e3bc0be4b3b28c2471d7c310d76f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:25:07 +0200 Subject: [PATCH 163/259] Update CMakeLists.txt --- CMakeLists.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e4a602..a2f8410 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,9 @@ file(GLOB_RECURSE SOURCE_FILES_ARM9 file(GLOB_RECURSE SOURCE_FILES_SCREENINIT screeninit/source/* ) +file(GLOB_RECURSE SOURCE_FILES_LOADER + loader/source/* +) # Filter file(GLOB FILTER_FILES @@ -74,6 +77,18 @@ set_target_properties(screeninit PROPERTIES LINK_FLAGS "-nostdlib -nostartfiles -g -mthumb -mthumb-interwork -Wl,-Map,screeninit.map -T ${CMAKE_SOURCE_DIR}/screeninit/linker.ld ") add_a9lh_target(screeninit_a9lh screeninit) +################### +# FIRM loader +################### +add_executable(loader ${SOURCE_FILES_LOADER}) +set(ASFLAGS "-mcpu=mpcore -mfloat-abi=hard") +set(CFLAGS "-Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math") +set_target_properties(loader PROPERTIES COMPILE_FLAGS ${CFLAGS}) +set_source_files_properties(loader/source/start.s PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp ${CFLAGS}") +set_target_properties(loader PROPERTIES LINK_FLAGS + "-nostdlib -nostartfiles -g -mthumb -mthumb-interwork -Wl,-Map,loader.map -T ${CMAKE_SOURCE_DIR}/loader/linker.ld ") +add_a9lh_target(loader_a9lh loader) + ################### # CtrBootManager9 ################### From aa35d2cc5f5718e905a247d6a2728afe7adcde3d Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:27:11 +0200 Subject: [PATCH 164/259] Create loader.h --- build/loader.h | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 build/loader.h diff --git a/build/loader.h b/build/loader.h new file mode 100644 index 0000000..6f9720f --- /dev/null +++ b/build/loader.h @@ -0,0 +1,10 @@ +const char loader[]={ +0x04,0xd0,0x9f,0xe5,0x35,0x00,0x00,0xea,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0x27,0x00,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x20,0x81,0xe1,0x5e,0x2f,0x07,0xee,0x20 +,0x00,0x80,0xe2,0x01,0x0b,0x50,0xe3,0xfa,0xff,0xff,0x1a,0x01,0x11,0x81,0xe2,0x00,0x00,0x51,0xe3,0xf6,0xff,0xff,0x1a,0x9a,0x1f,0x07,0xee,0x15,0x1f,0x07,0xee,0x1e +,0xff,0x2f,0xe1,0x00,0x00,0xa0,0xe1,0x00,0x00,0xa0,0xe1,0x00,0x00,0xa0,0xe1,0x30,0xb5,0x8b,0x24,0xc9,0xb0,0x09,0x68,0x00,0x23,0x02,0xa8,0x64,0x00,0x03,0xe0,0xc2 +,0x54,0x01,0x33,0xa3,0x42,0x2e,0xd0,0xca,0x5c,0x00,0x2a,0xf8,0xd1,0x20,0x21,0xff,0x31,0xc3,0x18,0x69,0x44,0x1a,0x70,0x01,0x33,0x99,0x42,0xfb,0xd1,0x01,0x90,0x12 +,0x4c,0x13,0x4d,0xa0,0x68,0x00,0x28,0x10,0xd0,0x90,0x21,0x89,0x05,0x8c,0x46,0x23,0x68,0x63,0x44,0x1a,0x00,0x63,0x68,0x18,0x18,0x11,0x78,0x19,0x70,0x01,0x33,0x01 +,0x32,0x83,0x42,0xf9,0xd1,0x30,0x34,0xac,0x42,0xeb,0xd1,0x90,0x24,0xa4,0x05,0x08,0x4b,0xa2,0x68,0x1a,0x60,0x00,0xf0,0x19,0xf8,0xe3,0x68,0x06,0x4a,0x01,0xa9,0x01 +,0x20,0x00,0xf0,0x0b,0xf8,0x00,0x22,0xc2,0x54,0xd8,0xe7,0x40,0x00,0x00,0x24,0x00,0x01,0x00,0x24,0xfc,0xff,0xff,0x1f,0xef,0xbe,0x00,0x00,0x18,0x47,0xc0,0x46,0x00 +,0xc0,0x9f,0xe5,0x1c,0xff,0x2f,0xe1,0x51,0xe0,0xff,0x27,0x78,0x47,0xc0,0x46,0xc6,0xff,0xff,0xea,0x00,0x00,0x00,0x00}; +const int loader_size=248; From 387301630283e10dc04188a8638e8bc22ebe56b9 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:27:48 +0200 Subject: [PATCH 165/259] Create linker.ld --- loader/linker.ld | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 loader/linker.ld diff --git a/loader/linker.ld b/loader/linker.ld new file mode 100644 index 0000000..a3a699a --- /dev/null +++ b/loader/linker.ld @@ -0,0 +1,14 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) + +ENTRY(_start) +SECTIONS +{ + . = 0x27FFE000; + + .text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); } + .rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); } + .data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); } + + . = ALIGN(4); +} From e5ee3a7450b8264d25d282de1df3de206143e73f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:28:07 +0200 Subject: [PATCH 166/259] Create Makefile --- loader/Makefile | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 loader/Makefile diff --git a/loader/Makefile b/loader/Makefile new file mode 100644 index 0000000..b33944c --- /dev/null +++ b/loader/Makefile @@ -0,0 +1,44 @@ +rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2)) + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/base_tools + +name := $(shell basename $(CURDIR)) + +dir_source := source +dir_build := build +dir_out := ../$(dir_build) + +ASFLAGS := -mcpu=arm946e-s +CFLAGS := -Wall -Wextra -mthumb $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math +LDFLAGS := -nostdlib + +objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ + $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ + $(call rwildcard, $(dir_source), *.s *.c))) + +.PHONY: all +all: $(dir_out)/$(name).bin + +.PHONY: clean +clean: + @rm -rf $(dir_build) + +$(dir_out)/$(name).bin: $(dir_build)/$(name).elf + $(OBJCOPY) -S -O binary $< $@ + +$(dir_build)/$(name).elf: $(objects) + $(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^ + +$(dir_build)/memory.o: CFLAGS += -O3 + +$(dir_build)/%.o: $(dir_source)/%.c + @mkdir -p "$(@D)" + $(COMPILE.c) $(OUTPUT_OPTION) $< + +$(dir_build)/%.o: $(dir_source)/%.s + @mkdir -p "$(@D)" + $(COMPILE.s) $(OUTPUT_OPTION) $< From 1dce43a464055141a141850ee9a44048924b14f7 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:28:37 +0200 Subject: [PATCH 167/259] Create cache.h --- loader/source/cache.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 loader/source/cache.h diff --git a/loader/source/cache.h b/loader/source/cache.h new file mode 100644 index 0000000..66aa4bf --- /dev/null +++ b/loader/source/cache.h @@ -0,0 +1,27 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified +* reasonable legal notices or author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +*/ + +#pragma once + +#include "types.h" + +void flushCaches(void); From 5ddb2ccaedfb3c02b01d27a7b14be0a6d30c546b Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:29:03 +0200 Subject: [PATCH 168/259] Create cache.s --- loader/source/cache.s | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 loader/source/cache.s diff --git a/loader/source/cache.s b/loader/source/cache.s new file mode 100644 index 0000000..c4d6477 --- /dev/null +++ b/loader/source/cache.s @@ -0,0 +1,56 @@ +@ This file is part of Luma3DS +@ Copyright (C) 2016 Aurora Wright, TuxSH +@ +@ This program is free software: you can redistribute it and/or modify +@ it under the terms of the GNU General Public License as published by +@ the Free Software Foundation, either version 3 of the License, or +@ (at your option) any later version. +@ +@ This program is distributed in the hope that it will be useful, +@ but WITHOUT ANY WARRANTY; without even the implied warranty of +@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +@ GNU General Public License for more details. +@ +@ You should have received a copy of the GNU General Public License +@ along with this program. If not, see . +@ +@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified +@ reasonable legal notices or author attributions in that material or in the Appropriate Legal +@ Notices displayed by works containing it. + +.text +.arm +.align 4 + +.global flushCaches +.type flushCaches, %function +flushCaches: + @ Clean and flush both the data cache and instruction caches + + @ Adpated from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html , + @ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well + @ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has) + + @ Implemented in bootROM at addresses 0xffff0830 (DCache) and 0xffff0ab4 (ICache) + + mov r1, #0 @ segment counter + outer_loop: + mov r0, #0 @ line counter + + inner_loop: + orr r2, r1, r0 @ generate segment and line address + mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line + add r0, #0x20 @ increment to next line + cmp r0, #0x400 + bne inner_loop + + add r1, #0x40000000 + cmp r1, #0 + bne outer_loop + + mcr p15, 0, r1, c7, c10, 4 @ drain write buffer + + @ Flush instruction cache + mcr p15, 0, r1, c7, c5, 0 + + bx lr From 6000e7614a8a3b2524b2d06e191c7c2b03e1168f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:29:25 +0200 Subject: [PATCH 169/259] Create firm.c --- loader/source/firm.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 loader/source/firm.c diff --git a/loader/source/firm.c b/loader/source/firm.c new file mode 100644 index 0000000..c336876 --- /dev/null +++ b/loader/source/firm.c @@ -0,0 +1,44 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2017 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified +* reasonable legal notices or author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +*/ + +#include "firm.h" +#include "memory.h" +#include "cache.h" + +void launchFirm(Firm *firm, int argc, char **argv) +{ + + //Copy FIRM sections to respective memory locations + for(u32 sectionNum = 0; sectionNum < 4 && firm->section[sectionNum].size != 0; sectionNum++) + memcpy(firm->section[sectionNum].address, (u8 *)firm + firm->section[sectionNum].offset, firm->section[sectionNum].size); + + //Set ARM11 entrypoint + *(vu32 *)0x1FFFFFFC = (u32)firm->arm11Entry; + + //Ensure that all memory transfers have completed and that the caches have been flushed + flushCaches(); + + //Jump to ARM9 entrypoint. Also give it additional arguments it can dismiss + ((void (*)(int, char**, u32))firm->arm9Entry)(argc, argv, 0x0000BEEF); + + __builtin_unreachable(); +} From d1b4c22cdd00629fddd8dcbbb76d9583c9938dd2 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:29:41 +0200 Subject: [PATCH 170/259] Create firm.h --- loader/source/firm.h | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 loader/source/firm.h diff --git a/loader/source/firm.h b/loader/source/firm.h new file mode 100644 index 0000000..47dc7ba --- /dev/null +++ b/loader/source/firm.h @@ -0,0 +1,46 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2017 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified +* reasonable legal notices or author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +*/ + +#pragma once + +#include "types.h" + +typedef struct __attribute__((packed)) +{ + u32 offset; + u8 *address; + u32 size; + u32 procType; + u8 hash[0x20]; +} FirmSection; + +typedef struct __attribute__((packed)) +{ + char magic[4]; + u32 reserved1; + u8 *arm11Entry; + u8 *arm9Entry; + u8 reserved2[0x30]; + FirmSection section[4]; +} Firm; + +void launchFirm(Firm *firm, int argc, char **argv); From f1fc5a50c827535f11c4f04d89df1028adea7dd8 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:29:55 +0200 Subject: [PATCH 171/259] Create main.c --- loader/source/main.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 loader/source/main.c diff --git a/loader/source/main.c b/loader/source/main.c new file mode 100644 index 0000000..c591cc4 --- /dev/null +++ b/loader/source/main.c @@ -0,0 +1,41 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified +* reasonable legal notices or author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +*/ + +#include "memory.h" +#include "cache.h" +#include "firm.h" + +void main(int argc __attribute__((unused)), char **argv) +{ + Firm *firm = (Firm *)0x24000000; + char absPath[24 + 255]; + + u32 i; + for(i = 0; i < 23 + 255 && argv[0][i] != 0; i++) + absPath[i] = argv[0][i]; + for(; i < 24 + 255; i++) + absPath[i] = 0; + + char *argvPassed[1] = {absPath}; + + launchFirm(firm, 1, argvPassed); +} From 322650916611d14b0e3a02dd81c0aaa5c051eb0a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:30:11 +0200 Subject: [PATCH 172/259] Create memory.c --- loader/source/memory.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 loader/source/memory.c diff --git a/loader/source/memory.c b/loader/source/memory.c new file mode 100644 index 0000000..3a92ee0 --- /dev/null +++ b/loader/source/memory.c @@ -0,0 +1,36 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified +* reasonable legal notices or author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +*/ + +/* +* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c +*/ + +#include "memory.h" + +void memcpy(void *dest, const void *src, u32 size) +{ + u8 *destc = (u8 *)dest; + const u8 *srcc = (const u8 *)src; + + for(u32 i = 0; i < size; i++) + destc[i] = srcc[i]; +} From acb3b6569f44079d16534078de0f86e8312fce3e Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:30:30 +0200 Subject: [PATCH 173/259] Create memory.h --- loader/source/memory.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 loader/source/memory.h diff --git a/loader/source/memory.h b/loader/source/memory.h new file mode 100644 index 0000000..0d81055 --- /dev/null +++ b/loader/source/memory.h @@ -0,0 +1,31 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified +* reasonable legal notices or author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +*/ + +/* +* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c +*/ + +#pragma once + +#include "types.h" + +void memcpy(void *dest, const void *src, u32 size); From 86659a82efaa74c035101039616acec4637ef919 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:30:50 +0200 Subject: [PATCH 174/259] Create start.s --- loader/source/start.s | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 loader/source/start.s diff --git a/loader/source/start.s b/loader/source/start.s new file mode 100644 index 0000000..07775ed --- /dev/null +++ b/loader/source/start.s @@ -0,0 +1,30 @@ +@ This file is part of Luma3DS +@ Copyright (C) 2017 Aurora Wright, TuxSH +@ +@ This program is free software: you can redistribute it and/or modify +@ it under the terms of the GNU General Public License as published by +@ the Free Software Foundation, either version 3 of the License, or +@ (at your option) any later version. +@ +@ This program is distributed in the hope that it will be useful, +@ but WITHOUT ANY WARRANTY; without even the implied warranty of +@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +@ GNU General Public License for more details. +@ +@ You should have received a copy of the GNU General Public License +@ along with this program. If not, see . +@ +@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified +@ reasonable legal notices or author attributions in that material or in the Appropriate Legal +@ Notices displayed by works containing it. + +.section .text.start +.align 4 +.global _start +_start: + ldr sp, =0x27ffe000 + b main + +.global payloadSize +payloadSize: + .word 0 From 9d7f6d601cfe461d8d545c03cea92087879f9c51 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:31:08 +0200 Subject: [PATCH 175/259] Create types.h --- loader/source/types.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 loader/source/types.h diff --git a/loader/source/types.h b/loader/source/types.h new file mode 100644 index 0000000..1b0c46f --- /dev/null +++ b/loader/source/types.h @@ -0,0 +1,35 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified +* reasonable legal notices or author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +*/ + +#pragma once + +#include + +//Common data types +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +typedef volatile u8 vu8; +typedef volatile u16 vu16; +typedef volatile u32 vu32; +typedef volatile u64 vu64; From 61f1a3279cf607a9e343d44a3ff4c41f1701d0e7 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:31:59 +0200 Subject: [PATCH 176/259] Update loader.c --- source/loader.c | 77 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/source/loader.c b/source/loader.c index f6117b0..cfadce7 100644 --- a/source/loader.c +++ b/source/loader.c @@ -11,6 +11,8 @@ #include "stage2_bin.h" #include "memory.h" #include "screeninit.h" +#include "arm9/source/firm.h" +#include "../build/loader.h" #endif @@ -73,25 +75,13 @@ unsigned char *memsearch(unsigned char *startPos, const void *pattern, int size, return NULL; } -int load_bin(char *path, long offset, binary_patch* patches, int patchesCount, char* splashTop, char* splashBot) { - - // Load binary - size_t size = fileSize(path); - if (!size) { - return -1; - } - - if (fileReadOffset(path, (void *) PTR_PAYLOAD_MAIN_DATA, PTR_PAYLOAD_SIZE_MAX, offset) != 0) { - return -1; - } - - // Apply patches - unsigned char* oriBinary = (unsigned char*)PTR_PAYLOAD_MAIN_DATA; +void applyPatches(unsigned char* binaryData, size_t binarySize, long offset, binary_patch* patches, int patchesCount) +{ for (int i = 0 ; i < patchesCount ; i++) { - unsigned char* binFound = oriBinary; + unsigned char* binFound = binaryData; int curOccurence = 0; - while ( NULL != (binFound = memsearch(binFound, patches[i].memToSearch, size-offset+oriBinary-binFound, patches[i].memToSearchSize)) ) + while ( NULL != (binFound = memsearch(binFound, patches[i].memToSearch, binarySize-offset+binaryData-binFound, patches[i].memToSearchSize)) ) { curOccurence++; if ( patches[i].occurence == 0 || curOccurence == patches[i].occurence ) @@ -106,7 +96,21 @@ int load_bin(char *path, long offset, binary_patch* patches, int patchesCount, c binFound += patches[i].memToSearchSize; } } - +} + +int load_bin(char *path, long offset, binary_patch* patches, int patchesCount, char* splashTop, char* splashBot) { + + // Load binary + size_t payloadSize = fileSize(path); + if (!payloadSize) { + return -1; + } + + if (fileReadOffset(path, (void *) PTR_PAYLOAD_MAIN_DATA, PTR_PAYLOAD_SIZE_MAX, offset) != 0) { + return -1; + } + + applyPatches((unsigned char*)PTR_PAYLOAD_MAIN_DATA, payloadSize, offset, patches, patchesCount); screensBehavior(splashTop, splashBot); memcpy((void *) PTR_PAYLOAD_STAGE2, stage2_bin, stage2_bin_size); @@ -115,6 +119,40 @@ int load_bin(char *path, long offset, binary_patch* patches, int patchesCount, c return 0; } +static Firm *const firm = (Firm *const)PTR_PAYLOAD_FIRM_DATA; + +int load_firm(char *path, binary_patch* patches, int patchesCount, char* splashTop, char* splashBot) +{ + u32 *loaderAddress = (u32 *)PTR_PAYLOAD_FIRM; + u32 maxPayloadSize = (u32)((u8 *)loaderAddress - (u8 *)firm); + + size_t payloadSize = fileSize(path); + if (!payloadSize || payloadSize > maxPayloadSize) { + return -1; + } + + if (fileRead(path, firm, payloadSize) != 0) { + return -1; + } + + if(!checkFirmPayload(firm)) { + return -1; + } + + applyPatches((unsigned char*)firm, payloadSize, sizeof(Firm), patches, patchesCount); + screensBehavior(splashTop, splashBot); + + // Luma3DS loading support + char absPath[256] = {0}; + sprintf(absPath, "sdmc:%s", path); + char *argv[1] = {absPath}; + + memcpy((void*)loaderAddress, loader, loader_size); + ((void (*)(int, char **, u32))loaderAddress)(1, argv, 0x0000BEEF); + + return 0; +} + #else char boot_app[512]; bool boot_app_enabled; @@ -166,7 +204,10 @@ int load(char *path, long offset, binary_patch* patches, int patchesCount, char* const char *ext = get_filename_ext(path); if (strcasecmp(ext, "bin") == 0 || strcasecmp(ext, "dat") == 0) { return load_bin(path, offset, patches, patchesCount, splashTop, splashBot); -#ifndef ARM9 +#ifdef ARM9 + } else if (strcasecmp(ext, "firm") == 0) { + return load_firm(path, patches, patchesCount, splashTop, splashBot); +#else } else if (strcasecmp(ext, "3dsx") == 0) { return load_3dsx(path, splashTop, splashBot); #endif From 6620876e92b6f0858c1a8fd702e3f6baa8930684 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:32:17 +0200 Subject: [PATCH 177/259] Update loader.h --- source/loader.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/loader.h b/source/loader.h index 36d690f..e66357b 100644 --- a/source/loader.h +++ b/source/loader.h @@ -13,7 +13,9 @@ int load(char *path, long offset, binary_patch* patches, int patchesCount, char* void screensBehavior(char* splashTop, char* splashBot); -#ifndef ARM9 +#ifdef ARM9 +int load_firm(char *path, binary_patch* patches, int patchesCount, char* splashTop, char* splashBot); +#else int load_3dsx(char *path, char* splashTop, char* splashBot); #endif From 7314daad3e22d11555640301749de5a655445d95 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:32:45 +0200 Subject: [PATCH 178/259] Update memory.h --- source/memory.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/memory.h b/source/memory.h index d5be655..b06dba7 100644 --- a/source/memory.h +++ b/source/memory.h @@ -25,4 +25,7 @@ #define PTR_PAYLOAD_SIZE_MAX 0x000FFD00 #define PTR_PAYLOAD_STAGE2 0x08006000 +#define PTR_PAYLOAD_FIRM 0x27FFE000 +#define PTR_PAYLOAD_FIRM_DATA 0x24000000 + #endif //CTRBOOTMANAGER_MEMORY_H From cce7c24274f7ad8e1112529334913e26914e4750 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:33:09 +0200 Subject: [PATCH 179/259] Update menu_config.c --- source/menu_config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/menu_config.c b/source/menu_config.c index 4dcd5b9..65687b5 100644 --- a/source/menu_config.c +++ b/source/menu_config.c @@ -333,10 +333,10 @@ int menu_config() { #ifdef ARM9 drawItem(menu_index == 3, 48, "Screen initialization brightness: %i", BRIGHTNESS_COUNT-config->brightness); - drawInfo("CtrBootManager9 v2.3.2"); + drawInfo("CtrBootManager9 v2.4.0"); #else drawItem(menu_index == 3, 48, "Bootfix: %i", config->autobootfix); - drawInfo("CtrBootManager v2.3.2"); + drawInfo("CtrBootManager v2.4.0"); #endif swapFrameBuffers(); From 10d7bcea4686ec7df9b4d83370e99e1178d5153d Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:33:37 +0200 Subject: [PATCH 180/259] Update menu_picker.c --- source/menu_picker.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/source/menu_picker.c b/source/menu_picker.c index dcb18c4..ec28cd8 100644 --- a/source/menu_picker.c +++ b/source/menu_picker.c @@ -52,7 +52,11 @@ void parse_file(struct dirent *file) { const char *ext = get_filename_ext(file->d_name); if (strcasecmp(ext, "bin") != 0 && strcasecmp(ext, "dat") != 0 + #ifdef ARM9 + && strcasecmp(ext, "firm") != 0) + #else && strcasecmp(ext, "3dsx") != 0) + #endif return; } @@ -245,11 +249,11 @@ void pick_file(file_s *picked, const char *path) { if (!picker->files[index].isDir) { const char *ext = get_filename_ext(picker->files[index].name); int noOffsetReq = 1; + if (strcasecmp(ext, "bin") == 0 || (noOffsetReq = strcasecmp(ext, "dat")) == 0 #ifdef ARM9 - if (strcasecmp(ext, "bin") == 0 || (noOffsetReq = strcasecmp(ext, "dat")) == 0) { - + || strcasecmp(ext, "firm") == 0) { #else - if (strcasecmp(ext, "3dsx") == 0) { + || strcasecmp(ext, "3dsx") == 0) { #endif if (confirm(3, "Add entry to boot menu: \"%s\" ?", picker->files[index].name)) { if (config->count > config->maxCount - 1) { From 69b8d73ef105c0e597e863cc1ae12abbfc908ae9 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:34:29 +0200 Subject: [PATCH 181/259] Create firm.c --- source/arm9/source/firm.c | 65 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 source/arm9/source/firm.c diff --git a/source/arm9/source/firm.c b/source/arm9/source/firm.c new file mode 100644 index 0000000..ee2dc89 --- /dev/null +++ b/source/arm9/source/firm.c @@ -0,0 +1,65 @@ +#include "firm.h" + +#include "sha.h" + +static __attribute__((noinline)) bool overlaps(u32 as, u32 ae, u32 bs, u32 be) +{ + if (as <= bs && bs <= ae) + return true; + else if (bs <= as && as <= be) + return true; + return false; +} + +bool checkFirmPayload(Firm* firm) +{ + if(memcmp(firm->magic, "FIRM", 4) != 0) + return false; + + if(firm->arm9Entry == NULL) //allow for the arm11 entrypoint to be zero in which case nothing is done on the arm11 side + return false; + + u32 size = 0x200; + for(u32 i = 0; i < 4; i++) + size += firm->section[i].size; + + bool arm9EpFound = false, arm11EpFound = false; + for(u32 i = 0; i < 4; i++) + { + __attribute__((aligned(4))) u8 hash[0x20]; + + FirmSection *section = &firm->section[i]; + + // allow empty sections + if (section->size == 0) + continue; + + if(section->offset < 0x200) + return false; + + if(section->address + section->size < section->address) //overflow check + return false; + + if(((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF)) //alignment check + return false; + + if(overlaps((u32)section->address, (u32)section->address + section->size, 0x27FFE000, 0x28000000)) + return false; + else if(overlaps((u32)section->address, (u32)section->address + section->size, 0x27FFE000 - 0x1000, 0x27FFE000)) + return false; + else if(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm, (u32)firm + size)) + return false; + + sha(hash, (u8 *)firm + section->offset, section->size, SHA_256_MODE); + if(memcmp(hash, section->hash, 0x20) != 0) + return false; + + if(firm->arm9Entry >= section->address && firm->arm9Entry < (section->address + section->size)) + arm9EpFound = true; + + if(firm->arm11Entry >= section->address && firm->arm11Entry < (section->address + section->size)) + arm11EpFound = true; + } + + return arm9EpFound && (firm->arm11Entry == NULL || arm11EpFound); +} From 5a5e05c540e9b02217af7a68bc7aea444fa86107 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:34:44 +0200 Subject: [PATCH 182/259] Create firm.h --- source/arm9/source/firm.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 source/arm9/source/firm.h diff --git a/source/arm9/source/firm.h b/source/arm9/source/firm.h new file mode 100644 index 0000000..738fb8c --- /dev/null +++ b/source/arm9/source/firm.h @@ -0,0 +1,24 @@ +#pragma once + +#include "common.h" + +typedef struct __attribute__((packed)) +{ + u32 offset; + u8 *address; + u32 size; + u32 procType; + u8 hash[0x20]; +} FirmSection; + +typedef struct __attribute__((packed)) +{ + char magic[4]; + u32 reserved1; + u8 *arm11Entry; + u8 *arm9Entry; + u8 reserved2[0x30]; + FirmSection section[4]; +} Firm; + +bool checkFirmPayload(Firm* firm); From 13f57b0cac9cf6fdb9314f7c78d2dda39fc6297b Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:35:00 +0200 Subject: [PATCH 183/259] Create sha.c --- source/arm9/source/sha.c | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 source/arm9/source/sha.c diff --git a/source/arm9/source/sha.c b/source/arm9/source/sha.c new file mode 100644 index 0000000..6b2c4d7 --- /dev/null +++ b/source/arm9/source/sha.c @@ -0,0 +1,44 @@ +#include "sha.h" + +static void sha_wait_idle() +{ + while(*REG_SHA_CNT & 1); +} + +void sha(void *res, const void *src, u32 size, u32 mode) +{ + sha_wait_idle(); + *REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND; + + const u32 *src32 = (const u32 *)src; + int i; + while(size >= 0x40) + { + sha_wait_idle(); + for(i = 0; i < 4; ++i) + { + *REG_SHA_INFIFO = *src32++; + *REG_SHA_INFIFO = *src32++; + *REG_SHA_INFIFO = *src32++; + *REG_SHA_INFIFO = *src32++; + } + + size -= 0x40; + } + + sha_wait_idle(); + memcpy((void *)REG_SHA_INFIFO, src32, size); + + *REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND; + + while(*REG_SHA_CNT & SHA_FINAL_ROUND); + sha_wait_idle(); + + u32 hashSize = SHA_256_HASH_SIZE; + if(mode == SHA_224_MODE) + hashSize = SHA_224_HASH_SIZE; + else if(mode == SHA_1_MODE) + hashSize = SHA_1_HASH_SIZE; + + memcpy(res, (void *)REG_SHA_HASH, hashSize); +} From 568a79dbb9adff665ac7ef055a22dc9b1dc04d32 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:35:16 +0200 Subject: [PATCH 184/259] Create sha.h --- source/arm9/source/sha.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 source/arm9/source/sha.h diff --git a/source/arm9/source/sha.h b/source/arm9/source/sha.h new file mode 100644 index 0000000..ec1fc07 --- /dev/null +++ b/source/arm9/source/sha.h @@ -0,0 +1,32 @@ +#pragma once + +#include "common.h" + +#define REG_SHA_CNT ((vu32 *)0x1000A000) +#define REG_SHA_BLKCNT ((vu32 *)0x1000A004) +#define REG_SHA_HASH ((vu32 *)0x1000A040) +#define REG_SHA_INFIFO ((vu32 *)0x1000A080) + +#define SHA_CNT_STATE 0x00000003 +#define SHA_CNT_UNK2 0x00000004 +#define SHA_CNT_OUTPUT_ENDIAN 0x00000008 +#define SHA_CNT_MODE 0x00000030 +#define SHA_CNT_ENABLE 0x00010000 +#define SHA_CNT_ACTIVE 0x00020000 + +#define SHA_HASH_READY 0x00000000 +#define SHA_NORMAL_ROUND 0x00000001 +#define SHA_FINAL_ROUND 0x00000002 + +#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN +#define SHA_OUTPUT_LE 0 + +#define SHA_256_MODE 0 +#define SHA_224_MODE 0x00000010 +#define SHA_1_MODE 0x00000020 + +#define SHA_256_HASH_SIZE (256 / 8) +#define SHA_224_HASH_SIZE (224 / 8) +#define SHA_1_HASH_SIZE (160 / 8) + +void sha(void *res, const void *src, u32 size, u32 mode); From e6b99443589aa81fc73e9cdfe3b279703bde27ec Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sun, 21 May 2017 00:39:27 +0200 Subject: [PATCH 185/259] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 72be248..f4dcc2c 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ CtrBootManager is a boot manager for some 3DS homebrew applications, like HBL an - libconfig in portlibs (tried with v1.5) ##Building + ###The recommended way: 1. `mkdir build/` 2. `cd build/` @@ -20,6 +21,7 @@ CtrBootManager is a boot manager for some 3DS homebrew applications, like HBL an Binaries should now be in the `build` folder. ##Credits + ###For contributions to hb_menu: * smea : code * GEMISIS : code @@ -37,10 +39,15 @@ Binaries should now be in the `build` folder. * delebile * tiniVi +###For FIRM loader code: + * Aurora Wright + * TuxSH + ###For movies support code example: * Wolfvak * d0k3 : compressed movies ###Other credits: + Readme by gemarcano This project also uses [Brahma](https://github.com/patois/Brahma). See its repository for its credits. From 5955df8a2919841b69fa39b2aecd8dc8680bbad2 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:09:35 +0200 Subject: [PATCH 186/259] Update changelog.txt --- changelog.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/changelog.txt b/changelog.txt index f667aaf..c20c7de 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,15 @@ +2.5.0 + +SysNAND location supported (only for A9LH/B9S versions): +- Binaries from SysNAND can be started or added as boot entry from "File Browser" (press Select key to switch for SD card to SysNAND) +- CtrBootManager can be put on SysNAND (for example, as "nand:/boot.firm"): in this case, its configuration file become "nand:/CtrBootManager.cfg" +- When CtrBootManager is put on SysNAND, safe mode is triggered: it won't save its configuration, you must manually change "CtrBootManager.cfg" + +New pathes prefixes: +- "sdmc:/" targets the SD card +- "nand:/" targets the SysNAND +- "/" targets the drive where CtrBootManager is booted from + 2.4.0 Include B9S version named "CtrBootManager9.firm" From f9719d295bc2f7e69a36a4918448937f9df9eb02 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:10:11 +0200 Subject: [PATCH 187/259] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f4dcc2c..c91edb2 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Binaries should now be in the `build` folder. * delebile * tiniVi -###For FIRM loader code: +###For FIRM loader and CtrNAND reading code: * Aurora Wright * TuxSH From 9a323edd638131b8fe966c638f8eb0367ecb58e6 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:11:29 +0200 Subject: [PATCH 188/259] Update config.c --- source/config.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/source/config.c b/source/config.c index 705d8c0..56753ec 100644 --- a/source/config.c +++ b/source/config.c @@ -3,7 +3,6 @@ // #include #include -#include #include "ini.h" #include "config.h" #include "font.h" @@ -14,6 +13,8 @@ #include "memory.h" #endif +#define COMPUTED_CONFIG_PATH (START_DRIVE_RO?CONFIG_PATH_RO:CONFIG_PATH) + #define SECTION_MATCH(s) strcmp(section, s) == 0 #define NAME_MATCH(n) strcmp(name, n) == 0 @@ -640,12 +641,12 @@ int configInit() { configThemeInit(); // read config file to buffer - size_t size = fileSize(CONFIG_PATH); + size_t size = fileSize(COMPUTED_CONFIG_PATH); if ( size != -1 && size > 0 ) { char buffer[size]; memset(buffer, 0, size); - if (fileRead(CONFIG_PATH, buffer, size) != 0) + if (fileRead(COMPUTED_CONFIG_PATH, buffer, size) != 0) { debug("Could not read config file, creating one..."); configSave(); @@ -745,6 +746,9 @@ int configRemoveEntry(int index) { void configSave() { + if (START_DRIVE_RO) + return; + int size = 0, i = 0; int buffSize = 256*(256*sizeof(char)); #ifdef ARM9 @@ -995,21 +999,9 @@ void configSave() { size += snprintf(cfg+size, 256, "key=%i;\n", entry->key); } -#ifdef ARM9 - FIL file; - unsigned int br = 0; - f_unlink(CONFIG_PATH); - if(f_open(&file, CONFIG_PATH, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) { - debug("Could not open cfg: %s", CONFIG_PATH); - return; - } - f_write(&file, cfg, size, &br); - f_close(&file); -#else - unlink(CONFIG_PATH); - FILE *file = fopen(CONFIG_PATH, "w"); - fwrite(cfg, 1 , size, file); - fclose(file); + + fileWrite(COMPUTED_CONFIG_PATH, cfg, size); +#ifndef ARM9 free(cfg); #endif } From 53c49d5492efcc4bd0fa1c6654b2bc77060f8018 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:11:49 +0200 Subject: [PATCH 189/259] Update config.h --- source/config.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/config.h b/source/config.h index 5ece679..49db7c0 100644 --- a/source/config.h +++ b/source/config.h @@ -9,15 +9,16 @@ extern "C" { #include "arm9/source/common.h" #define CONFIG_PATH "/a9lh.cfg\0Free space for binary patch to chainload another instance of CtrBootManager9... Space ends up now!" - +#define CONFIG_PATH_RO "/CtrBootManager.cfg" #else #include <3ds.h> #include "utility.h" #define CONFIG_PATH "/boot.cfg" - +#define CONFIG_PATH_RO CONFIG_PATH #endif + #include "draw.h" #include "loader.h" // Binary patches define From bd502fb49175749e11de84ae2df76b0d824e2c6e Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:12:37 +0200 Subject: [PATCH 190/259] Update loader.c --- source/loader.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/loader.c b/source/loader.c index cfadce7..282b4e1 100644 --- a/source/loader.c +++ b/source/loader.c @@ -143,9 +143,8 @@ int load_firm(char *path, binary_patch* patches, int patchesCount, char* splashT screensBehavior(splashTop, splashBot); // Luma3DS loading support - char absPath[256] = {0}; - sprintf(absPath, "sdmc:%s", path); - char *argv[1] = {absPath}; + char absPath[256]; + char *argv[1] = {computeFullPath(path, absPath)}; memcpy((void*)loaderAddress, loader, loader_size); ((void (*)(int, char **, u32))loaderAddress)(1, argv, 0x0000BEEF); From d3174f2acb3c0e21e8c36c5d7b17df4a7a7d8779 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:13:05 +0200 Subject: [PATCH 191/259] Update main.c --- source/main.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/source/main.c b/source/main.c index bcef4fa..4a0ee8a 100644 --- a/source/main.c +++ b/source/main.c @@ -56,13 +56,32 @@ void __appExit() { } #endif -int main() { +int main(int argc, char **argv) { #ifdef ARM9 *(u32 *) 0x10000020 = 0; *(u32 *) 0x10000020 = 0x340; - FATFS fs; - f_mount(&fs, "0:", 0); + + // Code inspired from Luma3DS + u16 launchedPath[4]; + if (1 == argc) + { + u32 i; + for(i = 0; i < 4 && argv[0][i] != 0; i++) + launchedPath[i] = argv[0][i]; + } + else if (2 == argc) + { + u32 i; + u16 *p = (u16 *)argv[0]; + for(i = 0; i < 4 && p[i] != 0; i++) + launchedPath[i] = p[i]; + } + else + launchedPath[0] = 0; + + bool loadedFromSD = (memcmp(launchedPath, "n\0a\0n\0d\0", 8) != 0); + initFileSystems(loadedFromSD); #else if (netloader_init() != 0) { // fix SOC_Initialize From b31b15c29bd336f95dfbe9eeb0aaf75889bf384e Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:13:33 +0200 Subject: [PATCH 192/259] Update memory.h --- source/memory.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/source/memory.h b/source/memory.h index b06dba7..8d93fd4 100644 --- a/source/memory.h +++ b/source/memory.h @@ -11,13 +11,14 @@ #define PTR_BOT_SCREEN_BUF (u8*)(0x25046500) #define PTR_TOP_BG (u8*)(0x2507E900) #define PTR_BOT_BG (u8*)(0x250DC500) -#define PTR_CFG (u8*)(0x25130000) -#define PTR_PICKER (u8*)(0x25140000) -#define PTR_PICKER_FILE (u8*)(0x25150000) -#define PTR_CFG_TMP (u8*)(0x25160000) -#define PTR_ANIM (u8*)(0x25170000) -#define PTR_MOVIE_COMP (u8*)(0x25180000) -#define PTR_DYNAMIC_MEM_START (u8*)(0x25290000) +#define PTR_FILE_SYSTEMS (u8*)(0x25130000) +#define PTR_CFG (u8*)(0x25140000) +#define PTR_PICKER (u8*)(0x25150000) +#define PTR_PICKER_FILE (u8*)(0x25160000) +#define PTR_CFG_TMP (u8*)(0x25170000) +#define PTR_ANIM (u8*)(0x25180000) +#define PTR_MOVIE_COMP (u8*)(0x25190000) +#define PTR_DYNAMIC_MEM_START (u8*)(0x252A0000) #define PTR_PAYLOAD_MAIN 0x23F00000 From 3abbb84960613d87fe12c64af42c20102c6e9102 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:14:09 +0200 Subject: [PATCH 193/259] Update menu_config.c --- source/menu_config.c | 248 ++++++++++++++++++++++++------------------- 1 file changed, 137 insertions(+), 111 deletions(-) diff --git a/source/menu_config.c b/source/menu_config.c index 65687b5..bc89696 100644 --- a/source/menu_config.c +++ b/source/menu_config.c @@ -201,142 +201,168 @@ int menu_config() { time(&t_start); // reset held timer } #endif - if (kDown & KEY_DOWN) { - menu_index++; - if (menu_index >= menu_count) - menu_index = 0; - } - else if (kDown & KEY_UP) { - menu_index--; - if (menu_index < 0) - menu_index = menu_count - 1; + if (START_DRIVE_RO) + { + if (kDown & KEY_B) + return 0; + + drawBg(); + drawTitle("*** Informations ***"); + + char* msg = "CtrBootManager has been started from SysNAND.\n\ +For safety reasons, the configuration file cannot be saved.\n\n\ +Please manually create a configuration file named\n\ +\"CtrBootManager.cfg\" and write it to SysNAND root.\n\n\ +I decline all responsability for any harm on your 3DS system!\n\ +Do it at your own risk!!!"; + + drawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 32, MENU_MIN_Y + 32, msg); + if ( IS3DACTIVE ) + drawTextf(GFX_TOP, GFX_RIGHT, &fontDefault, MENU_MIN_X + 32, MENU_MIN_Y + 32, msg); } + else + { + if (kDown & KEY_DOWN) { + menu_index++; + if (menu_index >= menu_count) + menu_index = 0; + } + else if (kDown & KEY_UP) { + menu_index--; + if (menu_index < 0) + menu_index = menu_count - 1; + } - if (kDown & KEY_LEFT) { - keyLeft(menu_index); - time(&t_start); - } else if (kHeld & KEY_LEFT) { - time(&t_end); - t_elapsed = t_end - t_start; - if (t_elapsed > 0) { + if (kDown & KEY_LEFT) { keyLeft(menu_index); - svcSleep(100); + time(&t_start); + } else if (kHeld & KEY_LEFT) { + time(&t_end); + t_elapsed = t_end - t_start; + if (t_elapsed > 0) { + keyLeft(menu_index); + svcSleep(100); + } } - } - if (kDown & KEY_RIGHT) { - keyRight(menu_index); - time(&t_start); - } else if (kHeld & KEY_RIGHT) { - time(&t_end); - t_elapsed = t_end - t_start; - if (t_elapsed > 0) { + if (kDown & KEY_RIGHT) { keyRight(menu_index); - svcSleep(100); + time(&t_start); + } else if (kHeld & KEY_RIGHT) { + time(&t_end); + t_elapsed = t_end - t_start; + if (t_elapsed > 0) { + keyRight(menu_index); + svcSleep(100); + } + } + + if (kDown & KEY_A) { + keyIn(menu_index); } - } - - if (kDown & KEY_A) { - keyIn(menu_index); - } - if (kDown & KEY_B) { + if (kDown & KEY_B) { - // Apply password failed behavior - int size = 0; - if ( pass_fail == config->count ) - size = snprintf(config->failPath, 256, "reboot"); - else if ( pass_fail == config->count+1 ) - size = snprintf(config->failPath, 256, "shutdown"); - #ifndef ARM9 - else if ( pass_fail == config->count+2 ) - size = snprintf(config->failPath, 256, "homemenu"); - #endif - else if ( pass_fail >= 0 ) - { - boot_entry_s* entry = &config->entries[pass_fail]; - size = snprintf(config->failPath, 256, entry->path); - config->failOffset = entry->offset; + // Apply password failed behavior + int size = 0; + if ( pass_fail == config->count ) + size = snprintf(config->failPath, 256, "reboot"); + else if ( pass_fail == config->count+1 ) + size = snprintf(config->failPath, 256, "shutdown"); + #ifndef ARM9 + else if ( pass_fail == config->count+2 ) + size = snprintf(config->failPath, 256, "homemenu"); + #endif + else if ( pass_fail >= 0 ) + { + boot_entry_s* entry = &config->entries[pass_fail]; + size = snprintf(config->failPath, 256, entry->path); + config->failOffset = entry->offset; + } + if ( pass_fail >= 0 || pass_fail_found ) + config->failPath[size] = '\0'; + + configSave(); + return 0; } - if ( pass_fail >= 0 || pass_fail_found ) - config->failPath[size] = '\0'; - - configSave(); - return 0; - } - drawBg(); - drawTitle("*** Boot configuration ***"); + drawBg(); + drawTitle("*** Boot configuration ***"); - if ( config->timeout >= 0 ) - drawItem(menu_index == 0, 0, "Timeout: %i", config->timeout); - else - drawItem(menu_index == 0, 0, "Timeout: Disabled"); + if ( config->timeout >= 0 ) + drawItem(menu_index == 0, 0, "Timeout: %i", config->timeout); + else + drawItem(menu_index == 0, 0, "Timeout: Disabled"); - drawItem(menu_index == 1, 16, "Default: %s", config->entries[config->index].title); - drawItem(menu_index == 2, 32, "Recovery key: %s", get_button(config->recovery)); - - if ( config->passMaxAttempt > 0 ) - drawItem(menu_index == 4, 80, "Password allowed attempts: %i", config->passMaxAttempt); - else - drawItem(menu_index == 4, 80, "Password allowed attempts: Infinite"); + drawItem(menu_index == 1, 16, "Default: %s", config->entries[config->index].title); + drawItem(menu_index == 2, 32, "Recovery key: %s", get_button(config->recovery)); + + if ( config->passMaxAttempt > 0 ) + drawItem(menu_index == 4, 80, "Password allowed attempts: %i", config->passMaxAttempt); + else + drawItem(menu_index == 4, 80, "Password allowed attempts: Infinite"); - char msg[256]; - int size = 0; - if ( pass_fail < 0 ) - { - if (config->failPath[0] == '\0' || pass_fail_found) + char msg[256]; + int size = 0; + if ( pass_fail < 0 ) { - if (config->failSplashTop[0] != '\0' || config->failSplashBot[0] != '\0') - size = snprintf(msg, 256, "Freeze on failure images"); - else if (config->splashTopDef[0] != '\0' || config->splashBotDef[0] != '\0') - size = snprintf(msg, 256, "Freeze on default splash screen"); + if (config->failPath[0] == '\0' || pass_fail_found) + { + if (config->failSplashTop[0] != '\0' || config->failSplashBot[0] != '\0') + size = snprintf(msg, 256, "Freeze on failure images"); + else if (config->splashTopDef[0] != '\0' || config->splashBotDef[0] != '\0') + size = snprintf(msg, 256, "Freeze on default splash screen"); + else + size = snprintf(msg, 256, "Freeze on last rendered image"); + } else - size = snprintf(msg, 256, "Freeze on last rendered image"); + size = snprintf(msg, 256, "Load \"%s\"", config->failPath); } + else if ( pass_fail == config->count ) + size = snprintf(msg, 256, "Reboot"); + else if ( pass_fail == config->count+1 ) + size = snprintf(msg, 256, "Power off"); + #ifndef ARM9 + else if ( pass_fail == config->count+2 ) + size = snprintf(msg, 256, "Return to home menu"); + #endif else - size = snprintf(msg, 256, "Load \"%s\"", config->failPath); - } - else if ( pass_fail == config->count ) - size = snprintf(msg, 256, "Reboot"); - else if ( pass_fail == config->count+1 ) - size = snprintf(msg, 256, "Power off"); -#ifndef ARM9 - else if ( pass_fail == config->count+2 ) - size = snprintf(msg, 256, "Return to home menu"); -#endif - else - size = snprintf(msg, 256, "Load %s", config->entries[pass_fail].title); - msg[size] = '\0'; + size = snprintf(msg, 256, "Load %s", config->entries[pass_fail].title); + msg[size] = '\0'; - drawItem(menu_index == 5, 96, "Password fail behavior: %s", msg); - drawItem(menu_index == 6, 112, "Password size: %i", pass_size); - drawItem(menu_index == 7, 128, "Password:"); - - size = 0; - if ( config->passSize > 0 ) - { - for ( int i = 0 ; i < config->passSize ; i++ ) + drawItem(menu_index == 5, 96, "Password fail behavior: %s", msg); + drawItem(menu_index == 6, 112, "Password size: %i", pass_size); + drawItem(menu_index == 7, 128, "Password:"); + + size = 0; + if ( config->passSize > 0 ) { - size += snprintf(msg+size, 256, get_button(config->password[i])); - if ( i < config->passSize-1 ) - size += snprintf(msg+size, 256, (i%4 == 3) ? "\n" : ", "); + for ( int i = 0 ; i < config->passSize ; i++ ) + { + size += snprintf(msg+size, 256, get_button(config->password[i])); + if ( i < config->passSize-1 ) + size += snprintf(msg+size, 256, (i%4 == 3) ? "\n" : ", "); + } } + else + size = snprintf(msg, 256, "None"); + msg[size] = '\0'; + + drawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 64, MENU_MIN_Y + 128, msg); + if ( IS3DACTIVE ) + drawTextf(GFX_TOP, GFX_RIGHT, &fontDefault, MENU_MIN_X + 64, MENU_MIN_Y + 128, msg); + + #ifdef ARM9 + drawItem(menu_index == 3, 48, "Screen initialization brightness: %i", BRIGHTNESS_COUNT-config->brightness); + #else + drawItem(menu_index == 3, 48, "Bootfix: %i", config->autobootfix); + #endif } - else - size = snprintf(msg, 256, "None"); - msg[size] = '\0'; - - drawTextf(GFX_TOP, GFX_LEFT, &fontDefault, MENU_MIN_X + 64, MENU_MIN_Y + 128, msg); - if ( IS3DACTIVE ) - drawTextf(GFX_TOP, GFX_RIGHT, &fontDefault, MENU_MIN_X + 64, MENU_MIN_Y + 128, msg); #ifdef ARM9 - drawItem(menu_index == 3, 48, "Screen initialization brightness: %i", BRIGHTNESS_COUNT-config->brightness); - drawInfo("CtrBootManager9 v2.4.0"); + drawInfo("CtrBootManager9 v2.5.0"); #else - drawItem(menu_index == 3, 48, "Bootfix: %i", config->autobootfix); - drawInfo("CtrBootManager v2.4.0"); + drawInfo("CtrBootManager v2.5.0"); #endif swapFrameBuffers(); From 17b87f0cf885d3dcb4f4f78192a49017c1bc1fed Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:14:35 +0200 Subject: [PATCH 194/259] Update menu_more.c --- source/menu_more.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/source/menu_more.c b/source/menu_more.c index ee9184a..cd80b24 100644 --- a/source/menu_more.c +++ b/source/menu_more.c @@ -7,6 +7,7 @@ #include <3ds.h> #include +#include #include "menu_netloaderarm9.h" #endif @@ -21,10 +22,12 @@ #ifdef ARM9 #define MENU_COUNT 4 static char menu_item[4][64] = {"File browser", "Settings", "Reboot", "PowerOff"}; +#define SETTING_ID 1 #else #define MENU_COUNT 6 static char menu_item[6][64] = {"File browser", "Netload 3dsx", "Netload arm9", "Settings", "Reboot", "PowerOff"}; +#define SETTING_ID 3 #endif static int menu_index = 0; @@ -46,6 +49,9 @@ int menu_choose() { } int menu_more() { + + if (START_DRIVE_RO) + sprintf(menu_item[SETTING_ID], "Informations"); menu_password(); menu_index = 0; @@ -123,7 +129,10 @@ static void draw() { drawInfo("Browse for a file to boot"); break; case 1: - drawInfo("Edit boot settings"); + if (START_DRIVE_RO) + drawInfo("See informations"); + else + drawInfo("Edit boot settings"); break; case 2: drawInfo("Reboot the 3ds..."); @@ -142,7 +151,10 @@ static void draw() { drawInfo("Netload a file (arm9) from the computer with nc"); break; case 3: - drawInfo("Edit boot settings"); + if (START_DRIVE_RO) + drawInfo("See informations"); + else + drawInfo("Edit boot settings"); break; case 4: drawInfo("Reboot the 3ds..."); From c16bba66c370e49d2a9063570400e75bb3b60a7c Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:15:14 +0200 Subject: [PATCH 195/259] Update menu_picker.c --- source/menu_picker.c | 57 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/source/menu_picker.c b/source/menu_picker.c index ec28cd8..2bea94b 100644 --- a/source/menu_picker.c +++ b/source/menu_picker.c @@ -150,8 +150,10 @@ static void draw() { drawItemN(i == picker->file_index, 47, 16 * y, picker->files[i].name); if (i == picker->file_index && !picker->files[i].isDir) { - drawInfo("Press (A) to launch\nPress (X) to add to boot menu"); - + if (START_DRIVE_RO) + drawInfo("Press (A) to launch"); + else + drawInfo("Press (A) to launch\nPress (X) to add to boot menu"); } y++; } @@ -163,6 +165,7 @@ void pick_file(file_s *picked, const char *path) { #ifdef ARM9 picker = (picker_s *) PTR_PICKER; + int curDrive = getDefaultDrive(); #else picker = malloc(sizeof(picker_s)); #endif @@ -234,7 +237,13 @@ void pick_file(file_s *picked, const char *path) { if (!picker->files[index].isDir) { if (confirm(0, "Launch \"%s\" ?", picker->files[index].name)) { strncpy(picked->name, picker->files[index].name, 128); + #ifdef ARM9 + if (curDrive != getDefaultDrive()) + computeFullPath(picker->files[index].path, picked->path); + else + #endif strncpy(picked->path, picker->files[index].path, 256); + picked->isDir = picker->files[index].isDir; picked->size = picker->files[index].size; break; @@ -244,7 +253,7 @@ void pick_file(file_s *picked, const char *path) { get_dir(picker->files[index].path); } } - } else if (kDown & KEY_X) { + } else if (kDown & KEY_X && !START_DRIVE_RO) { int index = picker->file_index; if (!picker->files[index].isDir) { const char *ext = get_filename_ext(picker->files[index].name); @@ -258,10 +267,23 @@ void pick_file(file_s *picked, const char *path) { if (confirm(3, "Add entry to boot menu: \"%s\" ?", picker->files[index].name)) { if (config->count > config->maxCount - 1) { debug("Maximum entries reached (%i)\n", config->maxCount); - } else if (configAddEntry(picker->files[index].name, picker->files[index].path, noOffsetReq?0:0x12000) == 0) { - debug("Added entry: %s\n", picker->files[index].name); - } else { - debug("Error adding entry: %s\n", picker->files[index].name); + } + else + { + #ifdef ARM9 + char entryPath[256]; + if (curDrive != getDefaultDrive()) + computeFullPath(picker->files[index].path, entryPath); + else + strncpy(entryPath, picker->files[index].path, 256); + #else + char* entryPath = picker->files[index].path; + #endif + if (configAddEntry(picker->files[index].name, entryPath, noOffsetReq?0:0x12000) == 0) { + debug("Added entry: %s\n", picker->files[index].name); + } else { + debug("Error adding entry: %s\n", picker->files[index].name); + } } } } @@ -286,8 +308,27 @@ void pick_file(file_s *picked, const char *path) { // enter new dir get_dir(picker->now_path); } + #ifdef ARM9 + else if (kDown & KEY_SELECT) { + int prevDrive = curDrive; + do { + curDrive = (curDrive+1)%MANAGED_DRIVES_COUNT; + } while (!switchCurrentDrive(curDrive)); + + if (curDrive != prevDrive) + { + memset(picker, 0, sizeof(picker_s)); + picker->file_count = 0; + picker->file_index = 0; + + get_dir(path); + } + } + #endif } -#ifndef ARM9 +#ifdef ARM9 + setCurrentDriveAsDefault(); +#else free(picker); #endif } From 369dd7eb3e8bcc6e9e6aa5492874f8e38268227a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:15:50 +0200 Subject: [PATCH 196/259] Update utility.c --- source/utility.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 167 insertions(+), 3 deletions(-) diff --git a/source/utility.c b/source/utility.c index 0d3744b..85e5e71 100644 --- a/source/utility.c +++ b/source/utility.c @@ -14,6 +14,7 @@ #include <3ds.h> #include +#include #endif @@ -23,7 +24,143 @@ #ifdef ARM9 -void ioDelay(uint32_t val); +void waitcycles(uint32_t val); + +#define SD_CARD_NAME "0:" +#define SD_CARD_PATH "sdmc:" +#define SD_CARD_PATH_SIZE 5 +#define SYSNAND_NAME "1:" +#define SYSNAND_PATH "nand:" +#define SYSNAND_PATH_SIZE 5 + +typedef struct +{ + char* driveNames[MANAGED_DRIVES_COUNT]; + char* drivePathes[MANAGED_DRIVES_COUNT]; + int drivePathSizes[MANAGED_DRIVES_COUNT]; + bool driveWritable[MANAGED_DRIVES_COUNT]; + FATFS driveFS[MANAGED_DRIVES_COUNT]; + int mountedDrives[MANAGED_DRIVES_COUNT]; + int curDrive; + int defaultDrive; +} file_systems_s; + +file_systems_s *fsConfig; + +void initFileSystems(bool isLoadedFromSD) +{ + fsConfig = (file_systems_s*)PTR_FILE_SYSTEMS; + + fsConfig->driveNames[SD_CARD_ID] = SD_CARD_NAME; + fsConfig->driveNames[SYSNAND_ID] = SYSNAND_NAME; + + fsConfig->drivePathes[SD_CARD_ID] = SD_CARD_PATH; + fsConfig->drivePathes[SYSNAND_ID] = SYSNAND_PATH; + + fsConfig->drivePathSizes[SD_CARD_ID] = SD_CARD_PATH_SIZE; + fsConfig->drivePathSizes[SYSNAND_ID] = SYSNAND_PATH_SIZE; + + fsConfig->driveWritable[SD_CARD_ID] = true; + fsConfig->driveWritable[SYSNAND_ID] = false; + + fsConfig->mountedDrives[SD_CARD_ID] = -1; + fsConfig->mountedDrives[SYSNAND_ID] = -1; + + fsConfig->defaultDrive = (isLoadedFromSD ? SD_CARD_ID : SYSNAND_ID); + fsConfig->curDrive = fsConfig->defaultDrive; + fsConfig->mountedDrives[fsConfig->curDrive] = + (f_mount(&fsConfig->driveFS[fsConfig->curDrive], fsConfig->driveNames[fsConfig->curDrive], 0) == FR_OK + && f_chdrive(fsConfig->driveNames[fsConfig->curDrive]) == FR_OK) ? 1 : 0; +} + +const char* prepareFileSystemForPath(const char* path) +{ + if (NULL == path) + return NULL; + + const char* relatPath = NULL; + if (path[0] == '/') + { + if (fsConfig->defaultDrive != fsConfig->curDrive) + { + // We assume default drive is always mounted. + fsConfig->curDrive = fsConfig->defaultDrive; + f_chdrive(fsConfig->driveNames[fsConfig->curDrive]); + } + relatPath = path; + } + else + { + int driveSize = 0; + while (path[driveSize] != '\0' && path[driveSize] != '/') + driveSize++; + if (path[driveSize] == '\0') + return NULL; + + for (int selDrive = 0 ; selDrive < MANAGED_DRIVES_COUNT ; selDrive++) + { + if (driveSize == fsConfig->drivePathSizes[selDrive] && memcmp(path, fsConfig->drivePathes[selDrive], driveSize) == 0) + { + relatPath = &path[driveSize]; + fsConfig->curDrive = selDrive; + if (fsConfig->mountedDrives[selDrive] < 0) + { + fsConfig->mountedDrives[selDrive] = + (f_mount(&fsConfig->driveFS[selDrive], fsConfig->driveNames[selDrive], 0) == FR_OK) ? 1 : 0; + } + f_chdrive(fsConfig->driveNames[selDrive]); + break; + } + } + } + return (1 == fsConfig->mountedDrives[fsConfig->curDrive]) ? relatPath : NULL; +} + +bool isDefaultDriveReadOnly() +{ + return !fsConfig->driveWritable[fsConfig->defaultDrive]; +} + +bool switchCurrentDrive(unsigned int driveID) +{ + if (driveID >= MANAGED_DRIVES_COUNT) + return false; + if (fsConfig->curDrive == driveID) + return true; + + if (fsConfig->mountedDrives[driveID] < 0) + { + fsConfig->mountedDrives[driveID] = + (f_mount(&fsConfig->driveFS[driveID], fsConfig->driveNames[driveID], 0) == FR_OK) ? 1 : 0; + } + if (fsConfig->mountedDrives[fsConfig->curDrive] < 1) + return false; + + fsConfig->curDrive = driveID; + f_chdrive(fsConfig->driveNames[driveID]); + return true; +} + +void setCurrentDriveAsDefault() +{ + switchCurrentDrive(fsConfig->defaultDrive); +} + +int getDefaultDrive() +{ + return fsConfig->defaultDrive; +} + +char* computeFullPath(const char* relative, char* absolute) +{ + if (NULL == relative || NULL == absolute) + return NULL; + if (relative[0] == '/') + sprintf(absolute, "%s%s", fsConfig->drivePathes[fsConfig->curDrive], relative); + else + sprintf(absolute, "%s", relative); + return absolute; +} #else @@ -46,7 +183,7 @@ void svcSleep(u32 millis) { #ifndef ARM9 svcSleepThread(nano); #else - ioDelay((u32) nano); + waitcycles((u32) nano); #endif } @@ -165,8 +302,9 @@ bool confirm(int confirmButton, const char *fmt, ...) { return false; } -bool fileExists(char *path) { +bool fileExists(const char *path) { #ifdef ARM9 + path = prepareFileSystemForPath(path); FIL file; if (f_open(&file, path, FA_READ) != FR_OK) { return false; @@ -191,6 +329,7 @@ bool fileExists(char *path) { size_t fileSize(const char *path) { size_t size = -1; #ifdef ARM9 + path = prepareFileSystemForPath(path); FIL file; if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) { return size; @@ -212,6 +351,7 @@ size_t fileSize(const char *path) { int fileReadOffset(const char *path, void *data, size_t size, u32 offset) { #ifdef ARM9 + path = prepareFileSystemForPath(path); FIL file; UINT bytes_read = 0; if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) { @@ -244,6 +384,29 @@ int fileRead(const char *path, void *data, size_t size) { return fileReadOffset(path, data, size, 0); } +int fileWrite(const char *path, void *data, size_t size) { +#ifdef ARM9 + path = prepareFileSystemForPath(path); + if (!fsConfig->driveWritable[fsConfig->curDrive]) + return -1; + + FIL file; + unsigned int br = 0; + f_unlink(path); + if(f_open(&file, path, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) { + return -1; + } + f_write(&file, data, size, &br); + f_close(&file); +#else + unlink(path); + FILE *file = fopen(path, "w"); + fwrite(data, 1 , size, file); + fclose(file); +#endif + return size; +} + int getFileHandleSize() { #ifdef ARM9 @@ -256,6 +419,7 @@ int getFileHandleSize() int fileHandleOpen(void* handlePtr, const char *filePath) { #ifdef ARM9 + filePath = prepareFileSystemForPath(filePath); return (f_open((FIL*)handlePtr, filePath, FA_READ | FA_OPEN_EXISTING) == FR_OK) ? 0 : -1; #else *(FILE**)handlePtr = fopen(filePath, "rb"); From a15e4e9221b2bb6f6630b84aac51cecd18b5cebf Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:16:17 +0200 Subject: [PATCH 197/259] Update utility.h --- source/utility.h | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/source/utility.h b/source/utility.h index f1a4753..0ecce38 100644 --- a/source/utility.h +++ b/source/utility.h @@ -7,10 +7,28 @@ extern "C" { #ifdef ARM9 +#define MANAGED_DRIVES_COUNT 2 +#define SD_CARD_ID 0 +#define SYSNAND_ID 1 + +void initFileSystems(bool isLoadedFromSD); + +bool isDefaultDriveReadOnly(); + +bool switchCurrentDrive(unsigned int driveID); + +void setCurrentDriveAsDefault(); + +int getDefaultDrive(); + +char* computeFullPath(const char* relative, char* absolute); + bool aptMainLoop(); void* memAlloc(unsigned int iSize); +#define START_DRIVE_RO (isDefaultDriveReadOnly()) + #else #include "descriptor.h" @@ -25,9 +43,11 @@ void openSDArchive(); void closeSDArchive(); +#define START_DRIVE_RO false + #endif -bool fileExists(char *path); +bool fileExists(const char *path); size_t fileSize(const char *path); @@ -35,6 +55,8 @@ int fileReadOffset(const char *path, void *data, size_t size, u32 offset); int fileRead(const char *path, void *data, size_t size); +int fileWrite(const char *path, void *data, size_t size); + int getFileHandleSize(); int fileHandleOpen(void* handlePtr, const char *filePath); From eb1d5e54ab7dea9116f6892bb07313236a7d711d Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:17:17 +0200 Subject: [PATCH 198/259] Update bs-start.s --- source/arm9/source/bs-start.s | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/arm9/source/bs-start.s b/source/arm9/source/bs-start.s index d8fa21e..c341c78 100644 --- a/source/arm9/source/bs-start.s +++ b/source/arm9/source/bs-start.s @@ -7,6 +7,10 @@ _start: @ Change the stack pointer mov sp, #0x27000000 + @ Store main arguments + mov r8, r0 + mov r9, r1 + @ Give read/write access to all the memory regions ldr r5, =0x33333333 mcr p15, 0, r5, c5, c0, 2 @ write data access @@ -55,6 +59,10 @@ _start: mov r1, #0x340 str r1, [r0] + @ Restore main arguments + mov r0, r8 + mov r1, r9 + bl main .die: From f03af2873865fc9fd6d7352725ccc3b50afdbf1b Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:17:59 +0200 Subject: [PATCH 199/259] Create 3dsheaders.h --- source/arm9/source/3dsheaders.h | 144 ++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 source/arm9/source/3dsheaders.h diff --git a/source/arm9/source/3dsheaders.h b/source/arm9/source/3dsheaders.h new file mode 100644 index 0000000..6e9e928 --- /dev/null +++ b/source/arm9/source/3dsheaders.h @@ -0,0 +1,144 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified +* reasonable legal notices or author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +*/ + +/* +* Adapted from 3DBrew and https://github.com/mid-kid/CakesForeveryWan/blob/master/source/headers.h +*/ + +#pragma once + +typedef struct __attribute__((packed)) +{ + u32 address; + u32 phyRegionSize; + u32 size; +} CodeSetInfo; + +typedef struct __attribute__((packed)) +{ + u32 saveDataSize[2]; + u32 jumpID[2]; + u8 reserved[0x30]; +} SystemInfo; + +typedef struct __attribute__((packed)) +{ + char appTitle[8]; + u8 reserved1[5]; + u8 flag; + u8 remasterVersion[2]; + CodeSetInfo textCodeSet; + u32 stackSize; + CodeSetInfo roCodeSet; + u8 reserved2[4]; + CodeSetInfo dataCodeSet; + u32 bssSize; + char depends[0x180]; + SystemInfo systemInfo; +} SystemControlInfo; + +typedef struct __attribute__((packed)) +{ + SystemControlInfo systemControlInfo; + u8 aci[0x200]; + u8 accessDescSig[0x100]; + u8 ncchPubKey[0x100]; + u8 aciLim[0x200]; +} ExHeader; + +typedef struct __attribute__((packed)) +{ + u8 sig[0x100]; //RSA-2048 signature of the NCCH header, using SHA-256 + char magic[4]; //NCCH + u32 contentSize; //Media unit + u8 partitionId[8]; + u8 makerCode[2]; + u16 version; + u8 reserved1[4]; + u8 programID[8]; + u8 reserved2[0x10]; + u8 logoHash[0x20]; //Logo Region SHA-256 hash + char productCode[0x10]; + u8 exHeaderHash[0x20]; //Extended header SHA-256 hash + u32 exHeaderSize; //Extended header size + u32 reserved3; + u8 flags[8]; + u32 plainOffset; //Media unit + u32 plainSize; //Media unit + u32 logoOffset; //Media unit + u32 logoSize; //Media unit + u32 exeFsOffset; //Media unit + u32 exeFsSize; //Media unit + u32 exeFsHashSize; //Media unit + u32 reserved4; + u32 romFsOffset; //Media unit + u32 romFsSize; //Media unit + u32 romFsHashSize; //Media unit + u32 reserved5; + u8 exeFsHash[0x20]; //ExeFS superblock SHA-256 hash + u8 romFsHash[0x20]; //RomFS superblock SHA-256 hash +} Ncch; + +typedef struct __attribute__((packed)) +{ + Ncch ncch; + ExHeader exHeader; +} Cxi; + +typedef struct __attribute__((packed)) +{ + char sigIssuer[0x40]; + u8 eccPubKey[0x3C]; + u8 version; + u8 caCrlVersion; + u8 signerCrlVersion; + u8 titleKey[0x10]; + u8 reserved1; + u8 ticketId[8]; + u8 consoleId[4]; + u8 titleId[8]; + u8 reserved2[2]; + u16 ticketTitleVersion; + u8 reserved3[8]; + u8 licenseType; + u8 ticketCommonKeyYIndex; //Ticket common keyY index, usually 0x1 for retail system titles. + u8 reserved4[0x2A]; + u8 unk[4]; //eShop Account ID? + u8 reserved5; + u8 audit; + u8 reserved6[0x42]; + u8 limits[0x40]; + u8 contentIndex[0xAC]; +} Ticket; + +typedef struct __attribute__((packed)) +{ + u8 keyX[0x10]; + u8 keyY[0x10]; + u8 ctr[0x10]; + char size[8]; + u8 reserved[8]; + u8 ctlBlock[0x10]; + char magic[4]; + u8 reserved2[0xC]; + u8 slot0x16keyX[0x10]; +} Arm9Bin; From 62ed427b02f8c67545199bee0aa7eb0f118dc32c Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:18:33 +0200 Subject: [PATCH 200/259] Create common.c --- source/arm9/source/common.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 source/arm9/source/common.c diff --git a/source/arm9/source/common.c b/source/arm9/source/common.c new file mode 100644 index 0000000..c5af4c6 --- /dev/null +++ b/source/arm9/source/common.c @@ -0,0 +1,23 @@ +#include "common.h" + +u32 hexAtoi(const char *in, u32 digits) +{ + u32 res = 0; + char *tmp = (char *)in; + + for(u32 i = 0; i < digits && *tmp != 0; tmp++, i++) + res = (*tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0') + (res << 4); + + return res; +} + +u32 decAtoi(const char *in, u32 digits) +{ + u32 res = 0; + char *tmp = (char *)in; + + for(u32 i = 0; i < digits && *tmp != 0; tmp++, i++) + res = *tmp - '0' + res * 10; + + return res; +} From 24797641d7f9312c8117ea924fe19cd57ea6b0ed Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:18:54 +0200 Subject: [PATCH 201/259] Update common.h --- source/arm9/source/common.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/source/arm9/source/common.h b/source/arm9/source/common.h index 7b86eff..271f0a9 100644 --- a/source/arm9/source/common.h +++ b/source/arm9/source/common.h @@ -38,3 +38,18 @@ #define getle64(d) (*((u64*) (d))) #define align(v,a) \ (((v) % (a)) ? ((v) + (a) - ((v) % (a))) : (v)) + +#define CFG_SYSPROT9 (*(vu8 *)0x10000000) +#define CFG_BOOTENV (*(vu32 *)0x10010000) +#define CFG_UNITINFO (*(vu8 *)0x10010010) +#define CFG_TWLUNITINFO (*(vu8 *)0x10010014) +#define OTP_DEVCONSOLEID (*(vu64 *)0x10012000) +#define OTP_TWLCONSOLEID (*(vu64 *)0x10012100) +#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC) +#define PDN_SPI_CNT (*(vu32 *)0x101401C0) + +#define ISN3DS (PDN_MPCORE_CFG == 7) +#define ISDEVUNIT (CFG_UNITINFO != 0) + +u32 hexAtoi(const char *in, u32 digits); +u32 decAtoi(const char *in, u32 digits); From ede907612051a541e4d3942732a27a771bce2cf1 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:19:51 +0200 Subject: [PATCH 202/259] Update and rename sha.c to crypto.c --- source/arm9/source/crypto.c | 500 ++++++++++++++++++++++++++++++++++++ source/arm9/source/sha.c | 44 ---- 2 files changed, 500 insertions(+), 44 deletions(-) create mode 100644 source/arm9/source/crypto.c delete mode 100644 source/arm9/source/sha.c diff --git a/source/arm9/source/crypto.c b/source/arm9/source/crypto.c new file mode 100644 index 0000000..0a99833 --- /dev/null +++ b/source/arm9/source/crypto.c @@ -0,0 +1,500 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified +* reasonable legal notices or author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +*/ + +/* +* Crypto libs from http://github.com/b1l1s/ctr +* kernel9Loader code originally adapted from https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233 +* decryptNusFirm code adapted from https://github.com/mid-kid/CakesForeveryWan/blob/master/source/firm.c +* ctrNandWrite logic adapted from https://github.com/d0k3/GodMode9/blob/master/source/nand/nand.c +*/ + +#include "crypto.h" + +//#include "memory.h" +#include "strings.h" +//#include "utils.h" +#include "fatfs/sdmmc/sdmmc.h" + +/**************************************************************** +* Crypto libs +****************************************************************/ + +/* original version by megazig */ + +#ifndef __thumb__ +#define BSWAP32(x) {\ + __asm__\ + (\ + "eor r1, %1, %1, ror #16\n\t"\ + "bic r1, r1, #0xFF0000\n\t"\ + "mov %0, %1, ror #8\n\t"\ + "eor %0, %0, r1, lsr #8\n\t"\ + :"=r"(x)\ + :"0"(x)\ + :"r1"\ + );\ +}; + +#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\ +__asm__\ + (\ + "adds %0, %4\n\t"\ + "addcss %1, %1, #1\n\t"\ + "addcss %2, %2, #1\n\t"\ + "addcs %3, %3, #1\n\t"\ + : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\ + : "r"(u32_0)\ + : "cc"\ + );\ +} +#else +#define BSWAP32(x) {x = __builtin_bswap32(x);} + +#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\ +__asm__\ + (\ + "mov r4, #0\n\t"\ + "add %0, %0, %4\n\t"\ + "adc %1, %1, r4\n\t"\ + "adc %2, %2, r4\n\t"\ + "adc %3, %3, r4\n\t"\ + : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\ + : "r"(u32_0)\ + : "cc", "r4"\ + );\ +} +#endif /*__thumb__*/ + +static void aes_setkey(u8 keyslot, const void *key, u32 keyType, u32 mode) +{ + u32 *key32 = (u32 *)key; + *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode; + + if(keyslot <= 3) + { + if((mode & AES_CNT_INPUT_ORDER) == AES_INPUT_REVERSED) + { + REGs_AESTWLKEYS[keyslot][keyType][0] = key32[3]; + REGs_AESTWLKEYS[keyslot][keyType][1] = key32[2]; + REGs_AESTWLKEYS[keyslot][keyType][2] = key32[1]; + REGs_AESTWLKEYS[keyslot][keyType][3] = key32[0]; + } + else + { + REGs_AESTWLKEYS[keyslot][keyType][0] = key32[0]; + REGs_AESTWLKEYS[keyslot][keyType][1] = key32[1]; + REGs_AESTWLKEYS[keyslot][keyType][2] = key32[2]; + REGs_AESTWLKEYS[keyslot][keyType][3] = key32[3]; + } + } + + else if(keyslot < 0x40) + { + *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE; + + REG_AESKEYFIFO[keyType] = key32[0]; + REG_AESKEYFIFO[keyType] = key32[1]; + REG_AESKEYFIFO[keyType] = key32[2]; + REG_AESKEYFIFO[keyType] = key32[3]; + } +} + +static void aes_use_keyslot(u8 keyslot) +{ + if(keyslot > 0x3F) + return; + + *REG_AESKEYSEL = keyslot; + *REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */ +} + +static void aes_setiv(const void *iv, u32 mode) +{ + const u32 *iv32 = (const u32 *)iv; + *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode; + + //Word order for IV can't be changed in REG_AESCNT and always default to reversed + if(mode & AES_INPUT_NORMAL) + { + REG_AESCTR[0] = iv32[3]; + REG_AESCTR[1] = iv32[2]; + REG_AESCTR[2] = iv32[1]; + REG_AESCTR[3] = iv32[0]; + } + else + { + REG_AESCTR[0] = iv32[0]; + REG_AESCTR[1] = iv32[1]; + REG_AESCTR[2] = iv32[2]; + REG_AESCTR[3] = iv32[3]; + } +} + +static void aes_advctr(void *ctr, u32 val, u32 mode) +{ + u32 *ctr32 = (u32 *)ctr; + + int i; + if(mode & AES_INPUT_BE) + { + for(i = 0; i < 4; ++i) //Endian swap + BSWAP32(ctr32[i]); + } + + if(mode & AES_INPUT_NORMAL) + { + ADD_u128_u32(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val); + } + else + { + ADD_u128_u32(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val); + } + + if(mode & AES_INPUT_BE) + { + for(i = 0; i < 4; ++i) //Endian swap + BSWAP32(ctr32[i]); + } +} + +static void aes_change_ctrmode(void *ctr, u32 fromMode, u32 toMode) +{ + u32 *ctr32 = (u32 *)ctr; + int i; + if((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN) + { + for(i = 0; i < 4; ++i) + BSWAP32(ctr32[i]); + } + + if((fromMode ^ toMode) & AES_CNT_INPUT_ORDER) + { + u32 temp = ctr32[0]; + ctr32[0] = ctr32[3]; + ctr32[3] = temp; + + temp = ctr32[1]; + ctr32[1] = ctr32[2]; + ctr32[2] = temp; + } +} + +static void aes_batch(void *dst, const void *src, u32 blockCount) +{ + *REG_AESBLKCNT = blockCount << 16; + *REG_AESCNT |= AES_CNT_START; + + const u32 *src32 = (const u32 *)src; + u32 *dst32 = (u32 *)dst; + + u32 wbc = blockCount; + u32 rbc = blockCount; + + while(rbc) + { + if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) //There's space for at least 4 ints + { + *REG_AESWRFIFO = *src32++; + *REG_AESWRFIFO = *src32++; + *REG_AESWRFIFO = *src32++; + *REG_AESWRFIFO = *src32++; + wbc--; + } + + if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) //At least 4 ints available for read + { + *dst32++ = *REG_AESRDFIFO; + *dst32++ = *REG_AESRDFIFO; + *dst32++ = *REG_AESRDFIFO; + *dst32++ = *REG_AESRDFIFO; + rbc--; + } + } +} + +void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode, u32 ivMode) +{ + *REG_AESCNT = mode | + AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | + AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN | + AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE; + + u32 blocks; + while(blockCount != 0) + { + if((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE + && (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE) + aes_setiv(iv, ivMode); + + blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount; + + //Save the last block for the next decryption CBC batch's iv + if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE) + { + memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); + aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode); + } + + //Process the current batch + aes_batch(dst, src, blocks); + + //Save the last block for the next encryption CBC batch's iv + if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE) + { + memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); + aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode); + } + + //Advance counter for CTR mode + else if((mode & AES_ALL_MODES) == AES_CTR_MODE) + aes_advctr(iv, blocks, ivMode); + + src += blocks * AES_BLOCK_SIZE; + dst += blocks * AES_BLOCK_SIZE; + blockCount -= blocks; + } +} + +static void sha_wait_idle() +{ + while(*REG_SHA_CNT & 1); +} + +void sha(void *res, const void *src, u32 size, u32 mode) +{ + sha_wait_idle(); + *REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND; + + const u32 *src32 = (const u32 *)src; + int i; + while(size >= 0x40) + { + sha_wait_idle(); + for(i = 0; i < 4; ++i) + { + *REG_SHA_INFIFO = *src32++; + *REG_SHA_INFIFO = *src32++; + *REG_SHA_INFIFO = *src32++; + *REG_SHA_INFIFO = *src32++; + } + + size -= 0x40; + } + + sha_wait_idle(); + memcpy((void *)REG_SHA_INFIFO, src32, size); + + *REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND; + + while(*REG_SHA_CNT & SHA_FINAL_ROUND); + sha_wait_idle(); + + u32 hashSize = SHA_256_HASH_SIZE; + if(mode == SHA_224_MODE) + hashSize = SHA_224_HASH_SIZE; + else if(mode == SHA_1_MODE) + hashSize = SHA_1_HASH_SIZE; + + memcpy(res, (void *)REG_SHA_HASH, hashSize); +} + +/*****************************************************************/ + +__attribute__((aligned(4))) static u8 nandCtr[AES_BLOCK_SIZE]; +static u8 nandSlot; +static u32 fatStart; + +void ctrNandInit(void) +{ + __attribute__((aligned(4))) u8 cid[AES_BLOCK_SIZE], + shaSum[SHA_256_HASH_SIZE]; + + sdmmc_get_cid(1, (u32 *)cid); + sha(shaSum, cid, sizeof(cid), SHA_256_MODE); + memcpy(nandCtr, shaSum, sizeof(nandCtr)); + + if(ISN3DS) + { + __attribute__((aligned(4))) u8 keyY0x5[AES_BLOCK_SIZE] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE}; + aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); + + nandSlot = 0x05; + fatStart = 0x5CAD7; + } + else + { + nandSlot = 0x04; + fatStart = 0x5CAE5; + } +} + +int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf) +{ + __attribute__((aligned(4))) u8 tmpCtr[sizeof(nandCtr)]; + memcpy(tmpCtr, nandCtr, sizeof(nandCtr)); + aes_advctr(tmpCtr, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL); + + //Read only SYSNAND + int result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf); + + //Decrypt + aes_use_keyslot(nandSlot); + aes(outbuf, outbuf, sectorCount * 0x200 / AES_BLOCK_SIZE, tmpCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + + return result; +} + +int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf) +{ + u8 *buffer = (u8 *)0x23000000; + u32 bufferSize = 0xF00000; + + __attribute__((aligned(4))) u8 tmpCtr[sizeof(nandCtr)]; + memcpy(tmpCtr, nandCtr, sizeof(nandCtr)); + aes_advctr(tmpCtr, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_use_keyslot(nandSlot); + + int result = 0; + for(u32 tempSector = 0; tempSector < sectorCount && !result; tempSector += bufferSize / 0x200) + { + u32 tempCount = (bufferSize / 0x200) < (sectorCount - tempSector) ? (bufferSize / 0x200) : (sectorCount - tempSector); + + memcpy(buffer, inbuf + (tempSector * 0x200), tempCount * 0x200); + + //Encrypt + aes(buffer, buffer, tempCount * 0x200 / AES_BLOCK_SIZE, tmpCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + + //Write + result = sdmmc_nand_writesectors(tempSector + sector + fatStart, tempCount, buffer); + } + + return result; +} + +bool decryptExeFs(Cxi *cxi) +{ + if(memcmp(cxi->ncch.magic, "NCCH", 4) != 0) return false; + + u8 *exeFsOffset = (u8 *)cxi + (cxi->ncch.exeFsOffset + 1) * 0x200; + u32 exeFsSize = (cxi->ncch.exeFsSize - 1) * 0x200; + __attribute__((aligned(4))) u8 ncchCtr[AES_BLOCK_SIZE] = {0}; + + for(u32 i = 0; i < 8; i++) + ncchCtr[7 - i] = cxi->ncch.partitionId[i]; + ncchCtr[8] = 2; + + aes_setkey(0x2C, cxi, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_advctr(ncchCtr, 0x200 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_use_keyslot(0x2C); + aes(cxi, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + + return memcmp(cxi, "FIRM", 4) == 0; +} + +bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize) +{ + if(memcmp(ticket->sigIssuer, "Root", 4) != 0) return false; + + __attribute__((aligned(4))) const u8 keyY0x3D[AES_BLOCK_SIZE] = {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C}; + __attribute__((aligned(4))) u8 titleKey[AES_BLOCK_SIZE], + cetkIv[AES_BLOCK_SIZE] = {0}; + memcpy(titleKey, ticket->titleKey, sizeof(titleKey)); + memcpy(cetkIv, ticket->titleId, sizeof(ticket->titleId)); + + aes_setkey(0x3D, keyY0x3D, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_use_keyslot(0x3D); + aes(titleKey, titleKey, 1, cetkIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + + __attribute__((aligned(4))) u8 ncchIv[AES_BLOCK_SIZE] = {0}; + + aes_setkey(0x16, titleKey, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_use_keyslot(0x16); + aes(cxi, cxi, ncchSize / AES_BLOCK_SIZE, ncchIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + + return decryptExeFs(cxi); +} + +void kernel9Loader(Arm9Bin *arm9Section) +{ + //Determine the kernel9loader version + u32 k9lVersion; + switch(arm9Section->magic[3]) + { + case 0xFF: + k9lVersion = 0; + break; + case '1': + k9lVersion = 1; + break; + default: + k9lVersion = 2; + } + + u32 *startOfArm9Bin = (u32 *)((u8 *)arm9Section + 0x800); + if(*startOfArm9Bin == 0x47704770 || *startOfArm9Bin == 0xB0862000) return; //Already decrypted + + //Set 0x11 keyslot + __attribute__((aligned(4))) const u8 key1s[2][AES_BLOCK_SIZE] = { + {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8}, + {0xA2, 0xF4, 0x00, 0x3C, 0x7A, 0x95, 0x10, 0x25, 0xDF, 0x4E, 0x9E, 0x74, 0xE3, 0x0C, 0x92, 0x99} + }, + key2s[2][AES_BLOCK_SIZE] = { + {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0}, + {0xFF, 0x77, 0xA0, 0x9A, 0x99, 0x81, 0xE9, 0x48, 0xEC, 0x51, 0xC9, 0x32, 0x5D, 0x14, 0xEC, 0x25} + }; + + aes_setkey(0x11, k9lVersion == 2 ? key2s[ISDEVUNIT ? 1 : 0] : key1s[ISDEVUNIT ? 1 : 0], AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); + + u8 arm9BinSlot = k9lVersion == 0 ? 0x15 : 0x16; + + //Set keyX + __attribute__((aligned(4))) u8 keyX[AES_BLOCK_SIZE]; + aes_use_keyslot(0x11); + aes(keyX, k9lVersion == 0 ? arm9Section->keyX : arm9Section->slot0x16keyX, 1, NULL, AES_ECB_DECRYPT_MODE, 0); + aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); + + //Set keyY + __attribute__((aligned(4))) u8 keyY[AES_BLOCK_SIZE]; + memcpy(keyY, arm9Section->keyY, sizeof(keyY)); + aes_setkey(arm9BinSlot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); + + //Set CTR + __attribute__((aligned(4))) u8 arm9BinCtr[AES_BLOCK_SIZE]; + memcpy(arm9BinCtr, arm9Section->ctr, sizeof(arm9BinCtr)); + + //Decrypt ARM9 binary + aes_use_keyslot(arm9BinSlot); + aes(startOfArm9Bin, startOfArm9Bin, decAtoi(arm9Section->size, sizeof(arm9Section->size)) / AES_BLOCK_SIZE, arm9BinCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + + //if(*startOfArm9Bin != 0x47704770 && *startOfArm9Bin != 0xB0862000) error("Failed to decrypt the ARM9 binary."); +} + +void computePinHash(u8 *outbuf, const u8 *inbuf) +{ + __attribute__((aligned(4))) u8 cid[AES_BLOCK_SIZE], + cipherText[AES_BLOCK_SIZE]; + + sdmmc_get_cid(1, (u32 *)cid); + aes_use_keyslot(0x04); //Console-unique keyslot whose keys are set by the ARM9 bootROM + aes(cipherText, inbuf, 1, cid, AES_CBC_ENCRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + sha(outbuf, cipherText, sizeof(cipherText), SHA_256_MODE); +} diff --git a/source/arm9/source/sha.c b/source/arm9/source/sha.c deleted file mode 100644 index 6b2c4d7..0000000 --- a/source/arm9/source/sha.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "sha.h" - -static void sha_wait_idle() -{ - while(*REG_SHA_CNT & 1); -} - -void sha(void *res, const void *src, u32 size, u32 mode) -{ - sha_wait_idle(); - *REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND; - - const u32 *src32 = (const u32 *)src; - int i; - while(size >= 0x40) - { - sha_wait_idle(); - for(i = 0; i < 4; ++i) - { - *REG_SHA_INFIFO = *src32++; - *REG_SHA_INFIFO = *src32++; - *REG_SHA_INFIFO = *src32++; - *REG_SHA_INFIFO = *src32++; - } - - size -= 0x40; - } - - sha_wait_idle(); - memcpy((void *)REG_SHA_INFIFO, src32, size); - - *REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND; - - while(*REG_SHA_CNT & SHA_FINAL_ROUND); - sha_wait_idle(); - - u32 hashSize = SHA_256_HASH_SIZE; - if(mode == SHA_224_MODE) - hashSize = SHA_224_HASH_SIZE; - else if(mode == SHA_1_MODE) - hashSize = SHA_1_HASH_SIZE; - - memcpy(res, (void *)REG_SHA_HASH, hashSize); -} From 09c2d088ea8ba88a2b316ac42589d66dc15ca59a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:20:23 +0200 Subject: [PATCH 203/259] Update and rename sha.h to crypto.h --- source/arm9/source/crypto.h | 118 ++++++++++++++++++++++++++++++++++++ source/arm9/source/sha.h | 32 ---------- 2 files changed, 118 insertions(+), 32 deletions(-) create mode 100644 source/arm9/source/crypto.h delete mode 100644 source/arm9/source/sha.h diff --git a/source/arm9/source/crypto.h b/source/arm9/source/crypto.h new file mode 100644 index 0000000..ddbae83 --- /dev/null +++ b/source/arm9/source/crypto.h @@ -0,0 +1,118 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified +* reasonable legal notices or author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +*/ + +/* +* Crypto libs from http://github.com/b1l1s/ctr +* kernel9Loader code originally adapted from https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233 +* decryptNusFirm code adapted from https://github.com/mid-kid/CakesForeveryWan/blob/master/source/firm.c +* ctrNandWrite logic adapted from https://github.com/d0k3/GodMode9/blob/master/source/nand/nand.c +*/ + +#pragma once + +#include "common.h" +#include "firm.h" +#include "3dsheaders.h" + +/**************************AES****************************/ +#define REG_AESCNT ((vu32 *)0x10009000) +#define REG_AESBLKCNT ((vu32 *)0x10009004) +#define REG_AESWRFIFO ((vu32 *)0x10009008) +#define REG_AESRDFIFO ((vu32 *)0x1000900C) +#define REG_AESKEYSEL ((vu8 *)0x10009010) +#define REG_AESKEYCNT ((vu8 *)0x10009011) +#define REG_AESCTR ((vu32 *)0x10009020) + +#define REG_AESKEYFIFO ((vu32 *)0x10009100) +#define REG_AESKEYXFIFO ((vu32 *)0x10009104) +#define REG_AESKEYYFIFO ((vu32 *)0x10009108) + +#define REGs_AESTWLKEYS (*((vu32 (*)[4][3][4])0x10009040)) + +#define AES_CCM_DECRYPT_MODE (0u << 27) +#define AES_CCM_ENCRYPT_MODE (1u << 27) +#define AES_CTR_MODE (2u << 27) +#define AES_CTR_MODE (2u << 27) +#define AES_CBC_DECRYPT_MODE (4u << 27) +#define AES_CBC_ENCRYPT_MODE (5u << 27) +#define AES_ECB_DECRYPT_MODE (6u << 27) +#define AES_ECB_ENCRYPT_MODE (7u << 27) +#define AES_ALL_MODES (7u << 27) + +#define AES_CNT_START 0x80000000 +#define AES_CNT_INPUT_ORDER 0x02000000 +#define AES_CNT_OUTPUT_ORDER 0x01000000 +#define AES_CNT_INPUT_ENDIAN 0x00800000 +#define AES_CNT_OUTPUT_ENDIAN 0x00400000 +#define AES_CNT_FLUSH_READ 0x00000800 +#define AES_CNT_FLUSH_WRITE 0x00000400 + +#define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN) +#define AES_INPUT_LE 0 +#define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER) +#define AES_INPUT_REVERSED 0 + +#define AES_BLOCK_SIZE 0x10 + +#define AES_KEYCNT_WRITE (1 << 0x7) +#define AES_KEYNORMAL 0 +#define AES_KEYX 1 +#define AES_KEYY 2 + +/**************************SHA****************************/ +#define REG_SHA_CNT ((vu32 *)0x1000A000) +#define REG_SHA_BLKCNT ((vu32 *)0x1000A004) +#define REG_SHA_HASH ((vu32 *)0x1000A040) +#define REG_SHA_INFIFO ((vu32 *)0x1000A080) + +#define SHA_CNT_STATE 0x00000003 +#define SHA_CNT_UNK2 0x00000004 +#define SHA_CNT_OUTPUT_ENDIAN 0x00000008 +#define SHA_CNT_MODE 0x00000030 +#define SHA_CNT_ENABLE 0x00010000 +#define SHA_CNT_ACTIVE 0x00020000 + +#define SHA_HASH_READY 0x00000000 +#define SHA_NORMAL_ROUND 0x00000001 +#define SHA_FINAL_ROUND 0x00000002 + +#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN +#define SHA_OUTPUT_LE 0 + +#define SHA_256_MODE 0 +#define SHA_224_MODE 0x00000010 +#define SHA_1_MODE 0x00000020 + +#define SHA_256_HASH_SIZE (256 / 8) +#define SHA_224_HASH_SIZE (224 / 8) +#define SHA_1_HASH_SIZE (160 / 8) + +void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode, u32 ivMode); +void sha(void *res, const void *src, u32 size, u32 mode); + +void ctrNandInit(void); +int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf); +int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf); +bool decryptExeFs(Cxi *cxi); +bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize); +void kernel9Loader(Arm9Bin *arm9Section); +void computePinHash(u8 *outbuf, const u8 *inbuf); diff --git a/source/arm9/source/sha.h b/source/arm9/source/sha.h deleted file mode 100644 index ec1fc07..0000000 --- a/source/arm9/source/sha.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "common.h" - -#define REG_SHA_CNT ((vu32 *)0x1000A000) -#define REG_SHA_BLKCNT ((vu32 *)0x1000A004) -#define REG_SHA_HASH ((vu32 *)0x1000A040) -#define REG_SHA_INFIFO ((vu32 *)0x1000A080) - -#define SHA_CNT_STATE 0x00000003 -#define SHA_CNT_UNK2 0x00000004 -#define SHA_CNT_OUTPUT_ENDIAN 0x00000008 -#define SHA_CNT_MODE 0x00000030 -#define SHA_CNT_ENABLE 0x00010000 -#define SHA_CNT_ACTIVE 0x00020000 - -#define SHA_HASH_READY 0x00000000 -#define SHA_NORMAL_ROUND 0x00000001 -#define SHA_FINAL_ROUND 0x00000002 - -#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN -#define SHA_OUTPUT_LE 0 - -#define SHA_256_MODE 0 -#define SHA_224_MODE 0x00000010 -#define SHA_1_MODE 0x00000020 - -#define SHA_256_HASH_SIZE (256 / 8) -#define SHA_224_HASH_SIZE (224 / 8) -#define SHA_1_HASH_SIZE (160 / 8) - -void sha(void *res, const void *src, u32 size, u32 mode); From 133c2482295e25cea6fe293b573ba2288f516492 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:20:48 +0200 Subject: [PATCH 204/259] Update firm.c --- source/arm9/source/firm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/arm9/source/firm.c b/source/arm9/source/firm.c index ee2dc89..d70fa9f 100644 --- a/source/arm9/source/firm.c +++ b/source/arm9/source/firm.c @@ -1,6 +1,6 @@ #include "firm.h" -#include "sha.h" +#include "crypto.h" static __attribute__((noinline)) bool overlaps(u32 as, u32 ae, u32 bs, u32 be) { From c09b109c0d49e270ffc9edf4e1bc6d632d479392 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:22:12 +0200 Subject: [PATCH 205/259] Update 00history.txt --- source/arm9/source/fatfs/00history.txt | 44 +++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/source/arm9/source/fatfs/00history.txt b/source/arm9/source/fatfs/00history.txt index 464850b..2d71a3d 100644 --- a/source/arm9/source/fatfs/00history.txt +++ b/source/arm9/source/fatfs/00history.txt @@ -10,7 +10,7 @@ R0.00 (February 26, 2006) R0.01 (April 29, 2006) - First stable version. + The first release. @@ -212,7 +212,7 @@ R0.10a (January 15, 2014) R0.10b (May 19, 2014) Fixed a hard error in the disk I/O layer can collapse the directory entry. - Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07) + Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07) @@ -246,9 +246,43 @@ R0.11a (September 05, 2015) R0.12 (April 12, 2016) - Added support of exFAT file system. (_FS_EXFAT) + Added support for exFAT file system. (_FS_EXFAT) Added f_expand(). (_USE_EXPAND) Changed some members in FINFO structure and behavior of f_readdir(). - Added an option _USE_CHMOD and removed an option _WORD_ACCESS. - Fixed errors in the case conversion teble of Unicode (cc*.c). + Added an option _USE_CHMOD. + Removed an option _WORD_ACCESS. + Fixed errors in the case conversion table of Unicode (cc*.c). + + + +R0.12a (July 10, 2016) + + Added support for creating exFAT volume with some changes of f_mkfs(). + Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed. + f_forward() is available regardless of _FS_TINY. + Fixed f_mkfs() creates wrong volume. (appeared at R0.12) + Fixed wrong memory read in create_name(). (appeared at R0.12) + Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD. + + + +R0.12b (September 04, 2016) + + Made f_rename() be able to rename objects with the same name but case. + Fixed an error in the case conversion teble of code page 866. (ff.c) + Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12) + Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12) + Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12) + Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12) + Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12) + Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12) + + + +R0.12c (March 04, 2017) + + Improved write throughput at the fragmented file on the exFAT volume. + Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN. + Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12) + Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c) From 872fb916581fa6d76c0eb862f2e137e48338f6a1 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:22:39 +0200 Subject: [PATCH 206/259] Update 00readme.txt --- source/arm9/source/fatfs/00readme.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/source/arm9/source/fatfs/00readme.txt b/source/arm9/source/fatfs/00readme.txt index bd04d18..dfa51ed 100644 --- a/source/arm9/source/fatfs/00readme.txt +++ b/source/arm9/source/fatfs/00readme.txt @@ -1,21 +1,21 @@ -FatFs Module Source Files R0.12 +FatFs Module Source Files R0.12c FILES - 00readme.txt This file. - history.txt Revision history. - ffconf.h Configuration file for FatFs module. - ff.h Common include file for FatFs and application module. - ff.c FatFs module. - diskio.h Common include file for FatFs and disk I/O module. - diskio.c An example of glue function to attach existing disk I/O module to FatFs. - integer.h Integer type definitions for FatFs. - option Optional external functions. + 00readme.txt This file. + 00history.txt Revision history. + ff.c FatFs module. + ffconf.h Configuration file of FatFs module. + ff.h Common include file for FatFs and application module. + diskio.h Common include file for FatFs and disk I/O module. + diskio.c An example of glue function to attach existing disk I/O module to FatFs. + integer.h Integer type definitions for FatFs. + option Optional external modules. Low level disk I/O module is not included in this archive because the FatFs - module is only a generic file system layer and not depend on any specific - storage device. You have to provide a low level disk I/O module that written - to control the target storage device. + module is only a generic file system layer and it does not depend on any specific + storage device. You have to provide a low level disk I/O module written to + control the storage device that attached to the target system. From 479f853fd7a0b17b404a83d931d883d1ba964152 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:23:07 +0200 Subject: [PATCH 207/259] Update diskio.c --- source/arm9/source/fatfs/diskio.c | 48 ++++++++++++------------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/source/arm9/source/fatfs/diskio.c b/source/arm9/source/fatfs/diskio.c index 1b2b83c..4dd504c 100644 --- a/source/arm9/source/fatfs/diskio.c +++ b/source/arm9/source/fatfs/diskio.c @@ -9,10 +9,11 @@ #include "diskio.h" /* FatFs lower layer API */ #include "sdmmc/sdmmc.h" +#include "../crypto.h" /* Definitions of physical drive number for each media */ #define SDCARD 0 -//#define CTRNAND 1 +#define CTRNAND 1 /*-----------------------------------------------------------------------*/ /* Get Drive Status */ @@ -36,19 +37,23 @@ DSTATUS disk_initialize ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { - switch(pdrv) + DSTATUS ret; + static u32 sdmmcInitResult = 4; + + if(sdmmcInitResult == 4) sdmmcInitResult = sdmmc_sdcard_init(); + + if(pdrv == CTRNAND) { - case SDCARD: - sdmmc_sdcard_init(); - break; - #ifdef CTRNAND - case CTRNAND: + if(!(sdmmcInitResult & 1)) + { ctrNandInit(); - break; - #endif + ret = 0; + } + else ret = STA_NOINIT; } + else ret = (!(sdmmcInitResult & 2)) ? 0 : STA_NOINIT; - return RES_OK; + return ret; } @@ -64,21 +69,8 @@ DRESULT disk_read ( UINT count /* Number of sectors to read */ ) { - switch(pdrv) - { - case SDCARD: - if(sdmmc_sdcard_readsectors(sector, count, (BYTE *)buff)) - return RES_PARERR; - break; - #ifdef CTRNAND - case CTRNAND: - if(ctrNandRead(sector, count, (BYTE *)buff)) - return RES_PARERR; - break; - #endif - } - - return RES_OK; + return ((pdrv == SDCARD && !sdmmc_sdcard_readsectors(sector, count, buff)) || + (pdrv == CTRNAND && !ctrNandRead(sector, count, buff))) ? RES_OK : RES_PARERR; } @@ -95,10 +87,8 @@ DRESULT disk_write ( UINT count /* Number of sectors to write */ ) { - if(pdrv == SDCARD && sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) - return RES_PARERR; - - return RES_OK; + return ((pdrv == SDCARD && !sdmmc_sdcard_writesectors(sector, count, buff)) || + (pdrv == CTRNAND && !ctrNandWrite(sector, count, buff))) ? RES_OK : RES_PARERR; } #endif From 46c493bb3821c1c60cf510469230eb5458c36589 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:23:46 +0200 Subject: [PATCH 208/259] Update ff.c --- source/arm9/source/fatfs/ff.c | 2315 +++++++++++++++++++-------------- 1 file changed, 1338 insertions(+), 977 deletions(-) diff --git a/source/arm9/source/fatfs/ff.c b/source/arm9/source/fatfs/ff.c index ac26023..eaf9d85 100644 --- a/source/arm9/source/fatfs/ff.c +++ b/source/arm9/source/fatfs/ff.c @@ -1,10 +1,12 @@ /*----------------------------------------------------------------------------/ -/ FatFs - FAT file system module R0.12 (C)ChaN, 2016 / +/ FatFs - Generic FAT file system module R0.12c / /-----------------------------------------------------------------------------/ -/ FatFs module is a free software that opened under license policy of -/ following conditions. / -/ Copyright (C) 2016, ChaN, all right reserved. +/ Copyright (C) 2017, ChaN, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: / / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. @@ -17,7 +19,7 @@ #include "ff.h" /* Declarations of FatFs API */ -#include "diskio.h" /* Declarations of disk I/O functions */ +#include "diskio.h" /* Declarations of device I/O functions */ /*-------------------------------------------------------------------------- @@ -26,63 +28,11 @@ ---------------------------------------------------------------------------*/ -#if _FATFS != 88100 /* Revision ID */ +#if _FATFS != 68300 /* Revision ID */ #error Wrong include file (ff.h). #endif -/* Reentrancy related */ -#if _FS_REENTRANT -#if _USE_LFN == 1 -#error Static LFN work area cannot be used at thread-safe configuration -#endif -#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } -#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } -#else -#define ENTER_FF(fs) -#define LEAVE_FF(fs, res) return res -#endif - -#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } - - -/* Definitions of sector size */ -#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096) -#error Wrong sector size configuration -#endif -#if _MAX_SS == _MIN_SS -#define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */ -#else -#define SS(fs) ((fs)->ssize) /* Variable sector size */ -#endif - - -/* Timestamp */ -#if _FS_NORTC == 1 -#if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31 -#error Invalid _FS_NORTC settings -#endif -#define GET_FATTIME() ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16) -#else -#define GET_FATTIME() get_fattime() -#endif - - -/* File lock controls */ -#if _FS_LOCK != 0 -#if _FS_READONLY -#error _FS_LOCK must be 0 at read-only configuration -#endif -typedef struct { - FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ - DWORD clu; /* Object ID 2, directory (0:root) */ - DWORD ofs; /* Object ID 3, directory offset */ - WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ -} FILESEM; -#endif - - - /* DBCS code ranges and SBCS upper conversion tables */ #if _CODE_PAGE == 932 /* Japanese Shift-JIS */ @@ -294,7 +244,7 @@ typedef struct { 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} #elif _CODE_PAGE == 869 /* Greek 2 */ @@ -347,29 +297,43 @@ typedef struct { #endif /* _DF1S */ -/* Name status flags */ -#define NSFLAG 11 /* Index of name status byte in fn[] */ +/* Additional file attribute bits for internal use */ +#define AM_VOL 0x08 /* Volume label */ +#define AM_LFN 0x0F /* LFN entry */ +#define AM_MASK 0x3F /* Mask of defined bits */ + + +/* Additional file access control and file status flags for internal use */ +#define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ +#define FA_MODIFIED 0x40 /* File has been modified */ +#define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ + + +/* Name status flags in fn[] */ +#define NSFLAG 11 /* Index of the name status byte */ #define NS_LOSS 0x01 /* Out of 8.3 format */ #define NS_LFN 0x02 /* Force to create LFN entry */ #define NS_LAST 0x04 /* Last segment */ #define NS_BODY 0x08 /* Lower case flag (body) */ #define NS_EXT 0x10 /* Lower case flag (ext) */ #define NS_DOT 0x20 /* Dot entry */ +#define NS_NOLFN 0x40 /* Do not find LFN */ #define NS_NONAME 0x80 /* Not followed */ -/* Limits and Boundaries (Differ from specs but correct for real DOS/Windows) */ -#define MIN_FAT16 4086U /* Minimum number of clusters of FAT16 */ -#define MIN_FAT32 65526U /* Minimum number of clusters of FAT32 */ -#define MAX_DIR 0x200000 /* Maximum size of FAT directory */ -#define MAX_DIR_EX 0x10000000 /* Maximum size of exFAT directory */ +/* Limits and boundaries */ +#define MAX_DIR 0x200000 /* Max size of FAT directory */ +#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ +#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but correct for real DOS/Windows behavior) */ +#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but correct for real DOS/Windows behavior) */ +#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ +#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ -/* FatFs refers the members in the FAT structures as byte array instead of -/ structure members because the structure is not binary compatible between -/ different platforms */ +/* FatFs refers the FAT structure as simple byte array instead of structure member +/ because the C structure is not binary compatible between different platforms */ -#define BS_jmpBoot 0 /* x86 jump instruction (3-byte) */ +#define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ #define BS_OEMName 3 /* OEM name (8-byte) */ #define BPB_BytsPerSec 11 /* Sector size [byte] (WORD) */ #define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */ @@ -377,7 +341,7 @@ typedef struct { #define BPB_NumFATs 16 /* Number of FATs (BYTE) */ #define BPB_RootEntCnt 17 /* Size of root directory area for FAT12/16 [entry] (WORD) */ #define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */ -#define BPB_Media 21 /* Media descriptor (BYTE) */ +#define BPB_Media 21 /* Media descriptor byte (BYTE) */ #define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */ #define BPB_SecPerTrk 24 /* Track size for int13h [sector] (WORD) */ #define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */ @@ -389,9 +353,11 @@ typedef struct { #define BS_VolID 39 /* Volume serial number (DWORD) */ #define BS_VolLab 43 /* Volume label string (8-byte) */ #define BS_FilSysType 54 /* File system type string (8-byte) */ -#define BPB_FATSz32 36 /* FAT size (32-bit) [sector] (DWORD) */ -#define BPB_ExtFlags 40 /* Extended flags (WORD) */ +#define BS_BootCode 62 /* Boot code (448-byte) */ +#define BS_55AA 510 /* Signature word (WORD) */ +#define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ +#define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ #define BPB_FSVer32 42 /* FAT32: File system version (WORD) */ #define BPB_RootClus32 44 /* FAT32: Root directory cluster (DWORD) */ #define BPB_FSInfo32 48 /* FAT32: Offset of FSINFO sector (WORD) */ @@ -402,78 +368,150 @@ typedef struct { #define BS_VolID32 67 /* FAT32: Volume serial number (DWORD) */ #define BS_VolLab32 71 /* FAT32: Volume label string (8-byte) */ #define BS_FilSysType32 82 /* FAT32: File system type string (8-byte) */ +#define BS_BootCode32 90 /* FAT32: Boot code (420-byte) */ -#define BPB_ZeroedEx 11 /* exFAT: Must be zero (35-byte) */ +#define BPB_ZeroedEx 11 /* exFAT: MBZ field (53-byte) */ #define BPB_VolOfsEx 64 /* exFAT: Volume offset from top of the drive [sector] (QWORD) */ #define BPB_TotSecEx 72 /* exFAT: Volume size [sector] (QWORD) */ #define BPB_FatOfsEx 80 /* exFAT: FAT offset from top of the volume [sector] (DWORD) */ #define BPB_FatSzEx 84 /* exFAT: FAT size [sector] (DWORD) */ #define BPB_DataOfsEx 88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */ #define BPB_NumClusEx 92 /* exFAT: Number of clusters (DWORD) */ -#define BPB_RootClusEx 96 /* exFAT: Root directory cluster (DWORD) */ +#define BPB_RootClusEx 96 /* exFAT: Root directory start cluster (DWORD) */ #define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ #define BPB_FSVerEx 104 /* exFAT: File system version (WORD) */ #define BPB_VolFlagEx 106 /* exFAT: Volume flags (BYTE) */ #define BPB_ActFatEx 107 /* exFAT: Active FAT flags (BYTE) */ -#define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in byte (BYTE) */ -#define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in sector (BYTE) */ +#define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in unit of byte (BYTE) */ +#define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in unit of sector (BYTE) */ #define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ #define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ #define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ +#define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ +#define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ + +#define DIR_Name 0 /* Short file name (11-byte) */ +#define DIR_Attr 11 /* Attribute (BYTE) */ +#define DIR_NTres 12 /* Lower case flag (BYTE) */ +#define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ +#define DIR_CrtTime 14 /* Created time (DWORD) */ +#define DIR_LstAccDate 18 /* Last accessed date (WORD) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ +#define DIR_ModTime 22 /* Modified time (DWORD) */ +#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ +#define DIR_FileSize 28 /* File size (DWORD) */ +#define LDIR_Ord 0 /* LFN: LFN order and LLE flag (BYTE) */ +#define LDIR_Attr 11 /* LFN: LFN attribute (BYTE) */ +#define LDIR_Type 12 /* LFN: Entry type (BYTE) */ +#define LDIR_Chksum 13 /* LFN: Checksum of the SFN (BYTE) */ +#define LDIR_FstClusLO 26 /* LFN: MBZ field (WORD) */ +#define XDIR_Type 0 /* exFAT: Type of exFAT directory entry (BYTE) */ +#define XDIR_NumLabel 1 /* exFAT: Number of volume label characters (BYTE) */ +#define XDIR_Label 2 /* exFAT: Volume label (11-WORD) */ +#define XDIR_CaseSum 4 /* exFAT: Sum of case conversion table (DWORD) */ +#define XDIR_NumSec 1 /* exFAT: Number of secondary entries (BYTE) */ +#define XDIR_SetSum 2 /* exFAT: Sum of the set of directory entries (WORD) */ +#define XDIR_Attr 4 /* exFAT: File attribute (WORD) */ +#define XDIR_CrtTime 8 /* exFAT: Created time (DWORD) */ +#define XDIR_ModTime 12 /* exFAT: Modified time (DWORD) */ +#define XDIR_AccTime 16 /* exFAT: Last accessed time (DWORD) */ +#define XDIR_CrtTime10 20 /* exFAT: Created time subsecond (BYTE) */ +#define XDIR_ModTime10 21 /* exFAT: Modified time subsecond (BYTE) */ +#define XDIR_CrtTZ 22 /* exFAT: Created timezone (BYTE) */ +#define XDIR_ModTZ 23 /* exFAT: Modified timezone (BYTE) */ +#define XDIR_AccTZ 24 /* exFAT: Last accessed timezone (BYTE) */ +#define XDIR_GenFlags 33 /* exFAT: General secondary flags (WORD) */ +#define XDIR_NumName 35 /* exFAT: Number of file name characters (BYTE) */ +#define XDIR_NameHash 36 /* exFAT: Hash of file name (WORD) */ +#define XDIR_ValidFileSize 40 /* exFAT: Valid file size (QWORD) */ +#define XDIR_FstClus 52 /* exFAT: First cluster of the file data (DWORD) */ +#define XDIR_FileSize 56 /* exFAT: File/Directory size (QWORD) */ + +#define SZDIRE 32 /* Size of a directory entry */ +#define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ +#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ +#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ #define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */ #define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ #define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ #define FSI_Nxt_Free 492 /* FAT32 FSI: Last allocated cluster (DWORD) */ -#define MBR_Table 446 /* MBR: Partition table offset */ +#define MBR_Table 446 /* MBR: Offset of partition table in the MBR */ #define SZ_PTE 16 /* MBR: Size of a partition table entry */ +#define PTE_Boot 0 /* MBR PTE: Boot indicator */ +#define PTE_StHead 1 /* MBR PTE: Start head */ +#define PTE_StSec 2 /* MBR PTE: Start sector */ +#define PTE_StCyl 3 /* MBR PTE: Start cylinder */ +#define PTE_System 4 /* MBR PTE: System ID */ +#define PTE_EdHead 5 /* MBR PTE: End head */ +#define PTE_EdSec 6 /* MBR PTE: End sector */ +#define PTE_EdCyl 7 /* MBR PTE: End cylinder */ +#define PTE_StLba 8 /* MBR PTE: Start in LBA */ +#define PTE_SizLba 12 /* MBR PTE: Size in LBA */ + + +/* Post process after fatal error on file operation */ +#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } -#define BS_55AA 510 /* Signature word (WORD) */ -#define DIR_Name 0 /* Short file name (11) */ -#define DIR_Attr 11 /* Attribute (1) */ -#define DIR_NTres 12 /* Lower case flag (1) */ -#define DIR_CrtTime10 13 /* Created time sub-second (1) */ -#define DIR_CrtTime 14 /* Created time (2) */ -#define DIR_CrtDate 16 /* Created date (2) */ -#define DIR_LstAccDate 18 /* Last accessed date (2) */ -#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ -#define DIR_WrtTime 22 /* Modified time (2) */ -#define DIR_WrtDate 24 /* Modified date (2) */ -#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ -#define DIR_FileSize 28 /* File size (DWORD) */ -#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */ -#define LDIR_Attr 11 /* LFN attribute (1) */ -#define LDIR_Type 12 /* LFN type (1) */ -#define LDIR_Chksum 13 /* Checksum of the SFN entry */ -#define LDIR_FstClusLO 26 /* Must be zero (WORD) */ -#define XDIR_Type 0 /* Type of exFAT directory entry (BYTE) */ -#define XDIR_NumLabel 1 /* Number of volume label characters (BYTE) */ -#define XDIR_Label 2 /* Volume label (11-WORD) */ -#define XDIR_CaseSum 4 /* Sum of case conversion table (DWORD) */ -#define XDIR_NumSec 1 /* Number of secondary entries (BYTE) */ -#define XDIR_SetSum 2 /* Sum of the set of directory entries (WORD) */ -#define XDIR_Attr 4 /* File attribute (WORD) */ -#define XDIR_CrtTime 8 /* Created time (4) */ -#define XDIR_ModTime 12 /* Modified time (4) */ -#define XDIR_AccTime 16 /* Last accessed time (4) */ -#define XDIR_CrtTime10 20 /* Created time subsecond (1) */ -#define XDIR_ModTime10 21 /* Modified time subsecond (1) */ -#define XDIR_CrtTZ 22 /* Created timezone (1) */ -#define XDIR_ModTZ 23 /* Modified timezone (1) */ -#define XDIR_AccTZ 24 /* Last accessed timezone (1) */ -#define XDIR_GenFlags 33 /* Gneral flags (1) */ -#define XDIR_NumName 35 /* Number of file name characters (BYTE) */ -#define XDIR_NameHash 36 /* Hash of file name (WORD) */ -#define XDIR_ValidFileSize 40 /* Valid file size (QWORD) */ -#define XDIR_FstClus 52 /* First cluster of the File/Directory (DWORD) */ -#define XDIR_FileSize 56 /* File/Directory size (QWORD) */ +/* Reentrancy related */ +#if _FS_REENTRANT +#if _USE_LFN == 1 +#error Static LFN work area cannot be used at thread-safe configuration +#endif +#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } +#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#else +#define ENTER_FF(fs) +#define LEAVE_FF(fs, res) return res +#endif -#define SZDIRE 32 /* Size of a directory entry */ -#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ -#define DDEM 0xE5 /* Deleted directory entry mark at DIR_Name[0] */ -#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ + +/* Definitions of volume - partition conversion */ +#if _MULTI_PARTITION +#define LD2PD(vol) VolToPart[vol].pd /* Get physical drive number */ +#define LD2PT(vol) VolToPart[vol].pt /* Get partition index */ +#else +#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ +#define LD2PT(vol) 0 /* Find first valid partition or in SFD */ +#endif + + +/* Definitions of sector size */ +#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096) +#error Wrong sector size configuration +#endif +#if _MAX_SS == _MIN_SS +#define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */ +#else +#define SS(fs) ((fs)->ssize) /* Variable sector size */ +#endif + + +/* Timestamp */ +#if _FS_NORTC == 1 +#if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31 +#error Invalid _FS_NORTC settings +#endif +#define GET_FATTIME() ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16) +#else +#define GET_FATTIME() get_fattime() +#endif + + +/* File lock controls */ +#if _FS_LOCK != 0 +#if _FS_READONLY +#error _FS_LOCK must be 0 at read-only configuration +#endif +typedef struct { + FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ + DWORD clu; /* Object ID 2, containing directory (0:root) */ + DWORD ofs; /* Object ID 3, offset in the directory */ + WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ +} FILESEM; +#endif @@ -485,11 +523,11 @@ typedef struct { ---------------------------------------------------------------------------*/ -/* Remark: Variables here without initial value shall be guaranteed zero/null -/ at start-up. If not, either the linker or start-up routine being used is +/* Remark: Variables defined here without initial value shall be guaranteed +/ zero/null at start-up. If not, the linker option or start-up routine is / not compliance with C standard. */ -#if _VOLUMES < 1 || _VOLUMES > 9 +#if _VOLUMES < 1 || _VOLUMES > 10 #error Wrong _VOLUMES setting #endif static FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ @@ -503,68 +541,53 @@ static BYTE CurrVol; /* Current drive */ static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */ #endif -#if _USE_LFN == 0 /* Non-LFN configuration */ -#define DEF_NAMBUF BYTE sfn[12] -#define INIT_NAMBUF(dobj) (dobj).fn = sfn +#if _USE_LFN == 0 /* Non-LFN configuration */ +#define DEF_NAMBUF +#define INIT_NAMBUF(fs) #define FREE_NAMBUF() -#define DEF_DIRBUF -#define INIT_DIRBUF(fs) -#define FREE_DIRBUF() -#else + +#else /* LFN configuration */ #if _MAX_LFN < 12 || _MAX_LFN > 255 -#error Wrong _MAX_LFN setting +#error Wrong _MAX_LFN value #endif +#define MAXDIRB(nc) ((nc + 44U) / 15 * SZDIRE) #if _USE_LFN == 1 /* LFN enabled with static working buffer */ #if _FS_EXFAT -static BYTE DirBuf[SZDIRE*19]; /* Directory entry block scratchpad buffer (19 entries in size) */ +static BYTE DirBuf[MAXDIRB(_MAX_LFN)]; /* Directory entry block scratchpad buffer */ #endif -static WCHAR LfnBuf[_MAX_LFN+1]; /* LFN enabled with static working buffer */ -#define DEF_NAMBUF BYTE sfn[12] -#define INIT_NAMBUF(dj) { (dj).fn = sfn; (dj).lfn = LfnBuf; } +static WCHAR LfnBuf[_MAX_LFN + 1]; /* LFN enabled with static working buffer */ +#define DEF_NAMBUF +#define INIT_NAMBUF(fs) #define FREE_NAMBUF() -#define DEF_DIRBUF -#define INIT_DIRBUF(fs) -#define FREE_DIRBUF() #elif _USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ #if _FS_EXFAT -#define DEF_NAMBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1]; BYTE dbuf[SZDIRE*19] -#define INIT_NAMBUF(dj) { (dj).fn = sfn; (dj).lfn = lbuf; (dj).obj.fs->dirbuf = dbuf; } +#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; BYTE dbuf[MAXDIRB(_MAX_LFN)]; +#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } #define FREE_NAMBUF() -#define DEF_DIRBUF BYTE dbuf[SZDIRE*19] -#define INIT_DIRBUF(fs) fs->dirbuf = dbuf -#define FREE_DIRBUF() #else -#define DEF_NAMBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1] -#define INIT_NAMBUF(dj) { (dj).fn = sfn; (dj).lfn = lbuf; } +#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; +#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; } #define FREE_NAMBUF() -#define DEF_DIRBUF -#define INIT_DIRBUF(fs) -#define FREE_DIRBUF() #endif #elif _USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ #if _FS_EXFAT -#define DEF_NAMBUF BYTE sfn[12]; WCHAR *lfn -#define INIT_NAMBUF(dj) { lfn = ff_memalloc((_MAX_LFN+1)*2 + SZDIRE*19); if (!lfn) LEAVE_FF((dj).obj.fs, FR_NOT_ENOUGH_CORE); (dj).fn = sfn; (dj).lfn = lfn; (dj).obj.fs->dirbuf = (BYTE*)(lfn+_MAX_LFN+1); } +#define DEF_NAMBUF WCHAR *lfn; +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2 + MAXDIRB(_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+_MAX_LFN+1); } #define FREE_NAMBUF() ff_memfree(lfn) -#define DEF_DIRBUF BYTE *dirb -#define INIT_DIRBUF(fs) { dirb = ff_memalloc(SZDIRE*19); if (!dirb) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); fs->dirbuf = dirb; } -#define FREE_DIRBUF() ff_memfree(dirb) #else -#define DEF_NAMBUF BYTE sfn[12]; WCHAR *lfn -#define INIT_NAMBUF(dj) { lfn = ff_memalloc((_MAX_LFN+1)*2); if (!lfn) LEAVE_FF((dj).obj.fs, FR_NOT_ENOUGH_CORE); (dj).fn = sfn; (dj).lfn = lfn; } +#define DEF_NAMBUF WCHAR *lfn; +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } #define FREE_NAMBUF() ff_memfree(lfn) -#define DEF_DIRBUF -#define INIT_DIRBUF(fs) -#define FREE_DIRBUF() #endif #else #error Wrong _USE_LFN setting + #endif -#endif +#endif /* else _USE_LFN == 0 */ #ifdef _EXCVT static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended characters */ @@ -672,7 +695,9 @@ void mem_cpy (void* dst, const void* src, UINT cnt) { const BYTE *s = (const BYTE*)src; if (cnt) { - do *d++ = *s++; while (--cnt); + do { + *d++ = *s++; + } while (--cnt); } } @@ -681,7 +706,9 @@ static void mem_set (void* dst, int val, UINT cnt) { BYTE *d = (BYTE*)dst; - do *d++ = (BYTE)val; while (--cnt); + do { + *d++ = (BYTE)val; + } while (--cnt); } /* Compare memory block */ @@ -707,16 +734,16 @@ int chk_chr (const char* str, int chr) { /* NZ:contained, ZR:not contained */ +#if _FS_REENTRANT /*-----------------------------------------------------------------------*/ /* Request/Release grant to access the volume */ /*-----------------------------------------------------------------------*/ -#if _FS_REENTRANT static int lock_fs ( FATFS* fs /* File system object */ ) { - return ff_req_grant(fs->sobj); + return (fs && ff_req_grant(fs->sobj)) ? 1 : 0; } @@ -730,15 +757,15 @@ void unlock_fs ( ff_rel_grant(fs->sobj); } } -#endif +#endif +#if _FS_LOCK != 0 /*-----------------------------------------------------------------------*/ /* File lock control functions */ /*-----------------------------------------------------------------------*/ -#if _FS_LOCK != 0 static FRESULT chk_lock ( /* Check if the file can be accessed */ @@ -843,8 +870,8 @@ void clear_lock ( /* Clear lock entries of the volume */ if (Files[i].fs == fs) Files[i].fs = 0; } } -#endif +#endif /* _FS_LOCK != 0 */ @@ -908,10 +935,11 @@ FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERROR */ +#if !_FS_READONLY /*-----------------------------------------------------------------------*/ /* Synchronize file system and strage device */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY + static FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ FATFS* fs /* File system object */ @@ -942,8 +970,8 @@ FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ return res; } -#endif +#endif @@ -993,17 +1021,17 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluste wc = fs->win[bc++ % SS(fs)]; if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; wc |= fs->win[bc % SS(fs)] << 8; - val = clst & 1 ? wc >> 4 : (wc & 0xFFF); + val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF); break; case FS_FAT16 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; - val = ld_word(&fs->win[clst * 2 % SS(fs)]); + val = ld_word(fs->win + clst * 2 % SS(fs)); break; case FS_FAT32 : if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; - val = ld_dword(&fs->win[clst * 4 % SS(fs)]) & 0x0FFFFFFF; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; break; #if _FS_EXFAT case FS_EXFAT : @@ -1017,17 +1045,21 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluste break; } } - if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the contiguous part? */ + if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the 1st fragment? */ val = clst + 1; /* Generate the value */ break; } if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */ - if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; - val = ld_dword(&fs->win[clst * 4 % SS(fs)]) & 0x7FFFFFFF; + if (obj->n_frag != 0) { /* Is it on the growing edge? */ + val = 0x7FFFFFFF; /* Generate EOC */ + } else { + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; + } break; } } - /* Go default */ + /* go to default */ #endif default: val = 1; /* Internal error */ @@ -1040,14 +1072,14 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluste +#if !_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT access - Change value of a FAT entry */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY static FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ - FATFS* fs, /* Corresponding object */ + FATFS* fs, /* Corresponding file system object */ DWORD clst, /* FAT index number (cluster number) to be changed */ DWORD val /* New value to be set to the entry */ ) @@ -1056,19 +1088,18 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ BYTE *p; FRESULT res = FR_INT_ERR; - if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */ switch (fs->fs_type) { case FS_FAT12 : /* Bitfield items */ bc = (UINT)clst; bc += bc / 2; res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; - p = &fs->win[bc++ % SS(fs)]; + p = fs->win + bc++ % SS(fs); *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; fs->wflag = 1; res = move_window(fs, fs->fatbase + (bc / SS(fs))); if (res != FR_OK) break; - p = &fs->win[bc % SS(fs)]; + p = fs->win + bc % SS(fs); *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); fs->wflag = 1; break; @@ -1076,7 +1107,7 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ case FS_FAT16 : /* WORD aligned items */ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); if (res != FR_OK) break; - st_word(&fs->win[clst * 2 % SS(fs)], (WORD)val); + st_word(fs->win + clst * 2 % SS(fs), (WORD)val); fs->wflag = 1; break; @@ -1087,15 +1118,16 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); if (res != FR_OK) break; if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { - val = (val & 0x0FFFFFFF) | (ld_dword(&fs->win[clst * 4 % SS(fs)]) & 0xF0000000); + val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); } - st_dword(&fs->win[clst * 4 % SS(fs)], val); + st_dword(fs->win + clst * 4 % SS(fs), val); fs->wflag = 1; break; } } return res; } + #endif /* !_FS_READONLY */ @@ -1106,11 +1138,12 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ /* exFAT: Accessing FAT and Allocation Bitmap */ /*-----------------------------------------------------------------------*/ -/*---------------------------------------------*/ -/* exFAT: Find a contiguous free cluster block */ -/*---------------------------------------------*/ +/*--------------------------------------*/ +/* Find a contiguous free cluster block */ +/*--------------------------------------*/ + static -DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Disk error */ +DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */ FATFS* fs, /* File system object */ DWORD clst, /* Cluster number to scan from */ DWORD ncl /* Number of contiguous clusters to find (1..) */ @@ -1125,18 +1158,18 @@ DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Dis if (clst >= fs->n_fatent - 2) clst = 0; scl = val = clst; ctr = 0; for (;;) { - if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; - i = val / 8 & (SS(fs) - 1); bm = 1 << (val % 8); + if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */ + i = val / 8 % SS(fs); bm = 1 << (val % 8); do { do { bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */ if (++val >= fs->n_fatent - 2) { /* Next cluster (with wrap-around) */ - val = 0; bm = 0; i = 4096; + val = 0; bm = 0; i = SS(fs); } if (!bv) { /* Is it a free cluster? */ - if (++ctr == ncl) return scl + 2; /* Check run length */ + if (++ctr == ncl) return scl + 2; /* Check if run length is sufficient for required */ } else { - scl = val; ctr = 0; /* Encountered a live cluster, restart to scan */ + scl = val; ctr = 0; /* Encountered a cluster in-use, restart to scan */ } if (val == clst) return 0; /* All cluster scanned? */ } while (bm); @@ -1145,9 +1178,11 @@ DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Dis } } -/*------------------------------------*/ -/* exFAT: Set/Clear a block of bitmap */ -/*------------------------------------*/ + +/*----------------------------------------*/ +/* Set/Clear a block of allocation bitmap */ +/*----------------------------------------*/ + static FRESULT change_bitmap ( FATFS* fs, /* File system object */ @@ -1160,10 +1195,9 @@ FRESULT change_bitmap ( UINT i; DWORD sect; - clst -= 2; /* The first bit corresponds to cluster #2 */ - sect = fs->database + clst / 8 / SS(fs); /* Sector address */ - i = clst / 8 & (SS(fs) - 1); /* Byte offset in the sector */ + sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */ + i = clst / 8 % SS(fs); /* Byte offset in the sector */ bm = 1 << (clst % 8); /* Bit mask in the byte */ for (;;) { if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; @@ -1176,22 +1210,24 @@ FRESULT change_bitmap ( } while (bm <<= 1); /* Next bit */ bm = 1; } while (++i < SS(fs)); /* Next byte */ + i = 0; } } /*---------------------------------------------*/ -/* Complement contiguous part of the FAT chain */ +/* Fill the first fragment of the FAT chain */ /*---------------------------------------------*/ + static -FRESULT fill_fat_chain ( +FRESULT fill_first_frag ( _FDID* obj /* Pointer to the corresponding object */ ) { FRESULT res; DWORD cl, n; - if (obj->stat == 3) { /* Has the object got fragmented? */ + if (obj->stat == 3) { /* Has the object been changed 'fragmented'? */ for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */ res = put_fat(obj->fs, cl, cl + 1); if (res != FR_OK) return res; @@ -1201,14 +1237,36 @@ FRESULT fill_fat_chain ( return FR_OK; } -#endif +/*---------------------------------------------*/ +/* Fill the last fragment of the FAT chain */ +/*---------------------------------------------*/ +static +FRESULT fill_last_frag ( + _FDID* obj, /* Pointer to the corresponding object */ + DWORD lcl, /* Last cluster of the fragment */ + DWORD term /* Value to set the last FAT entry */ +) +{ + FRESULT res; + while (obj->n_frag > 0) { /* Create the last chain on the FAT */ + res = put_fat(obj->fs, lcl - obj->n_frag + 1, (obj->n_frag > 1) ? lcl - obj->n_frag + 2 : term); + if (res != FR_OK) return res; + obj->n_frag--; + } + return FR_OK; +} + +#endif /* _FS_EXFAT && !_FS_READONLY */ + + + +#if !_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT handling - Remove a cluster chain */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ _FDID* obj, /* Corresponding object */ @@ -1244,14 +1302,14 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ if (res != FR_OK) return res; } - if (fs->free_clst != 0xFFFFFFFF) { /* Update FSINFO */ + if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ fs->free_clst++; fs->fsi_flag |= 1; } #if _FS_EXFAT || _USE_TRIM if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ ecl = nxt; - } else { /* End of contiguous cluster block */ + } else { /* End of contiguous cluster block */ #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */ @@ -1271,18 +1329,31 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { - if (pclst == 0) { /* Does object have no chain? */ + if (pclst == 0) { /* Does the object have no chain? */ obj->stat = 0; /* Change the object status 'initial' */ } else { - if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Did the chain got contiguous? */ - obj->stat = 2; /* Change the object status 'contiguous' */ + if (obj->stat == 0) { /* Is it a fragmented chain from the beginning of this session? */ + clst = obj->sclust; /* Follow the chain to check if it gets contiguous */ + while (clst != pclst) { + nxt = get_fat(obj, clst); + if (nxt < 2) return FR_INT_ERR; + if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; + if (nxt != clst + 1) break; /* Not contiguous? */ + clst++; + } + if (clst == pclst) { /* Has the chain got contiguous again? */ + obj->stat = 2; /* Change the chain status 'contiguous' */ + } + } else { + if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Was the chain fragmented in this session and got contiguous again? */ + obj->stat = 2; /* Change the chain status 'contiguous' */ + } } } } #endif return FR_OK; } -#endif @@ -1290,7 +1361,6 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ /*-----------------------------------------------------------------------*/ /* FAT handling - Stretch a chain or Create a new chain */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY static DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ _FDID* obj, /* Corresponding object */ @@ -1303,35 +1373,44 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err if (clst == 0) { /* Create a new chain */ - scl = fs->last_clst; /* Get suggested cluster to start at */ + scl = fs->last_clst; /* Get suggested cluster to start from */ if (scl == 0 || scl >= fs->n_fatent) scl = 1; } else { /* Stretch current chain */ cs = get_fat(obj, clst); /* Check the cluster status */ - if (cs < 2) return 1; /* Invalid value */ + if (cs < 2) return 1; /* Invalid FAT value */ if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */ if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ scl = clst; } #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */ if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */ res = change_bitmap(fs, ncl, 1, 1); /* Mark the cluster 'in use' */ if (res == FR_INT_ERR) return 1; if (res == FR_DISK_ERR) return 0xFFFFFFFF; if (clst == 0) { /* Is it a new chain? */ - obj->stat = 2; /* Set status 'contiguous chain' */ - } else { /* This is a stretched chain */ + obj->stat = 2; /* Set status 'contiguous' */ + } else { /* It is a stretched chain */ if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */ obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */ obj->stat = 3; /* Change status 'just fragmented' */ } } + if (obj->stat != 2) { /* Is the file non-contiguous? */ + if (ncl == clst + 1) { /* Is the cluster next to previous one? */ + obj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2; /* Increment size of last framgent */ + } else { /* New fragment */ + if (obj->n_frag == 0) obj->n_frag = 1; + res = fill_last_frag(obj, clst, ncl); /* Fill last fragment on the FAT and link it to new one */ + if (res == FR_OK) obj->n_frag = 1; + } + } } else #endif - { /* At the FAT12/16/32 */ + { /* On the FAT12/16/32 volume */ ncl = scl; /* Start cluster */ for (;;) { ncl++; /* Next cluster */ @@ -1344,37 +1423,33 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* An error occurred */ if (ncl == scl) return 0; /* No free cluster */ } - } - - if (_FS_EXFAT && fs->fs_type == FS_EXFAT && obj->stat == 2) { /* Is it a contiguous chain? */ - res = FR_OK; /* FAT does not need to be written */ - } else { res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ - if (res == FR_OK && clst) { + if (res == FR_OK && clst != 0) { res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ } } if (res == FR_OK) { /* Update FSINFO if function succeeded. */ fs->last_clst = ncl; - if (fs->free_clst < fs->n_fatent - 2) fs->free_clst--; + if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; fs->fsi_flag |= 1; } else { - ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Create error status */ + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */ } return ncl; /* Return new cluster number or error status */ } + #endif /* !_FS_READONLY */ +#if _USE_FASTSEEK /*-----------------------------------------------------------------------*/ /* FAT handling - Convert offset into cluster with link map table */ /*-----------------------------------------------------------------------*/ -#if _USE_FASTSEEK static DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ FIL* fp, /* Pointer to the file object */ @@ -1395,10 +1470,12 @@ DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ } return cl + *tbl; /* Return the cluster number */ } + #endif /* _USE_FASTSEEK */ + /*-----------------------------------------------------------------------*/ /* Directory handling - Set directory index */ /*-----------------------------------------------------------------------*/ @@ -1499,7 +1576,7 @@ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Cou } fs->winsect -= n; /* Restore window offset */ #else - if (!stretch) dp->sect = 0; /* If no stretch, report EOT (this is to suppress warning) */ + if (!stretch) dp->sect = 0; /* (this line is to suppress compiler warning) */ dp->sect = 0; return FR_NO_FILE; /* Report EOT */ #endif } @@ -1509,7 +1586,7 @@ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Cou } } dp->dptr = ofs; /* Current entry */ - dp->dir = &fs->win[ofs % SS(fs)]; /* Pointer to the entry in the win[] */ + dp->dir = fs->win + ofs % SS(fs); /* Pointer to the entry in the win[] */ return FR_OK; } @@ -1517,11 +1594,11 @@ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Cou +#if !_FS_READONLY /*-----------------------------------------------------------------------*/ /* Directory handling - Reserve a block of directory entries */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY static FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ DIR* dp, /* Pointer to the directory object */ @@ -1540,7 +1617,7 @@ FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ res = move_window(fs, dp->sect); if (res != FR_OK) break; #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { + if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { #else if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) { #endif @@ -1555,7 +1632,8 @@ FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ return res; } -#endif + +#endif /* !_FS_READONLY */ @@ -1598,14 +1676,14 @@ void st_clust ( - +#if _USE_LFN != 0 /*------------------------------------------------------------------------*/ /* FAT-LFN: LFN handling */ /*------------------------------------------------------------------------*/ -#if _USE_LFN != 0 static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN characters in the directory entry */ + /*--------------------------------------------------------*/ /* FAT-LFN: Compare a part of file name with an LFN entry */ /*--------------------------------------------------------*/ @@ -1641,8 +1719,7 @@ int cmp_lfn ( /* 1:matched, 0:not matched */ } - -#if _FS_MINIMIZE <= 1 || _FS_EXFAT +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT /*-----------------------------------------------------*/ /* FAT-LFN: Pick a part of file name from an LFN entry */ /*-----------------------------------------------------*/ @@ -1656,9 +1733,9 @@ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ WCHAR wc, uc; - if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO is 0 */ - i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ @@ -1679,6 +1756,7 @@ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ } #endif + #if !_FS_READONLY /*-----------------------------------------*/ /* FAT-LFN: Create an entry of LFN entries */ @@ -1711,15 +1789,16 @@ void put_lfn ( dir[LDIR_Ord] = ord; /* Set the LFN order */ } -#endif -#endif +#endif /* !_FS_READONLY */ +#endif /* _USE_LFN != 0 */ +#if _USE_LFN != 0 && !_FS_READONLY /*-----------------------------------------------------------------------*/ /* FAT-LFN: Create a Numbered SFN */ /*-----------------------------------------------------------------------*/ -#if _USE_LFN != 0 && !_FS_READONLY + static void gen_numname ( BYTE* dst, /* Pointer to the buffer to store numbered SFN */ @@ -1752,7 +1831,7 @@ void gen_numname ( /* itoa (hexdecimal) */ i = 7; do { - c = (seq % 16) + '0'; + c = (BYTE)((seq % 16) + '0'); if (c > '9') c += 7; ns[i--] = c; seq /= 16; @@ -1770,14 +1849,15 @@ void gen_numname ( dst[j++] = (i < 8) ? ns[i++] : ' '; } while (j < 8); } -#endif +#endif /* _USE_LFN != 0 && !_FS_READONLY */ +#if _USE_LFN != 0 /*-----------------------------------------------------------------------*/ /* FAT-LFN: Calculate checksum of an SFN entry */ /*-----------------------------------------------------------------------*/ -#if _USE_LFN != 0 + static BYTE sum_sfn ( const BYTE* dir /* Pointer to the SFN entry */ @@ -1786,17 +1866,19 @@ BYTE sum_sfn ( BYTE sum = 0; UINT n = 11; - do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n); + do { + sum = (sum >> 1) + (sum << 7) + *dir++; + } while (--n); return sum; } -#endif +#endif /* _USE_LFN != 0 */ #if _FS_EXFAT /*-----------------------------------------------------------------------*/ -/* exFAT: Directory handling - Load/Store a block of directory entries */ +/* exFAT: Checksum */ /*-----------------------------------------------------------------------*/ static @@ -1839,43 +1921,57 @@ WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ } +#if !_FS_READONLY && _USE_MKFS +static +DWORD xsum32 ( + BYTE dat, /* Data to be sumed */ + DWORD sum /* Previous value */ +) +{ + sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat; + return sum; +} +#endif + + +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 /*------------------------------------------------------*/ /* exFAT: Get object information from a directory block */ /*------------------------------------------------------*/ + static void get_xdir_info ( BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ FILINFO* fno /* Buffer to store the extracted file information */ ) { - UINT di, si, nc; + UINT di, si; WCHAR w; +#if !_LFN_UNICODE + UINT nc; +#endif /* Get file name */ + di = 0; #if _LFN_UNICODE - if (dirb[XDIR_NumName] <= _MAX_LFN) { - for (si = SZDIRE * 2, di = 0; di < dirb[XDIR_NumName]; si += 2, di++) { - if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ - w = ld_word(dirb + si); /* Get a character */ - fno->fname[di] = w; /* Store it */ - } - } else { - di = 0; /* Buffer overflow and inaccessible object */ + for (si = SZDIRE * 2; di < dirb[XDIR_NumName]; si += 2, di++) { + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + w = ld_word(dirb + si); /* Get a character */ + if (di >= _MAX_LFN) { di = 0; break; } /* Buffer overflow --> inaccessible object name */ + fno->fname[di] = w; /* Store it */ } #else - for (si = SZDIRE * 2, di = nc = 0; nc < dirb[XDIR_NumName]; si += 2, nc++) { - if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ - w = ld_word(dirb + si); /* Get a character */ - w = ff_convert(w, 0); /* Unicode -> OEM */ - if (w == 0) { di = 0; break; } /* Could not be converted and inaccessible object */ - if (_DF1S && w >= 0x100) { /* Put 1st byte if it is a DBC (always false at SBCS cfg) */ - fno->fname[di++] = (char)(w >> 8); + for (si = SZDIRE * 2, nc = 0; nc < dirb[XDIR_NumName]; si += 2, nc++) { + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + w = ff_convert(ld_word(dirb + si), 0); /* Get a character and Unicode -> OEM */ + if (_DF1S && w >= 0x100) { /* Is it a double byte char? (always false at SBCS cfg) */ + fno->fname[di++] = (char)(w >> 8); /* Put 1st byte of the DBC */ } - if (di >= _MAX_LFN) { di = 0; break; } /* Buffer overflow and inaccessible object */ + if (w == 0 || di >= _MAX_LFN) { di = 0; break; } /* Invalid char or buffer overflow --> inaccessible object name */ fno->fname[di++] = (char)w; } #endif - if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object? */ + if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ fno->fname[di] = 0; /* Terminate file name */ fno->altname[0] = 0; /* No SFN */ @@ -1885,17 +1981,20 @@ void get_xdir_info ( fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */ } +#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ + /*-----------------------------------*/ /* exFAT: Get a directry entry block */ /*-----------------------------------*/ + static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ DIR* dp /* Pointer to the reading direcotry object pointing the 85 entry */ ) { FRESULT res; - UINT i, nent; + UINT i, sz_ent; BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ @@ -1903,8 +2002,9 @@ FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; - mem_cpy(&dirb[0], dp->dir, SZDIRE); - nent = dirb[XDIR_NumSec] + 1; + mem_cpy(dirb + 0, dp->dir, SZDIRE); + sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; + if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; /* Load C0 entry */ res = dir_next(dp, 0); @@ -1913,48 +2013,48 @@ FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; mem_cpy(dirb + SZDIRE, dp->dir, SZDIRE); + if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; /* Load C1 entries */ - if (nent < 3 || nent > 19) return FR_NO_FILE; - i = SZDIRE * 2; nent *= SZDIRE; + i = SZDIRE * 2; /* C1 offset */ do { res = dir_next(dp, 0); if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; - mem_cpy(dirb + i, dp->dir, SZDIRE); - i += SZDIRE; - } while (i < nent); - - /* Sanity check */ - if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + if (i < MAXDIRB(_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); + } while ((i += SZDIRE) < sz_ent); + /* Sanity check (do it when accessible object name) */ + if (i <= MAXDIRB(_MAX_LFN)) { + if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + } return FR_OK; } -#if !_FS_READONLY || _FS_RPATH != 0 +#if !_FS_READONLY || _FS_RPATH != 0 /*------------------------------------------------*/ /* exFAT: Load the object's directory entry block */ /*------------------------------------------------*/ static FRESULT load_obj_dir ( DIR* dp, /* Blank directory object to be used to access containing direcotry */ - const _FDID* obj /* Object with containing directory information */ + const _FDID* obj /* Object with its containing directory information */ ) { FRESULT res; - /* Open object containing directory */ dp->obj.fs = obj->fs; dp->obj.sclust = obj->c_scl; dp->obj.stat = (BYTE)obj->c_size; dp->obj.objsize = obj->c_size & 0xFFFFFF00; + dp->obj.n_frag = 0; dp->blk_ofs = obj->c_ofs; - res = dir_sdi(dp, dp->blk_ofs); /* Goto the block location */ + res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */ if (res == FR_OK) { res = load_xdir(dp); /* Load the object's entry block */ } @@ -1974,16 +2074,17 @@ FRESULT store_xdir ( { FRESULT res; UINT nent; - WORD sum; BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ /* Create set sum */ - sum = xdir_sum(dirb); - st_word(dirb + XDIR_SetSum, sum); + st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); nent = dirb[XDIR_NumSec] + 1; + /* Store the set of directory to the volume */ res = dir_sdi(dp, dp->blk_ofs); - while (res == FR_OK && (res = move_window(dp->obj.fs, dp->sect)) == FR_OK) { + while (res == FR_OK) { + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) break; mem_cpy(dp->dir, dirb, SZDIRE); dp->obj.fs->wflag = 1; if (--nent == 0) break; @@ -1994,9 +2095,11 @@ FRESULT store_xdir ( } + /*-------------------------------------------*/ /* exFAT: Create a new directory enrty block */ /*-------------------------------------------*/ + static void create_xdir ( BYTE* dirb, /* Pointer to the direcotry entry block buffer */ @@ -2006,38 +2109,39 @@ void create_xdir ( UINT i; BYTE nb, nc; WCHAR chr; - WORD hash; - mem_set(dirb, 0, 2 * SZDIRE); /* Initialize 85+C0 entry */ + /* Create 85+C0 entry */ + mem_set(dirb, 0, 2 * SZDIRE); dirb[XDIR_Type] = 0x85; dirb[XDIR_Type + SZDIRE] = 0xC0; - hash = xname_sum(lfn); - st_word(dirb + XDIR_NameHash, hash); /* Set name hash */ - i = SZDIRE * 2; /* C1 offset */ - nc = 0; nb = 1; chr = 1; + /* Create C1 entries */ + nc = 0; nb = 1; chr = 1; i = SZDIRE * 2; do { dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ do { /* Fill name field */ if (chr && (chr = lfn[nc]) != 0) nc++; /* Get a character if exist */ - st_word(dirb + i, chr); i += 2; /* Store it */ - } while (i % SZDIRE); + st_word(dirb + i, chr); /* Store it */ + } while ((i += 2) % SZDIRE != 0); nb++; } while (lfn[nc]); /* Fill next entry if any char follows */ dirb[XDIR_NumName] = nc; /* Set name length */ - dirb[XDIR_NumSec] = nb; /* Set number of C0+C1s */ + dirb[XDIR_NumSec] = nb; /* Set block length */ + st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ } -#endif -#endif + +#endif /* !_FS_READONLY */ +#endif /* _FS_EXFAT */ +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT /*-----------------------------------------------------------------------*/ /* Read an object from the directory */ /*-----------------------------------------------------------------------*/ -#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT + static FRESULT dir_read ( DIR* dp, /* Pointer to the directory object */ @@ -2055,14 +2159,16 @@ FRESULT dir_read ( res = move_window(fs, dp->sect); if (res != FR_OK) break; c = dp->dir[DIR_Name]; /* Test for the entry type */ - if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of the directory */ + if (c == 0) { + res = FR_NO_FILE; break; /* Reached to end of the directory */ + } #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ if (_USE_LABEL && vol) { if (c == 0x83) break; /* Volume label entry? */ } else { - if (c == 0x85) { /* Start of the entry block? */ - dp->blk_ofs = dp->dptr; /* Set location of block */ + if (c == 0x85) { /* Start of the file entry block? */ + dp->blk_ofs = dp->dptr; /* Get location of the block */ res = load_xdir(dp); /* Load the entry block */ if (res == FR_OK) { dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */ @@ -2072,7 +2178,7 @@ FRESULT dir_read ( } } else #endif - { /* At the FAT12/16/32 */ + { /* On the FAT12/16/32 volume */ dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ #if _USE_LFN != 0 /* LFN configuration */ if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ @@ -2081,11 +2187,11 @@ FRESULT dir_read ( if (a == AM_LFN) { /* An LFN entry is found */ if (c & LLEF) { /* Is it start of an LFN sequence? */ sum = dp->dir[LDIR_Chksum]; - c &= ~LLEF; ord = c; + c &= (BYTE)~LLEF; ord = c; dp->blk_ofs = dp->dptr; } /* Check LFN validity and capture it */ - ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(dp->lfn, dp->dir)) ? ord - 1 : 0xFF; + ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } else { /* An SFN entry is found */ if (ord || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ @@ -2106,6 +2212,7 @@ FRESULT dir_read ( if (res != FR_OK) dp->sect = 0; /* Terminate the read operation on error or EOT */ return res; } + #endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */ @@ -2129,23 +2236,26 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ res = dir_sdi(dp, 0); /* Rewind directory object */ if (res != FR_OK) return res; #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ BYTE nc; UINT di, ni; - WORD hash = xname_sum(dp->lfn); /* Hash value of the name to find */ + WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ while ((res = dir_read(dp, 0)) == FR_OK) { /* Read an item */ - if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip the comparison if hash value mismatched */ +#if _MAX_LFN < 255 + if (fs->dirbuf[XDIR_NumName] > _MAX_LFN) continue; /* Skip comparison if inaccessible object name */ +#endif + if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ if ((di % SZDIRE) == 0) di += 2; - if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(dp->lfn[ni])) break; + if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; } - if (nc == 0 && !dp->lfn[ni]) break; /* Name matched? */ + if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */ } return res; } #endif - /* At the FAT12/16/32 */ + /* On the FAT12/16/32 volume */ #if _USE_LFN != 0 ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ #endif @@ -2160,14 +2270,14 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ } else { if (a == AM_LFN) { /* An LFN entry is found */ - if (dp->lfn) { + if (!(dp->fn[NSFLAG] & NS_NOLFN)) { if (c & LLEF) { /* Is it start of LFN sequence? */ sum = dp->dir[LDIR_Chksum]; - c &= ~LLEF; ord = c; /* LFN start order */ + c &= (BYTE)~LLEF; ord = c; /* LFN start order */ dp->blk_ofs = dp->dptr; /* Start offset of LFN */ } /* Check validity of the LFN entry and compare it with given name */ - ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(dp->lfn, dp->dir)) ? ord - 1 : 0xFF; + ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; } } else { /* An SFN entry is found */ if (!ord && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ @@ -2188,10 +2298,11 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ +#if !_FS_READONLY /*-----------------------------------------------------------------------*/ /* Register an object to the directory */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY + static FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ DIR* dp /* Target directory with object name to be created */ @@ -2201,53 +2312,55 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S FATFS *fs = dp->obj.fs; #if _USE_LFN != 0 /* LFN configuration */ UINT n, nlen, nent; - BYTE sn[12], *fn, sum; - WCHAR *lfn; + BYTE sn[12], sum; - fn = dp->fn; lfn = dp->lfn; - if (fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ - for (nlen = 0; lfn[nlen]; nlen++) ; /* Get lfn length */ + if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ + for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ DIR dj; nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ res = dir_alloc(dp, nent); /* Allocate entries */ if (res != FR_OK) return res; - dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set block position */ + dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ - if (dp->obj.stat & 4) { /* Has the sub-directory been stretched? */ - dp->obj.stat &= 3; - dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase object size by cluster size */ - res = fill_fat_chain(&dp->obj); /* Complement FAT chain if needed */ + if (dp->obj.stat & 4) { /* Has the directory been stretched? */ + dp->obj.stat &= ~4; + res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */ if (res != FR_OK) return res; - res = load_obj_dir(&dj, &dp->obj); - if (res != FR_OK) return res; /* Load the object status */ - st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ - st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); - fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; - res = store_xdir(&dj); /* Store the object status */ + res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */ if (res != FR_OK) return res; + if (dp->obj.sclust != 0) { /* Is it a sub directory? */ + res = load_obj_dir(&dj, &dp->obj); /* Load the object status */ + if (res != FR_OK) return res; + dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ + st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ + st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); + fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; + res = store_xdir(&dj); /* Store the object status */ + if (res != FR_OK) return res; + } } - create_xdir(fs->dirbuf, lfn); /* Create on-memory directory block to be written later */ + create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ return FR_OK; } #endif - /* At the FAT12/16/32 */ - mem_cpy(sn, fn, 12); + /* On the FAT12/16/32 volume */ + mem_cpy(sn, dp->fn, 12); if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ - fn[NSFLAG] = 0; dp->lfn = 0; /* Find only SFN */ + dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ for (n = 1; n < 100; n++) { - gen_numname(fn, sn, lfn, n); /* Generate a numbered name */ + gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */ res = dir_find(dp); /* Check if the name collides with existing SFN */ if (res != FR_OK) break; } if (n == 100) return FR_DENIED; /* Abort if too many collisions */ if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ - fn[NSFLAG] = sn[NSFLAG]; dp->lfn = lfn; + dp->fn[NSFLAG] = sn[NSFLAG]; } /* Create an SFN with/without LFNs. */ @@ -2260,7 +2373,7 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S do { /* Store LFN entries in bottom first */ res = move_window(fs, dp->sect); if (res != FR_OK) break; - put_lfn(dp->lfn, dp->dir, (BYTE)nent, sum); + put_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum); fs->wflag = 1; res = dir_next(dp, 0); /* Next entry */ } while (res == FR_OK && --nent); @@ -2287,15 +2400,16 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S return res; } -#endif /* !_FS_READONLY */ +#endif /* !_FS_READONLY */ +#if !_FS_READONLY && _FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ /* Remove an object from the directory */ /*-----------------------------------------------------------------------*/ -#if !_FS_READONLY && !_FS_MINIMIZE + static FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ DIR* dp /* Directory object pointing the entry to be removed */ @@ -2306,15 +2420,15 @@ FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ #if _USE_LFN != 0 /* LFN configuration */ DWORD last = dp->dptr; - res = dp->blk_ofs == 0xFFFFFFFF ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ + res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ if (res == FR_OK) { do { res = move_window(fs, dp->sect); if (res != FR_OK) break; /* Mark an entry 'deleted' */ - if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ dp->dir[XDIR_Type] &= 0x7F; - } else { /* At the FAT12/16/32 */ + } else { /* On the FAT12/16/32 volume */ dp->dir[DIR_Name] = DDEM; } fs->wflag = 1; @@ -2334,15 +2448,16 @@ FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ return res; } -#endif /* !_FS_READONLY */ +#endif /* !_FS_READONLY && _FS_MINIMIZE == 0 */ +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 /*-----------------------------------------------------------------------*/ /* Get file information from directory entry */ /*-----------------------------------------------------------------------*/ -#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 + static void get_fileinfo ( /* No return code */ DIR* dp, /* Pointer to the directory object */ @@ -2351,9 +2466,10 @@ void get_fileinfo ( /* No return code */ { UINT i, j; TCHAR c; + DWORD tm; #if _USE_LFN != 0 - WCHAR w, *lfn; - WCHAR lfv; + WCHAR w, lfv; + FATFS *fs = dp->obj.fs; #endif @@ -2362,15 +2478,15 @@ void get_fileinfo ( /* No return code */ #if _USE_LFN != 0 /* LFN configuration */ #if _FS_EXFAT - if (dp->obj.fs->fs_type == FS_EXFAT) { /* At the exFAT */ - get_xdir_info(dp->obj.fs->dirbuf, fno); + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + get_xdir_info(fs->dirbuf, fno); return; } else #endif - { /* At the FAT12/16/32 */ + { /* On the FAT12/16/32 volume */ if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ - i = 0; lfn = dp->lfn; - while ((w = *lfn++) != 0) { /* Get an LFN character */ + i = j = 0; + while ((w = fs->lfnbuf[j++]) != 0) { /* Get an LFN character */ #if !_LFN_UNICODE w = ff_convert(w, 0); /* Unicode -> OEM */ if (w == 0) { i = 0; break; } /* No LFN if it could not be converted */ @@ -2379,7 +2495,7 @@ void get_fileinfo ( /* No return code */ } #endif if (i >= _MAX_LFN) { i = 0; break; } /* No LFN if buffer overflow */ - fno->fname[i++] = (char)w; + fno->fname[i++] = (TCHAR)w; } fno->fname[i] = 0; /* Terminate the LFN */ } @@ -2404,7 +2520,7 @@ void get_fileinfo ( /* No return code */ #endif fno->altname[j] = c; if (!lfv) { - if (IsUpper(c) && (dp->dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) { + if (IsUpper(c) && (dp->dir[DIR_NTres] & ((i >= 9) ? NS_EXT : NS_BODY))) { c += 0x20; /* To lower */ } fno->fname[j] = c; @@ -2431,18 +2547,19 @@ void get_fileinfo ( /* No return code */ fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ - fno->fdate = ld_word(dp->dir + DIR_WrtDate); /* Date */ - fno->ftime = ld_word(dp->dir + DIR_WrtTime); /* Time */ + tm = ld_dword(dp->dir + DIR_ModTime); /* Timestamp */ + fno->ftime = (WORD)tm; fno->fdate = (WORD)(tm >> 16); } -#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ +#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ +#if _USE_FIND && _FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Pattern matching */ /*-----------------------------------------------------------------------*/ -#if _USE_FIND && _FS_MINIMIZE <= 1 + static WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */ const TCHAR** ptr /* Pointer to pointer to the SBCS/DBCS/Unicode string */ @@ -2493,7 +2610,7 @@ int pattern_matching ( /* 0:not matched, 1:matched */ do { /* Analyze the wildcard chars */ if (*pp++ == '?') nm++; else nx = 1; } while (*pp == '?' || *pp == '*'); - if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recursions upto number of wildcard blocks in the pattern) */ + if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ nc = *np; break; /* Branch mismatched */ } pc = get_achar(&pp); /* Get a pattern char */ @@ -2506,8 +2623,8 @@ int pattern_matching ( /* 0:not matched, 1:matched */ return 0; } -#endif /* _USE_FIND && _FS_MINIMIZE <= 1 */ +#endif /* _USE_FIND && _FS_MINIMIZE <= 1 */ @@ -2528,11 +2645,12 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ const TCHAR *p; /* Create LFN in Unicode */ - p = *path; lfn = dp->lfn; si = di = 0; + p = *path; lfn = dp->obj.fs->lfnbuf; si = di = 0; for (;;) { w = p[si++]; /* Get a character */ - if (w < ' ' || w == '/' || w == '\\') { /* Break on end of segment */ - while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator */ + if (w < ' ') break; /* Break if end of the path name */ + if (w == '/' || w == '\\') { /* Break if a separator is found */ + while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ break; } if (di >= _MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ @@ -2550,7 +2668,7 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ lfn[di++] = w; /* Store the Unicode character */ } *path = &p[si]; /* Return pointer to the next segment */ - cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ + cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ #if _FS_RPATH != 0 if ((di == 1 && lfn[di - 1] == '.') || (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ @@ -2575,7 +2693,7 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ if (si) cf |= NS_LOSS | NS_LFN; while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */ - b = i = 0; ni = 8; + i = b = 0; ni = 8; for (;;) { w = lfn[si++]; /* Get an LFN character */ if (!w) break; /* Break on end of the LFN */ @@ -2638,15 +2756,15 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ return FR_OK; -#else /* Non-LFN configuration */ - BYTE b, c, d, *sfn; +#else /* _USE_LFN != 0 : Non-LFN configuration */ + BYTE c, d, *sfn; UINT ni, si, i; const char *p; /* Create file name in directory form */ p = *path; sfn = dp->fn; mem_set(sfn, ' ', 11); - si = i = b = 0; ni = 8; + si = i = 0; ni = 8; #if _FS_RPATH != 0 if (p[si] == '.') { /* Is this a dot entry? */ for (;;) { @@ -2655,29 +2773,29 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ sfn[i++] = c; } if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; - *path = &p[si]; /* Return pointer to the next segment */ - sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */ + *path = p + si; /* Return pointer to the next segment */ + sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of the path */ return FR_OK; } #endif for (;;) { c = (BYTE)p[si++]; - if (c <= ' ' || c == '/' || c == '\\') { /* Break on end of segment */ - while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator */ + if (c <= ' ') break; /* Break if end of the path name */ + if (c == '/' || c == '\\') { /* Break if a separator is found */ + while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ break; } - if (c == '.' || i >= ni) { - if (ni != 8 || c != '.') return FR_INVALID_NAME; - i = 8; ni = 11; - b <<= 2; continue; + if (c == '.' || i >= ni) { /* End of body or over size? */ + if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Over size or invalid dot */ + i = 8; ni = 11; /* Goto extension */ + continue; } if (c >= 0x80) { /* Extended character? */ - b |= 3; /* Eliminate NT flag */ #ifdef _EXCVT c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */ #else #if !_DF1S - return FR_INVALID_NAME; /* Reject extended characters (ASCII cfg) */ + return FR_INVALID_NAME; /* Reject extended characters (ASCII only cfg) */ #endif #endif } @@ -2688,30 +2806,18 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ sfn[i++] = d; } else { /* SBC */ if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */ - if (IsUpper(c)) { /* ASCII large capital? */ - b |= 2; - } else { - if (IsLower(c)) { /* ASCII small capital? */ - b |= 1; c -= 0x20; - } - } + if (IsLower(c)) c -= 0x20; /* To upper */ sfn[i++] = c; } } - *path = &p[si]; /* Return pointer to the next segment */ - c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ - + *path = p + si; /* Return pointer to the next segment */ if (i == 0) return FR_INVALID_NAME; /* Reject nul string */ - if (sfn[0] == DDEM) sfn[0] = RDDEM; /* When first character collides with DDEM, replace it with RDDEM */ - - if (ni == 8) b <<= 2; - if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */ - if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Name body has only small capital) */ - sfn[NSFLAG] = c; /* Store NT flag, File name is created */ + if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ + sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ return FR_OK; -#endif +#endif /* _USE_LFN != 0 */ } @@ -2735,14 +2841,16 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ #if _FS_RPATH != 0 if (*path != '/' && *path != '\\') { /* Without heading separator */ - obj->sclust = fs->cdir; /* Start from the current directory */ + obj->sclust = fs->cdir; /* Start from current directory */ } else #endif { /* With heading separator */ while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ - obj->sclust = 0; /* Start from the root directory */ + obj->sclust = 0; /* Start from root directory */ } -#if _FS_EXFAT && _FS_RPATH != 0 +#if _FS_EXFAT + obj->n_frag = 0; /* Invalidate last fragment counter of the object */ +#if _FS_RPATH != 0 if (fs->fs_type == FS_EXFAT && obj->sclust) { /* Retrieve the sub-directory status if needed */ DIR dj; @@ -2754,6 +2862,7 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ obj->objsize = ld_dword(fs->dirbuf + XDIR_FileSize); obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; } +#endif #endif if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ @@ -2784,8 +2893,8 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ res = FR_NO_PATH; break; } #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { - obj->c_scl = obj->sclust; /* Save containing directory information for next dir */ + if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ + obj->c_scl = obj->sclust; obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; obj->c_ofs = dp->blk_ofs; obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Open next directory */ @@ -2794,7 +2903,7 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ } else #endif { - obj->sclust = ld_clust(fs, &fs->win[dp->dptr % SS(fs)]); /* Open next directory */ + obj->sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ } } } @@ -2818,7 +2927,7 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ UINT i; int vol = -1; #if _STR_VOLUME_ID /* Find string drive id */ - static const char* const str[] = {_VOLUME_STRS}; + static const char* const volid[] = {_VOLUME_STRS}; const char *sp; char c; TCHAR tc; @@ -2829,7 +2938,7 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ for (tt = *path; (UINT)*tt >= (_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find ':' in the path */ if (*tt == ':') { /* If a ':' is exist in the path name */ tp = *path; - i = *tp++ - '0'; + i = *tp++ - '0'; if (i < 10 && tp == tt) { /* Is there a numeric drive id? */ if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */ vol = (int)i; @@ -2840,7 +2949,7 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ else { /* No numeric drive number, find string drive id */ i = 0; tt++; do { - sp = str[i]; tp = *path; + sp = volid[i]; tp = *path; do { /* Compare a string drive id with path name */ c = *sp++; tc = *tp++; if (IsLower(tc)) tc -= 0x20; @@ -2873,18 +2982,20 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ static BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ FATFS* fs, /* File system object */ - DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */ + DWORD sect /* Sector# (lba) to load and check if it is an FAT-VBR or not */ ) { fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */ - if (ld_word(&fs->win[BS_55AA]) != 0xAA55) return 3; /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */ + if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed here even if the sector size is >512) */ - if ((ld_dword(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */ - if ((ld_dword(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */ + if (fs->win[BS_JmpBoot] == 0xE9 || (fs->win[BS_JmpBoot] == 0xEB && fs->win[BS_JmpBoot + 2] == 0x90)) { + if ((ld_dword(fs->win + BS_FilSysType) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */ + if (ld_dword(fs->win + BS_FilSysType32) == 0x33544146) return 0; /* Check "FAT3" string */ + } #if _FS_EXFAT - if (!mem_cmp(&fs->win[BS_OEMName], "EXFAT ", 8)) return 1; + if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; #endif return 2; } @@ -2912,7 +3023,7 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ UINT i; - /* Get logical drive number from the path name */ + /* Get logical drive number */ *rfs = 0; vol = get_ldnumber(path); if (vol < 0) return FR_INVALID_DRIVE; @@ -2924,7 +3035,7 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ ENTER_FF(fs); /* Lock the volume */ *rfs = fs; /* Return pointer to the file system object */ - mode &= ~FA_READ; /* Desired access mode, write access or not */ + mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ if (fs->fs_type) { /* If the volume has been mounted */ stat = disk_status(fs->drv); if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ @@ -2947,62 +3058,64 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ return FR_WRITE_PROTECTED; } -#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ - if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK - || SS(fs) < _MIN_SS || SS(fs) > _MAX_SS) return FR_DISK_ERR; +#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ + if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; + if (SS(fs) > _MAX_SS || SS(fs) < _MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif - /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */ + + /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */ bsect = 0; - fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT boot sector as SFD */ - if (fmt == 2 || (fmt < 2 && LD2PT(vol))) { /* Not an FAT boot sector or forced partition number */ - for (i = 0; i < 4; i++) { /* Get partition offset */ - pt = fs->win + MBR_Table + i * SZ_PTE; - br[i] = pt[4] ? ld_dword(&pt[8]) : 0; + fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ + if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */ + for (i = 0; i < 4; i++) { /* Get partition offset */ + pt = fs->win + (MBR_Table + i * SZ_PTE); + br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0; } - i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ + i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ if (i) i--; - do { /* Find an FAT volume */ + do { /* Find an FAT volume */ bsect = br[i]; fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ - } while (!LD2PT(vol) && fmt >= 2 && ++i < 4); + } while (LD2PT(vol) == 0 && fmt >= 2 && ++i < 4); } if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ - /* An FAT volume is found. Following code initializes the file system object */ + /* An FAT volume is found (bsect). Following code initializes the file system object */ #if _FS_EXFAT if (fmt == 1) { QWORD maxlba; - for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && !fs->win[i]; i++) ; /* Check zero filler */ + for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT revision (Must be 1.0) */ - if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ + if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ return FR_NO_FILESYSTEM; + } - maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Number of sectors on the volume */ + maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ - if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Must be 1) */ + if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */ nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ + if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ fs->n_fatent = nclst + 2; - if (fs->n_fatent >= 0x80000000) return FR_NO_FILESYSTEM; /* (Must be <= 0x7FFFFFFF) */ /* Boundaries and Limits */ fs->volbase = bsect; fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); - if (maxlba < fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ + if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); /* Check if bitmap location is in assumption (at the first cluster) */ @@ -3013,68 +3126,63 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ if (i == SS(fs)) return FR_NO_FILESYSTEM; #if !_FS_READONLY fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ -#endif -#if _USE_LFN == 1 - fs->dirbuf = DirBuf; /* Static directory block working buuffer */ #endif fmt = FS_EXFAT; /* FAT sub-type */ } else -#endif +#endif /* _FS_EXFAT */ { if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ - fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ + fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); fs->fsize = fasize; - fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ - fasize *= fs->n_fats; /* Number of sectors for FAT area */ + fasize *= fs->n_fats; /* Number of sectors for FAT area */ - fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ + fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ - tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ + tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); - nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ - if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ + nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ + if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ /* Determine the FAT sub type */ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ - if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ - if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - fmt = FS_FAT12; - if (nclst >= MIN_FAT16) fmt = FS_FAT16; - if (nclst >= MIN_FAT32) fmt = FS_FAT32; + if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ + if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + fmt = FS_FAT32; + if (nclst <= MAX_FAT16) fmt = FS_FAT16; + if (nclst <= MAX_FAT12) fmt = FS_FAT12; /* Boundaries and Limits */ - fs->n_fatent = nclst + 2; /* Number of FAT entries */ - fs->volbase = bsect; /* Volume start sector */ - fs->fatbase = bsect + nrsv; /* FAT start sector */ - fs->database = bsect + sysect; /* Data start sector */ + fs->n_fatent = nclst + 2; /* Number of FAT entries */ + fs->volbase = bsect; /* Volume start sector */ + fs->fatbase = bsect + nrsv; /* FAT start sector */ + fs->database = bsect + sysect; /* Data start sector */ if (fmt == FS_FAT32) { if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ - if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ + if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ - szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ + szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ } else { if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM;/* (BPB_RootEntCnt must not be 0) */ - fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ - szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ + fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ + szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); } if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ #if !_FS_READONLY - /* Initialize cluster allocation information */ - fs->last_clst = fs->free_clst = 0xFFFFFFFF; - /* Get FSINFO if available */ + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ fs->fsi_flag = 0x80; #if (_FS_NOFSINFO & 3) != 3 if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo32 == 1 */ @@ -3094,16 +3202,22 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ #endif } } +#endif /* (_FS_NOFSINFO & 3) != 3 */ +#endif /* !_FS_READONLY */ + } + + fs->fs_type = fmt; /* FAT sub-type */ + fs->id = ++Fsid; /* File system mount ID */ +#if _USE_LFN == 1 + fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ +#if _FS_EXFAT + fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ #endif #endif - } - - fs->fs_type = fmt; /* FAT sub-type */ - fs->id = ++Fsid; /* File system mount ID */ #if _FS_RPATH != 0 - fs->cdir = 0; /* Initialize current directory */ + fs->cdir = 0; /* Initialize current directory */ #endif -#if _FS_LOCK != 0 /* Clear file lock semaphores */ +#if _FS_LOCK != 0 /* Clear file lock semaphores */ clear_lock(fs); #endif return FR_OK; @@ -3118,21 +3232,19 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ - void* dfp, /* Pointer to the FIL/DIR object to check validity */ + _FDID* obj, /* Pointer to the _OBJ, the 1st member in the FIL/DIR object, to check validity */ FATFS** fs /* Pointer to pointer to the owner file system object to return */ ) { - _FDID *obj = (_FDID*)dfp; /* Assuming .obj in the FIL/DIR is the first member */ FRESULT res; - - if (!dfp || !obj->fs || !obj->fs->fs_type || obj->fs->id != obj->id || (disk_status(obj->fs->drv) & STA_NOINIT)) { - *fs = 0; /* The object is invalid */ - res = FR_INVALID_OBJECT; + if (!obj || !obj->fs || !obj->fs->fs_type || obj->fs->id != obj->id || (disk_status(obj->fs->drv) & STA_NOINIT)) { + *fs = 0; + res = FR_INVALID_OBJECT; /* The object is invalid */ } else { *fs = obj->fs; /* Owner file sytem object */ ENTER_FF(obj->fs); /* Lock file system */ - res = FR_OK; + res = FR_OK; /* Valid object */ } return res; } @@ -3164,6 +3276,7 @@ FRESULT f_mount ( const TCHAR *rp = path; + /* Get logical drive number */ vol = get_ldnumber(&rp); if (vol < 0) return FR_INVALID_DRIVE; cfs = FatFs[vol]; /* Pointer to fs object */ @@ -3209,20 +3322,20 @@ FRESULT f_open ( DIR dj; FATFS *fs; #if !_FS_READONLY - DWORD dw, cl; + DWORD dw, cl, bcs, clst, sc; + FSIZE_t ofs; #endif - DEF_NAMBUF; + DEF_NAMBUF if (!fp) return FR_INVALID_OBJECT; - fp->obj.fs = 0; /* Clear file object */ - /* Get logical drive number */ - mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW; + /* Get logical drive */ + mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND | FA_SEEKEND; res = find_volume(&path, &fs, mode); if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(dj); + INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ #if !_FS_READONLY /* R/W configuration */ if (res == FR_OK) { @@ -3238,12 +3351,13 @@ FRESULT f_open ( /* Create or Open a file */ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { if (res != FR_OK) { /* No file, create new */ - if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ + if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ #if _FS_LOCK != 0 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else res = dir_register(&dj); #endif + } mode |= FA_CREATE_ALWAYS; /* File is created */ } else { /* Any object is already existing */ @@ -3262,6 +3376,7 @@ FRESULT f_open ( fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + fp->obj.n_frag = 0; /* Initialize directory entry block */ st_dword(fs->dirbuf + XDIR_CrtTime, dw); /* Set created time */ fs->dirbuf[XDIR_CrtTime10] = 0; @@ -3282,7 +3397,7 @@ FRESULT f_open ( { /* Clean directory info */ st_dword(dj.dir + DIR_CrtTime, dw); /* Set created time */ - st_dword(dj.dir + DIR_WrtTime, dw); /* Set modified time */ + st_dword(dj.dir + DIR_ModTime, dw); /* Set modified time */ dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ cl = ld_clust(fs, dj.dir); /* Get cluster chain */ st_clust(fs, dj.dir, 0); /* Reset file allocation info */ @@ -3313,7 +3428,7 @@ FRESULT f_open ( } if (res == FR_OK) { if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ - mode |= _FA_MODIFIED; + mode |= FA_MODIFIED; fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dj.dir; #if _FS_LOCK != 0 @@ -3336,33 +3451,62 @@ FRESULT f_open ( if (res == FR_OK) { #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { - fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get allocation info */ - fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); - fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; - fp->obj.c_scl = dj.obj.sclust; + fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */ fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; fp->obj.c_ofs = dj.blk_ofs; + fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object allocation info */ + fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + fp->obj.n_frag = 0; } else #endif { - fp->obj.sclust = ld_clust(fs, dj.dir); /* Get allocation info */ + fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */ fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); } #if _USE_FASTSEEK - fp->cltbl = 0; /* Normal seek mode */ + fp->cltbl = 0; /* Disable fast seek mode */ #endif - fp->err = 0; /* Clear error flag */ - fp->fptr = 0; /* Set file pointer */ - fp->sect = 0; /* Invalidate current data sector */ - fp->flag = mode; /* File access mode */ fp->obj.fs = fs; /* Validate the file object */ fp->obj.id = fs->id; + fp->flag = mode; /* Set file access mode */ + fp->err = 0; /* Clear error flag */ + fp->sect = 0; /* Invalidate current data sector */ + fp->fptr = 0; /* Set file pointer top of the file */ +#if !_FS_READONLY +#if !_FS_TINY + mem_set(fp->buf, 0, _MAX_SS); /* Clear sector buffer */ +#endif + if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ + fp->fptr = fp->obj.objsize; /* Offset to seek */ + bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */ + clst = fp->obj.sclust; /* Follow the cluster chain */ + for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) { + clst = get_fat(&fp->obj, clst); + if (clst <= 1) res = FR_INT_ERR; + if (clst == 0xFFFFFFFF) res = FR_DISK_ERR; + } + fp->clust = clst; + if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ + if ((sc = clust2sect(fs, clst)) == 0) { + res = FR_INT_ERR; + } else { + fp->sect = sc + (DWORD)(ofs / SS(fs)); +#if !_FS_TINY + if (disk_read(fs->drv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; +#endif + } + } + } +#endif } FREE_NAMBUF(); } - LEAVE_FF(dj.obj.fs, res); + if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */ + + LEAVE_FF(fs, res); } @@ -3388,7 +3532,7 @@ FRESULT f_read ( *br = 0; /* Clear read byte counter */ - res = validate(fp, &fs); + res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ remain = fp->obj.objsize - fp->fptr; @@ -3396,7 +3540,7 @@ FRESULT f_read ( for ( ; btr; /* Repeat until all data read */ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { - if ((fp->fptr % SS(fs)) == 0) { /* On the sector boundary? */ + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ @@ -3423,16 +3567,14 @@ FRESULT f_read ( if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } - if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) { - ABORT(fs, FR_DISK_ERR); - } + if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); #if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ #if _FS_TINY if (fs->wflag && fs->winsect - sect < cc) { mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); } #else - if ((fp->flag & _FA_DIRTY) && fp->sect - sect < cc) { + if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) { mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); } #endif @@ -3443,29 +3585,23 @@ FRESULT f_read ( #if !_FS_TINY if (fp->sect != sect) { /* Load data sector if not in cache */ #if !_FS_READONLY - if (fp->flag & _FA_DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { - ABORT(fs, FR_DISK_ERR); - } - fp->flag &= ~_FA_DIRTY; + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { /* Fill sector cache */ - ABORT(fs, FR_DISK_ERR); - } + if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ } #endif fp->sect = sect; } - rcnt = SS(fs) - ((UINT)fp->fptr % SS(fs)); /* Get partial sector data from sector buffer */ - if (rcnt > btr) rcnt = btr; + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ #if _FS_TINY - if (move_window(fs, fp->sect) != FR_OK) { /* Move sector window */ - ABORT(fs, FR_DISK_ERR); - } - mem_cpy(rbuff, &fs->win[fp->fptr % SS(fs)], rcnt); /* Pick partial sector */ + if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ + mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ #else - mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fs)], rcnt); /* Pick partial sector */ + mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ #endif } @@ -3495,19 +3631,18 @@ FRESULT f_write ( *bw = 0; /* Clear write byte counter */ - res = validate(fp, &fs); + res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ - /* Check fptr wrap-around (file size cannot exceed the limit on each FAT specs) */ - if ((_FS_EXFAT && fs->fs_type == FS_EXFAT && fp->fptr + btw < fp->fptr) - || (DWORD)fp->fptr + btw < (DWORD)fp->fptr) { + /* Check fptr wrap-around (file size cannot reach 4GiB on FATxx) */ + if ((!_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); } for ( ; btw; /* Repeat until all data written */ wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize, *bw += wcnt, btw -= wcnt) { - if ((fp->fptr % SS(fs)) == 0) { /* On the sector boundary? */ + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ if (csect == 0) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ @@ -3532,15 +3667,11 @@ FRESULT f_write ( if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */ } #if _FS_TINY - if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) { /* Write-back sector cache */ - ABORT(fs, FR_DISK_ERR); - } + if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ #else - if (fp->flag & _FA_DIRTY) { /* Write-back sector cache */ - if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { - ABORT(fs, FR_DISK_ERR); - } - fp->flag &= ~_FA_DIRTY; + if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; } #endif sect = clust2sect(fs, fp->clust); /* Get current sector */ @@ -3551,9 +3682,7 @@ FRESULT f_write ( if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } - if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) { - ABORT(fs, FR_DISK_ERR); - } + if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); #if _FS_MINIMIZE <= 2 #if _FS_TINY if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ @@ -3563,7 +3692,7 @@ FRESULT f_write ( #else if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); - fp->flag &= ~_FA_DIRTY; + fp->flag &= (BYTE)~FA_DIRTY; } #endif #endif @@ -3571,35 +3700,32 @@ FRESULT f_write ( continue; } #if _FS_TINY - if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling at growing edge */ + if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */ if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); fs->winsect = sect; } #else - if (fp->sect != sect) { /* Fill sector cache with file data */ - if (fp->fptr < fp->obj.objsize && - disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { - ABORT(fs, FR_DISK_ERR); - } + if (fp->sect != sect && /* Fill sector cache with file data */ + fp->fptr < fp->obj.objsize && + disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { + ABORT(fs, FR_DISK_ERR); } #endif fp->sect = sect; } - wcnt = SS(fs) - ((UINT)fp->fptr % SS(fs)); /* Put partial sector into file I/O buffer */ - if (wcnt > btw) wcnt = btw; + wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ #if _FS_TINY - if (move_window(fs, fp->sect) != FR_OK) { /* Move sector window */ - ABORT(fs, FR_DISK_ERR); - } - mem_cpy(&fs->win[fp->fptr % SS(fs)], wbuff, wcnt); /* Fit partial sector */ + if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ + mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ fs->wflag = 1; #else - mem_cpy(&fp->buf[fp->fptr % SS(fs)], wbuff, wcnt); /* Fit partial sector */ - fp->flag |= _FA_DIRTY; + mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ + fp->flag |= FA_DIRTY; #endif } - fp->flag |= _FA_MODIFIED; /* Set file change flag */ + fp->flag |= FA_MODIFIED; /* Set file change flag */ LEAVE_FF(fs, FR_OK); } @@ -3619,46 +3745,47 @@ FRESULT f_sync ( FATFS *fs; DWORD tm; BYTE *dir; - DEF_DIRBUF; - +#if _FS_EXFAT + DIR dj; + DEF_NAMBUF +#endif - res = validate(fp, &fs); /* Check validity of the object */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { - if (fp->flag & _FA_MODIFIED) { /* Is there any change to the file? */ + if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ #if !_FS_TINY - if (fp->flag & _FA_DIRTY) { /* Write-back cached data if needed */ - if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { - LEAVE_FF(fs, FR_DISK_ERR); - } - fp->flag &= ~_FA_DIRTY; + if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; } #endif /* Update the directory entry */ tm = GET_FATTIME(); /* Modified time */ #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { - res = fill_fat_chain(&fp->obj); /* Create FAT chain if needed */ + res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */ if (res == FR_OK) { - DIR dj; - - INIT_DIRBUF(fs); + res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + } + if (res == FR_OK) { + INIT_NAMBUF(fs); res = load_obj_dir(&dj, &fp->obj); /* Load directory entry block */ if (res == FR_OK) { - fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive bit */ - fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation info */ + fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive bit */ + fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation info */ st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); - st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */ + st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */ fs->dirbuf[XDIR_ModTime10] = 0; st_dword(fs->dirbuf + XDIR_AccTime, 0); res = store_xdir(&dj); /* Restore it to the directory */ if (res == FR_OK) { res = sync_fs(fs); - fp->flag &= ~_FA_MODIFIED; + fp->flag &= (BYTE)~FA_MODIFIED; } } - FREE_DIRBUF(); + FREE_NAMBUF(); } } else #endif @@ -3669,11 +3796,11 @@ FRESULT f_sync ( dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation info */ st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ - st_dword(dir + DIR_WrtTime, tm); /* Update modified time */ + st_dword(dir + DIR_ModTime, tm); /* Update modified time */ st_word(dir + DIR_LstAccDate, 0); fs->wflag = 1; res = sync_fs(fs); /* Restore it to the directory */ - fp->flag &= ~_FA_MODIFIED; + fp->flag &= (BYTE)~FA_MODIFIED; } } } @@ -3703,7 +3830,7 @@ FRESULT f_close ( if (res == FR_OK) #endif { - res = validate(fp, &fs); /* Lock volume */ + res = validate(&fp->obj, &fs); /* Lock volume */ if (res == FR_OK) { #if _FS_LOCK != 0 res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ @@ -3723,11 +3850,11 @@ FRESULT f_close ( +#if _FS_RPATH >= 1 /*-----------------------------------------------------------------------*/ /* Change Current Directory or Current Drive, Get Current Directory */ /*-----------------------------------------------------------------------*/ -#if _FS_RPATH >= 1 #if _VOLUMES >= 2 FRESULT f_chdrive ( const TCHAR* path /* Drive number */ @@ -3736,10 +3863,11 @@ FRESULT f_chdrive ( int vol; + /* Get logical drive number */ vol = get_ldnumber(&path); if (vol < 0) return FR_INVALID_DRIVE; - CurrVol = (BYTE)vol; + CurrVol = (BYTE)vol; /* Set it as current volume */ return FR_OK; } @@ -3753,13 +3881,13 @@ FRESULT f_chdir ( FRESULT res; DIR dj; FATFS *fs; - DEF_NAMBUF; + DEF_NAMBUF - /* Get logical drive number */ + /* Get logical drive */ res = find_volume(&path, &fs, 0); if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(dj); + INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the path */ if (res == FR_OK) { /* Follow completed */ if (dj.fn[NSFLAG] & NS_NONAME) { @@ -3810,15 +3938,15 @@ FRESULT f_getcwd ( DWORD ccl; TCHAR *tp; FILINFO fno; - DEF_NAMBUF; + DEF_NAMBUF *buff = 0; - /* Get logical drive number */ + /* Get logical drive */ res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ if (res == FR_OK) { dj.obj.fs = fs; - INIT_NAMBUF(dj); + INIT_NAMBUF(fs); i = len; /* Bottom of buffer (directory stack base) */ if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ @@ -3867,6 +3995,7 @@ FRESULT f_getcwd ( LEAVE_FF(fs, res); } + #endif /* _FS_RPATH >= 2 */ #endif /* _FS_RPATH >= 1 */ @@ -3890,14 +4019,21 @@ FRESULT f_lseek ( DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; #endif - res = validate(fp, &fs); /* Check validity of the object */ - if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res == FR_OK) res = (FRESULT)fp->err; +#if _FS_EXFAT && !_FS_READONLY + if (res == FR_OK && fs->fs_type == FS_EXFAT) { + res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + } +#endif + if (res != FR_OK) LEAVE_FF(fs, res); + #if _USE_FASTSEEK if (fp->cltbl) { /* Fast seek */ if (ofs == CREATE_LINKMAP) { /* Create CLMT */ tbl = fp->cltbl; tlen = *tbl++; ulen = 2; /* Given table size and required table size */ - cl = fp->obj.sclust; /* Top of the chain */ + cl = fp->obj.sclust; /* Origin of the chain */ if (cl) { do { /* Get a fragment */ @@ -3926,20 +4062,16 @@ FRESULT f_lseek ( fp->clust = clmt_clust(fp, ofs - 1); dsc = clust2sect(fs, fp->clust); if (!dsc) ABORT(fs, FR_INT_ERR); - dsc += (ofs - 1) / SS(fs) & (fs->csize - 1); + dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1); if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */ #if !_FS_TINY #if !_FS_READONLY - if (fp->flag & _FA_DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { - ABORT(fp, FR_DISK_ERR); - } - fp->flag &= ~_FA_DIRTY; + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) { /* Load current sector */ - ABORT(fs, FR_DISK_ERR); - } + if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ #endif fp->sect = dsc; } @@ -3950,19 +4082,19 @@ FRESULT f_lseek ( /* Normal Seek */ { - if (ofs > fp->obj.objsize /* In read-only mode, clip offset with the file size */ -#if !_FS_READONLY - && !(fp->flag & FA_WRITE) +#if _FS_EXFAT + if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4GiB-1 if at FATxx */ #endif - ) ofs = fp->obj.objsize; - + if (ofs > fp->obj.objsize && (_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ + ofs = fp->obj.objsize; + } ifptr = fp->fptr; fp->fptr = nsect = 0; if (ofs) { bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ if (ifptr > 0 && (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ - fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */ + fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1); /* start from the current cluster */ ofs -= fp->fptr; clst = fp->clust; } else { /* When seek to back cluster, */ @@ -3979,20 +4111,25 @@ FRESULT f_lseek ( } if (clst != 0) { while (ofs > bcs) { /* Cluster following loop */ + ofs -= bcs; fp->fptr += bcs; #if !_FS_READONLY if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ - clst = create_chain(&fp->obj, clst); /* Force stretch if in write mode */ - if (clst == 0) { /* When disk gets full, clip file size */ - ofs = bcs; break; + if (_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ + fp->obj.objsize = fp->fptr; + fp->flag |= FA_MODIFIED; + } + clst = create_chain(&fp->obj, clst); /* Follow chain with forceed stretch */ + if (clst == 0) { /* Clip file size in case of disk full */ + ofs = 0; break; } } else #endif + { clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */ + } if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR); fp->clust = clst; - fp->fptr += bcs; - ofs -= bcs; } fp->fptr += ofs; if (ofs % SS(fs)) { @@ -4002,28 +4139,22 @@ FRESULT f_lseek ( } } } + if (!_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ + fp->obj.objsize = fp->fptr; + fp->flag |= FA_MODIFIED; + } if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ #if !_FS_TINY #if !_FS_READONLY - if (fp->flag & _FA_DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { - ABORT(fs, FR_DISK_ERR); - } - fp->flag &= ~_FA_DIRTY; + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) { /* Fill sector cache */ - ABORT(fs, FR_DISK_ERR); - } + if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ #endif fp->sect = nsect; } -#if !_FS_READONLY - if (fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ - fp->obj.objsize = fp->fptr; - fp->flag |= _FA_MODIFIED; - } -#endif } LEAVE_FF(fs, res); @@ -4044,33 +4175,33 @@ FRESULT f_opendir ( FRESULT res; FATFS *fs; _FDID *obj; - DEF_NAMBUF; + DEF_NAMBUF if (!dp) return FR_INVALID_OBJECT; - /* Get logical drive number */ + /* Get logical drive */ obj = &dp->obj; res = find_volume(&path, &fs, 0); if (res == FR_OK) { obj->fs = fs; - INIT_NAMBUF(*dp); + INIT_NAMBUF(fs); res = follow_path(dp, path); /* Follow the path to the directory */ if (res == FR_OK) { /* Follow completed */ if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ if (obj->attr & AM_DIR) { /* This object is a sub-directory */ #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { - obj->c_scl = obj->sclust; /* Save containing directory inforamation */ + obj->c_scl = obj->sclust; /* Get containing directory inforamation */ obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; obj->c_ofs = dp->blk_ofs; - obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object location and status */ + obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object allocation info */ obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; } else #endif { - obj->sclust = ld_clust(fs, dp->dir); /* Get object location */ + obj->sclust = ld_clust(fs, dp->dir); /* Get object allocation info */ } } else { /* This object is a file */ res = FR_NO_PATH; @@ -4114,7 +4245,7 @@ FRESULT f_closedir ( FATFS *fs; - res = validate(dp, &fs); + res = validate(&dp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { #if _FS_LOCK != 0 if (dp->obj.lockid) { /* Decrement sub-directory open counter */ @@ -4146,15 +4277,15 @@ FRESULT f_readdir ( { FRESULT res; FATFS *fs; - DEF_NAMBUF; + DEF_NAMBUF - res = validate(dp, &fs); /* Check validity of the object */ + res = validate(&dp->obj, &fs); /* Check validity of the directory object */ if (res == FR_OK) { if (!fno) { res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { - INIT_NAMBUF(*dp); + INIT_NAMBUF(fs); res = dir_read(dp, 0); /* Read an item */ if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ if (res == FR_OK) { /* A valid entry is found */ @@ -4234,13 +4365,13 @@ FRESULT f_stat ( { FRESULT res; DIR dj; - DEF_NAMBUF; + DEF_NAMBUF - /* Get logical drive number */ + /* Get logical drive */ res = find_volume(&path, &dj.obj.fs, 0); if (res == FR_OK) { - INIT_NAMBUF(dj); + INIT_NAMBUF(dj.obj.fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK) { /* Follow completed */ if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */ @@ -4276,7 +4407,7 @@ FRESULT f_getfree ( _FDID obj; - /* Get logical drive number */ + /* Get logical drive */ res = find_volume(&path, &fs, 0); if (res == FR_OK) { *fatfs = fs; /* Return ptr to the fs object */ @@ -4309,7 +4440,7 @@ FRESULT f_getfree ( if (!(bm & 1)) nfree++; bm >>= 1; } - i = (i + 1) & (SS(fs) - 1); + i = (i + 1) % SS(fs); } while (clst); } else #endif @@ -4358,11 +4489,11 @@ FRESULT f_truncate ( DWORD ncl; - res = validate(fp, &fs); /* Check validity of the object */ - if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ - if (fp->obj.objsize > fp->fptr) { + if (fp->fptr < fp->obj.objsize) { /* Process when fptr is not on the eof */ if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ res = remove_chain(&fp->obj, fp->obj.sclust, 0); fp->obj.sclust = 0; @@ -4376,13 +4507,13 @@ FRESULT f_truncate ( } } fp->obj.objsize = fp->fptr; /* Set file size to current R/W point */ - fp->flag |= _FA_MODIFIED; + fp->flag |= FA_MODIFIED; #if !_FS_TINY - if (res == FR_OK && (fp->flag & _FA_DIRTY)) { + if (res == FR_OK && (fp->flag & FA_DIRTY)) { if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { res = FR_DISK_ERR; } else { - fp->flag &= ~_FA_DIRTY; + fp->flag &= (BYTE)~FA_DIRTY; } } #endif @@ -4410,14 +4541,14 @@ FRESULT f_unlink ( #if _FS_EXFAT _FDID obj; #endif - DEF_NAMBUF; + DEF_NAMBUF - /* Get logical drive number */ + /* Get logical drive */ res = find_volume(&path, &fs, FA_WRITE); dj.obj.fs = fs; if (res == FR_OK) { - INIT_NAMBUF(dj); + INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { res = FR_INVALID_NAME; /* Cannot remove dot entry */ @@ -4445,7 +4576,7 @@ FRESULT f_unlink ( { dclst = ld_clust(fs, dj.dir); } - if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory ? */ + if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ #if _FS_RPATH != 0 if (dclst == fs->cdir) { /* Is it the current directory? */ res = FR_DENIED; @@ -4504,14 +4635,14 @@ FRESULT f_mkdir ( BYTE *dir; UINT n; DWORD dsc, dcl, pcl, tm; - DEF_NAMBUF; + DEF_NAMBUF - /* Get logical drive number */ + /* Get logical drive */ res = find_volume(&path, &fs, FA_WRITE); dj.obj.fs = fs; if (res == FR_OK) { - INIT_NAMBUF(dj); + INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { @@ -4534,12 +4665,11 @@ FRESULT f_mkdir ( mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ dir[DIR_Name] = '.'; dir[DIR_Attr] = AM_DIR; - st_dword(dir + DIR_WrtTime, tm); + st_dword(dir + DIR_ModTime, tm); st_clust(fs, dir, dcl); mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */ dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; - if (fs->fs_type == FS_FAT32 && pcl == fs->dirbase) - pcl = 0; + if (fs->fs_type == FS_FAT32 && pcl == fs->dirbase) pcl = 0; st_clust(fs, dir + SZDIRE, pcl); } for (n = fs->csize; n; n--) { /* Write dot entries and clear following sectors */ @@ -4550,27 +4680,31 @@ FRESULT f_mkdir ( mem_set(dir, 0, SS(fs)); } } - if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */ + if (res == FR_OK) { + res = dir_register(&dj); /* Register the object to the directoy */ + } if (res == FR_OK) { #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { - st_dword(fs->dirbuf + XDIR_ModTime, tm); - st_dword(fs->dirbuf + XDIR_FstClus, dcl); - st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); + if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ + st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ + st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ + st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */ st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize); - fs->dirbuf[XDIR_GenFlags] = 3; - fs->dirbuf[XDIR_Attr] = AM_DIR; + fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag (contiguous) */ + fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ res = store_xdir(&dj); } else #endif { dir = dj.dir; - st_dword(dir + DIR_WrtTime, tm); /* Created time */ + st_dword(dir + DIR_ModTime, tm); /* Created time */ st_clust(fs, dir, dcl); /* Table start cluster */ dir[DIR_Attr] = AM_DIR; /* Attribute */ fs->wflag = 1; } - res = sync_fs(fs); + if (res == FR_OK) { + res = sync_fs(fs); + } } else { remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ } @@ -4598,18 +4732,20 @@ FRESULT f_rename ( FATFS *fs; BYTE buf[_FS_EXFAT ? SZDIRE * 2 : 24], *dir; DWORD dw; - DEF_NAMBUF; + DEF_NAMBUF - get_ldnumber(&path_new); /* Ignore drive number of new name */ - res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive number of the old object */ + get_ldnumber(&path_new); /* Snip drive number of new name off */ + res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */ if (res == FR_OK) { djo.obj.fs = fs; - INIT_NAMBUF(djo); + INIT_NAMBUF(fs); res = follow_path(&djo, path_old); /* Check old object */ if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ #if _FS_LOCK != 0 - if (res == FR_OK) res = chk_lock(&djo, 2); + if (res == FR_OK) { + res = chk_lock(&djo, 2); + } #endif if (res == FR_OK) { /* Object to be renamed is found */ #if _FS_EXFAT @@ -4619,17 +4755,19 @@ FRESULT f_rename ( mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ mem_cpy(&djn, &djo, sizeof djo); - res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ - if (res == FR_OK) res = FR_EXIST; /* Is new name already in use? */ - if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ - res = dir_register(&djn); /* Register the new entry */ + res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ + if (res == FR_OK) { /* Is new name already in use by any other object? */ + res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; + } + if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; nh = ld_word(fs->dirbuf + XDIR_NameHash); mem_cpy(fs->dirbuf, buf, SZDIRE * 2); fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; st_word(fs->dirbuf + XDIR_NameHash, nh); -/* Start of critical section where any interruption can cause a cross-link */ +/* Start of critical section where an interruption can cause a cross-link */ res = store_xdir(&djn); } } @@ -4639,7 +4777,9 @@ FRESULT f_rename ( mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about the object except name */ mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ - if (res == FR_OK) res = FR_EXIST; /* Is new name already in use? */ + if (res == FR_OK) { /* Is new name already in use by any other object? */ + res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; + } if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ res = dir_register(&djn); /* Register the new entry */ if (res == FR_OK) { @@ -4652,7 +4792,7 @@ FRESULT f_rename ( if (!dw) { res = FR_INT_ERR; } else { -/* Start of critical section where any interruption can cause a cross-link */ +/* Start of critical section where an interruption can cause a cross-link */ res = move_window(fs, dw); dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ if (res == FR_OK && dir[1] == '.') { @@ -4670,7 +4810,7 @@ FRESULT f_rename ( res = sync_fs(fs); } } -/* End of critical section */ +/* End of the critical section */ } FREE_NAMBUF(); } @@ -4678,8 +4818,6 @@ FRESULT f_rename ( LEAVE_FF(fs, res); } - - #endif /* !_FS_READONLY */ #endif /* _FS_MINIMIZE == 0 */ #endif /* _FS_MINIMIZE <= 1 */ @@ -4701,13 +4839,13 @@ FRESULT f_chmod ( FRESULT res; DIR dj; FATFS *fs; - DEF_NAMBUF; + DEF_NAMBUF - res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive number */ + res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ dj.obj.fs = fs; if (res == FR_OK) { - INIT_NAMBUF(dj); + INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { @@ -4722,7 +4860,9 @@ FRESULT f_chmod ( dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ fs->wflag = 1; } - res = sync_fs(fs); + if (res == FR_OK) { + res = sync_fs(fs); + } } FREE_NAMBUF(); } @@ -4745,29 +4885,29 @@ FRESULT f_utime ( FRESULT res; DIR dj; FATFS *fs; - DEF_NAMBUF; + DEF_NAMBUF - res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive number */ + res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ dj.obj.fs = fs; if (res == FR_OK) { - INIT_NAMBUF(dj); + INIT_NAMBUF(fs); res = follow_path(&dj, path); /* Follow the file path */ if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ if (res == FR_OK) { #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { - st_word(fs->dirbuf + XDIR_ModTime, fno->ftime); - st_word(fs->dirbuf + XDIR_ModTime + 2, fno->fdate); + st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); res = store_xdir(&dj); } else #endif { - st_word(dj.dir + DIR_WrtTime, fno->ftime); - st_word(dj.dir + DIR_WrtDate, fno->fdate); + st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); fs->wflag = 1; } - if (res == FR_OK) res = sync_fs(fs); + if (res == FR_OK) { + res = sync_fs(fs); + } } FREE_NAMBUF(); } @@ -4798,7 +4938,7 @@ FRESULT f_getlabel ( WCHAR w; #endif - /* Get logical drive number */ + /* Get logical drive */ res = find_volume(&path, &fs, 0); /* Get volume label */ @@ -4855,11 +4995,16 @@ FRESULT f_getlabel ( res = move_window(fs, fs->volbase); if (res == FR_OK) { switch (fs->fs_type) { - case FS_EXFAT: di = BPB_VolIDEx; break; - case FS_FAT32: di = BS_VolID32; break; - default: di = BS_VolID; + case FS_EXFAT: + di = BPB_VolIDEx; break; + + case FS_FAT32: + di = BS_VolID32; break; + + default: + di = BS_VolID; } - *vsn = ld_dword(&fs->win[di]); + *vsn = ld_dword(fs->win + di); } } @@ -4886,7 +5031,7 @@ FRESULT f_setlabel ( static const char badchr[] = "\"*+,.:;<=>\?[]|\x7F"; - /* Get logical drive number */ + /* Get logical drive */ res = find_volume(&label, &fs, FA_WRITE); if (res != FR_OK) LEAVE_FF(fs, res); dj.obj.fs = fs; @@ -4895,7 +5040,7 @@ FRESULT f_setlabel ( for (slen = 0; (UINT)label[slen] >= ' '; slen++) ; /* Get name length */ #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { /* At the exFAT */ + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ for (i = j = 0; i < slen; ) { /* Create volume label in directory form */ w = label[i++]; #if !_LFN_UNICODE @@ -4912,7 +5057,7 @@ FRESULT f_setlabel ( slen = j; } else #endif - { /* At the FAT12/16/32 */ + { /* On the FAT12/16/32 volume */ for ( ; slen && label[slen - 1] == ' '; slen--) ; /* Remove trailing spaces */ if (slen) { /* Is there a volume label to be set? */ dirvn[0] = 0; i = j = 0; /* Create volume label in directory form */ @@ -4953,7 +5098,7 @@ FRESULT f_setlabel ( res = dir_read(&dj, 1); /* Get volume label entry */ if (res == FR_OK) { if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { - dj.dir[XDIR_NumLabel] = slen / 2; /* Change the volume label */ + dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2); /* Change the volume label */ mem_cpy(dj.dir + XDIR_Label, dirvn, slen); } else { if (slen) { @@ -4973,7 +5118,7 @@ FRESULT f_setlabel ( mem_set(dj.dir, 0, SZDIRE); /* Clear the entry */ if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ - dj.dir[XDIR_NumLabel] = slen / 2; + dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2); mem_cpy(dj.dir + XDIR_Label, dirvn, slen); } else { dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ @@ -5008,32 +5153,31 @@ FRESULT f_expand ( { FRESULT res; FATFS *fs; - DWORD val, clst, csz, stcl, scl, ncl, tcl; + DWORD n, clst, stcl, scl, ncl, tcl, lclst; - res = validate(fp, &fs); /* Check validity of the object */ - if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); #if _FS_EXFAT if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ #endif - csz = (DWORD)fs->csize * SS(fs); /* Cluster size */ - tcl = (DWORD)(fsz / csz) + ((fsz & (csz - 1)) ? 1 : 0); /* Number of clusters required */ - stcl = fs->last_clst; + n = (DWORD)fs->csize * SS(fs); /* Cluster size */ + tcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0); /* Number of clusters required */ + stcl = fs->last_clst; lclst = 0; if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2; #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ - if (scl == 1) res = FR_INT_ERR; if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; - if (res == FR_OK) { - if (opt) { + if (res == FR_OK) { /* A contiguous free area is found */ + if (opt) { /* Allocate it now */ res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ - fs->last_clst = scl + tcl - 1; - } else { - fs->last_clst = scl - 1; /* Set suggested cluster to start next */ + lclst = scl + tcl - 1; + } else { /* Set it as suggested point for next allocation */ + lclst = scl - 1; } } } else @@ -5041,36 +5185,42 @@ FRESULT f_expand ( { scl = clst = stcl; ncl = 0; for (;;) { /* Find a contiguous cluster block */ - val = get_fat(&fp->obj, clst); + n = get_fat(&fp->obj, clst); if (++clst >= fs->n_fatent) clst = 2; - if (val == 1) { res = FR_INT_ERR; break; } - if (val == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } - if (val == 0) { /* Is it a free cluster? */ - if (++ncl == tcl) break; /* Break if a contiguous cluster block was found */ + if (n == 1) { res = FR_INT_ERR; break; } + if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (n == 0) { /* Is it a free cluster? */ + if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ } else { scl = clst; ncl = 0; /* Not a free cluster */ } - if (clst == stcl) { res = FR_DENIED; break; } /* All cluster scanned? */ + if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ } - if (res == FR_OK) { - if (opt) { - for (clst = scl; tcl; clst++, tcl--) { /* Create a cluster chain on the FAT */ - val = (tcl == 1) ? 0xFFFFFFFF : clst + 1; - res = put_fat(fs, clst, val); + if (res == FR_OK) { /* A contiguous free area is found */ + if (opt) { /* Allocate it now */ + for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ + res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); if (res != FR_OK) break; - fs->last_clst = clst; + lclst = clst; } - } else { - fs->last_clst = scl - 1; /* Set suggested cluster to start next */ + } else { /* Set it as suggested point for next allocation */ + lclst = scl - 1; } } } - if (opt && res == FR_OK) { - fp->obj.sclust = scl; /* Update allocation information */ - fp->obj.objsize = fsz; - if (_FS_EXFAT) fp->obj.stat = 2; - fp->flag |= _FA_MODIFIED; + if (res == FR_OK) { + fs->last_clst = lclst; /* Set suggested start cluster to start next */ + if (opt) { /* Is it allocated now? */ + fp->obj.sclust = scl; /* Update object allocation information */ + fp->obj.objsize = fsz; + if (_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ + fp->flag |= FA_MODIFIED; + if (fs->free_clst <= fs->n_fatent - 2) { /* Update FSINFO */ + fs->free_clst -= tcl; + fs->fsi_flag |= 1; + } + } } LEAVE_FF(fs, res); @@ -5080,10 +5230,10 @@ FRESULT f_expand ( +#if _USE_FORWARD /*-----------------------------------------------------------------------*/ /* Forward data to the stream directly */ /*-----------------------------------------------------------------------*/ -#if _USE_FORWARD FRESULT f_forward ( FIL* fp, /* Pointer to the file object */ @@ -5097,12 +5247,12 @@ FRESULT f_forward ( DWORD clst, sect; FSIZE_t remain; UINT rcnt, csect; - const BYTE *dbuf; + BYTE *dbuf; *bf = 0; /* Clear transfer byte counter */ - res = validate(fp, &fs); /* Check validity of the object */ - if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ remain = fp->obj.objsize - fp->fptr; @@ -5129,9 +5279,9 @@ FRESULT f_forward ( #else if (fp->sect != sect) { /* Fill sector cache with file data */ #if !_FS_READONLY - if (fp->flag & _FA_DIRTY) { /* Write-back dirty sector cache */ + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); - fp->flag &= ~_FA_DIRTY; + fp->flag &= (BYTE)~FA_DIRTY; } #endif if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); @@ -5153,259 +5303,457 @@ FRESULT f_forward ( #if _USE_MKFS && !_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Create file system on the logical drive */ +/* Create an FAT/exFAT volume */ /*-----------------------------------------------------------------------*/ -#define N_ROOTDIR 512 /* Number of root directory entries for FAT12/16 */ -#define N_FATS 1 /* Number of FATs (1 or 2) */ - FRESULT f_mkfs ( const TCHAR* path, /* Logical drive number */ - BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */ - UINT au /* Size of allocation unit in unit of byte or sector */ + BYTE opt, /* Format option */ + DWORD au, /* Size of allocation unit (cluster) [byte] */ + void* work, /* Pointer to working buffer */ + UINT len /* Size of working buffer */ ) { - static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0}; - static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512}; - int vol; - BYTE fmt, md, sys, *tbl, pdrv, part; - DWORD n_clst, vs, n, wsect; + const UINT n_fats = 1; /* Number of FATs for FAT12/16/32 volume (1 or 2) */ + const UINT n_rootdir = 512; /* Number of root directory entries for FAT12/16 volume */ + static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT12/16 volume (4Ks unit) */ + static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ + BYTE fmt, sys, *buf, *pte, pdrv, part; + WORD ss; + DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n; + DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */ + DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */ UINT i; - DWORD b_vol, b_fat, b_dir, b_data; /* LBA */ - DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */ - FATFS *fs; + int vol; DSTATUS stat; -#if _USE_TRIM - DWORD eb[2]; +#if _USE_TRIM || _FS_EXFAT + DWORD tbl[3]; #endif /* Check mounted drive and clear work area */ - if (sfd > 1) return FR_INVALID_PARAMETER; - vol = get_ldnumber(&path); /* Get target volume */ + vol = get_ldnumber(&path); /* Get target logical drive */ if (vol < 0) return FR_INVALID_DRIVE; - fs = FatFs[vol]; /* Check if the volume has work area */ - if (!fs) return FR_NOT_ENABLED; - fs->fs_type = 0; + if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the volume */ pdrv = LD2PD(vol); /* Physical drive */ - part = LD2PT(vol); /* Partition (0:auto detect, 1-4:get from partition table)*/ + part = LD2PT(vol); /* Partition (0:create as new, 1-4:get from partition table) */ - /* Get disk statics */ + /* Check physical drive status */ stat = disk_initialize(pdrv); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; -#if _MAX_SS != _MIN_SS /* Get disk sector size */ - if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS || SS(fs) < _MIN_SS) { - return FR_DISK_ERR; - } + if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Erase block to align data area */ +#if _MAX_SS != _MIN_SS /* Get sector size of the medium if variable sector size cfg. */ + if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; + if (ss > _MAX_SS || ss < _MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; +#else + ss = _MAX_SS; #endif - if (_MULTI_PARTITION && part) { + if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */ + au /= ss; /* Cluster size in unit of sector */ + + /* Get working buffer */ + buf = (BYTE*)work; /* Working buffer */ + sz_buf = len / ss; /* Size of working buffer (sector) */ + szb_buf = sz_buf * ss; /* Size of working buffer (byte) */ + if (!szb_buf) return FR_MKFS_ABORTED; + + /* Determine where the volume to be located (b_vol, sz_vol) */ + if (_MULTI_PARTITION && part != 0) { /* Get partition information from partition table in the MBR */ - if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR; - if (ld_word(fs->win + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; - tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; - if (!tbl[4]) return FR_MKFS_ABORTED; /* No partition? */ - b_vol = ld_dword(tbl + 8); /* Volume start sector */ - n_vol = ld_dword(tbl + 12); /* Volume size */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Load MBR */ + if (ld_word(buf + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; /* Check if MBR is valid */ + pte = buf + (MBR_Table + (part - 1) * SZ_PTE); + if (!pte[PTE_System]) return FR_MKFS_ABORTED; /* No partition? */ + b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ + sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ } else { /* Create a single-partition in this function */ - if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128) { - return FR_DISK_ERR; - } - b_vol = (sfd) ? 0 : 63; /* Volume start sector */ - n_vol -= b_vol; /* Volume size */ + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) return FR_DISK_ERR; + b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ + if (sz_vol < b_vol) return FR_MKFS_ABORTED; + sz_vol -= b_vol; /* Volume size */ } + if (sz_vol < 128) return FR_MKFS_ABORTED; /* Check if volume size is >=128s */ - if (au & (au - 1)) au = 0; - if (!au) { /* AU auto selection */ - vs = n_vol / (2000 / (SS(fs) / 512)); - for (i = 0; vs < vst[i]; i++) ; - au = cst[i]; - } - if (au >= _MIN_SS) au /= SS(fs); /* Number of sectors per cluster */ - if (!au) au = 1; - if (au > 128) au = 128; - - /* Pre-compute number of clusters and FAT sub-type */ - n_clst = n_vol / au; - fmt = FS_FAT12; - if (n_clst >= MIN_FAT16) fmt = FS_FAT16; - if (n_clst >= MIN_FAT32) fmt = FS_FAT32; - - /* Determine offset and size of FAT structure */ - if (fmt == FS_FAT32) { - n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs); - n_rsv = 32; - n_dir = 0; - } else { - n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4; - n_fat = (n_fat + SS(fs) - 1) / SS(fs); - n_rsv = 1; - n_dir = (DWORD)N_ROOTDIR * SZDIRE / SS(fs); - } - b_fat = b_vol + n_rsv; /* FAT area start sector */ - b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */ - b_data = b_dir + n_dir; /* Data area start sector */ - if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED; /* Too small volume */ - - /* Align data start sector to erase block boundary (for flash memory media) */ - if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1; - n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */ - n = (n - b_data) / N_FATS; - if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */ - n_rsv += n; - b_fat += n; - } else { /* FAT12/16: Expand FAT size */ - n_fat += n; - } + /* Pre-determine the FAT type */ + do { + if (_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */ + if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) { /* exFAT only, vol >= 64Ms or au > 128s ? */ + fmt = FS_EXFAT; break; + } + } + if (au > 128) return FR_INVALID_PARAMETER; /* Too large au for FAT/FAT32 */ + if (opt & FM_FAT32) { /* FAT32 possible? */ + if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) { /* FAT32 only or no-FAT? */ + fmt = FS_FAT32; break; + } + } + if (!(opt & FM_FAT)) return FR_INVALID_PARAMETER; /* no-FAT? */ + fmt = FS_FAT16; + } while (0); - /* Determine number of clusters and final check of validity of the FAT sub-type */ - n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au; - if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16) - || (fmt == FS_FAT32 && n_clst < MIN_FAT32)) { - return FR_MKFS_ABORTED; - } +#if _FS_EXFAT + if (fmt == FS_EXFAT) { /* Create an exFAT volume */ + DWORD szb_bit, szb_case, sum, nb, cl; + WCHAR ch, si; + UINT j, st; + BYTE b; - /* Determine system ID in the partition table */ - if (fmt == FS_FAT32) { - sys = 0x0C; /* FAT32X */ - } else { - if (fmt == FS_FAT12 && n_vol < 0x10000) { - sys = 0x01; /* FAT12(<65536) */ - } else { - sys = (n_vol < 0x10000) ? 0x04 : 0x06; /* FAT16(<65536) : FAT12/16(>=65536) */ + if (sz_vol < 0x1000) return FR_MKFS_ABORTED; /* Too small volume? */ +#if _USE_TRIM + tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area may be erased */ + disk_ioctl(pdrv, CTRL_TRIM, tbl); +#endif + /* Determine FAT location, data location and number of clusters */ + if (!au) { /* au auto-selection */ + au = 8; + if (sz_vol >= 0x80000) au = 64; /* >= 512Ks */ + if (sz_vol >= 0x4000000) au = 256; /* >= 64Ms */ } - } + b_fat = b_vol + 32; /* FAT start at offset 32 */ + sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ + b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ + if (b_data >= sz_vol / 2) return FR_MKFS_ABORTED; /* Too small volume? */ + n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ + if (n_clst <16) return FR_MKFS_ABORTED; /* Too few clusters? */ + if (n_clst > MAX_EXFAT) return FR_MKFS_ABORTED; /* Too many clusters? */ + + szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ + tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of allocation bitmap clusters */ + + /* Create a compressed up-case table */ + sect = b_data + au * tbl[0]; /* Table start sector */ + sum = 0; /* Table checksum to be stored in the 82 entry */ + st = si = i = j = szb_case = 0; + do { + switch (st) { + case 0: + ch = ff_wtoupper(si); /* Get an up-case char */ + if (ch != si) { + si++; break; /* Store the up-case char if exist */ + } + for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ; /* Get run length of no-case block */ + if (j >= 128) { + ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */ + } + st = 1; /* Do not compress short run */ + /* go to next case */ + case 1: + ch = si++; /* Fill the short run */ + if (--j == 0) st = 0; + break; - if (_MULTI_PARTITION && part) { - /* Update system ID in the partition table */ - tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; - tbl[4] = sys; - if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) { /* Write it to teh MBR */ - return FR_DISK_ERR; - } - md = 0xF8; - } else { - if (sfd) { /* No partition table (SFD) */ - md = 0xF0; - } else { /* Create partition table (FDISK) */ - mem_set(fs->win, 0, SS(fs)); - tbl = fs->win + MBR_Table; /* Create partition table for single partition in the drive */ - tbl[1] = 1; /* Partition start head */ - tbl[2] = 1; /* Partition start sector */ - tbl[3] = 0; /* Partition start cylinder */ - tbl[4] = sys; /* System type */ - tbl[5] = 254; /* Partition end head */ - n = (b_vol + n_vol) / 63 / 255; - tbl[6] = (BYTE)(n >> 2 | 63); /* Partition end sector */ - tbl[7] = (BYTE)n; /* End cylinder */ - st_dword(tbl + 8, 63); /* Partition start in LBA */ - st_dword(tbl + 12, n_vol); /* Partition size in LBA */ - st_word(fs->win + BS_55AA, 0xAA55); /* MBR signature */ - if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) { /* Write it to the MBR */ - return FR_DISK_ERR; + default: + ch = (WCHAR)j; si += j; /* Number of chars to skip */ + st = 0; + } + sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ + sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); + i += 2; szb_case += 2; + if (!si || i == szb_buf) { /* Write buffered data when buffer full or end of process */ + n = (i + ss - 1) / ss; + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + sect += n; i = 0; + } + } while (si); + tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case table clusters */ + tbl[2] = 1; /* Number of root dir clusters */ + + /* Initialize the allocation bitmap */ + sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */ + nb = tbl[0] + tbl[1] + tbl[2]; /* Number of clusters in-use by system */ + do { + mem_set(buf, 0, szb_buf); + for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ; + for (b = 1; nb && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ; + n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + sect += n; nsect -= n; + } while (nsect); + + /* Initialize the FAT */ + sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */ + j = nb = cl = 0; + do { + mem_set(buf, 0, szb_buf); i = 0; /* Clear work area and reset write index */ + if (cl == 0) { /* Set entry 0 and 1 */ + st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++; + st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++; } - md = 0xF8; + do { /* Create chains of bitmap, up-case and root dir */ + while (nb && i < szb_buf) { /* Create a chain */ + st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF); + i += 4; cl++; nb--; + } + if (!nb && j < 3) nb = tbl[j++]; /* Next chain */ + } while (nb && i < szb_buf); + n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + sect += n; nsect -= n; + } while (nsect); + + /* Initialize the root directory */ + mem_set(buf, 0, szb_buf); + buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */ + buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */ + st_dword(buf + SZDIRE * 1 + 20, 2); + st_dword(buf + SZDIRE * 1 + 24, szb_bit); + buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */ + st_dword(buf + SZDIRE * 2 + 4, sum); + st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); + st_dword(buf + SZDIRE * 2 + 24, szb_case); + sect = b_data + au * (tbl[0] + tbl[1]); nsect = au; /* Start of the root directory and number of sectors */ + do { /* Fill root directory sectors */ + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + mem_set(buf, 0, ss); + sect += n; nsect -= n; + } while (nsect); + + /* Create two set of the exFAT VBR blocks */ + sect = b_vol; + for (n = 0; n < 2; n++) { + /* Main record (+0) */ + mem_set(buf, 0, ss); + mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ + st_dword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ + st_dword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ + st_dword(buf + BPB_FatOfsEx, b_fat - b_vol); /* FAT offset [sector] */ + st_dword(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */ + st_dword(buf + BPB_DataOfsEx, b_data - b_vol); /* Data offset [sector] */ + st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ + st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */ + st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */ + st_word(buf + BPB_FSVerEx, 0x100); /* File system version (1.00) */ + for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ + for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ + buf[BPB_NumFATsEx] = 1; /* Number of FATs */ + buf[BPB_DrvNumEx] = 0x80; /* Drive number (for int13) */ + st_word(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */ + st_word(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ + for (i = sum = 0; i < ss; i++) { /* VBR checksum */ + if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); + } + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + /* Extended bootstrap record (+1..+8) */ + mem_set(buf, 0, ss); + st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ + for (j = 1; j < 9; j++) { + for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + } + /* OEM/Reserved record (+9..+10) */ + mem_set(buf, 0, ss); + for ( ; j < 11; j++) { + for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + } + /* Sum record (+11) */ + for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; } - } - /* Create BPB in the VBR */ - tbl = fs->win; /* Clear sector */ - mem_set(tbl, 0, SS(fs)); - mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */ - i = SS(fs); /* Sector size */ - st_word(tbl + BPB_BytsPerSec, (WORD)i); - tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */ - st_word(tbl + BPB_RsvdSecCnt, (WORD)n_rsv); /* Reserved sectors */ - tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */ - i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of root directory entries */ - st_word(tbl + BPB_RootEntCnt, (WORD)i); - if (n_vol < 0x10000) { /* Number of total sectors */ - st_word(tbl + BPB_TotSec16, (WORD)n_vol); - } else { - st_dword(tbl + BPB_TotSec32, (WORD)n_vol); - } - tbl[BPB_Media] = md; /* Media descriptor */ - st_word(tbl + BPB_SecPerTrk, 63); /* Number of sectors per track */ - st_word(tbl + BPB_NumHeads, 255); /* Number of heads */ - st_dword(tbl + BPB_HiddSec, b_vol); /* Volume offset */ - n = GET_FATTIME(); /* Use current time as VSN */ - if (fmt == FS_FAT32) { - st_dword(tbl + BS_VolID32, n); /* VSN */ - st_dword(tbl + BPB_FATSz32, n_fat); /* Number of sectors per FAT */ - st_dword(tbl + BPB_RootClus32, 2); /* Root directory start cluster (2) */ - st_word(tbl + BPB_FSInfo32, 1); /* FSINFO record offset (VBR + 1) */ - st_word(tbl + BPB_BkBootSec32, 6); /* Backup boot record offset (VBR + 6) */ - tbl[BS_DrvNum32] = 0x80; /* Drive number */ - tbl[BS_BootSig32] = 0x29; /* Extended boot signature */ - mem_cpy(tbl + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ - } else { - st_dword(tbl + BS_VolID, n); /* VSN */ - st_word(tbl + BPB_FATSz16, (WORD)n_fat); /* Number of sectors per FAT */ - tbl[BS_DrvNum] = 0x80; /* Drive number */ - tbl[BS_BootSig] = 0x29; /* Extended boot signature */ - mem_cpy(tbl + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ - } - st_word(tbl + BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ - if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) { /* Write it to the VBR sector */ - return FR_DISK_ERR; - } - if (fmt == FS_FAT32) { /* Write it to the backup VBR if needed (VBR + 6) */ - disk_write(pdrv, tbl, b_vol + 6, 1); - } + } else +#endif /* _FS_EXFAT */ + { /* Create an FAT12/16/32 volume */ + do { + pau = au; + /* Pre-determine number of clusters and FAT sub-type */ + if (fmt == FS_FAT32) { /* FAT32 volume */ + if (!pau) { /* au auto-selection */ + n = sz_vol / 0x20000; /* Volume size in unit of 128KS */ + for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ + } + n_clst = sz_vol / pau; /* Number of clusters */ + sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ + sz_rsv = 32; /* Number of reserved sectors */ + sz_dir = 0; /* No static directory */ + if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) return FR_MKFS_ABORTED; + } else { /* FAT12/16 volume */ + if (!pau) { /* au auto-selection */ + n = sz_vol / 0x1000; /* Volume size in unit of 4KS */ + for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */ + } + n_clst = sz_vol / pau; + if (n_clst > MAX_FAT12) { + n = n_clst * 2 + 4; /* FAT size [byte] */ + } else { + fmt = FS_FAT12; + n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] */ + } + sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ + sz_rsv = 1; /* Number of reserved sectors */ + sz_dir = (DWORD)n_rootdir * SZDIRE / ss; /* Rootdir size [sector] */ + } + b_fat = b_vol + sz_rsv; /* FAT base */ + b_data = b_fat + sz_fat * n_fats + sz_dir; /* Data base */ + + /* Align data base to erase block boundary (for flash memory media) */ + n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */ + if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ + sz_rsv += n; b_fat += n; + } else { /* FAT12/16: Expand FAT size */ + sz_fat += n / n_fats; + } + + /* Determine number of clusters and final check of validity of the FAT sub-type */ + if (sz_vol < b_data + pau * 16 - b_vol) return FR_MKFS_ABORTED; /* Too small volume */ + n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau; + if (fmt == FS_FAT32) { + if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32 */ + if (!au && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ + return FR_MKFS_ABORTED; + } + } + if (fmt == FS_FAT16) { + if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ + if (!au && (pau * 2) <= 64) { + au = pau * 2; continue; /* Adjust cluster size and retry */ + } + if ((opt & FM_FAT32)) { + fmt = FS_FAT32; continue; /* Switch type to FAT32 and retry */ + } + if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + return FR_MKFS_ABORTED; + } + if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */ + if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + return FR_MKFS_ABORTED; + } + } + if (fmt == FS_FAT12 && n_clst > MAX_FAT12) return FR_MKFS_ABORTED; /* Too many clusters for FAT12 */ + + /* Ok, it is the valid cluster configuration */ + break; + } while (1); - /* Initialize FAT area */ - wsect = b_fat; - for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */ - mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */ - n = md; /* Media descriptor byte */ - if (fmt != FS_FAT32) { - n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00; - st_dword(tbl + 0, n); /* Reserve cluster #0-1 (FAT12/16) */ +#if _USE_TRIM + tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ + disk_ioctl(pdrv, CTRL_TRIM, tbl); +#endif + /* Create FAT VBR */ + mem_set(buf, 0, ss); + mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */ + st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ + buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ + st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ + buf[BPB_NumFATs] = (BYTE)n_fats; /* Number of FATs */ + st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir)); /* Number of root directory entries */ + if (sz_vol < 0x10000) { + st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ + } else { + st_dword(buf + BPB_TotSec32, sz_vol); /* Volume size in 32-bit LBA */ + } + buf[BPB_Media] = 0xF8; /* Media descriptor byte */ + st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ + st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ + st_dword(buf + BPB_HiddSec, b_vol); /* Volume offset in the physical drive [sector] */ + if (fmt == FS_FAT32) { + st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */ + st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ + st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ + st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ + st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ + buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ + buf[BS_BootSig32] = 0x29; /* Extended boot signature */ + mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ } else { - n |= 0xFFFFFF00; - st_dword(tbl + 0, n); /* Reserve cluster #0-1 (FAT32) */ - st_dword(tbl + 4, 0xFFFFFFFF); - st_dword(tbl + 8, 0x0FFFFFFF); /* Reserve cluster #2 for root directory */ + st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ + st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ + buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ + buf[BS_BootSig] = 0x29; /* Extended boot signature */ + mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ } - if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) { - return FR_DISK_ERR; + st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ + if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the VBR sector */ + + /* Create FSINFO record if needed */ + if (fmt == FS_FAT32) { + disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ + mem_set(buf, 0, ss); + st_dword(buf + FSI_LeadSig, 0x41615252); + st_dword(buf + FSI_StrucSig, 0x61417272); + st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ + st_dword(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ + st_word(buf + BS_55AA, 0xAA55); + disk_write(pdrv, buf, b_vol + 7, 1); /* Write backup FSINFO (VBR + 7) */ + disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ } - mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */ - for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */ - if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) { - return FR_DISK_ERR; + + /* Initialize FAT area */ + mem_set(buf, 0, (UINT)szb_buf); + sect = b_fat; /* FAT start sector */ + for (i = 0; i < n_fats; i++) { /* Initialize FATs each */ + if (fmt == FS_FAT32) { + st_dword(buf + 0, 0xFFFFFFF8); /* Entry 0 */ + st_dword(buf + 4, 0xFFFFFFFF); /* Entry 1 */ + st_dword(buf + 8, 0x0FFFFFFF); /* Entry 2 (root directory) */ + } else { + st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* Entry 0 and 1 */ } + nsect = sz_fat; /* Number of FAT sectors */ + do { /* Fill FAT sectors */ + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR; + mem_set(buf, 0, ss); + sect += n; nsect -= n; + } while (nsect); } + + /* Initialize root directory (fill with zero) */ + nsect = (fmt == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ + do { + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR; + sect += n; nsect -= n; + } while (nsect); } - /* Initialize root directory */ - i = (fmt == FS_FAT32) ? au : (UINT)n_dir; - do { - if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) { - return FR_DISK_ERR; + /* Determine system ID in the partition table */ + if (_FS_EXFAT && fmt == FS_EXFAT) { + sys = 0x07; /* HPFS/NTFS/exFAT */ + } else { + if (fmt == FS_FAT32) { + sys = 0x0C; /* FAT32X */ + } else { + if (sz_vol >= 0x10000) { + sys = 0x06; /* FAT12/16 (>=64KS) */ + } else { + sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 (<64KS) : FAT12 (<64KS) */ + } } - } while (--i); - -#if _USE_TRIM /* Erase data area if needed */ - { - eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1; - disk_ioctl(pdrv, CTRL_TRIM, eb); } -#endif - /* Create FSINFO if needed */ - if (fmt == FS_FAT32) { - st_dword(tbl + FSI_LeadSig, 0x41615252); - st_dword(tbl + FSI_StrucSig, 0x61417272); - st_dword(tbl + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ - st_dword(tbl + FSI_Nxt_Free, 2); /* Last allocated cluster# */ - st_word(tbl + BS_55AA, 0xAA55); - disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR + 1) */ - disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR + 7) */ + /* Update partition information */ + if (_MULTI_PARTITION && part != 0) { /* Created in the existing partition */ + /* Update system ID in the partition table */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Read the MBR */ + buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it back to the MBR */ + } else { /* Created as a new single partition */ + if (!(opt & FM_SFD)) { /* Create partition table if in FDISK format */ + mem_set(buf, 0, ss); + st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ + pte = buf + MBR_Table; /* Create partition table for single partition in the drive */ + pte[PTE_Boot] = 0; /* Boot indicator */ + pte[PTE_StHead] = 1; /* Start head */ + pte[PTE_StSec] = 1; /* Start sector */ + pte[PTE_StCyl] = 0; /* Start cylinder */ + pte[PTE_System] = sys; /* System type */ + n = (b_vol + sz_vol) / (63 * 255); /* (End CHS may be invalid) */ + pte[PTE_EdHead] = 254; /* End head */ + pte[PTE_EdSec] = (BYTE)(n >> 2 | 63); /* End sector */ + pte[PTE_EdCyl] = (BYTE)n; /* End cylinder */ + st_dword(pte + PTE_StLba, b_vol); /* Start offset in LBA */ + st_dword(pte + PTE_SizLba, sz_vol); /* Size in sectors */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */ + } } - return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; + if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) return FR_DISK_ERR; + + return FR_OK; } @@ -5417,7 +5765,7 @@ FRESULT f_mkfs ( FRESULT f_fdisk ( BYTE pdrv, /* Physical drive number */ - const DWORD szt[], /* Pointer to the size table for each partitions */ + const DWORD* szt, /* Pointer to the size table for each partitions */ void* work /* Pointer to the working buffer */ ) { @@ -5432,7 +5780,7 @@ FRESULT f_fdisk ( if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; - /* Determine CHS in the table regardless of the drive geometry */ + /* Determine the CHS without any consideration of the drive geometry */ for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; if (n == 256) n--; e_hd = n - 1; @@ -5443,7 +5791,7 @@ FRESULT f_fdisk ( mem_set(buf, 0, _MAX_SS); p = buf + MBR_Table; b_cyl = 0; for (i = 0; i < 4; i++, p += SZ_PTE) { - p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; + p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; /* Number of cylinders */ if (!p_cyl) continue; s_part = (DWORD)sz_cyl * b_cyl; sz_part = (DWORD)sz_cyl * p_cyl; @@ -5453,19 +5801,19 @@ FRESULT f_fdisk ( } else { s_hd = 0; } - e_cyl = b_cyl + p_cyl - 1; + e_cyl = b_cyl + p_cyl - 1; /* End cylinder */ if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER; /* Set partition table */ p[1] = s_hd; /* Start head */ p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */ p[3] = (BYTE)b_cyl; /* Start cylinder */ - p[4] = 0x06; /* System type (temporary setting) */ + p[4] = 0x07; /* System type (temporary setting) */ p[5] = e_hd; /* End head */ p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ p[7] = (BYTE)e_cyl; /* End cylinder */ st_dword(p + 8, s_part); /* Start sector in LBA */ - st_dword(p + 12, sz_part); /* Partition size */ + st_dword(p + 12, sz_part); /* Number of sectors */ /* Next partition */ b_cyl += p_cyl; @@ -5476,7 +5824,6 @@ FRESULT f_fdisk ( return (disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? FR_DISK_ERR : FR_OK; } - #endif /* _MULTI_PARTITION */ #endif /* _USE_MKFS && !_FS_READONLY */ @@ -5508,17 +5855,17 @@ TCHAR* f_gets ( c = s[0]; if (c >= 0x80) { if (c < 0xC0) continue; /* Skip stray trailer */ - if (c < 0xE0) { /* Two-byte sequence */ + if (c < 0xE0) { /* Two-byte sequence (0x80-0x7FF) */ f_read(fp, s, 1, &rc); if (rc != 1) break; c = (c & 0x1F) << 6 | (s[0] & 0x3F); - if (c < 0x80) c = '?'; + if (c < 0x80) c = '?'; /* Reject invalid code range */ } else { - if (c < 0xF0) { /* Three-byte sequence */ + if (c < 0xF0) { /* Three-byte sequence (0x800-0xFFFF) */ f_read(fp, s, 2, &rc); if (rc != 2) break; c = c << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F); - if (c < 0x800) c = '?'; + if (c < 0x800) c = '?'; /* Reject invalid code range */ } else { /* Reject four-byte sequence */ c = '?'; } @@ -5568,14 +5915,14 @@ TCHAR* f_gets ( /*-----------------------------------------------------------------------*/ typedef struct { - FIL* fp; - int idx, nchr; - BYTE buf[64]; + FIL *fp; /* Ptr to the writing file */ + int idx, nchr; /* Write index of buf[] (-1:error), number of chars written */ + BYTE buf[64]; /* Write buffer */ } putbuff; static -void putc_bfd ( +void putc_bfd ( /* Buffered write with code conversion */ putbuff* pb, TCHAR c ) @@ -5588,7 +5935,7 @@ void putc_bfd ( putc_bfd(pb, '\r'); } - i = pb->idx; /* Buffer write index (-1:error) */ + i = pb->idx; /* Write index of pb->buf[] */ if (i < 0) return; #if _LFN_UNICODE @@ -5630,6 +5977,31 @@ void putc_bfd ( } +static +int putc_flush ( /* Flush left characters in the buffer */ + putbuff* pb +) +{ + UINT nw; + + if ( pb->idx >= 0 /* Flush buffered characters to the file */ + && f_write(pb->fp, pb->buf, (UINT)pb->idx, &nw) == FR_OK + && (UINT)pb->idx == nw) return pb->nchr; + return EOF; +} + + +static +void putc_init ( /* Initialize write buffer */ + putbuff* pb, + FIL* fp +) +{ + pb->fp = fp; + pb->nchr = pb->idx = 0; +} + + int f_putc ( TCHAR c, /* A character to be output */ @@ -5637,18 +6009,11 @@ int f_putc ( ) { putbuff pb; - UINT nw; - - pb.fp = fp; /* Initialize output buffer */ - pb.nchr = pb.idx = 0; - putc_bfd(&pb, c); /* Put a character */ - - if ( pb.idx >= 0 /* Flush buffered characters to the file */ - && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK - && (UINT)pb.idx == nw) return pb.nchr; - return EOF; + putc_init(&pb, fp); + putc_bfd(&pb, c); /* Put the character */ + return putc_flush(&pb); } @@ -5664,19 +6029,11 @@ int f_puts ( ) { putbuff pb; - UINT nw; - - pb.fp = fp; /* Initialize output buffer */ - pb.nchr = pb.idx = 0; - while (*str) /* Put the string */ - putc_bfd(&pb, *str++); - - if ( pb.idx >= 0 /* Flush buffered characters to the file */ - && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK - && (UINT)pb.idx == nw) return pb.nchr; - return EOF; + putc_init(&pb, fp); + while (*str) putc_bfd(&pb, *str++); /* Put the string */ + return putc_flush(&pb); } @@ -5693,15 +6050,14 @@ int f_printf ( ) { va_list arp; + putbuff pb; BYTE f, r; - UINT nw, i, j, w; + UINT i, j, w; DWORD v; TCHAR c, d, str[32], *p; - putbuff pb; - pb.fp = fp; /* Initialize output buffer */ - pb.nchr = pb.idx = 0; + putc_init(&pb, fp); va_start(arp, fmt); @@ -5741,17 +6097,23 @@ int f_printf ( while (*p) putc_bfd(&pb, *p++); while (j++ < w) putc_bfd(&pb, ' '); continue; + case 'C' : /* Character */ putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; + case 'B' : /* Binary */ r = 2; break; + case 'O' : /* Octal */ r = 8; break; + case 'D' : /* Signed decimal */ case 'U' : /* Unsigned decimal */ r = 10; break; + case 'X' : /* Hexdecimal */ r = 16; break; + default: /* Unknown type (pass-through) */ putc_bfd(&pb, c); continue; } @@ -5771,16 +6133,15 @@ int f_printf ( if (f & 8) str[i++] = '-'; j = i; d = (f & 1) ? '0' : ' '; while (!(f & 2) && j++ < w) putc_bfd(&pb, d); - do putc_bfd(&pb, str[--i]); while (i); + do { + putc_bfd(&pb, str[--i]); + } while (i); while (j++ < w) putc_bfd(&pb, d); } va_end(arp); - if ( pb.idx >= 0 /* Flush buffered characters to the file */ - && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK - && (UINT)pb.idx == nw) return pb.nchr; - return EOF; + return putc_flush(&pb); } #endif /* !_FS_READONLY */ From cb288ba62a94adfe4a0b0ac30d2114b2ac064062 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:24:09 +0200 Subject: [PATCH 209/259] Update ff.h --- source/arm9/source/fatfs/ff.h | 123 ++++++++++++++++------------------ 1 file changed, 59 insertions(+), 64 deletions(-) diff --git a/source/arm9/source/fatfs/ff.h b/source/arm9/source/fatfs/ff.h index 6a94693..a2bc3c0 100644 --- a/source/arm9/source/fatfs/ff.h +++ b/source/arm9/source/fatfs/ff.h @@ -1,11 +1,13 @@ -/*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module include R0.12 (C)ChaN, 2016 -/----------------------------------------------------------------------------/ -/ FatFs module is a free software that opened under license policy of -/ following conditions. +/*----------------------------------------------------------------------------/ +/ FatFs - Generic FAT file system module R0.12c / +/-----------------------------------------------------------------------------/ / -/ Copyright (C) 2016, ChaN, all right reserved. +/ Copyright (C) 2017, ChaN, all right reserved. / +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: + / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. / @@ -13,11 +15,11 @@ / and any warranties related to this software are DISCLAIMED. / The copyright owner or contributors be NOT LIABLE for any damages caused / by use of this software. -/---------------------------------------------------------------------------*/ +/----------------------------------------------------------------------------*/ #ifndef _FATFS -#define _FATFS 88100 /* Revision ID */ +#define _FATFS 68300 /* Revision ID */ #ifdef __cplusplus extern "C" { @@ -25,6 +27,7 @@ extern "C" { #include "integer.h" /* Basic integer types */ #include "ffconf.h" /* FatFs configuration options */ + #if _FATFS != _FFCONF #error Wrong configuration file (ffconf.h). #endif @@ -39,20 +42,13 @@ typedef struct { BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ } PARTITION; extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ -#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */ -#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */ - -#else /* Single partition configuration */ -#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ -#define LD2PT(vol) 0 /* Find first valid partition or in SFD */ - #endif /* Type of path name strings on FatFs API */ -#if _LFN_UNICODE /* Unicode string */ +#if _LFN_UNICODE /* Unicode (UTF-16) string */ #if _USE_LFN == 0 #error _LFN_UNICODE must be 0 at non-LFN cfg. #endif @@ -61,14 +57,25 @@ typedef WCHAR TCHAR; #define _T(x) L ## x #define _TEXT(x) L ## x #endif - #else /* ANSI/OEM string */ #ifndef _INC_TCHAR typedef char TCHAR; #define _T(x) x #define _TEXT(x) x #endif +#endif + + +/* Type of file size variables */ + +#if _FS_EXFAT +#if _USE_LFN == 0 +#error LFN must be enabled when enable exFAT +#endif +typedef QWORD FSIZE_t; +#else +typedef DWORD FSIZE_t; #endif @@ -87,6 +94,9 @@ typedef struct { #if _MAX_SS != _MIN_SS WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ #endif +#if _USE_LFN != 0 + WCHAR* lfnbuf; /* LFN working buffer */ +#endif #if _FS_EXFAT BYTE* dirbuf; /* Directory entry block scratchpad buffer */ #endif @@ -117,33 +127,21 @@ typedef struct { -/* Type of file size variables and object identifier */ - -#if _FS_EXFAT -#if _USE_LFN == 0 -#error LFN must be enabled when enable exFAT -#endif -typedef QWORD FSIZE_t; -#else -typedef DWORD FSIZE_t; -#endif - - - /* Object ID and allocation information (_FDID) */ typedef struct { FATFS* fs; /* Pointer to the owner file system object */ WORD id; /* Owner file system mount ID */ BYTE attr; /* Object attribute */ - BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */ + BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:flagmented in this session, b2:sub-directory stretched) */ DWORD sclust; /* Object start cluster (0:no cluster or root directory) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */ #if _FS_EXFAT - DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */ + DWORD n_cont; /* Size of first fragment, clusters - 1 (valid when stat == 3) */ + DWORD n_frag; /* Size of last fragment needs to be written (valid when not zero) */ DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ - DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */ + DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0 and non-directory object) */ #endif #if _FS_LOCK != 0 UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ @@ -155,18 +153,18 @@ typedef struct { /* File object structure (FIL) */ typedef struct { - _FDID obj; /* Object identifier */ + _FDID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ - DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ + DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ #if !_FS_READONLY DWORD dir_sect; /* Sector number containing the directory entry */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ #endif #if _USE_FASTSEEK - DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */ + DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ #endif #if !_FS_TINY BYTE buf[_MAX_SS]; /* File private data read/write window */ @@ -181,12 +179,11 @@ typedef struct { _FDID obj; /* Object identifier */ DWORD dptr; /* Current read/write offset */ DWORD clust; /* Current cluster */ - DWORD sect; /* Current sector */ + DWORD sect; /* Current sector (0:Read operation has terminated) */ BYTE* dir; /* Pointer to the directory item in the win[] */ - BYTE* fn; /* Pointer to the SFN (in/out) {body[8],ext[3],status[1]} */ + BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ #if _USE_LFN != 0 DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ - WCHAR* lfn; /* Pointer to the LFN working buffer */ #endif #if _USE_FIND const TCHAR* pat; /* Pointer to the name matching pattern */ @@ -229,7 +226,7 @@ typedef enum { FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ FR_NOT_ENABLED, /* (12) The volume has no work area */ FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ - FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */ + FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ @@ -244,11 +241,11 @@ typedef enum { FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_close (FIL* fp); /* Close an open file object */ -FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */ -FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */ -FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of a file object */ -FRESULT f_truncate (FIL* fp); /* Truncate file */ -FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */ +FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ +FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ +FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ +FRESULT f_truncate (FIL* fp); /* Truncate the file */ +FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ FRESULT f_closedir (DIR* dp); /* Close an open directory */ FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ @@ -258,8 +255,8 @@ FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ -FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */ -FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of the file/dir */ +FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ +FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ FRESULT f_chdir (const TCHAR* path); /* Change current directory */ FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ @@ -269,8 +266,8 @@ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ -FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */ -FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */ +FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ +FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ @@ -282,6 +279,7 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil #define f_size(fp) ((fp)->obj.objsize) #define f_rewind(fp) f_lseek((fp), 0) #define f_rewinddir(dp) f_readdir((dp), 0) +#define f_rmdir(path) f_unlink(path) #ifndef EOF #define EOF (-1) @@ -323,40 +321,37 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ /* Flags and offset address */ -/* File access control and file status flags (FIL.flag) */ - +/* File access mode and open method flags (3rd argument of f_open) */ #define FA_READ 0x01 #define FA_WRITE 0x02 #define FA_OPEN_EXISTING 0x00 #define FA_CREATE_NEW 0x04 #define FA_CREATE_ALWAYS 0x08 #define FA_OPEN_ALWAYS 0x10 -#define _FA_MODIFIED 0x20 -#define _FA_DIRTY 0x40 +#define FA_OPEN_APPEND 0x30 +/* Fast seek controls (2nd argument of f_lseek) */ +#define CREATE_LINKMAP ((FSIZE_t)0 - 1) -/* FAT sub type (FATFS.fs_type) */ +/* Format options (2nd argument of f_mkfs) */ +#define FM_FAT 0x01 +#define FM_FAT32 0x02 +#define FM_EXFAT 0x04 +#define FM_ANY 0x07 +#define FM_SFD 0x08 +/* Filesystem type (FATFS.fs_type) */ #define FS_FAT12 1 #define FS_FAT16 2 #define FS_FAT32 3 #define FS_EXFAT 4 - -/* File attribute bits for directory entry */ - +/* File attribute bits for directory entry (FILINFO.fattrib) */ #define AM_RDO 0x01 /* Read only */ #define AM_HID 0x02 /* Hidden */ #define AM_SYS 0x04 /* System */ -#define AM_VOL 0x08 /* Volume label */ -#define AM_LFN 0x0F /* LFN entry */ #define AM_DIR 0x10 /* Directory */ #define AM_ARC 0x20 /* Archive */ -#define AM_MASK 0x3F /* Mask of defined bits */ - - -/* Fast seek controls */ -#define CREATE_LINKMAP ((FSIZE_t)0 - 1) #ifdef __cplusplus From 71896ec6cec1a02ff64bd6d244e0bb22685543b1 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:24:41 +0200 Subject: [PATCH 210/259] Update ffconf.h --- source/arm9/source/fatfs/ffconf.h | 52 ++++++++++++++++--------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/source/arm9/source/fatfs/ffconf.h b/source/arm9/source/fatfs/ffconf.h index 45e8c20..b199767 100644 --- a/source/arm9/source/fatfs/ffconf.h +++ b/source/arm9/source/fatfs/ffconf.h @@ -1,8 +1,8 @@ /*---------------------------------------------------------------------------/ -/ FatFs - FAT file system module configuration file R0.12 (C)ChaN, 2016 +/ FatFs - FAT file system module configuration file /---------------------------------------------------------------------------*/ -#define _FFCONF 88100 /* Revision ID */ +#define _FFCONF 68300 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations @@ -34,7 +34,7 @@ / 2: Enable with LF-CRLF conversion. */ -#define _USE_FIND 0 +#define _USE_FIND 1 /* This option switches filtered directory read functions, f_findfirst() and / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ @@ -62,8 +62,7 @@ #define _USE_FORWARD 0 -/* This option switches f_forward() function. (0:Disable or 1:Enable) -/ To enable it, also _FS_TINY need to be 1. */ +/* This option switches f_forward() function. (0:Disable or 1:Enable) */ /*---------------------------------------------------------------------------/ @@ -74,7 +73,7 @@ /* This option specifies the OEM code page to be used on the target system. / Incorrect setting of the code page can cause a file open failure. / -/ 1 - ASCII (No extended character. Non-LFN cfg. only) +/ 1 - ASCII (No support of extended character. Non-LFN cfg. only) / 437 - U.S. / 720 - Arabic / 737 - Greek @@ -118,13 +117,13 @@ #define _LFN_UNICODE 0 -/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) +/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16) / To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. / This option also affects behavior of string I/O functions. */ -#define _STRF_ENCODE 0 -/* When _LFN_UNICODE == 1, this option selects the character encoding on the file to +#define _STRF_ENCODE 3 +/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to / be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). / / 0: ANSI/OEM @@ -135,7 +134,7 @@ / This option has no effect when _LFN_UNICODE == 0. */ -#define _FS_RPATH 0 +#define _FS_RPATH 1 /* This option configures support of relative path. / / 0: Disable relative path and remove related functions. @@ -148,12 +147,12 @@ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ -#define _VOLUMES 1 -/* Number of volumes (logical drives) to be used. */ +#define _VOLUMES 2 +/* Number of volumes (logical drives) to be used. (1-10) */ #define _STR_VOLUME_ID 0 -#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" +#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" /* _STR_VOLUME_ID switches string support of volume ID. / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive / number in the path name. _VOLUME_STRS defines the drive ID strings for each @@ -173,11 +172,11 @@ #define _MIN_SS 512 #define _MAX_SS 512 /* These options configure the range of sector size to be supported. (512, 1024, -/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and +/ 2048 or 4096) Always set both 512 for most systems, generic memory card and / harddisk. But a larger value may be required for on-board flash memory and some / type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured -/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the -/ disk_ioctl() function. */ +/ to variable sector size and GET_SECTOR_SIZE command needs to be implemented to +/ the disk_ioctl() function. */ #define _USE_TRIM 0 @@ -205,28 +204,28 @@ #define _FS_TINY 0 /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) -/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS bytes. +/ At the tiny configuration, size of file object (FIL) is shrinked _MAX_SS bytes. / Instead of private sector buffer eliminated from the file object, common sector / buffer in the file system object (FATFS) is used for the file data transfer. */ #define _FS_EXFAT 0 -/* This option switches support of exFAT file system in addition to the traditional -/ FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled. -/ Note that enabling exFAT discards C89 compatibility. */ +/* This option switches support of exFAT file system. (0:Disable or 1:Enable) +/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1) +/ Note that enabling exFAT discards ANSI C (C89) compatibility. */ #define _FS_NORTC 1 -#define _NORTC_MON 3 +#define _NORTC_MON 1 #define _NORTC_MDAY 1 -#define _NORTC_YEAR 2016 +#define _NORTC_YEAR 2017 /* The option _FS_NORTC switches timestamp functiton. If the system does not have / any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable / the timestamp function. All objects modified by FatFs will have a fixed timestamp / defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time. / To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be / added to the project to get current time form real-time clock. _NORTC_MON, -/ _NORTC_MDAY and _NORTC_YEAR have no effect. +/ _NORTC_MDAY and _NORTC_YEAR have no effect. / These options have no effect at read-only configuration (_FS_READONLY = 1). */ @@ -259,8 +258,11 @@ / / The _FS_TIMEOUT defines timeout period in unit of time tick. / The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, -/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be -/ included somewhere in the scope of ff.c. */ +/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be +/ included somewhere in the scope of ff.h. */ + +/* #include // O/S definitions */ + /*--- End of configuration options ---*/ From d4df38c1825f066af7c40125bdf3d51d14c76aba Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:24:59 +0200 Subject: [PATCH 211/259] Update integer.h --- source/arm9/source/fatfs/integer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/arm9/source/fatfs/integer.h b/source/arm9/source/fatfs/integer.h index 5dd8ec3..9ce7865 100644 --- a/source/arm9/source/fatfs/integer.h +++ b/source/arm9/source/fatfs/integer.h @@ -30,7 +30,7 @@ typedef unsigned short WCHAR; typedef long LONG; typedef unsigned long DWORD; -/* This type MUST be 64-bit (Remove this for C89 compatibility) */ +/* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */ typedef unsigned long long QWORD; #endif From 3063dbb27eb1463e3470b9cadd5a0c340300c3e4 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:26:27 +0200 Subject: [PATCH 212/259] Delete syscall.c --- source/arm9/source/fatfs/option/syscall.c | 151 ---------------------- 1 file changed, 151 deletions(-) delete mode 100644 source/arm9/source/fatfs/option/syscall.c diff --git a/source/arm9/source/fatfs/option/syscall.c b/source/arm9/source/fatfs/option/syscall.c deleted file mode 100644 index 8e25898..0000000 --- a/source/arm9/source/fatfs/option/syscall.c +++ /dev/null @@ -1,151 +0,0 @@ -/*------------------------------------------------------------------------*/ -/* Sample code of OS dependent controls for FatFs */ -/* (C)ChaN, 2014 */ -/*------------------------------------------------------------------------*/ - - -#include "../ff.h" - - -#if _FS_REENTRANT -/*------------------------------------------------------------------------*/ -/* Create a Synchronization Object */ -/*------------------------------------------------------------------------*/ -/* This function is called in f_mount() function to create a new -/ synchronization object, such as semaphore and mutex. When a 0 is returned, -/ the f_mount() function fails with FR_INT_ERR. -*/ - -int ff_cre_syncobj ( /* !=0:Function succeeded, ==0:Could not create due to any error */ - BYTE vol, /* Corresponding logical drive being processed */ - _SYNC_t *sobj /* Pointer to return the created sync object */ -) -{ - int ret; - - - *sobj = CreateMutex(NULL, FALSE, NULL); /* Win32 */ - ret = (int)(*sobj != INVALID_HANDLE_VALUE); - -// *sobj = SyncObjects[vol]; /* uITRON (give a static created sync object) */ -// ret = 1; /* The initial value of the semaphore must be 1. */ - -// *sobj = OSMutexCreate(0, &err); /* uC/OS-II */ -// ret = (int)(err == OS_NO_ERR); - -// *sobj = xSemaphoreCreateMutex(); /* FreeRTOS */ -// ret = (int)(*sobj != NULL); - - return ret; -} - - - -/*------------------------------------------------------------------------*/ -/* Delete a Synchronization Object */ -/*------------------------------------------------------------------------*/ -/* This function is called in f_mount() function to delete a synchronization -/ object that created with ff_cre_syncobj function. When a 0 is returned, -/ the f_mount() function fails with FR_INT_ERR. -*/ - -int ff_del_syncobj ( /* !=0:Function succeeded, ==0:Could not delete due to any error */ - _SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ -) -{ - int ret; - - - ret = CloseHandle(sobj); /* Win32 */ - -// ret = 1; /* uITRON (nothing to do) */ - -// OSMutexDel(sobj, OS_DEL_ALWAYS, &err); /* uC/OS-II */ -// ret = (int)(err == OS_NO_ERR); - -// vSemaphoreDelete(sobj); /* FreeRTOS */ -// ret = 1; - - return ret; -} - - - -/*------------------------------------------------------------------------*/ -/* Request Grant to Access the Volume */ -/*------------------------------------------------------------------------*/ -/* This function is called on entering file functions to lock the volume. -/ When a 0 is returned, the file function fails with FR_TIMEOUT. -*/ - -int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ - _SYNC_t sobj /* Sync object to wait */ -) -{ - int ret; - - ret = (int)(WaitForSingleObject(sobj, _FS_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */ - -// ret = (int)(wai_sem(sobj) == E_OK); /* uITRON */ - -// OSMutexPend(sobj, _FS_TIMEOUT, &err)); /* uC/OS-II */ -// ret = (int)(err == OS_NO_ERR); - -// ret = (int)(xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE); /* FreeRTOS */ - - return ret; -} - - - -/*------------------------------------------------------------------------*/ -/* Release Grant to Access the Volume */ -/*------------------------------------------------------------------------*/ -/* This function is called on leaving file functions to unlock the volume. -*/ - -void ff_rel_grant ( - _SYNC_t sobj /* Sync object to be signaled */ -) -{ - ReleaseMutex(sobj); /* Win32 */ - -// sig_sem(sobj); /* uITRON */ - -// OSMutexPost(sobj); /* uC/OS-II */ - -// xSemaphoreGive(sobj); /* FreeRTOS */ -} - -#endif - - - - -#if _USE_LFN == 3 /* LFN with a working buffer on the heap */ -/*------------------------------------------------------------------------*/ -/* Allocate a memory block */ -/*------------------------------------------------------------------------*/ -/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE. -*/ - -void* ff_memalloc ( /* Returns pointer to the allocated memory block */ - UINT msize /* Number of bytes to allocate */ -) -{ - return malloc(msize); /* Allocate a new memory block with POSIX API */ -} - - -/*------------------------------------------------------------------------*/ -/* Free a memory block */ -/*------------------------------------------------------------------------*/ - -void ff_memfree ( - void* mblock /* Pointer to the memory block to free */ -) -{ - free(mblock); /* Discard the memory block with POSIX API */ -} - -#endif From 997d60d282eee6a592ce5dd38c64efde27fdfd7a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:26:54 +0200 Subject: [PATCH 213/259] Delete common.h --- source/arm9/source/fatfs/sdmmc/common.h | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 source/arm9/source/fatfs/sdmmc/common.h diff --git a/source/arm9/source/fatfs/sdmmc/common.h b/source/arm9/source/fatfs/sdmmc/common.h deleted file mode 100644 index b4ab486..0000000 --- a/source/arm9/source/fatfs/sdmmc/common.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include -#include -#include - -#define u8 uint8_t -#define u16 uint16_t -#define u32 uint32_t -#define u64 uint64_t - -#define vu8 volatile u8 -#define vu16 volatile u16 -#define vu32 volatile u32 -#define vu64 volatile u64 From 3f801f564c4096bacb2b3ccacbc3b1d11a62ddfe Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:27:19 +0200 Subject: [PATCH 214/259] Update delay.h --- source/arm9/source/fatfs/sdmmc/delay.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/source/arm9/source/fatfs/sdmmc/delay.h b/source/arm9/source/fatfs/sdmmc/delay.h index afad438..c211085 100644 --- a/source/arm9/source/fatfs/sdmmc/delay.h +++ b/source/arm9/source/fatfs/sdmmc/delay.h @@ -1,9 +1,5 @@ -// Copyright 2014 Normmatt -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - #pragma once -#include "common.h" +#include "../../common.h" -void ioDelay(u32 us); +void waitcycles(u32 us); From 1666a2c556747afedd1928d7ea38f840c0fc2eea Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:27:36 +0200 Subject: [PATCH 215/259] Update delay.s --- source/arm9/source/fatfs/sdmmc/delay.s | 29 +++++++++++++------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/source/arm9/source/fatfs/sdmmc/delay.s b/source/arm9/source/fatfs/sdmmc/delay.s index b3baccd..0bf19c2 100644 --- a/source/arm9/source/fatfs/sdmmc/delay.s +++ b/source/arm9/source/fatfs/sdmmc/delay.s @@ -1,17 +1,16 @@ -// Copyright 2014 Normmatt -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - +.text .arm -.global ioDelay -.type ioDelay STT_FUNC +.align 4 -@ioDelay ( u32 us ) -ioDelay: - ldr r1, =0x18000000 @ VRAM -1: - @ Loop doing uncached reads from VRAM to make loop timing more reliable - ldr r2, [r1] - subs r0, #1 - bgt 1b - bx lr +.global waitcycles +.type waitcycles, %function +waitcycles: + push {r0-r2, lr} + str r0, [sp, #4] + waitcycles_loop: + ldr r3, [sp, #4] + subs r2, r3, #1 + str r2, [sp, #4] + cmp r3, #0 + bne waitcycles_loop + pop {r0-r2, pc} From a6c4aa752c17671f1a3bec2976269450f37b210a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:28:02 +0200 Subject: [PATCH 216/259] Update sdmmc.c --- source/arm9/source/fatfs/sdmmc/sdmmc.c | 553 ++++++++++++++----------- 1 file changed, 302 insertions(+), 251 deletions(-) diff --git a/source/arm9/source/fatfs/sdmmc/sdmmc.c b/source/arm9/source/fatfs/sdmmc/sdmmc.c index a5b5043..7b9e2f4 100644 --- a/source/arm9/source/fatfs/sdmmc/sdmmc.c +++ b/source/arm9/source/fatfs/sdmmc/sdmmc.c @@ -1,30 +1,55 @@ -// Copyright 2014 Normmatt -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2014-2015, Normmatt + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 2, as described below: + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ #include "sdmmc.h" #include "delay.h" -struct mmcdevice handleNAND; -struct mmcdevice handleSD; +static struct mmcdevice handleNAND; +static struct mmcdevice handleSD; -static inline u16 sdmmc_read16(u16 reg) { - return *(vu16*)(SDMMC_BASE + reg); +static inline u16 sdmmc_read16(u16 reg) +{ + return *(vu16 *)(SDMMC_BASE + reg); } -static inline void sdmmc_write16(u16 reg, u16 val) { - *(vu16*)(SDMMC_BASE + reg) = val; +static inline void sdmmc_write16(u16 reg, u16 val) +{ + *(vu16 *)(SDMMC_BASE + reg) = val; } -static inline u32 sdmmc_read32(u16 reg) { - return *(vu32*)(SDMMC_BASE + reg); +static inline u32 sdmmc_read32(u16 reg) +{ + return *(vu32 *)(SDMMC_BASE + reg); } -static inline void sdmmc_write32(u16 reg, u32 val) { - *(vu32*)(SDMMC_BASE + reg) = val; +static inline void sdmmc_write32(u16 reg, u32 val) +{ + *(vu32 *)(SDMMC_BASE + reg) = val; } -static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set) { +static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set) +{ u16 val = sdmmc_read16(reg); val &= ~clear; val |= set; @@ -38,192 +63,257 @@ static inline void setckl(u32 data) sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100); } - mmcdevice *getMMCDevice(int drive) { - if(drive==0) return &handleNAND; + if(drive == 0) return &handleNAND; return &handleSD; } -static u32 __attribute__((noinline)) geterror(struct mmcdevice *ctx) +static int geterror(struct mmcdevice *ctx) { - return (ctx->error << 29) >> 31; + return (int)((ctx->error << 29) >> 31); } -static void __attribute__((noinline)) inittarget(struct mmcdevice *ctx) +static void inittarget(struct mmcdevice *ctx) { - sdmmc_mask16(REG_SDPORTSEL,0x3,(u16)ctx->devicenumber); + sdmmc_mask16(REG_SDPORTSEL, 0x3, (u16)ctx->devicenumber); setckl(ctx->clk); - if (ctx->SDOPT == 0) { - sdmmc_mask16(REG_SDOPT, 0, 0x8000); - } else { - sdmmc_mask16(REG_SDOPT, 0x8000, 0); - } - + if(ctx->SDOPT == 0) sdmmc_mask16(REG_SDOPT, 0, 0x8000); + else sdmmc_mask16(REG_SDOPT, 0x8000, 0); } static void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd, u32 args) { - bool getSDRESP = (cmd << 15) >> 31; + u32 getSDRESP = (cmd << 15) >> 31; u16 flags = (cmd << 15) >> 31; - const bool readdata = cmd & 0x20000; - const bool writedata = cmd & 0x40000; + const int readdata = cmd & 0x20000; + const int writedata = cmd & 0x40000; - if (readdata || writedata) + if(readdata || writedata) flags |= TMIO_STAT0_DATAEND; ctx->error = 0; - while (sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY); //mmc working? - sdmmc_write16(REG_SDIRMASK0,0); - sdmmc_write16(REG_SDIRMASK1,0); - sdmmc_write16(REG_SDSTATUS0,0); - sdmmc_write16(REG_SDSTATUS1,0); - sdmmc_mask16(REG_SDDATACTL32,0x1800,0); - - sdmmc_write16(REG_SDCMDARG0,args &0xFFFF); - sdmmc_write16(REG_SDCMDARG1,args >> 16); - sdmmc_write16(REG_SDCMD,cmd &0xFFFF); + while((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)); //mmc working? + sdmmc_write16(REG_SDIRMASK0, 0); + sdmmc_write16(REG_SDIRMASK1, 0); + sdmmc_write16(REG_SDSTATUS0, 0); + sdmmc_write16(REG_SDSTATUS1, 0); + sdmmc_mask16(REG_DATACTL32, 0x1800, 0); + sdmmc_write16(REG_SDCMDARG0, args & 0xFFFF); + sdmmc_write16(REG_SDCMDARG1, args >> 16); + sdmmc_write16(REG_SDCMD, cmd & 0xFFFF); u32 size = ctx->size; - vu8 *dataPtr = ctx->data; + u8 *rDataPtr = ctx->rData; + const u8 *tDataPtr = ctx->tData; - bool useBuf = ( NULL != dataPtr ); + bool rUseBuf = rDataPtr != NULL; + bool tUseBuf = tDataPtr != NULL; u16 status0 = 0; - while(true) { - u16 status1 = sdmmc_read16(REG_SDSTATUS1); - if (status1 & TMIO_STAT1_RXRDY) { - if (readdata && useBuf) { - sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0); - //sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY); - if (size > 0x1FF) { - for(int i = 0; i<0x200; i+=2) { - u16 data = sdmmc_read16(REG_SDFIFO); - *dataPtr++ = data & 0xFF; - *dataPtr++ = data >> 8; + while(true) + { + vu16 status1 = sdmmc_read16(REG_SDSTATUS1); + vu16 ctl32 = sdmmc_read16(REG_DATACTL32); + if((ctl32 & 0x100)) + { + if(readdata) + { + if(rUseBuf) + { + sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0); + if(size > 0x1FF) + { + //Gabriel Marcano: This implementation doesn't assume alignment. + //I've removed the alignment check doen with former rUseBuf32 as a result + for(int i = 0; i < 0x200; i += 4) + { + u32 data = sdmmc_read32(REG_SDFIFO32); + *rDataPtr++ = data; + *rDataPtr++ = data >> 8; + *rDataPtr++ = data >> 16; + *rDataPtr++ = data >> 24; + } + size -= 0x200; } - size -= 0x200; } + + sdmmc_mask16(REG_DATACTL32, 0x800, 0); } } - - if (status1 & TMIO_STAT1_TXRQ) { - if (writedata && useBuf) { - sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0); - //sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ); - if (size > 0x1FF) { - for (int i = 0; i<0x200; i+=2) { - u16 data = *dataPtr++; - data |= *dataPtr++ << 8; - sdmmc_write16(REG_SDFIFO, data); + if(!(ctl32 & 0x200)) + { + if(writedata) + { + if(tUseBuf) + { + sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0); + if(size > 0x1FF) + { + for(int i = 0; i < 0x200; i += 4) + { + u32 data = *tDataPtr++; + data |= (u32)*tDataPtr++ << 8; + data |= (u32)*tDataPtr++ << 16; + data |= (u32)*tDataPtr++ << 24; + sdmmc_write32(REG_SDFIFO32, data); + } + size -= 0x200; } - size -= 0x200; } + + sdmmc_mask16(REG_DATACTL32, 0x1000, 0); } } - if (status1 & TMIO_MASK_GW) { + if(status1 & TMIO_MASK_GW) + { ctx->error |= 4; break; } - if (!(status1 & TMIO_STAT1_CMD_BUSY)) { + if(!(status1 & TMIO_STAT1_CMD_BUSY)) + { status0 = sdmmc_read16(REG_SDSTATUS0); - if (sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND) + if(sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND) + { ctx->error |= 0x1; - if (status0 & TMIO_STAT0_DATAEND) + } + if(status0 & TMIO_STAT0_DATAEND) + { ctx->error |= 0x2; + } - if ((status0 & flags) == flags) + if((status0 & flags) == flags) break; } } ctx->stat0 = sdmmc_read16(REG_SDSTATUS0); ctx->stat1 = sdmmc_read16(REG_SDSTATUS1); - sdmmc_write16(REG_SDSTATUS0,0); - sdmmc_write16(REG_SDSTATUS1,0); - - if (getSDRESP != 0) { - ctx->ret[0] = (u32)sdmmc_read16(REG_SDRESP0) | (u32)(sdmmc_read16(REG_SDRESP1) << 16); - ctx->ret[1] = (u32)sdmmc_read16(REG_SDRESP2) | (u32)(sdmmc_read16(REG_SDRESP3) << 16); - ctx->ret[2] = (u32)sdmmc_read16(REG_SDRESP4) | (u32)(sdmmc_read16(REG_SDRESP5) << 16); - ctx->ret[3] = (u32)sdmmc_read16(REG_SDRESP6) | (u32)(sdmmc_read16(REG_SDRESP7) << 16); + sdmmc_write16(REG_SDSTATUS0, 0); + sdmmc_write16(REG_SDSTATUS1, 0); + + if(getSDRESP != 0) + { + ctx->ret[0] = (u32)(sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16)); + ctx->ret[1] = (u32)(sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16)); + ctx->ret[2] = (u32)(sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16)); + ctx->ret[3] = (u32)(sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16)); } } -u32 __attribute__((noinline)) sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in) +int __attribute__((noinline)) sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in) { - if (handleSD.isSDHC == 0) - sector_no <<= 9; + if(handleSD.isSDHC == 0) sector_no <<= 9; inittarget(&handleSD); - sdmmc_write16(REG_SDSTOP,0x100); - - sdmmc_write16(REG_SDBLKCOUNT,numsectors); - handleSD.data = in; + sdmmc_write16(REG_SDSTOP, 0x100); + sdmmc_write16(REG_SDBLKCOUNT32, numsectors); + sdmmc_write16(REG_SDBLKLEN32, 0x200); + sdmmc_write16(REG_SDBLKCOUNT, numsectors); + handleSD.tData = in; handleSD.size = numsectors << 9; - sdmmc_send_command(&handleSD,0x52C19,sector_no); + sdmmc_send_command(&handleSD, 0x52C19, sector_no); return geterror(&handleSD); } -u32 __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out) +int __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out) { - if (handleSD.isSDHC == 0) - sector_no <<= 9; + if(handleSD.isSDHC == 0) sector_no <<= 9; inittarget(&handleSD); - sdmmc_write16(REG_SDSTOP,0x100); - - sdmmc_write16(REG_SDBLKCOUNT,numsectors); - handleSD.data = out; + sdmmc_write16(REG_SDSTOP, 0x100); + sdmmc_write16(REG_SDBLKCOUNT32, numsectors); + sdmmc_write16(REG_SDBLKLEN32, 0x200); + sdmmc_write16(REG_SDBLKCOUNT, numsectors); + handleSD.rData = out; handleSD.size = numsectors << 9; - sdmmc_send_command(&handleSD,0x33C12,sector_no); + sdmmc_send_command(&handleSD, 0x33C12, sector_no); return geterror(&handleSD); } -u32 __attribute__((noinline)) sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out) +int __attribute__((noinline)) sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out) { - if (handleNAND.isSDHC == 0) - sector_no <<= 9; + if(handleNAND.isSDHC == 0) sector_no <<= 9; inittarget(&handleNAND); - sdmmc_write16(REG_SDSTOP,0x100); - - sdmmc_write16(REG_SDBLKCOUNT,numsectors); + sdmmc_write16(REG_SDSTOP, 0x100); + sdmmc_write16(REG_SDBLKCOUNT32, numsectors); + sdmmc_write16(REG_SDBLKLEN32, 0x200); + sdmmc_write16(REG_SDBLKCOUNT, numsectors); + handleNAND.rData = out; + handleNAND.size = numsectors << 9; + sdmmc_send_command(&handleNAND, 0x33C12, sector_no); + inittarget(&handleSD); + return geterror(&handleNAND); +} - handleNAND.data = out; +int __attribute__((noinline)) sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, const u8 *in) //experimental +{ + if(handleNAND.isSDHC == 0) sector_no <<= 9; + inittarget(&handleNAND); + sdmmc_write16(REG_SDSTOP, 0x100); + sdmmc_write16(REG_SDBLKCOUNT32, numsectors); + sdmmc_write16(REG_SDBLKLEN32, 0x200); + sdmmc_write16(REG_SDBLKCOUNT, numsectors); + handleNAND.tData = in; handleNAND.size = numsectors << 9; - sdmmc_send_command(&handleNAND,0x33C12,sector_no); + sdmmc_send_command(&handleNAND, 0x52C19, sector_no); inittarget(&handleSD); return geterror(&handleNAND); } -static u32 calcSDSize(u8* csd, int type) +static u32 calcSDSize(u8 *csd, int type) { u32 result = 0; - if (type == -1) type = csd[14] >> 6; - switch (type) { + if(type == -1) type = csd[14] >> 6; + switch(type) + { case 0: - { - u32 block_len = csd[9] & 0xf; - block_len = 1u << block_len; - u32 mult = (u32)(csd[4] >> 7) | (u32)((csd[5] & 3) << 1); - mult = 1u << (mult + 2); - result = csd[8] & 3; - result = (result << 8) | csd[7]; - result = (result << 2) | (csd[6] >> 6); - result = (result + 1) * mult * block_len / 512; - } + { + u32 block_len = csd[9] & 0xF; + block_len = 1u << block_len; + u32 mult = (u32)((csd[4] >> 7) | ((csd[5] & 3) << 1)); + mult = 1u << (mult + 2); + result = csd[8] & 3; + result = (result << 8) | csd[7]; + result = (result << 2) | (csd[6] >> 6); + result = (result + 1) * mult * block_len / 512; break; + } case 1: - result = csd[7] & 0x3f; + result = csd[7] & 0x3F; result = (result << 8) | csd[6]; result = (result << 8) | csd[5]; result = (result + 1) * 1024; break; - default: - break; //Do nothing otherwise + default: + break; //Do nothing otherwise FIXME perhaps return some error? } return result; } static void InitSD() +{ + *(vu16 *)0x10006100 &= 0xF7FFu; //SDDATACTL32 + *(vu16 *)0x10006100 &= 0xEFFFu; //SDDATACTL32 + *(vu16 *)0x10006100 |= 0x402u; //SDDATACTL32 + *(vu16 *)0x100060D8 = (*(vu16 *)0x100060D8 & 0xFFDD) | 2; + *(vu16 *)0x10006100 &= 0xFFFFu; //SDDATACTL32 + *(vu16 *)0x100060D8 &= 0xFFDFu; //SDDATACTL + *(vu16 *)0x10006104 = 512; //SDBLKLEN32 + *(vu16 *)0x10006108 = 1; //SDBLKCOUNT32 + *(vu16 *)0x100060E0 &= 0xFFFEu; //SDRESET + *(vu16 *)0x100060E0 |= 1u; //SDRESET + *(vu16 *)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0 + *(vu16 *)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1 + *(vu16 *)0x100060FC |= 0xDBu; //SDCTL_RESERVED7 + *(vu16 *)0x100060FE |= 0xDBu; //SDCTL_RESERVED8 + *(vu16 *)0x10006002 &= 0xFFFCu; //SDPORTSEL + *(vu16 *)0x10006024 = 0x20; + *(vu16 *)0x10006028 = 0x40EE; + *(vu16 *)0x10006002 &= 0xFFFCu; ////SDPORTSEL + *(vu16 *)0x10006026 = 512; //SDBLKLEN + *(vu16 *)0x10006008 = 0; //SDSTOP +} + +static int Nand_Init() { //NAND handleNAND.isSDHC = 0; @@ -233,80 +323,50 @@ static void InitSD() handleNAND.clk = 0x80; handleNAND.devicenumber = 1; - //SD - handleSD.isSDHC = 0; - handleSD.SDOPT = 0; - handleSD.res = 0; - handleSD.initarg = 0; - handleSD.clk = 0x80; - handleSD.devicenumber = 0; - - *(vu16*)0x10006100 &= 0xF7FFu; //SDDATACTL32 - *(vu16*)0x10006100 &= 0xEFFFu; //SDDATACTL32 - *(vu16*)0x10006100 |= 0x402u; //SDDATACTL32 - *(vu16*)0x100060D8 = (*(vu16*)0x100060D8 & 0xFFDD) | 2; - *(vu16*)0x10006100 &= 0xFFFDu; //SDDATACTL32 - *(vu16*)0x100060D8 &= 0xFFDDu; //SDDATACTL - *(vu16*)0x10006104 = 0; //SDBLKLEN32 - *(vu16*)0x10006108 = 1; //SDBLKCOUNT32 - *(vu16*)0x100060E0 &= 0xFFFEu; //SDRESET - *(vu16*)0x100060E0 |= 1u; //SDRESET - *(vu16*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0 - *(vu16*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1 - *(vu16*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7 - *(vu16*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8 - *(vu16*)0x10006002 &= 0xFFFCu; //SDPORTSEL - *(vu16*)0x10006024 = 0x40; //Nintendo sets this to 0x20 - *(vu16*)0x10006028 = 0x40EB; //Nintendo sets this to 0x40EE - *(vu16*)0x10006002 &= 0xFFFCu; ////SDPORTSEL - *(vu16*)0x10006026 = 512; //SDBLKLEN - *(vu16*)0x10006008 = 0; //SDSTOP - - inittarget(&handleSD); -} - -static int Nand_Init() -{ inittarget(&handleNAND); - ioDelay(0xF000); + waitcycles(0xF000); - sdmmc_send_command(&handleNAND,0,0); + sdmmc_send_command(&handleNAND, 0, 0); - do { - do { - sdmmc_send_command(&handleNAND,0x10701,0x100000); - } while ( !(handleNAND.error & 1) ); - } while((handleNAND.ret[0] & 0x80000000) == 0); + do + { + do + { + sdmmc_send_command(&handleNAND, 0x10701, 0x100000); + } + while(!(handleNAND.error & 1)); + } + while((handleNAND.ret[0] & 0x80000000) == 0); - sdmmc_send_command(&handleNAND,0x10602,0x0); - if (handleNAND.error & 0x4) return -1; + sdmmc_send_command(&handleNAND, 0x10602, 0x0); + if((handleNAND.error & 0x4)) return -1; - sdmmc_send_command(&handleNAND,0x10403,handleNAND.initarg << 0x10); - if (handleNAND.error & 0x4) return -1; + sdmmc_send_command(&handleNAND, 0x10403, handleNAND.initarg << 0x10); + if((handleNAND.error & 0x4)) return -1; - sdmmc_send_command(&handleNAND,0x10609,handleNAND.initarg << 0x10); - if (handleNAND.error & 0x4) return -1; + sdmmc_send_command(&handleNAND, 0x10609, handleNAND.initarg << 0x10); + if((handleNAND.error & 0x4)) return -1; - handleNAND.total_size = calcSDSize((u8*)&handleNAND.ret[0],0); + handleNAND.total_size = calcSDSize((u8*)&handleNAND.ret[0], 0); handleNAND.clk = 1; setckl(1); - sdmmc_send_command(&handleNAND,0x10407,handleNAND.initarg << 0x10); - if (handleNAND.error & 0x4) return -1; + sdmmc_send_command(&handleNAND, 0x10407, handleNAND.initarg << 0x10); + if((handleNAND.error & 0x4)) return -1; handleNAND.SDOPT = 1; - sdmmc_send_command(&handleNAND,0x10506,0x3B70100); - if (handleNAND.error & 0x4) return -1; + sdmmc_send_command(&handleNAND, 0x10506, 0x3B70100); + if((handleNAND.error & 0x4)) return -1; - sdmmc_send_command(&handleNAND,0x10506,0x3B90100); - if (handleNAND.error & 0x4) return -1; + sdmmc_send_command(&handleNAND, 0x10506, 0x3B90100); + if((handleNAND.error & 0x4)) return -1; - sdmmc_send_command(&handleNAND,0x1040D,handleNAND.initarg << 0x10); - if (handleNAND.error & 0x4) return -1; + sdmmc_send_command(&handleNAND, 0x1040D, handleNAND.initarg << 0x10); + if((handleNAND.error & 0x4)) return -1; - sdmmc_send_command(&handleNAND,0x10410,0x200); - if (handleNAND.error & 0x4) return -1; + sdmmc_send_command(&handleNAND, 0x10410, 0x200); + if((handleNAND.error & 0x4)) return -1; handleNAND.clk |= 0x200; @@ -317,113 +377,104 @@ static int Nand_Init() static int SD_Init() { + //SD + handleSD.isSDHC = 0; + handleSD.SDOPT = 0; + handleSD.res = 0; + handleSD.initarg = 0; + handleSD.clk = 0x80; + handleSD.devicenumber = 0; + inittarget(&handleSD); - ioDelay(1u << 18); //Card needs a little bit of time to be detected, it seems - + waitcycles(1u << 22); //Card needs a little bit of time to be detected, it seems FIXME test again to see what a good number is for the delay + //If not inserted - if (!(*((vu16*)0x1000601c) & TMIO_STAT0_SIGSTATE)) return -1; - - sdmmc_send_command(&handleSD,0,0); - sdmmc_send_command(&handleSD,0x10408,0x1AA); - //u32 temp = (handleSD.ret[0] == 0x1AA) << 0x1E; + if(!(*((vu16 *)(SDMMC_BASE + REG_SDSTATUS0)) & TMIO_STAT0_SIGSTATE)) return 5; + + sdmmc_send_command(&handleSD, 0, 0); + sdmmc_send_command(&handleSD, 0x10408, 0x1AA); u32 temp = (handleSD.error & 0x1) << 0x1E; - //int count = 0; u32 temp2 = 0; - do { - do { - sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10); - sdmmc_send_command(&handleSD,0x10769,0x00FF8000 | temp); + do + { + do + { + sdmmc_send_command(&handleSD, 0x10437, handleSD.initarg << 0x10); + sdmmc_send_command(&handleSD, 0x10769, 0x00FF8000 | temp); temp2 = 1; - } while ( !(handleSD.error & 1) ); - - } while((handleSD.ret[0] & 0x80000000) == 0); + } + while(!(handleSD.error & 1)); + } + while((handleSD.ret[0] & 0x80000000) == 0); if(!((handleSD.ret[0] >> 30) & 1) || !temp) temp2 = 0; handleSD.isSDHC = temp2; - sdmmc_send_command(&handleSD,0x10602,0); - if (handleSD.error & 0x4) return -1; + sdmmc_send_command(&handleSD, 0x10602, 0); + if((handleSD.error & 0x4)) return -1; - sdmmc_send_command(&handleSD,0x10403,0); - if (handleSD.error & 0x4) return -1; + sdmmc_send_command(&handleSD, 0x10403, 0); + if((handleSD.error & 0x4)) return -2; handleSD.initarg = handleSD.ret[0] >> 0x10; - sdmmc_send_command(&handleSD,0x10609,handleSD.initarg << 0x10); - if (handleSD.error & 0x4) return -1; + sdmmc_send_command(&handleSD, 0x10609, handleSD.initarg << 0x10); + if((handleSD.error & 0x4)) return -3; - handleSD.total_size = calcSDSize((u8*)&handleSD.ret[0],-1); + handleSD.total_size = calcSDSize((u8*)&handleSD.ret[0], -1); handleSD.clk = 1; setckl(1); - sdmmc_send_command(&handleSD,0x10507,handleSD.initarg << 0x10); - if (handleSD.error & 0x4) return -1; + sdmmc_send_command(&handleSD, 0x10507, handleSD.initarg << 0x10); + if((handleSD.error & 0x4)) return -4; - sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10); - if (handleSD.error & 0x4) return -1; + sdmmc_send_command(&handleSD, 0x10437, handleSD.initarg << 0x10); + if((handleSD.error & 0x4)) return -5; handleSD.SDOPT = 1; - sdmmc_send_command(&handleSD,0x10446,0x2); - if (handleSD.error & 0x4) return -1; + sdmmc_send_command(&handleSD, 0x10446, 0x2); + if((handleSD.error & 0x4)) return -6; - sdmmc_send_command(&handleSD,0x1040D,handleSD.initarg << 0x10); - if (handleSD.error & 0x4) return -1; + sdmmc_send_command(&handleSD, 0x1040D, handleSD.initarg << 0x10); + if((handleSD.error & 0x4)) return -7; - sdmmc_send_command(&handleSD,0x10410,0x200); - if (handleSD.error & 0x4) return -1; + sdmmc_send_command(&handleSD, 0x10410, 0x200); + if((handleSD.error & 0x4)) return -8; handleSD.clk |= 0x200; return 0; } -void sdmmc_sdcard_init() +void sdmmc_get_cid(bool isNand, u32 *info) { - InitSD(); - Nand_Init(); - SD_Init(); + struct mmcdevice *device = isNand ? &handleNAND : &handleSD; + + inittarget(device); + + // use cmd7 to put sd card in standby mode + // CMD7 + sdmmc_send_command(device, 0x10507, 0); + + // get sd card info + // use cmd10 to read CID + sdmmc_send_command(device, 0x1060A, device->initarg << 0x10); + + for(int i = 0; i < 4; ++i) + info[i] = device->ret[i]; + + // put sd card back to transfer mode + // CMD7 + sdmmc_send_command(device, 0x10507, device->initarg << 0x10); } -int sdmmc_get_cid(int isNand, uint32_t *info) +u32 sdmmc_sdcard_init() { - struct mmcdevice *device; - if(isNand) - device = &handleNAND; - else - device = &handleSD; - - inittarget(device); - // use cmd7 to put sd card in standby mode - // CMD7 - { - sdmmc_send_command(device,0x10507,0); - //if((device->error & 0x4)) return -1; - } - - // get sd card info - // use cmd10 to read CID - { - sdmmc_send_command(device,0x1060A,device->initarg << 0x10); - //if((device->error & 0x4)) return -2; - - for( int i = 0; i < 4; ++i ) { - info[i] = device->ret[i]; - } - } - - // put sd card back to transfer mode - // CMD7 - { - sdmmc_send_command(device,0x10507,device->initarg << 0x10); - //if((device->error & 0x4)) return -3; - } - - if(isNand) - { - inittarget(&handleSD); - } - - return 0; + u32 ret = 0; + InitSD(); + if(Nand_Init() != 0) ret &= 1; + if(SD_Init() != 0) ret &= 2; + return ret; } From 569b2d9c8766c4fd120b6f5b661a3f2e5a68a4f6 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Thu, 25 May 2017 02:28:28 +0200 Subject: [PATCH 217/259] Update sdmmc.h --- source/arm9/source/fatfs/sdmmc/sdmmc.h | 115 +++++++++---------------- 1 file changed, 43 insertions(+), 72 deletions(-) diff --git a/source/arm9/source/fatfs/sdmmc/sdmmc.h b/source/arm9/source/fatfs/sdmmc/sdmmc.h index 9d58a22..d2c198b 100644 --- a/source/arm9/source/fatfs/sdmmc/sdmmc.h +++ b/source/arm9/source/fatfs/sdmmc/sdmmc.h @@ -1,52 +1,48 @@ -// Copyright 2014 Normmatt -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - #pragma once -#include "common.h" +#include "../../common.h" -#define SDMMC_BASE 0x10006000u +#define SDMMC_BASE 0x10006000 -#define REG_SDCMD 0x00 -#define REG_SDPORTSEL 0x02 -#define REG_SDCMDARG 0x04 -#define REG_SDCMDARG0 0x04 -#define REG_SDCMDARG1 0x06 -#define REG_SDSTOP 0x08 -#define REG_SDBLKCOUNT 0x0a +#define REG_SDCMD 0x00 +#define REG_SDPORTSEL 0x02 +#define REG_SDCMDARG 0x04 +#define REG_SDCMDARG0 0x04 +#define REG_SDCMDARG1 0x06 +#define REG_SDSTOP 0x08 +#define REG_SDBLKCOUNT 0x0A -#define REG_SDRESP0 0x0c -#define REG_SDRESP1 0x0e -#define REG_SDRESP2 0x10 -#define REG_SDRESP3 0x12 -#define REG_SDRESP4 0x14 -#define REG_SDRESP5 0x16 -#define REG_SDRESP6 0x18 -#define REG_SDRESP7 0x1a +#define REG_SDRESP0 0x0C +#define REG_SDRESP1 0x0E +#define REG_SDRESP2 0x10 +#define REG_SDRESP3 0x12 +#define REG_SDRESP4 0x14 +#define REG_SDRESP5 0x16 +#define REG_SDRESP6 0x18 +#define REG_SDRESP7 0x1A -#define REG_SDSTATUS0 0x1c -#define REG_SDSTATUS1 0x1e +#define REG_SDSTATUS0 0x1C +#define REG_SDSTATUS1 0x1E -#define REG_SDIRMASK0 0x20 -#define REG_SDIRMASK1 0x22 -#define REG_SDCLKCTL 0x24 +#define REG_SDIRMASK0 0x20 +#define REG_SDIRMASK1 0x22 +#define REG_SDCLKCTL 0x24 -#define REG_SDBLKLEN 0x26 -#define REG_SDOPT 0x28 -#define REG_SDFIFO 0x30 +#define REG_SDBLKLEN 0x26 +#define REG_SDOPT 0x28 +#define REG_SDFIFO 0x30 -#define REG_SDDATACTL 0xd8 -#define REG_SDRESET 0xe0 -#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not? +#define REG_DATACTL 0xD8 +#define REG_SDRESET 0xE0 +#define REG_SDPROTECTED 0xF6 //bit 0 determines if sd is protected or not? -#define REG_SDDATACTL32 0x100 -#define REG_SDBLKLEN32 0x104 -#define REG_SDBLKCOUNT32 0x108 -#define REG_SDFIFO32 0x10C +#define REG_DATACTL32 0x100 +#define REG_SDBLKLEN32 0x104 +#define REG_SDBLKCOUNT32 0x108 +#define REG_SDFIFO32 0x10C -#define REG_CLK_AND_WAIT_CTL 0x138 -#define REG_RESET_SDIO 0x1e0 +#define REG_CLK_AND_WAIT_CTL 0x138 +#define REG_RESET_SDIO 0x1E0 #define TMIO_STAT0_CMDRESPEND 0x0001 #define TMIO_STAT0_DATAEND 0x0004 @@ -70,31 +66,7 @@ #define TMIO_STAT1_CMD_BUSY 0x4000 #define TMIO_STAT1_ILL_ACCESS 0x8000 -//Comes from TWLSDK mongoose.tef DWARF info -#define SDMC_NORMAL 0x00000000 -#define SDMC_ERR_COMMAND 0x00000001 -#define SDMC_ERR_CRC 0x00000002 -#define SDMC_ERR_END 0x00000004 -#define SDMC_ERR_TIMEOUT 0x00000008 -#define SDMC_ERR_FIFO_OVF 0x00000010 -#define SDMC_ERR_FIFO_UDF 0x00000020 -#define SDMC_ERR_WP 0x00000040 -#define SDMC_ERR_ABORT 0x00000080 -#define SDMC_ERR_FPGA_TIMEOUT 0x00000100 -#define SDMC_ERR_PARAM 0x00000200 -#define SDMC_ERR_R1_STATUS 0x00000800 -#define SDMC_ERR_NUM_WR_SECTORS 0x00001000 -#define SDMC_ERR_RESET 0x00002000 -#define SDMC_ERR_ILA 0x00004000 -#define SDMC_ERR_INFO_DETECT 0x00008000 - -#define SDMC_STAT_ERR_UNKNOWN 0x00080000 -#define SDMC_STAT_ERR_CC 0x00100000 -#define SDMC_STAT_ERR_ECC_FAILED 0x00200000 -#define SDMC_STAT_ERR_CRC 0x00800000 -#define SDMC_STAT_ERR_OTHER 0xf9c70008 - -#define TMIO_MASK_ALL 0x837f031d +#define TMIO_MASK_ALL 0x837F031D #define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \ TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR) @@ -103,7 +75,8 @@ #define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND) typedef struct mmcdevice { - vu8* data; + u8 *rData; + const u8 *tData; u32 size; u32 error; u16 stat0; @@ -118,12 +91,10 @@ typedef struct mmcdevice { u32 res; } mmcdevice; +u32 sdmmc_sdcard_init(); +int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out); +int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in); +int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out); +int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, const u8 *in); +void sdmmc_get_cid(bool isNand, u32 *info); mmcdevice *getMMCDevice(int drive); - -void sdmmc_sdcard_init(); -u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out); -u32 sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in); - -u32 sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out); - -int sdmmc_get_cid( int isNand, uint32_t *info); From bb9817a1de2d4642b88390d77ed0afd2aac086bc Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Mon, 29 May 2017 18:25:01 +0200 Subject: [PATCH 218/259] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c91edb2..73182f8 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,9 @@ Binaries should now be in the `build` folder. ##Credits +###To original developer: + * Cpasjuste + ###For contributions to hb_menu: * smea : code * GEMISIS : code From 3a139f11727ddd9a24ecf8c6f81412f3751d4dca Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:21:48 +0200 Subject: [PATCH 219/259] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 73182f8..dcf11a9 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ CtrBootManager is a boot manager for some 3DS homebrew applications, like HBL an 3. `cmake -DCMAKE_TOOLCHAIN_FILE=../DevkitArm3DS.cmake ../` 4. `cmake --build . --target screeninit_a9lh` 5. `bin2h -c screeninit < screeninit.bin > screeninit.h` - 6. `cmake --build . --target loader_a9lh` - 7. `bin2h -c loader < loader.bin > loader.h` + 6. `cmake --build . --target chainloader_a9lh` + 7. `bin2h -c chainloader < chainloader.bin > chainloader.h` 8. `cmake --build . --target CtrBootManager_a9lh` Binaries should now be in the `build` folder. From 339ca720c2fa18391dd0fbd506098e145c0e1ad4 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:22:25 +0200 Subject: [PATCH 220/259] Update changelog.txt --- changelog.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.txt b/changelog.txt index c20c7de..07f4adb 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +2.5.1 + +Boot9Strap v1.2 support + 2.5.0 SysNAND location supported (only for A9LH/B9S versions): From 93bed32838862a420cbd6c2a07635d7f64512aa3 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:25:08 +0200 Subject: [PATCH 221/259] Update and rename loader.h to chainloader.h --- build/chainloader.h | 12 ++++++++++++ build/loader.h | 10 ---------- 2 files changed, 12 insertions(+), 10 deletions(-) create mode 100644 build/chainloader.h delete mode 100644 build/loader.h diff --git a/build/chainloader.h b/build/chainloader.h new file mode 100644 index 0000000..2a4b7fd --- /dev/null +++ b/build/chainloader.h @@ -0,0 +1,12 @@ +const char chainloader[]={ +0x00,0xd0,0x1f,0xe5,0x45,0x00,0x00,0xea,0x00,0xb8,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x20,0x81,0xe1,0x5e,0x2f,0x07,0xee,0x20 +,0x00,0x80,0xe2,0x01,0x0b,0x50,0xe3,0xfa,0xff,0xff,0x1a,0x01,0x11,0x81,0xe2,0x00,0x00,0x51,0xe3,0xf6,0xff,0xff,0x1a,0x9a,0x1f,0x07,0xee,0x15,0x1f,0x07,0xee,0x1e +,0xff,0x2f,0xe1,0xf0,0xb5,0xcf,0xb0,0x0f,0x00,0x69,0x46,0x00,0x28,0x12,0xdd,0x8b,0x26,0x3d,0x68,0x00,0x23,0x08,0xac,0x76,0x00,0x03,0xe0,0xe2,0x54,0x01,0x33,0xb3 +,0x42,0x02,0xd0,0xea,0x5c,0x00,0x2a,0xf8,0xd1,0x00,0x22,0x00,0x94,0xe2,0x54,0x69,0x46,0x02,0x28,0x18,0xd0,0x14,0x4e,0x14,0x4f,0xb5,0x68,0x73,0x68,0x32,0x68,0x00 +,0x2d,0x09,0xd0,0x12,0x4c,0xa4,0x46,0x5d,0x19,0x62,0x44,0x14,0x78,0x1c,0x70,0x01,0x33,0x01,0x32,0xab,0x42,0xf9,0xd1,0x30,0x36,0xbe,0x42,0xed,0xd1,0x0c,0x4a,0x93 +,0x68,0xd2,0x68,0x00,0xf0,0x38,0xf8,0x79,0x68,0x13,0x00,0x02,0xaa,0xcc,0x5c,0xd4,0x54,0x01,0x33,0x0c,0x2b,0xfa,0xd1,0xcc,0x5c,0xd4,0x54,0x01,0x33,0x18,0x2b,0xfa +,0xd1,0x69,0x46,0x01,0x92,0xd6,0xe7,0x40,0x10,0x00,0x20,0x00,0x11,0x00,0x20,0x00,0x10,0x00,0x20,0x00,0x40,0xa0,0xe1,0x01,0x50,0xa0,0xe1,0x02,0x60,0xa0,0xe1,0x03 +,0x70,0xa0,0xe1,0xc9,0xff,0xff,0xeb,0x10,0x0f,0x11,0xee,0x01,0x0a,0xc0,0xe3,0x04,0x00,0xc0,0xe3,0x01,0x00,0xc0,0xe3,0x10,0x0f,0x01,0xee,0x02,0x02,0xa0,0xe3,0x04 +,0x70,0x00,0xe5,0x04,0x00,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x00,0x20,0x1f,0xe5,0x16,0xff,0x2f,0xe1,0xef,0xbe,0x01,0x00,0x78,0x47,0xc0,0x46,0xec,0xff,0xff,0xea,0x00 +,0xc0,0x9f,0xe5,0x1c,0xff,0x2f,0xe1,0x45,0x90,0xff,0x01,0x00,0x00,0x00,0x00}; +const int chainloader_size=304; diff --git a/build/loader.h b/build/loader.h deleted file mode 100644 index 6f9720f..0000000 --- a/build/loader.h +++ /dev/null @@ -1,10 +0,0 @@ -const char loader[]={ -0x04,0xd0,0x9f,0xe5,0x35,0x00,0x00,0xea,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0x27,0x00,0x10,0xa0,0xe3,0x00,0x00,0xa0,0xe3,0x00,0x20,0x81,0xe1,0x5e,0x2f,0x07,0xee,0x20 -,0x00,0x80,0xe2,0x01,0x0b,0x50,0xe3,0xfa,0xff,0xff,0x1a,0x01,0x11,0x81,0xe2,0x00,0x00,0x51,0xe3,0xf6,0xff,0xff,0x1a,0x9a,0x1f,0x07,0xee,0x15,0x1f,0x07,0xee,0x1e -,0xff,0x2f,0xe1,0x00,0x00,0xa0,0xe1,0x00,0x00,0xa0,0xe1,0x00,0x00,0xa0,0xe1,0x30,0xb5,0x8b,0x24,0xc9,0xb0,0x09,0x68,0x00,0x23,0x02,0xa8,0x64,0x00,0x03,0xe0,0xc2 -,0x54,0x01,0x33,0xa3,0x42,0x2e,0xd0,0xca,0x5c,0x00,0x2a,0xf8,0xd1,0x20,0x21,0xff,0x31,0xc3,0x18,0x69,0x44,0x1a,0x70,0x01,0x33,0x99,0x42,0xfb,0xd1,0x01,0x90,0x12 -,0x4c,0x13,0x4d,0xa0,0x68,0x00,0x28,0x10,0xd0,0x90,0x21,0x89,0x05,0x8c,0x46,0x23,0x68,0x63,0x44,0x1a,0x00,0x63,0x68,0x18,0x18,0x11,0x78,0x19,0x70,0x01,0x33,0x01 -,0x32,0x83,0x42,0xf9,0xd1,0x30,0x34,0xac,0x42,0xeb,0xd1,0x90,0x24,0xa4,0x05,0x08,0x4b,0xa2,0x68,0x1a,0x60,0x00,0xf0,0x19,0xf8,0xe3,0x68,0x06,0x4a,0x01,0xa9,0x01 -,0x20,0x00,0xf0,0x0b,0xf8,0x00,0x22,0xc2,0x54,0xd8,0xe7,0x40,0x00,0x00,0x24,0x00,0x01,0x00,0x24,0xfc,0xff,0xff,0x1f,0xef,0xbe,0x00,0x00,0x18,0x47,0xc0,0x46,0x00 -,0xc0,0x9f,0xe5,0x1c,0xff,0x2f,0xe1,0x51,0xe0,0xff,0x27,0x78,0x47,0xc0,0x46,0xc6,0xff,0xff,0xea,0x00,0x00,0x00,0x00}; -const int loader_size=248; From 29e1c4f455cda13c21d8b4bbbe790cfcafb7288e Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:25:38 +0200 Subject: [PATCH 222/259] Update screeninit.h --- build/screeninit.h | 60 +++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/build/screeninit.h b/build/screeninit.h index 4874089..a47b39a 100644 --- a/build/screeninit.h +++ b/build/screeninit.h @@ -1,31 +1,31 @@ const char screeninit[]={ -0xc0,0x01,0x0c,0xf1,0x01,0x00,0x00,0xea,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0xe1,0x00,0xc0,0x9f,0xe5,0x1c,0xff,0x2f,0xe1,0x21,0xfc,0xff,0x24,0x00,0x00,0x00,0x00,0x30 -,0xb5,0x85,0xb0,0x69,0x46,0x7b,0x4a,0x31,0xca,0x31,0xc1,0x12,0x68,0x7a,0x48,0x0a,0x60,0x7a,0x49,0x7a,0x4a,0x12,0x68,0x08,0x60,0x01,0x20,0x6b,0x46,0x79,0x49,0x79 -,0x4c,0x08,0x60,0x79,0x49,0x25,0x68,0x29,0x40,0x21,0x60,0x92,0x00,0xd4,0x58,0x77,0x49,0x0c,0x60,0xd2,0x58,0x77,0x4b,0x1a,0x60,0x77,0x4b,0x77,0x4a,0x13,0x60,0x77 -,0x4a,0x13,0x60,0xe1,0x22,0x77,0x4b,0x52,0x00,0x1a,0x60,0x76,0x4b,0xf1,0x3a,0x1a,0x60,0xc2,0x23,0x75,0x49,0xff,0x33,0x0b,0x60,0x75,0x49,0x0b,0x60,0x00,0x23,0xcf -,0x24,0x74,0x49,0x0b,0x60,0x74,0x49,0x0c,0x60,0x74,0x49,0x0a,0x60,0x74,0x49,0x74,0x4a,0x11,0x60,0x80,0x21,0x74,0x4a,0x49,0x02,0x11,0x60,0x9e,0x21,0x73,0x4a,0xff -,0x31,0x11,0x60,0x72,0x4a,0x9c,0x39,0xff,0x39,0x11,0x60,0xc9,0x22,0x71,0x4c,0x52,0x00,0x22,0x60,0x70,0x4c,0x22,0x60,0x70,0x4c,0x22,0x60,0x70,0x4a,0x10,0x60,0x70 -,0x4a,0x11,0x60,0x70,0x49,0x71,0x4a,0x11,0x60,0x71,0x4a,0x13,0x60,0x71,0x4a,0x71,0x49,0x13,0x60,0x71,0x4a,0x11,0x60,0x71,0x49,0x72,0x4a,0x11,0x60,0x72,0x49,0x72 -,0x4a,0x11,0x60,0x72,0x49,0x73,0x4a,0x11,0x60,0x73,0x49,0x73,0x4a,0x11,0x60,0x73,0x49,0x74,0x4a,0x11,0x60,0xb4,0x21,0x73,0x4a,0x13,0x60,0x73,0x4a,0x89,0x00,0x11 -,0x60,0x73,0x4a,0x73,0x49,0x13,0x60,0x73,0x4a,0x74,0x48,0x84,0x46,0x0b,0x60,0x63,0x44,0x93,0x42,0xf9,0xd1,0xe1,0x22,0x71,0x4b,0x52,0x00,0x1a,0x60,0xd1,0x23,0x70 -,0x4a,0x13,0x60,0xc2,0x22,0x70,0x49,0xff,0x32,0x0a,0x60,0x6f,0x49,0x0a,0x60,0xcd,0x21,0x6f,0x4a,0x11,0x60,0x6f,0x4a,0x02,0x31,0x11,0x60,0x6e,0x4a,0x13,0x60,0x47 -,0x4a,0x6e,0x4b,0x1a,0x60,0x80,0x22,0x6d,0x4b,0x52,0x02,0x1a,0x60,0x9e,0x22,0x6c,0x4b,0xff,0x32,0x1a,0x60,0x52,0x23,0x6b,0x4a,0x13,0x60,0xc9,0x22,0x6b,0x49,0x52 -,0x00,0x0a,0x60,0x6a,0x49,0x0a,0x60,0x4f,0x21,0x6a,0x4a,0x11,0x60,0x6a,0x4a,0x01,0x31,0x11,0x60,0x69,0x4a,0x13,0x60,0x69,0x4a,0x6a,0x4b,0x1a,0x60,0x00,0x23,0x69 -,0x4a,0x13,0x60,0x69,0x4a,0x3f,0x39,0x11,0x60,0x69,0x49,0x69,0x4a,0x11,0x60,0x43,0x49,0x69,0x4a,0x11,0x60,0x69,0x49,0x69,0x4a,0x11,0x60,0x69,0x49,0x6a,0x4a,0x11 -,0x60,0x6a,0x49,0x6a,0x4a,0x11,0x60,0x45,0x49,0x6a,0x4a,0x11,0x60,0xb4,0x21,0x69,0x4a,0x13,0x60,0x69,0x4a,0x89,0x00,0x11,0x60,0x69,0x4a,0x69,0x49,0x13,0x60,0x45 -,0x4a,0x46,0x48,0x84,0x46,0x0b,0x60,0x63,0x44,0x93,0x42,0xf9,0xd1,0x38,0x4b,0x38,0x4a,0x13,0x60,0x64,0x4a,0x13,0x60,0x64,0x4a,0x13,0x60,0x64,0x4a,0x5a,0x49,0x13 -,0x60,0x58,0x4a,0x0a,0x60,0x63,0x49,0x0a,0x60,0x63,0x49,0x0b,0x60,0x63,0x49,0x0b,0x60,0x63,0x4b,0x1a,0x60,0x00,0x23,0x62,0x4a,0x13,0x60,0x13,0x68,0x00,0x2b,0xfc -,0xd0,0x60,0x4b,0x1b,0x68,0x00,0xf0,0xbf,0xf8,0x05,0xb0,0x30,0xbc,0x01,0xbc,0x00,0x47,0xc0,0x46,0x8c,0xff,0xff,0x24,0x7f,0x00,0x01,0x00,0x00,0x12,0x14,0x10,0x08 -,0xfc,0xff,0x24,0x14,0x20,0x20,0x10,0x0c,0x20,0x20,0x10,0xfe,0xff,0xfe,0xff,0x40,0x22,0x20,0x10,0x40,0x2a,0x20,0x10,0x3e,0x02,0x01,0x00,0x44,0x22,0x20,0x10,0x44 -,0x2a,0x20,0x10,0x00,0x04,0x40,0x10,0x04,0x04,0x40,0x10,0x08,0x04,0x40,0x10,0x0c,0x04,0x40,0x10,0x10,0x04,0x40,0x10,0x14,0x04,0x40,0x10,0x18,0x04,0x40,0x10,0xc1 -,0x01,0xc5,0x01,0x1c,0x04,0x40,0x10,0x20,0x04,0x40,0x10,0x24,0x04,0x40,0x10,0x28,0x04,0x40,0x10,0x2c,0x04,0x40,0x10,0x30,0x04,0x40,0x10,0x34,0x04,0x40,0x10,0x38 -,0x04,0x40,0x10,0x3c,0x04,0x40,0x10,0x92,0x01,0x96,0x01,0x40,0x04,0x40,0x10,0x44,0x04,0x40,0x10,0x48,0x04,0x40,0x10,0x90,0x01,0xf0,0x00,0x5c,0x04,0x40,0x10,0xd1 -,0x00,0xc1,0x01,0x60,0x04,0x40,0x10,0x02,0x00,0x92,0x01,0x64,0x04,0x40,0x10,0x00,0x00,0x30,0x18,0x68,0x04,0x40,0x10,0x41,0x03,0x08,0x00,0x70,0x04,0x40,0x10,0x01 -,0x05,0x01,0x00,0x74,0x04,0x40,0x10,0x78,0x04,0x40,0x10,0x90,0x04,0x40,0x10,0x9c,0x04,0x40,0x10,0x84,0x04,0x40,0x10,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00 -,0x05,0x40,0x10,0x04,0x05,0x40,0x10,0x08,0x05,0x40,0x10,0x0c,0x05,0x40,0x10,0x10,0x05,0x40,0x10,0x14,0x05,0x40,0x10,0x18,0x05,0x40,0x10,0x1c,0x05,0x40,0x10,0x20 -,0x05,0x40,0x10,0x24,0x05,0x40,0x10,0x28,0x05,0x40,0x10,0x2c,0x05,0x40,0x10,0x30,0x05,0x40,0x10,0x34,0x05,0x40,0x10,0x38,0x05,0x40,0x10,0x3c,0x05,0x40,0x10,0x94 -,0x01,0x98,0x01,0x40,0x05,0x40,0x10,0x44,0x05,0x40,0x10,0x48,0x05,0x40,0x10,0x40,0x01,0xf0,0x00,0x5c,0x05,0x40,0x10,0x60,0x05,0x40,0x10,0x52,0x00,0x92,0x01,0x64 -,0x05,0x40,0x10,0x00,0x65,0x34,0x18,0x68,0x05,0x40,0x10,0x01,0x03,0x08,0x00,0x70,0x05,0x40,0x10,0x74,0x05,0x40,0x10,0x78,0x05,0x40,0x10,0x90,0x05,0x40,0x10,0x9c -,0x05,0x40,0x10,0x84,0x05,0x40,0x10,0x6c,0x04,0x40,0x10,0x94,0x04,0x40,0x10,0x98,0x04,0x40,0x10,0x6c,0x05,0x40,0x10,0x00,0xfe,0xff,0x23,0x04,0xfe,0xff,0x23,0x08 -,0xfe,0xff,0x23,0xf8,0xff,0xff,0x1f,0x18,0x47,0xc0,0x46,0x5f,0x00,0x00,0x00,0x4c,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x26,0x00,0x00,0x00}; -const int screeninit_size=924; +0xc0,0x01,0x0c,0xf1,0x01,0x00,0x00,0xea,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x9f,0xe5,0x1c,0xff,0x2f,0xe1,0x21,0xfc,0xff,0x24,0x00,0x00,0x00,0x00,0x30 +,0xb5,0x85,0xb0,0x69,0x46,0x7a,0x4a,0x31,0xca,0x31,0xc1,0x12,0x68,0x79,0x48,0x0a,0x60,0x79,0x49,0x79,0x4a,0x12,0x68,0x08,0x60,0x01,0x20,0x6b,0x46,0x78,0x49,0x78 +,0x4c,0x08,0x60,0x78,0x4d,0x21,0x68,0x29,0x40,0x21,0x60,0x92,0x00,0xd4,0x58,0x76,0x49,0x0c,0x60,0xd2,0x58,0x76,0x4b,0x1a,0x60,0x76,0x4b,0x76,0x4a,0x13,0x60,0x76 +,0x4a,0x13,0x60,0xe1,0x22,0x76,0x4b,0x52,0x00,0x1a,0x60,0x75,0x4b,0xf1,0x3a,0x1a,0x60,0xc2,0x23,0x74,0x49,0xff,0x33,0x0b,0x60,0x74,0x49,0x0b,0x60,0x00,0x23,0xcf +,0x24,0x73,0x49,0x0b,0x60,0x73,0x49,0x0c,0x60,0x73,0x49,0x0a,0x60,0x73,0x49,0x73,0x4a,0x11,0x60,0x80,0x21,0x73,0x4a,0x49,0x02,0x11,0x60,0x9e,0x21,0x72,0x4a,0xff +,0x31,0x11,0x60,0x71,0x4a,0x9c,0x39,0xff,0x39,0x11,0x60,0xc9,0x22,0x70,0x4c,0x52,0x00,0x22,0x60,0x6f,0x4c,0x22,0x60,0x6f,0x4c,0x22,0x60,0x6f,0x4a,0x10,0x60,0x6f +,0x4a,0x11,0x60,0x6f,0x49,0x70,0x4a,0x11,0x60,0x70,0x4a,0x13,0x60,0x70,0x4a,0x70,0x49,0x13,0x60,0x70,0x4a,0x11,0x60,0x70,0x49,0x71,0x4a,0x11,0x60,0x71,0x49,0x71 +,0x4a,0x11,0x60,0x71,0x49,0x72,0x4a,0x11,0x60,0x72,0x49,0x72,0x4a,0x11,0x60,0x72,0x49,0x73,0x4a,0x11,0x60,0xb4,0x21,0x72,0x4a,0x13,0x60,0x72,0x4a,0x89,0x00,0x11 +,0x60,0x72,0x4a,0x72,0x49,0x13,0x60,0x72,0x4a,0x73,0x48,0x84,0x46,0x0b,0x60,0x63,0x44,0x93,0x42,0xf9,0xd1,0xe1,0x22,0x70,0x4b,0x52,0x00,0x1a,0x60,0xd1,0x23,0x6f +,0x4a,0x13,0x60,0xc2,0x22,0x6f,0x49,0xff,0x32,0x0a,0x60,0x6e,0x49,0x0a,0x60,0xcd,0x21,0x6e,0x4a,0x11,0x60,0x6e,0x4a,0x02,0x31,0x11,0x60,0x6d,0x4a,0x13,0x60,0x46 +,0x4a,0x6d,0x4b,0x1a,0x60,0x80,0x22,0x6c,0x4b,0x52,0x02,0x1a,0x60,0x9e,0x22,0x6b,0x4b,0xff,0x32,0x1a,0x60,0x52,0x23,0x6a,0x4a,0x13,0x60,0xc9,0x22,0x6a,0x49,0x52 +,0x00,0x0a,0x60,0x69,0x49,0x0a,0x60,0x4f,0x21,0x69,0x4a,0x11,0x60,0x69,0x4a,0x01,0x31,0x11,0x60,0x68,0x4a,0x13,0x60,0x68,0x4a,0x69,0x4b,0x1a,0x60,0x00,0x23,0x68 +,0x4a,0x13,0x60,0x68,0x4a,0x3f,0x39,0x11,0x60,0x68,0x49,0x68,0x4a,0x11,0x60,0x42,0x49,0x68,0x4a,0x11,0x60,0x68,0x49,0x68,0x4a,0x11,0x60,0x68,0x49,0x69,0x4a,0x11 +,0x60,0x69,0x49,0x69,0x4a,0x11,0x60,0x44,0x49,0x69,0x4a,0x11,0x60,0xb4,0x21,0x68,0x4a,0x13,0x60,0x68,0x4a,0x89,0x00,0x11,0x60,0x68,0x4a,0x68,0x49,0x13,0x60,0x44 +,0x4a,0x45,0x48,0x84,0x46,0x0b,0x60,0x63,0x44,0x93,0x42,0xf9,0xd1,0x37,0x4b,0x37,0x4a,0x13,0x60,0x63,0x4a,0x13,0x60,0x63,0x4a,0x13,0x60,0x63,0x4a,0x59,0x49,0x13 +,0x60,0x57,0x4a,0x0a,0x60,0x62,0x49,0x0a,0x60,0x62,0x49,0x0b,0x60,0x62,0x49,0x0b,0x60,0x62,0x4b,0x1a,0x60,0x00,0x23,0x61,0x4a,0x13,0x60,0x13,0x68,0x00,0x2b,0xfc +,0xd0,0x13,0x68,0x00,0xf0,0xbe,0xf8,0x05,0xb0,0x30,0xbc,0x01,0xbc,0x00,0x47,0x88,0xff,0xff,0x24,0x7f,0x00,0x01,0x00,0x00,0x12,0x14,0x10,0x08,0xfc,0xff,0x24,0x14 +,0x20,0x20,0x10,0x0c,0x20,0x20,0x10,0xfe,0xff,0xfe,0xff,0x40,0x22,0x20,0x10,0x40,0x2a,0x20,0x10,0x3e,0x02,0x01,0x00,0x44,0x22,0x20,0x10,0x44,0x2a,0x20,0x10,0x00 +,0x04,0x40,0x10,0x04,0x04,0x40,0x10,0x08,0x04,0x40,0x10,0x0c,0x04,0x40,0x10,0x10,0x04,0x40,0x10,0x14,0x04,0x40,0x10,0x18,0x04,0x40,0x10,0xc1,0x01,0xc5,0x01,0x1c +,0x04,0x40,0x10,0x20,0x04,0x40,0x10,0x24,0x04,0x40,0x10,0x28,0x04,0x40,0x10,0x2c,0x04,0x40,0x10,0x30,0x04,0x40,0x10,0x34,0x04,0x40,0x10,0x38,0x04,0x40,0x10,0x3c +,0x04,0x40,0x10,0x92,0x01,0x96,0x01,0x40,0x04,0x40,0x10,0x44,0x04,0x40,0x10,0x48,0x04,0x40,0x10,0x90,0x01,0xf0,0x00,0x5c,0x04,0x40,0x10,0xd1,0x00,0xc1,0x01,0x60 +,0x04,0x40,0x10,0x02,0x00,0x92,0x01,0x64,0x04,0x40,0x10,0x00,0x00,0x30,0x18,0x68,0x04,0x40,0x10,0x41,0x03,0x08,0x00,0x70,0x04,0x40,0x10,0x01,0x05,0x01,0x00,0x74 +,0x04,0x40,0x10,0x78,0x04,0x40,0x10,0x90,0x04,0x40,0x10,0x9c,0x04,0x40,0x10,0x84,0x04,0x40,0x10,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x05,0x40,0x10,0x04 +,0x05,0x40,0x10,0x08,0x05,0x40,0x10,0x0c,0x05,0x40,0x10,0x10,0x05,0x40,0x10,0x14,0x05,0x40,0x10,0x18,0x05,0x40,0x10,0x1c,0x05,0x40,0x10,0x20,0x05,0x40,0x10,0x24 +,0x05,0x40,0x10,0x28,0x05,0x40,0x10,0x2c,0x05,0x40,0x10,0x30,0x05,0x40,0x10,0x34,0x05,0x40,0x10,0x38,0x05,0x40,0x10,0x3c,0x05,0x40,0x10,0x94,0x01,0x98,0x01,0x40 +,0x05,0x40,0x10,0x44,0x05,0x40,0x10,0x48,0x05,0x40,0x10,0x40,0x01,0xf0,0x00,0x5c,0x05,0x40,0x10,0x60,0x05,0x40,0x10,0x52,0x00,0x92,0x01,0x64,0x05,0x40,0x10,0x00 +,0x65,0x34,0x18,0x68,0x05,0x40,0x10,0x01,0x03,0x08,0x00,0x70,0x05,0x40,0x10,0x74,0x05,0x40,0x10,0x78,0x05,0x40,0x10,0x90,0x05,0x40,0x10,0x9c,0x05,0x40,0x10,0x84 +,0x05,0x40,0x10,0x6c,0x04,0x40,0x10,0x94,0x04,0x40,0x10,0x98,0x04,0x40,0x10,0x6c,0x05,0x40,0x10,0x00,0xfe,0xff,0x23,0x04,0xfe,0xff,0x23,0x08,0xfe,0xff,0x23,0xf8 +,0xff,0xff,0x1f,0x18,0x47,0xc0,0x46,0x5f,0x00,0x00,0x00,0x4c,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x26,0x00,0x00,0x00}; +const int screeninit_size=920; From dc1b0d352bce6069f11ca690b70e3d8dbd336be8 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:27:58 +0200 Subject: [PATCH 223/259] Update and rename loader/linker.ld to chainloader/linker.ld --- {loader => chainloader}/linker.ld | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) rename {loader => chainloader}/linker.ld (68%) diff --git a/loader/linker.ld b/chainloader/linker.ld similarity index 68% rename from loader/linker.ld rename to chainloader/linker.ld index a3a699a..c5903f0 100644 --- a/loader/linker.ld +++ b/chainloader/linker.ld @@ -4,11 +4,18 @@ OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { - . = 0x27FFE000; + . = 0x01FF9000; + + __start__ = ABSOLUTE(.); .text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); } .rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); } .data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); } . = ALIGN(4); + + __end__ = ABSOLUTE(.); + + __stack_top__ = 0x01FFB800; + __stack_bottom__ = 0x01FFA800; } From 1367f5cb3a24c6646ff34d8b25d298d5a9e1c986 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:28:30 +0200 Subject: [PATCH 224/259] Update and rename loader/Makefile to chainloader/Makefile --- {loader => chainloader}/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename {loader => chainloader}/Makefile (88%) diff --git a/loader/Makefile b/chainloader/Makefile similarity index 88% rename from loader/Makefile rename to chainloader/Makefile index b33944c..6ab2a45 100644 --- a/loader/Makefile +++ b/chainloader/Makefile @@ -13,8 +13,8 @@ dir_build := build dir_out := ../$(dir_build) ASFLAGS := -mcpu=arm946e-s -CFLAGS := -Wall -Wextra -mthumb $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math -LDFLAGS := -nostdlib +CFLAGS := -Wall -Wextra -marm $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math +LDFLAGS := -nostartfiles -Wl,--nmagic objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ From 38d1115f85520b53898d09a3a9b8bc216053f4f1 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:29:42 +0200 Subject: [PATCH 225/259] Update and rename loader/source/cache.h to chainloader/source/cache.h --- {loader => chainloader}/source/cache.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) rename {loader => chainloader}/source/cache.h (58%) diff --git a/loader/source/cache.h b/chainloader/source/cache.h similarity index 58% rename from loader/source/cache.h rename to chainloader/source/cache.h index 66aa4bf..d5e03cc 100644 --- a/loader/source/cache.h +++ b/chainloader/source/cache.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* Copyright (C) 2016-2017 Aurora Wright, TuxSH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified -* reasonable legal notices or author attributions in that material or in the Appropriate Legal -* Notices displayed by works containing it. +* Additional Terms 7.b and 7.c of GPLv3 apply to this file: +* * Requiring preservation of specified reasonable legal notices or +* author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +* * Prohibiting misrepresentation of the origin of that material, +* or requiring that modified versions of such material be marked in +* reasonable ways as different from the original version. */ #pragma once From 499bc901e2554465b516aba4c2f8fdc894228411 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:30:27 +0200 Subject: [PATCH 226/259] Update and rename loader/source/cache.s to chainloader/source/cache.s --- {loader => chainloader}/source/cache.s | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) rename {loader => chainloader}/source/cache.s (77%) diff --git a/loader/source/cache.s b/chainloader/source/cache.s similarity index 77% rename from loader/source/cache.s rename to chainloader/source/cache.s index c4d6477..29e157f 100644 --- a/loader/source/cache.s +++ b/chainloader/source/cache.s @@ -1,5 +1,5 @@ @ This file is part of Luma3DS -@ Copyright (C) 2016 Aurora Wright, TuxSH +@ Copyright (C) 2016-2017 Aurora Wright, TuxSH @ @ This program is free software: you can redistribute it and/or modify @ it under the terms of the GNU General Public License as published by @@ -14,9 +14,13 @@ @ You should have received a copy of the GNU General Public License @ along with this program. If not, see . @ -@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified -@ reasonable legal notices or author attributions in that material or in the Appropriate Legal -@ Notices displayed by works containing it. +@ Additional Terms 7.b and 7.c of GPLv3 apply to this file: +@ * Requiring preservation of specified reasonable legal notices or +@ author attributions in that material or in the Appropriate Legal +@ Notices displayed by works containing it. +@ * Prohibiting misrepresentation of the origin of that material, +@ or requiring that modified versions of such material be marked in +@ reasonable ways as different from the original version. .text .arm From c5b6588baffd10ece9a252b6a9a316a0ae3baa9a Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:31:13 +0200 Subject: [PATCH 227/259] Update and rename loader/source/firm.c to chainloader/source/firm.c --- {loader => chainloader}/source/firm.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) rename {loader => chainloader}/source/firm.c (57%) diff --git a/loader/source/firm.c b/chainloader/source/firm.c similarity index 57% rename from loader/source/firm.c rename to chainloader/source/firm.c index c336876..54842b3 100644 --- a/loader/source/firm.c +++ b/chainloader/source/firm.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2017 Aurora Wright, TuxSH +* Copyright (C) 2016-2017 Aurora Wright, TuxSH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,30 +15,28 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified -* reasonable legal notices or author attributions in that material or in the Appropriate Legal -* Notices displayed by works containing it. +* Additional Terms 7.b and 7.c of GPLv3 apply to this file: +* * Requiring preservation of specified reasonable legal notices or +* author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +* * Prohibiting misrepresentation of the origin of that material, +* or requiring that modified versions of such material be marked in +* reasonable ways as different from the original version. */ #include "firm.h" #include "memory.h" #include "cache.h" +void disableMpuAndJumpToEntrypoints(int argc, char **argv, void *arm11Entry, void *arm9Entry); + void launchFirm(Firm *firm, int argc, char **argv) { - //Copy FIRM sections to respective memory locations - for(u32 sectionNum = 0; sectionNum < 4 && firm->section[sectionNum].size != 0; sectionNum++) + for(u32 sectionNum = 0; sectionNum < 4; sectionNum++) memcpy(firm->section[sectionNum].address, (u8 *)firm + firm->section[sectionNum].offset, firm->section[sectionNum].size); - //Set ARM11 entrypoint - *(vu32 *)0x1FFFFFFC = (u32)firm->arm11Entry; - - //Ensure that all memory transfers have completed and that the caches have been flushed - flushCaches(); - - //Jump to ARM9 entrypoint. Also give it additional arguments it can dismiss - ((void (*)(int, char**, u32))firm->arm9Entry)(argc, argv, 0x0000BEEF); + disableMpuAndJumpToEntrypoints(argc, argv, firm->arm9Entry, firm->arm11Entry); __builtin_unreachable(); } From 830fc0f9154cc0d1b18ca24a2ea14051ae1e32c4 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:32:20 +0200 Subject: [PATCH 228/259] Update and rename loader/source/firm.h to chainloader/source/firm.h --- {loader => chainloader}/source/firm.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) rename {loader => chainloader}/source/firm.h (67%) diff --git a/loader/source/firm.h b/chainloader/source/firm.h similarity index 67% rename from loader/source/firm.h rename to chainloader/source/firm.h index 47dc7ba..0f9c84d 100644 --- a/loader/source/firm.h +++ b/chainloader/source/firm.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2017 Aurora Wright, TuxSH +* Copyright (C) 2016-2017 Aurora Wright, TuxSH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified -* reasonable legal notices or author attributions in that material or in the Appropriate Legal -* Notices displayed by works containing it. +* Additional Terms 7.b and 7.c of GPLv3 apply to this file: +* * Requiring preservation of specified reasonable legal notices or +* author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +* * Prohibiting misrepresentation of the origin of that material, +* or requiring that modified versions of such material be marked in +* reasonable ways as different from the original version. */ #pragma once From fd7dd37bf82fbcc72b3857a073671f06c711f02f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:32:54 +0200 Subject: [PATCH 229/259] Update and rename loader/source/main.c to chainloader/source/main.c --- chainloader/source/main.c | 59 +++++++++++++++++++++++++++++++++++++++ loader/source/main.c | 41 --------------------------- 2 files changed, 59 insertions(+), 41 deletions(-) create mode 100644 chainloader/source/main.c delete mode 100644 loader/source/main.c diff --git a/chainloader/source/main.c b/chainloader/source/main.c new file mode 100644 index 0000000..568a5f9 --- /dev/null +++ b/chainloader/source/main.c @@ -0,0 +1,59 @@ +/* +* This file is part of Luma3DS +* Copyright (C) 2016-2017 Aurora Wright, TuxSH +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* +* Additional Terms 7.b and 7.c of GPLv3 apply to this file: +* * Requiring preservation of specified reasonable legal notices or +* author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +* * Prohibiting misrepresentation of the origin of that material, +* or requiring that modified versions of such material be marked in +* reasonable ways as different from the original version. +*/ + +#include "memory.h" +#include "cache.h" +#include "firm.h" + +void main(int argc, char **argv) +{ + Firm *firm = (Firm *)0x20001000; + char *argvPassed[2], + absPath[24 + 255]; + struct fb fbs[2]; + + if(argc > 0) + { + u32 i; + for(i = 0; i < sizeof(absPath) - 1 && argv[0][i] != 0; i++) + absPath[i] = argv[0][i]; + absPath[i] = 0; + + argvPassed[0] = (char *)absPath; + } + + if(argc == 2) + { + struct fb *fbsrc = (struct fb *)argv[1]; + + memcpy(&fbs[0], &fbsrc[0], sizeof(struct fb));//fbs[0] = fbsrc[0]; + memcpy(&fbs[1], &fbsrc[1], sizeof(struct fb));//fbs[1] = fbsrc[1]; + + argvPassed[1] = (char *)&fbs; + } + + launchFirm(firm, argc, argvPassed); +} diff --git a/loader/source/main.c b/loader/source/main.c deleted file mode 100644 index c591cc4..0000000 --- a/loader/source/main.c +++ /dev/null @@ -1,41 +0,0 @@ -/* -* This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -* -* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified -* reasonable legal notices or author attributions in that material or in the Appropriate Legal -* Notices displayed by works containing it. -*/ - -#include "memory.h" -#include "cache.h" -#include "firm.h" - -void main(int argc __attribute__((unused)), char **argv) -{ - Firm *firm = (Firm *)0x24000000; - char absPath[24 + 255]; - - u32 i; - for(i = 0; i < 23 + 255 && argv[0][i] != 0; i++) - absPath[i] = argv[0][i]; - for(; i < 24 + 255; i++) - absPath[i] = 0; - - char *argvPassed[1] = {absPath}; - - launchFirm(firm, 1, argvPassed); -} From 1900e55e79cd662ac9494b85b1cd63d569475528 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:33:40 +0200 Subject: [PATCH 230/259] Update and rename loader/source/memory.c to chainloader/source/memory.c --- {loader => chainloader}/source/memory.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) rename {loader => chainloader}/source/memory.c (66%) diff --git a/loader/source/memory.c b/chainloader/source/memory.c similarity index 66% rename from loader/source/memory.c rename to chainloader/source/memory.c index 3a92ee0..5f20707 100644 --- a/loader/source/memory.c +++ b/chainloader/source/memory.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* Copyright (C) 2016-2017 Aurora Wright, TuxSH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified -* reasonable legal notices or author attributions in that material or in the Appropriate Legal -* Notices displayed by works containing it. +* Additional Terms 7.b and 7.c of GPLv3 apply to this file: +* * Requiring preservation of specified reasonable legal notices or +* author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +* * Prohibiting misrepresentation of the origin of that material, +* or requiring that modified versions of such material be marked in +* reasonable ways as different from the original version. */ /* From 93d01bc82dacea47cda2496f9ba3e97bd5296932 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:34:38 +0200 Subject: [PATCH 231/259] Update and rename loader/source/memory.h to chainloader/source/memory.h --- {loader => chainloader}/source/memory.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) rename {loader => chainloader}/source/memory.h (63%) diff --git a/loader/source/memory.h b/chainloader/source/memory.h similarity index 63% rename from loader/source/memory.h rename to chainloader/source/memory.h index 0d81055..2e120c4 100644 --- a/loader/source/memory.h +++ b/chainloader/source/memory.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* Copyright (C) 2016-2017 Aurora Wright, TuxSH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified -* reasonable legal notices or author attributions in that material or in the Appropriate Legal -* Notices displayed by works containing it. +* Additional Terms 7.b and 7.c of GPLv3 apply to this file: +* * Requiring preservation of specified reasonable legal notices or +* author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +* * Prohibiting misrepresentation of the origin of that material, +* or requiring that modified versions of such material be marked in +* reasonable ways as different from the original version. */ /* From fb0bb6b65489b8bafa9c4608ec4fa499fba8b765 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:35:21 +0200 Subject: [PATCH 232/259] Update and rename loader/source/start.s to chainloader/source/start.s --- chainloader/source/start.s | 60 ++++++++++++++++++++++++++++++++++++++ loader/source/start.s | 30 ------------------- 2 files changed, 60 insertions(+), 30 deletions(-) create mode 100644 chainloader/source/start.s delete mode 100644 loader/source/start.s diff --git a/chainloader/source/start.s b/chainloader/source/start.s new file mode 100644 index 0000000..60f149e --- /dev/null +++ b/chainloader/source/start.s @@ -0,0 +1,60 @@ +@ This file is part of Luma3DS +@ Copyright (C) 2016-2017 Aurora Wright, TuxSH +@ +@ This program is free software: you can redistribute it and/or modify +@ it under the terms of the GNU General Public License as published by +@ the Free Software Foundation, either version 3 of the License, or +@ (at your option) any later version. +@ +@ This program is distributed in the hope that it will be useful, +@ but WITHOUT ANY WARRANTY; without even the implied warranty of +@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +@ GNU General Public License for more details. +@ +@ You should have received a copy of the GNU General Public License +@ along with this program. If not, see . +@ +@ Additional Terms 7.b and 7.c of GPLv3 apply to this file: +@ * Requiring preservation of specified reasonable legal notices or +@ author attributions in that material or in the Appropriate Legal +@ Notices displayed by works containing it. +@ * Prohibiting misrepresentation of the origin of that material, +@ or requiring that modified versions of such material be marked in +@ reasonable ways as different from the original version. +.arm + +.section .text.start +.align 4 +.global _start +_start: + ldr sp, =__stack_top__ + b main + +.text +.balign 4 +.global disableMpuAndJumpToEntrypoints +.type disableMpuAndJumpToEntrypoints, %function +disableMpuAndJumpToEntrypoints: + mov r4, r0 + mov r5, r1 + mov r6, r2 + mov r7, r3 + + bl flushCaches + + @ Disable caches / MPU + mrc p15, 0, r0, c1, c0, 0 @ read control register + bic r0, #(1<<12) @ - instruction cache disable + bic r0, #(1<<2) @ - data cache disable + bic r0, #(1<<0) @ - MPU disable + mcr p15, 0, r0, c1, c0, 0 @ write control register + + @ Set the ARM11 entrypoint + mov r0, #0x20000000 + str r7, [r0, #-4] + + @ Jump to the ARM9 entrypoint + mov r0, r4 + mov r1, r5 + ldr r2, =0x1BEEF + bx r6 diff --git a/loader/source/start.s b/loader/source/start.s deleted file mode 100644 index 07775ed..0000000 --- a/loader/source/start.s +++ /dev/null @@ -1,30 +0,0 @@ -@ This file is part of Luma3DS -@ Copyright (C) 2017 Aurora Wright, TuxSH -@ -@ This program is free software: you can redistribute it and/or modify -@ it under the terms of the GNU General Public License as published by -@ the Free Software Foundation, either version 3 of the License, or -@ (at your option) any later version. -@ -@ This program is distributed in the hope that it will be useful, -@ but WITHOUT ANY WARRANTY; without even the implied warranty of -@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -@ GNU General Public License for more details. -@ -@ You should have received a copy of the GNU General Public License -@ along with this program. If not, see . -@ -@ Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified -@ reasonable legal notices or author attributions in that material or in the Appropriate Legal -@ Notices displayed by works containing it. - -.section .text.start -.align 4 -.global _start -_start: - ldr sp, =0x27ffe000 - b main - -.global payloadSize -payloadSize: - .word 0 From 59cb6427ae0fa02b35601b36865663d3ee8535e0 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:36:00 +0200 Subject: [PATCH 233/259] Update and rename loader/source/types.h to chainloader/source/types.h --- {loader => chainloader}/source/types.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) rename {loader => chainloader}/source/types.h (60%) diff --git a/loader/source/types.h b/chainloader/source/types.h similarity index 60% rename from loader/source/types.h rename to chainloader/source/types.h index 1b0c46f..c4565be 100644 --- a/loader/source/types.h +++ b/chainloader/source/types.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* Copyright (C) 2016-2017 Aurora Wright, TuxSH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified -* reasonable legal notices or author attributions in that material or in the Appropriate Legal -* Notices displayed by works containing it. +* Additional Terms 7.b and 7.c of GPLv3 apply to this file: +* * Requiring preservation of specified reasonable legal notices or +* author attributions in that material or in the Appropriate Legal +* Notices displayed by works containing it. +* * Prohibiting misrepresentation of the origin of that material, +* or requiring that modified versions of such material be marked in +* reasonable ways as different from the original version. */ #pragma once @@ -33,3 +37,9 @@ typedef volatile u8 vu8; typedef volatile u16 vu16; typedef volatile u32 vu32; typedef volatile u64 vu64; + +struct fb { + u8 *top_left; + u8 *top_right; + u8 *bottom; +} __attribute__((packed)); From 4517e85cc819223c1b6493fcc28438e6b7b9cb24 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:37:01 +0200 Subject: [PATCH 234/259] Update and rename source/screeninit.h to source/arm9/source/screen.h --- source/{screeninit.h => arm9/source/screen.h} | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) rename source/{screeninit.h => arm9/source/screen.h} (65%) diff --git a/source/screeninit.h b/source/arm9/source/screen.h similarity index 65% rename from source/screeninit.h rename to source/arm9/source/screen.h index 590909e..e1765a8 100644 --- a/source/screeninit.h +++ b/source/arm9/source/screen.h @@ -7,15 +7,19 @@ #pragma once -#ifdef ARM9 - -#include "arm9/source/common.h" +#include "common.h" #define BRIGHTNESS_COUNT 0x4 #define PDN_GPU_CNT (*(vu8 *)0x10141200) -void deinitScreens(void); +struct fb { + u8 *top_left; + u8 *top_right; + u8 *bottom; +} __attribute__((packed)); + +extern struct fb fbs[2]; + +//void deinitScreens(void); void initScreens(u8 brightnessLevel); //void updateBrightness(u8 brightnessLevel); - -#endif From e5da0b7edd83aab1c5955a2a12f4a299e2b0f1ea Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:37:45 +0200 Subject: [PATCH 235/259] Update and rename source/screeninit.c to source/arm9/source/screen.c --- source/{screeninit.c => arm9/source/screen.c} | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) rename source/{screeninit.c => arm9/source/screen.c} (93%) diff --git a/source/screeninit.c b/source/arm9/source/screen.c similarity index 93% rename from source/screeninit.c rename to source/arm9/source/screen.c index 5d71adb..4ff7a4d 100644 --- a/source/screeninit.c +++ b/source/arm9/source/screen.c @@ -5,17 +5,17 @@ * Screen deinit code by tiniVi. */ -#ifdef ARM9 - -#include "screeninit.h" +#include "screen.h" #include -#include "arm9/source/i2c.h" -#include "../build/screeninit.h" +#include "i2c.h" +#include "../../../build/screeninit.h" + +struct fb fbs[2]; vu32 *arm11Entry = (u32 *)0x1FFFFFF8; -void deinitScreens(void) +/*void deinitScreens(void) { void __attribute__((naked)) ARM11(void) { @@ -42,7 +42,7 @@ void deinitScreens(void) *arm11Entry = (u32)ARM11; while(*arm11Entry); } -} +}*/ const u32 brightness[BRIGHTNESS_COUNT] = {0x5F, 0x4C, 0x39, 0x26}; @@ -91,5 +91,3 @@ void initScreens(u8 brightnessLevel) *arm11Entry = (u32)ARM11; while(*arm11Entry); }*/ - -#endif From 19b4b83d5dec0a8879bb17aecc8ebb7d886de8cb Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:39:54 +0200 Subject: [PATCH 236/259] Update brahma.c --- source/CakeBrah/source/brahma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/CakeBrah/source/brahma.c b/source/CakeBrah/source/brahma.c index 9677ce4..d112d3a 100644 --- a/source/CakeBrah/source/brahma.c +++ b/source/CakeBrah/source/brahma.c @@ -49,7 +49,7 @@ void redirect_codeflow (u32 *dst_addr, u32 *src_addr) { returns: 0 on failure, 1 on success */ s32 get_exploit_data (struct exploit_data *data) { u32 fversion = 0; - u8 isN3DS = 0; + bool isN3DS = 0; u32 i; s32 result = 0; u32 sysmodel = SYS_MODEL_NONE; From 8ea25b321b843a3527494c08f9b4d5307da128b7 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:42:02 +0200 Subject: [PATCH 237/259] Update boot.c --- source/hb_menu/boot.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/hb_menu/boot.c b/source/hb_menu/boot.c index 81bb0e4..70f04bf 100644 --- a/source/hb_menu/boot.c +++ b/source/hb_menu/boot.c @@ -69,8 +69,7 @@ bool isNinjhax2(void) { int bootApp(char *executablePath, executableMetadata_s *em, char *arg) { // open file that we're going to boot up fsInit(); - FSUSER_OpenFileDirectly(&hbFileHandle, sdmcArchive, fsMakePath(PATH_ASCII, executablePath), - FS_OPEN_READ, 0); + FSUSER_OpenFile(&hbFileHandle, sdmcArchive, fsMakePath(PATH_ASCII, executablePath), FS_OPEN_READ, 0); fsExit(); // set argv/argc @@ -161,4 +160,4 @@ int bootApp(char *executablePath, executableMetadata_s *em, char *arg) { } return 0; -} \ No newline at end of file +} From ac9157c54d9357224bec4dba55183e568f172c88 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:43:19 +0200 Subject: [PATCH 238/259] Update draw.c --- source/draw.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/draw.c b/source/draw.c index 1e5b46e..3bb9206 100644 --- a/source/draw.c +++ b/source/draw.c @@ -5,6 +5,7 @@ #ifdef ARM9 #include "arm9/source/common.h" #include "memory.h" +#include "arm9/source/screen.h" #else #include <3ds.h> #endif @@ -15,6 +16,8 @@ #ifdef ARM9 +extern struct fb fbs[2]; + u8 *gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16 *width, u16 *height) { //WARNING: width and height must stay inverted to simulate 3DSX version behavior! if (screen == GFX_TOP) { @@ -279,8 +282,8 @@ void clearBot(u8 bot[8]) { void swapFrameBuffers() { #ifdef ARM9 - memcpy(PTR_TOP_SCREEN, PTR_TOP_SCREEN_BUF, TOP_SCREEN_SIZE); - memcpy(PTR_BOT_SCREEN, PTR_BOT_SCREEN_BUF, BOT_SCREEN_SIZE); + memcpy(fbs[0].top_left, PTR_TOP_SCREEN_BUF, TOP_SCREEN_SIZE); + memcpy(fbs[0].bottom, PTR_BOT_SCREEN_BUF, BOT_SCREEN_SIZE); #else gfxFlushBuffers(); gfxSwapBuffers(); From f83be1a0f102a7750cf20e3b87b9458c7a7ac102 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:43:49 +0200 Subject: [PATCH 239/259] Update loader.c --- source/loader.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/source/loader.c b/source/loader.c index 282b4e1..2c31a46 100644 --- a/source/loader.c +++ b/source/loader.c @@ -1,7 +1,7 @@ #ifndef ARM9 -#include #include <3ds.h> +#include #include "brahma.h" #else @@ -10,12 +10,12 @@ #include "arm9/source/fatfs/ff.h" #include "stage2_bin.h" #include "memory.h" -#include "screeninit.h" #include "arm9/source/firm.h" -#include "../build/loader.h" +#include "arm9/source/screen.h" #endif +#include #include "draw.h" #include "loader.h" #include "utility.h" @@ -120,6 +120,7 @@ int load_bin(char *path, long offset, binary_patch* patches, int patchesCount, c } static Firm *const firm = (Firm *const)PTR_PAYLOAD_FIRM_DATA; +extern struct fb fbs[2]; int load_firm(char *path, binary_patch* patches, int patchesCount, char* splashTop, char* splashBot) { @@ -127,7 +128,7 @@ int load_firm(char *path, binary_patch* patches, int patchesCount, char* splashT u32 maxPayloadSize = (u32)((u8 *)loaderAddress - (u8 *)firm); size_t payloadSize = fileSize(path); - if (!payloadSize || payloadSize > maxPayloadSize) { + if (!payloadSize || payloadSize <= 0x200 || payloadSize > maxPayloadSize) { return -1; } @@ -135,7 +136,7 @@ int load_firm(char *path, binary_patch* patches, int patchesCount, char* splashT return -1; } - if(!checkFirmPayload(firm)) { + if(!checkFirmPayload(firm, payloadSize)) { return -1; } @@ -144,11 +145,9 @@ int load_firm(char *path, binary_patch* patches, int patchesCount, char* splashT // Luma3DS loading support char absPath[256]; - char *argv[1] = {computeFullPath(path, absPath)}; - - memcpy((void*)loaderAddress, loader, loader_size); - ((void (*)(int, char **, u32))loaderAddress)(1, argv, 0x0000BEEF); + char *argv[2] = {computeFullPath(path, absPath), (char *)fbs}; + launchFirm((firm->reserved2[0] & 1) ? 2 : 1, argv); return 0; } From 1bf9d565cc2e6a01b02802010ff787bfa4d5e7e7 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:44:13 +0200 Subject: [PATCH 240/259] Update main.c --- source/main.c | 53 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/source/main.c b/source/main.c index 4a0ee8a..908c9b1 100644 --- a/source/main.c +++ b/source/main.c @@ -8,16 +8,17 @@ #ifdef ARM9 +#include "memory.h" #include "arm9/source/common.h" #include "arm9/source/hid.h" #include "arm9/source/fatfs/ff.h" -#include "screeninit.h" +#include "arm9/source/screen.h" #else + #include <3ds.h> #include "hb_menu/netloader.h" - extern char boot_app[512]; extern bool boot_app_enabled; @@ -56,7 +57,11 @@ void __appExit() { } #endif -int main(int argc, char **argv) { +#ifdef ARM9 +int startCtrBootManager(int argc, char **argv, u32 magicWord) { +#else +int main() { +#endif #ifdef ARM9 *(u32 *) 0x10000020 = 0; @@ -64,13 +69,13 @@ int main(int argc, char **argv) { // Code inspired from Luma3DS u16 launchedPath[4]; - if (1 == argc) + if ((magicWord & 0xFFFF) == 0xBEEF && argc >= 1) { u32 i; for(i = 0; i < 4 && argv[0][i] != 0; i++) launchedPath[i] = argv[0][i]; } - else if (2 == argc) + else if (magicWord == 0xBABE && argc == 2) { u32 i; u16 *p = (u16 *)argv[0]; @@ -80,6 +85,40 @@ int main(int argc, char **argv) { else launchedPath[0] = 0; + // Framebuffers management + if(argc >= 2) + { + u8 **fb = (u8 **)(void *)argv[1]; + fbs[0].top_left = fb[0]; + fbs[0].top_right = fb[1]; + fbs[0].bottom = fb[2]; + + if (argc >= 4) + { + fbs[1].top_left = fb[3]; + fbs[1].top_right = fb[4]; + fbs[1].bottom = fb[5]; + } + else + { + fbs[1].top_left = fbs[0].top_left; + fbs[1].top_right = fbs[0].top_right; + fbs[1].bottom = fbs[0].bottom; + } + + *PTR_TOP_SCREEN = fbs[0].top_left; + *PTR_BOT_SCREEN = fbs[0].bottom; + } + else + { + fbs[0].top_left = (u8 *)0x18300000; + fbs[1].top_left = (u8 *)0x18300000; + fbs[0].top_right = (u8 *)0x18300000; + fbs[1].top_right = (u8 *)0x18300000; + fbs[0].bottom = (u8 *)0x18346500; + fbs[1].bottom = (u8 *)0x18346500; + } + bool loadedFromSD = (memcmp(launchedPath, "n\0a\0n\0d\0", 8) != 0); initFileSystems(loadedFromSD); #else @@ -91,9 +130,9 @@ int main(int argc, char **argv) { osSetSpeedupEnable(true); // offset potential issues caused by homebrew that just ran (from hb_menu) - aptOpenSession(); + //aptOpenSession(); APT_SetAppCpuTimeLimit(0); - aptCloseSession(); + //aptCloseSession(); if (!boot_app_enabled) { // fix SOC_Initialize #endif From 3d45a15cc32819335d3a5d3f999060e0e14b5ac4 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:44:40 +0200 Subject: [PATCH 241/259] Update memory.h --- source/memory.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/memory.h b/source/memory.h index 8d93fd4..8a69f7c 100644 --- a/source/memory.h +++ b/source/memory.h @@ -5,8 +5,8 @@ #ifndef CTRBOOTMANAGER_MEMORY_H #define CTRBOOTMANAGER_MEMORY_H -#define PTR_TOP_SCREEN (u8*)(*(u32*)0x23FFFE00) -#define PTR_BOT_SCREEN (u8*)(*(u32*)0x23FFFE08) +#define PTR_TOP_SCREEN (void**)(0x23FFFE00) +#define PTR_BOT_SCREEN (void**)(0x23FFFE08) #define PTR_TOP_SCREEN_BUF (u8*)(0x25000000) #define PTR_BOT_SCREEN_BUF (u8*)(0x25046500) #define PTR_TOP_BG (u8*)(0x2507E900) @@ -27,6 +27,6 @@ #define PTR_PAYLOAD_STAGE2 0x08006000 #define PTR_PAYLOAD_FIRM 0x27FFE000 -#define PTR_PAYLOAD_FIRM_DATA 0x24000000 +#define PTR_PAYLOAD_FIRM_DATA 0x20001000 #endif //CTRBOOTMANAGER_MEMORY_H From b038639f7f86326d4fcf959e8a88266b0669d65f Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:45:09 +0200 Subject: [PATCH 242/259] Update menu_boot.c --- source/menu_boot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/menu_boot.c b/source/menu_boot.c index 4c9face..d625daf 100644 --- a/source/menu_boot.c +++ b/source/menu_boot.c @@ -2,7 +2,7 @@ #include "arm9/source/common.h" #include "arm9/source/hid.h" -#include "screeninit.h" +#include "arm9/source/screen.h" #else #include <3ds.h> From 648ab75c2c83b05e168d91de3d1136e623dd4dcf Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:45:35 +0200 Subject: [PATCH 243/259] Update menu_config.c --- source/menu_config.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/menu_config.c b/source/menu_config.c index bc89696..22ee904 100644 --- a/source/menu_config.c +++ b/source/menu_config.c @@ -1,11 +1,11 @@ -#include +#include #include #include #ifdef ARM9 #include "arm9/source/common.h" #include "arm9/source/hid.h" -#include "screeninit.h" +#include "arm9/source/screen.h" #else #include <3ds.h> #endif @@ -360,9 +360,9 @@ Do it at your own risk!!!"; } #ifdef ARM9 - drawInfo("CtrBootManager9 v2.5.0"); + drawInfo("CtrBootManager9 v2.5.1"); #else - drawInfo("CtrBootManager v2.5.0"); + drawInfo("CtrBootManager v2.5.1"); #endif swapFrameBuffers(); From 9e5605fb942b90b19fa68ea0b855abbe58a38713 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:46:02 +0200 Subject: [PATCH 244/259] Update menu_more.c --- source/menu_more.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/menu_more.c b/source/menu_more.c index cd80b24..12bfbcd 100644 --- a/source/menu_more.c +++ b/source/menu_more.c @@ -6,12 +6,13 @@ #else #include <3ds.h> -#include #include +#include #include "menu_netloaderarm9.h" #endif +#include #include "config.h" #include "draw.h" #include "utility.h" From fe9e4765e0d8de825494d25bc7a9667790f2b771 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:47:03 +0200 Subject: [PATCH 245/259] Update menu_picker.c --- source/menu_picker.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/menu_picker.c b/source/menu_picker.c index 2bea94b..abed7c8 100644 --- a/source/menu_picker.c +++ b/source/menu_picker.c @@ -4,15 +4,18 @@ #include "arm9/source/hid.h" #include "arm9/source/fatfs/ff.h" #include "memory.h" + #else + #include <3ds.h> #include -#include #include #include +#include #endif +#include #include "draw.h" #include "picker.h" #include "utility.h" From 9e9b31396e18ff981c1711a80b6c189f2960db71 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:47:30 +0200 Subject: [PATCH 246/259] Update utility.c --- source/utility.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/source/utility.c b/source/utility.c index 85e5e71..c9e8a98 100644 --- a/source/utility.c +++ b/source/utility.c @@ -168,12 +168,11 @@ FS_Archive sdmcArchive; extern void __appExit(); void openSDArchive() { - sdmcArchive = (FS_Archive) {0x00000009, (FS_Path) {PATH_EMPTY, 1, (u8 *) ""}}; - FSUSER_OpenArchive(&sdmcArchive); + FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")); } void closeSDArchive() { - FSUSER_CloseArchive(&sdmcArchive); + FSUSER_CloseArchive(sdmcArchive); } #endif @@ -485,9 +484,9 @@ void reboot() { while (true); #else aptInit(); - aptOpenSession(); + //aptOpenSession(); APT_HardwareResetAsync(); - aptCloseSession(); + //aptCloseSession(); aptExit(); #endif } From 830a356fcd90d5bc0873fde5e13cdc18c081bcc9 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:48:08 +0200 Subject: [PATCH 247/259] Update bs-start.s --- source/arm9/source/bs-start.s | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/source/arm9/source/bs-start.s b/source/arm9/source/bs-start.s index c341c78..986ec89 100644 --- a/source/arm9/source/bs-start.s +++ b/source/arm9/source/bs-start.s @@ -8,8 +8,9 @@ _start: mov sp, #0x27000000 @ Store main arguments - mov r8, r0 - mov r9, r1 + mov r9, r0 + mov r10, r1 + mov r11, r2 @ Give read/write access to all the memory regions ldr r5, =0x33333333 @@ -25,9 +26,7 @@ _start: ldr r5, =0x20000035 @ 20000000 128M ldr r6, =0x1FF00027 @ 1FF00000 1M ldr r7, =0x1800002D @ 18000000 8M - mov r10, #0x25 - mov r11, #0x25 - mov r12, #0x25 + mov r8, #0x25 mcr p15, 0, r0, c6, c0, 0 mcr p15, 0, r1, c6, c1, 0 mcr p15, 0, r2, c6, c2, 0 @@ -36,9 +35,9 @@ _start: mcr p15, 0, r5, c6, c5, 0 mcr p15, 0, r6, c6, c6, 0 mcr p15, 0, r7, c6, c7, 0 - mcr p15, 0, r10, c3, c0, 0 @ Write bufferable 0, 2, 5 - mcr p15, 0, r11, c2, c0, 0 @ Data cacheable 0, 2, 5 - mcr p15, 0, r12, c2, c0, 1 @ Inst cacheable 0, 2, 5 + mcr p15, 0, r8, c3, c0, 0 @ Write bufferable 0, 2, 5 + mcr p15, 0, r8, c2, c0, 0 @ Data cacheable 0, 2, 5 + mcr p15, 0, r8, c2, c0, 1 @ Inst cacheable 0, 2, 5 @ Enable caches mrc p15, 0, r4, c1, c0, 0 @ read control register @@ -60,10 +59,11 @@ _start: str r1, [r0] @ Restore main arguments - mov r0, r8 - mov r1, r9 + mov r0, r9 + mov r1, r10 + mov r2, r11 - bl main + bl startCtrBootManager .die: b .die From 683a4d2b3c59652c557ef53270b0e19b54212611 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:49:22 +0200 Subject: [PATCH 248/259] Update firm.c --- source/arm9/source/firm.c | 65 ++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/source/arm9/source/firm.c b/source/arm9/source/firm.c index d70fa9f..19ad8e3 100644 --- a/source/arm9/source/firm.c +++ b/source/arm9/source/firm.c @@ -1,56 +1,60 @@ #include "firm.h" #include "crypto.h" +#include "../../../build/chainloader.h" static __attribute__((noinline)) bool overlaps(u32 as, u32 ae, u32 bs, u32 be) { - if (as <= bs && bs <= ae) + if(as <= bs && bs <= ae) return true; - else if (bs <= as && as <= be) + if(bs <= as && as <= be) return true; return false; } -bool checkFirmPayload(Firm* firm) +static __attribute__((noinline)) bool inRange(u32 as, u32 ae, u32 bs, u32 be) { - if(memcmp(firm->magic, "FIRM", 4) != 0) - return false; + if(as >= bs && ae <= be) + return true; + return false; +} - if(firm->arm9Entry == NULL) //allow for the arm11 entrypoint to be zero in which case nothing is done on the arm11 side +bool checkFirmPayload(Firm* firm, u32 payloadSize) +{ + if(memcmp(firm->magic, "FIRM", 4) != 0 || firm->arm9Entry == NULL) //Allow for the ARM11 entrypoint to be zero in which case nothing is done on the ARM11 side return false; + bool arm9EpFound = false, + arm11EpFound = false; + u32 size = 0x200; for(u32 i = 0; i < 4; i++) size += firm->section[i].size; - bool arm9EpFound = false, arm11EpFound = false; + if(size != payloadSize) return false; + for(u32 i = 0; i < 4; i++) { - __attribute__((aligned(4))) u8 hash[0x20]; - FirmSection *section = &firm->section[i]; - // allow empty sections - if (section->size == 0) + //Allow empty sections + if(section->size == 0) continue; - if(section->offset < 0x200) - return false; - - if(section->address + section->size < section->address) //overflow check - return false; - - if(((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF)) //alignment check + if((section->offset < 0x200) || + (section->address + section->size < section->address) || //Overflow check + ((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF) || //Alignment check + (overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm, (u32)firm + size)) || + ((!inRange((u32)section->address, (u32)section->address + section->size, 0x08000000, 0x08000000 + 0x00100000)) && + (!inRange((u32)section->address, (u32)section->address + section->size, 0x18000000, 0x18000000 + 0x00600000)) && + (!inRange((u32)section->address, (u32)section->address + section->size, 0x1FF00000, 0x1FFFFC00)) && + (!inRange((u32)section->address, (u32)section->address + section->size, 0x20000000, 0x20000000 + 0x8000000)))) return false; - if(overlaps((u32)section->address, (u32)section->address + section->size, 0x27FFE000, 0x28000000)) - return false; - else if(overlaps((u32)section->address, (u32)section->address + section->size, 0x27FFE000 - 0x1000, 0x27FFE000)) - return false; - else if(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm, (u32)firm + size)) - return false; + __attribute__((aligned(4))) u8 hash[0x20]; sha(hash, (u8 *)firm + section->offset, section->size, SHA_256_MODE); + if(memcmp(hash, section->hash, 0x20) != 0) return false; @@ -63,3 +67,16 @@ bool checkFirmPayload(Firm* firm) return arm9EpFound && (firm->arm11Entry == NULL || arm11EpFound); } + +void launchFirm(int argc, char **argv) +{ + u32 *chainloaderAddress = (u32 *)0x01FF9000; + + // Should not be needed: no ARM11 process in background + //prepareArm11ForFirmlaunch(); + + memcpy(chainloaderAddress, chainloader, chainloader_size); + + // No need to flush caches here, the chainloader is in ITCM + ((void (*)(int, char **, u32))chainloaderAddress)(argc, argv, 0x0000BEEF); +} From dcb9693165baaed2d24cc35158bee43b6fdeba68 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:49:38 +0200 Subject: [PATCH 249/259] Update firm.h --- source/arm9/source/firm.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/arm9/source/firm.h b/source/arm9/source/firm.h index 738fb8c..232a120 100644 --- a/source/arm9/source/firm.h +++ b/source/arm9/source/firm.h @@ -21,4 +21,5 @@ typedef struct __attribute__((packed)) FirmSection section[4]; } Firm; -bool checkFirmPayload(Firm* firm); +bool checkFirmPayload(Firm* firm, u32 payloadSize); +void launchFirm(int argc, char **argv); From 268bd85fabe1e44638fa27cbeb10e2046cf6d8aa Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Wed, 7 Jun 2017 23:53:32 +0200 Subject: [PATCH 250/259] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dcf11a9..a6933ab 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ CtrBootManager is a boot manager for some 3DS homebrew applications, like HBL and CFW. ##Dependencies -- devkitpro-4.5 at least (ctrulib-1.0 at least) +- devkitpro-4.5 at least (ctrulib-1.2.1 at least) - libconfig in portlibs (tried with v1.5) ##Building From f94b644d9b7b55489d20c8a4e827d709f0b62230 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 10 Jun 2017 00:26:50 +0200 Subject: [PATCH 251/259] Update screeninit.h --- build/screeninit.h | 57 +++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/build/screeninit.h b/build/screeninit.h index a47b39a..4c56f47 100644 --- a/build/screeninit.h +++ b/build/screeninit.h @@ -1,31 +1,32 @@ const char screeninit[]={ 0xc0,0x01,0x0c,0xf1,0x01,0x00,0x00,0xea,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x9f,0xe5,0x1c,0xff,0x2f,0xe1,0x21,0xfc,0xff,0x24,0x00,0x00,0x00,0x00,0x30 -,0xb5,0x85,0xb0,0x69,0x46,0x7a,0x4a,0x31,0xca,0x31,0xc1,0x12,0x68,0x79,0x48,0x0a,0x60,0x79,0x49,0x79,0x4a,0x12,0x68,0x08,0x60,0x01,0x20,0x6b,0x46,0x78,0x49,0x78 -,0x4c,0x08,0x60,0x78,0x4d,0x21,0x68,0x29,0x40,0x21,0x60,0x92,0x00,0xd4,0x58,0x76,0x49,0x0c,0x60,0xd2,0x58,0x76,0x4b,0x1a,0x60,0x76,0x4b,0x76,0x4a,0x13,0x60,0x76 -,0x4a,0x13,0x60,0xe1,0x22,0x76,0x4b,0x52,0x00,0x1a,0x60,0x75,0x4b,0xf1,0x3a,0x1a,0x60,0xc2,0x23,0x74,0x49,0xff,0x33,0x0b,0x60,0x74,0x49,0x0b,0x60,0x00,0x23,0xcf -,0x24,0x73,0x49,0x0b,0x60,0x73,0x49,0x0c,0x60,0x73,0x49,0x0a,0x60,0x73,0x49,0x73,0x4a,0x11,0x60,0x80,0x21,0x73,0x4a,0x49,0x02,0x11,0x60,0x9e,0x21,0x72,0x4a,0xff -,0x31,0x11,0x60,0x71,0x4a,0x9c,0x39,0xff,0x39,0x11,0x60,0xc9,0x22,0x70,0x4c,0x52,0x00,0x22,0x60,0x6f,0x4c,0x22,0x60,0x6f,0x4c,0x22,0x60,0x6f,0x4a,0x10,0x60,0x6f -,0x4a,0x11,0x60,0x6f,0x49,0x70,0x4a,0x11,0x60,0x70,0x4a,0x13,0x60,0x70,0x4a,0x70,0x49,0x13,0x60,0x70,0x4a,0x11,0x60,0x70,0x49,0x71,0x4a,0x11,0x60,0x71,0x49,0x71 -,0x4a,0x11,0x60,0x71,0x49,0x72,0x4a,0x11,0x60,0x72,0x49,0x72,0x4a,0x11,0x60,0x72,0x49,0x73,0x4a,0x11,0x60,0xb4,0x21,0x72,0x4a,0x13,0x60,0x72,0x4a,0x89,0x00,0x11 -,0x60,0x72,0x4a,0x72,0x49,0x13,0x60,0x72,0x4a,0x73,0x48,0x84,0x46,0x0b,0x60,0x63,0x44,0x93,0x42,0xf9,0xd1,0xe1,0x22,0x70,0x4b,0x52,0x00,0x1a,0x60,0xd1,0x23,0x6f -,0x4a,0x13,0x60,0xc2,0x22,0x6f,0x49,0xff,0x32,0x0a,0x60,0x6e,0x49,0x0a,0x60,0xcd,0x21,0x6e,0x4a,0x11,0x60,0x6e,0x4a,0x02,0x31,0x11,0x60,0x6d,0x4a,0x13,0x60,0x46 -,0x4a,0x6d,0x4b,0x1a,0x60,0x80,0x22,0x6c,0x4b,0x52,0x02,0x1a,0x60,0x9e,0x22,0x6b,0x4b,0xff,0x32,0x1a,0x60,0x52,0x23,0x6a,0x4a,0x13,0x60,0xc9,0x22,0x6a,0x49,0x52 -,0x00,0x0a,0x60,0x69,0x49,0x0a,0x60,0x4f,0x21,0x69,0x4a,0x11,0x60,0x69,0x4a,0x01,0x31,0x11,0x60,0x68,0x4a,0x13,0x60,0x68,0x4a,0x69,0x4b,0x1a,0x60,0x00,0x23,0x68 -,0x4a,0x13,0x60,0x68,0x4a,0x3f,0x39,0x11,0x60,0x68,0x49,0x68,0x4a,0x11,0x60,0x42,0x49,0x68,0x4a,0x11,0x60,0x68,0x49,0x68,0x4a,0x11,0x60,0x68,0x49,0x69,0x4a,0x11 -,0x60,0x69,0x49,0x69,0x4a,0x11,0x60,0x44,0x49,0x69,0x4a,0x11,0x60,0xb4,0x21,0x68,0x4a,0x13,0x60,0x68,0x4a,0x89,0x00,0x11,0x60,0x68,0x4a,0x68,0x49,0x13,0x60,0x44 -,0x4a,0x45,0x48,0x84,0x46,0x0b,0x60,0x63,0x44,0x93,0x42,0xf9,0xd1,0x37,0x4b,0x37,0x4a,0x13,0x60,0x63,0x4a,0x13,0x60,0x63,0x4a,0x13,0x60,0x63,0x4a,0x59,0x49,0x13 -,0x60,0x57,0x4a,0x0a,0x60,0x62,0x49,0x0a,0x60,0x62,0x49,0x0b,0x60,0x62,0x49,0x0b,0x60,0x62,0x4b,0x1a,0x60,0x00,0x23,0x61,0x4a,0x13,0x60,0x13,0x68,0x00,0x2b,0xfc -,0xd0,0x13,0x68,0x00,0xf0,0xbe,0xf8,0x05,0xb0,0x30,0xbc,0x01,0xbc,0x00,0x47,0x88,0xff,0xff,0x24,0x7f,0x00,0x01,0x00,0x00,0x12,0x14,0x10,0x08,0xfc,0xff,0x24,0x14 -,0x20,0x20,0x10,0x0c,0x20,0x20,0x10,0xfe,0xff,0xfe,0xff,0x40,0x22,0x20,0x10,0x40,0x2a,0x20,0x10,0x3e,0x02,0x01,0x00,0x44,0x22,0x20,0x10,0x44,0x2a,0x20,0x10,0x00 -,0x04,0x40,0x10,0x04,0x04,0x40,0x10,0x08,0x04,0x40,0x10,0x0c,0x04,0x40,0x10,0x10,0x04,0x40,0x10,0x14,0x04,0x40,0x10,0x18,0x04,0x40,0x10,0xc1,0x01,0xc5,0x01,0x1c -,0x04,0x40,0x10,0x20,0x04,0x40,0x10,0x24,0x04,0x40,0x10,0x28,0x04,0x40,0x10,0x2c,0x04,0x40,0x10,0x30,0x04,0x40,0x10,0x34,0x04,0x40,0x10,0x38,0x04,0x40,0x10,0x3c -,0x04,0x40,0x10,0x92,0x01,0x96,0x01,0x40,0x04,0x40,0x10,0x44,0x04,0x40,0x10,0x48,0x04,0x40,0x10,0x90,0x01,0xf0,0x00,0x5c,0x04,0x40,0x10,0xd1,0x00,0xc1,0x01,0x60 -,0x04,0x40,0x10,0x02,0x00,0x92,0x01,0x64,0x04,0x40,0x10,0x00,0x00,0x30,0x18,0x68,0x04,0x40,0x10,0x41,0x03,0x08,0x00,0x70,0x04,0x40,0x10,0x01,0x05,0x01,0x00,0x74 -,0x04,0x40,0x10,0x78,0x04,0x40,0x10,0x90,0x04,0x40,0x10,0x9c,0x04,0x40,0x10,0x84,0x04,0x40,0x10,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x05,0x40,0x10,0x04 -,0x05,0x40,0x10,0x08,0x05,0x40,0x10,0x0c,0x05,0x40,0x10,0x10,0x05,0x40,0x10,0x14,0x05,0x40,0x10,0x18,0x05,0x40,0x10,0x1c,0x05,0x40,0x10,0x20,0x05,0x40,0x10,0x24 -,0x05,0x40,0x10,0x28,0x05,0x40,0x10,0x2c,0x05,0x40,0x10,0x30,0x05,0x40,0x10,0x34,0x05,0x40,0x10,0x38,0x05,0x40,0x10,0x3c,0x05,0x40,0x10,0x94,0x01,0x98,0x01,0x40 -,0x05,0x40,0x10,0x44,0x05,0x40,0x10,0x48,0x05,0x40,0x10,0x40,0x01,0xf0,0x00,0x5c,0x05,0x40,0x10,0x60,0x05,0x40,0x10,0x52,0x00,0x92,0x01,0x64,0x05,0x40,0x10,0x00 -,0x65,0x34,0x18,0x68,0x05,0x40,0x10,0x01,0x03,0x08,0x00,0x70,0x05,0x40,0x10,0x74,0x05,0x40,0x10,0x78,0x05,0x40,0x10,0x90,0x05,0x40,0x10,0x9c,0x05,0x40,0x10,0x84 -,0x05,0x40,0x10,0x6c,0x04,0x40,0x10,0x94,0x04,0x40,0x10,0x98,0x04,0x40,0x10,0x6c,0x05,0x40,0x10,0x00,0xfe,0xff,0x23,0x04,0xfe,0xff,0x23,0x08,0xfe,0xff,0x23,0xf8 +,0xb5,0x85,0xb0,0x69,0x46,0x81,0x4a,0x31,0xca,0x31,0xc1,0x12,0x68,0x80,0x48,0x0a,0x60,0x80,0x49,0x80,0x4a,0x12,0x68,0x08,0x60,0x01,0x20,0x6b,0x46,0x7f,0x49,0x7f +,0x4c,0x08,0x60,0x7f,0x4d,0x21,0x68,0x29,0x40,0x21,0x60,0x92,0x00,0xd4,0x58,0x7d,0x49,0x0c,0x60,0xd2,0x58,0x7d,0x4b,0x1a,0x60,0x7d,0x4b,0x7d,0x4a,0x13,0x60,0x7d +,0x4a,0x13,0x60,0xe1,0x22,0x7d,0x4b,0x52,0x00,0x1a,0x60,0x7c,0x4b,0xf1,0x3a,0x1a,0x60,0xc2,0x23,0x7b,0x49,0xff,0x33,0x0b,0x60,0x7b,0x49,0x0b,0x60,0x00,0x23,0xcf +,0x24,0x7a,0x49,0x0b,0x60,0x7a,0x49,0x0c,0x60,0x7a,0x49,0x0a,0x60,0x7a,0x49,0x7a,0x4a,0x11,0x60,0x80,0x21,0x7a,0x4a,0x49,0x02,0x11,0x60,0x9e,0x21,0x79,0x4a,0xff +,0x31,0x11,0x60,0x78,0x4a,0x9c,0x39,0xff,0x39,0x11,0x60,0xc9,0x22,0x77,0x4c,0x52,0x00,0x22,0x60,0x76,0x4c,0x22,0x60,0x76,0x4c,0x22,0x60,0x76,0x4a,0x10,0x60,0x76 +,0x4a,0x11,0x60,0x76,0x49,0x77,0x4a,0x11,0x60,0x77,0x4a,0x13,0x60,0x77,0x4a,0x77,0x49,0x13,0x60,0x77,0x4a,0x11,0x60,0x77,0x49,0x78,0x4a,0x11,0x60,0x78,0x49,0x78 +,0x4a,0x11,0x60,0x78,0x49,0x79,0x4a,0x11,0x60,0xc2,0x22,0x78,0x48,0x52,0x05,0x02,0x60,0x78,0x4c,0x78,0x48,0x04,0x60,0x78,0x4c,0x79,0x48,0x04,0x60,0xb4,0x24,0x78 +,0x48,0x03,0x60,0x78,0x48,0xa4,0x00,0x04,0x60,0x78,0x48,0x01,0x60,0x78,0x49,0x0a,0x60,0x78,0x4a,0x78,0x49,0x13,0x60,0x78,0x4a,0x79,0x48,0x84,0x46,0x0b,0x60,0x63 +,0x44,0x93,0x42,0xf9,0xd1,0xe1,0x22,0x76,0x4b,0x52,0x00,0x1a,0x60,0xd1,0x23,0x75,0x4a,0x13,0x60,0xc2,0x22,0x75,0x49,0xff,0x32,0x0a,0x60,0x74,0x49,0x0a,0x60,0xcd +,0x21,0x74,0x4a,0x11,0x60,0x74,0x4a,0x02,0x31,0x11,0x60,0x73,0x4a,0x13,0x60,0x49,0x4a,0x73,0x4b,0x1a,0x60,0x80,0x22,0x72,0x4b,0x52,0x02,0x1a,0x60,0x9e,0x22,0x71 +,0x4b,0xff,0x32,0x1a,0x60,0x52,0x23,0x70,0x4a,0x13,0x60,0xc9,0x22,0x70,0x49,0x52,0x00,0x0a,0x60,0x6f,0x49,0x0a,0x60,0x4f,0x21,0x6f,0x4a,0x11,0x60,0x6f,0x4a,0x01 +,0x31,0x11,0x60,0x6e,0x4a,0x13,0x60,0x6e,0x4a,0x6f,0x4b,0x1a,0x60,0x00,0x23,0x6e,0x4a,0x13,0x60,0x6e,0x4a,0x3f,0x39,0x11,0x60,0x6e,0x49,0x6e,0x4a,0x11,0x60,0x45 +,0x49,0x6e,0x4a,0x11,0x60,0x6e,0x49,0x6e,0x4a,0x11,0x60,0x6e,0x49,0x6f,0x4a,0x11,0x60,0x6f,0x49,0x6f,0x4a,0x11,0x60,0x6f,0x49,0x70,0x4a,0x11,0x60,0x47,0x49,0x6f +,0x4a,0x11,0x60,0xb4,0x21,0x6f,0x4a,0x13,0x60,0x6f,0x4a,0x89,0x00,0x11,0x60,0x6e,0x4a,0x6f,0x49,0x13,0x60,0x49,0x4a,0x49,0x48,0x84,0x46,0x0b,0x60,0x63,0x44,0x93 +,0x42,0xf9,0xd1,0x38,0x4b,0x39,0x4a,0x13,0x60,0xc2,0x22,0x38,0x49,0x52,0x05,0x0a,0x60,0x3e,0x49,0x0b,0x60,0x3e,0x49,0x0a,0x60,0x5b,0x4a,0x5b,0x49,0x5c,0x48,0x0a +,0x60,0x5c,0x49,0x08,0x60,0x63,0x49,0x0b,0x60,0x63,0x49,0x0b,0x60,0x63,0x4b,0x1a,0x60,0x00,0x23,0x62,0x4a,0x13,0x60,0x13,0x68,0x00,0x2b,0xfc,0xd0,0x13,0x68,0x00 +,0xf0,0xc0,0xf8,0x05,0xb0,0x30,0xbc,0x01,0xbc,0x00,0x47,0xa8,0xff,0xff,0x24,0x7f,0x00,0x01,0x00,0x00,0x12,0x14,0x10,0x08,0xfc,0xff,0x24,0x14,0x20,0x20,0x10,0x0c +,0x20,0x20,0x10,0xfe,0xff,0xfe,0xff,0x40,0x22,0x20,0x10,0x40,0x2a,0x20,0x10,0x3e,0x02,0x01,0x00,0x44,0x22,0x20,0x10,0x44,0x2a,0x20,0x10,0x00,0x04,0x40,0x10,0x04 +,0x04,0x40,0x10,0x08,0x04,0x40,0x10,0x0c,0x04,0x40,0x10,0x10,0x04,0x40,0x10,0x14,0x04,0x40,0x10,0x18,0x04,0x40,0x10,0xc1,0x01,0xc5,0x01,0x1c,0x04,0x40,0x10,0x20 +,0x04,0x40,0x10,0x24,0x04,0x40,0x10,0x28,0x04,0x40,0x10,0x2c,0x04,0x40,0x10,0x30,0x04,0x40,0x10,0x34,0x04,0x40,0x10,0x38,0x04,0x40,0x10,0x3c,0x04,0x40,0x10,0x92 +,0x01,0x96,0x01,0x40,0x04,0x40,0x10,0x44,0x04,0x40,0x10,0x48,0x04,0x40,0x10,0x90,0x01,0xf0,0x00,0x5c,0x04,0x40,0x10,0xd1,0x00,0xc1,0x01,0x60,0x04,0x40,0x10,0x02 +,0x00,0x92,0x01,0x64,0x04,0x40,0x10,0x00,0x00,0x30,0x18,0x68,0x04,0x40,0x10,0x6c,0x04,0x40,0x10,0x41,0x03,0x08,0x00,0x70,0x04,0x40,0x10,0x01,0x05,0x01,0x00,0x74 +,0x04,0x40,0x10,0x78,0x04,0x40,0x10,0x90,0x04,0x40,0x10,0x94,0x04,0x40,0x10,0x98,0x04,0x40,0x10,0x9c,0x04,0x40,0x10,0x84,0x04,0x40,0x10,0x00,0x01,0x01,0x01,0x01 +,0x01,0x01,0x00,0x00,0x05,0x40,0x10,0x04,0x05,0x40,0x10,0x08,0x05,0x40,0x10,0x0c,0x05,0x40,0x10,0x10,0x05,0x40,0x10,0x14,0x05,0x40,0x10,0x18,0x05,0x40,0x10,0x1c +,0x05,0x40,0x10,0x20,0x05,0x40,0x10,0x24,0x05,0x40,0x10,0x28,0x05,0x40,0x10,0x2c,0x05,0x40,0x10,0x30,0x05,0x40,0x10,0x34,0x05,0x40,0x10,0x38,0x05,0x40,0x10,0x3c +,0x05,0x40,0x10,0x94,0x01,0x98,0x01,0x40,0x05,0x40,0x10,0x44,0x05,0x40,0x10,0x48,0x05,0x40,0x10,0x40,0x01,0xf0,0x00,0x5c,0x05,0x40,0x10,0x60,0x05,0x40,0x10,0x52 +,0x00,0x92,0x01,0x64,0x05,0x40,0x10,0x00,0x65,0x34,0x18,0x68,0x05,0x40,0x10,0x00,0x65,0x44,0x18,0x6c,0x05,0x40,0x10,0x01,0x03,0x08,0x00,0x70,0x05,0x40,0x10,0x74 +,0x05,0x40,0x10,0x78,0x05,0x40,0x10,0x90,0x05,0x40,0x10,0x9c,0x05,0x40,0x10,0x84,0x05,0x40,0x10,0x00,0xfe,0xff,0x23,0x04,0xfe,0xff,0x23,0x08,0xfe,0xff,0x23,0xf8 ,0xff,0xff,0x1f,0x18,0x47,0xc0,0x46,0x5f,0x00,0x00,0x00,0x4c,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x26,0x00,0x00,0x00}; -const int screeninit_size=920; +const int screeninit_size=952; From 1a2ac4862a29b7f9ed68be36c89397dd966d6be7 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 10 Jun 2017 00:27:39 +0200 Subject: [PATCH 252/259] Update main.c --- screeninit/source/main.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/screeninit/source/main.c b/screeninit/source/main.c index 0f3328d..0254a77 100644 --- a/screeninit/source/main.c +++ b/screeninit/source/main.c @@ -37,11 +37,14 @@ void main(void) *(vu32 *)0x1040045C = 0x00f00190; *(vu32 *)0x10400460 = 0x01c100d1; *(vu32 *)0x10400464 = 0x01920002; - *(vu32 *)0x10400468 = 0x18300000; + *(vu32 *)0x10400468 = 0x18300000; // Framebuffer top left first address + *(vu32 *)0x1040046C = 0x18400000; // Framebuffer top left second address *(vu32 *)0x10400470 = 0x80341; *(vu32 *)0x10400474 = 0x00010501; - *(vu32 *)0x10400478 = 0; + *(vu32 *)0x10400478 = 0; // Framebuffer bottom select *(vu32 *)0x10400490 = 0x000002D0; + *(vu32 *)0x10400494 = 0x18300000; // Framebuffer top right first address + *(vu32 *)0x10400498 = 0x18400000; // Framebuffer top right second address *(vu32 *)0x1040049C = 0x00000000; // Disco register @@ -71,10 +74,11 @@ void main(void) *(vu32 *)0x1040055C = 0x00f00140; *(vu32 *)0x10400560 = 0x01c100d1; *(vu32 *)0x10400564 = 0x01920052; - *(vu32 *)0x10400568 = 0x18300000 + 0x46500; + *(vu32 *)0x10400568 = 0x18300000 + 0x46500; // Framebuffer bottom first address + *(vu32 *)0x1040056C = 0x18400000 + 0x46500; // Framebuffer bottom second address *(vu32 *)0x10400570 = 0x80301; *(vu32 *)0x10400574 = 0x00010501; - *(vu32 *)0x10400578 = 0; + *(vu32 *)0x10400578 = 0; // Framebuffer bottom select *(vu32 *)0x10400590 = 0x000002D0; *(vu32 *)0x1040059C = 0x00000000; @@ -83,11 +87,11 @@ void main(void) *(vu32 *)0x10400584 = 0x10101 * i; *(vu32 *)0x10400468 = 0x18300000; - *(vu32 *)0x1040046c = 0x18300000; + *(vu32 *)0x1040046c = 0x18400000; *(vu32 *)0x10400494 = 0x18300000; - *(vu32 *)0x10400498 = 0x18300000; + *(vu32 *)0x10400498 = 0x18400000; *(vu32 *)0x10400568 = 0x18346500; - *(vu32 *)0x1040056c = 0x18346500; + *(vu32 *)0x1040056c = 0x18446500; //Set CakeBrah framebuffers *((vu32 *)0x23FFFE00) = 0x18300000; From 8d0799bf56e171fc1e81c39ae7cc5bb1352f25fa Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 10 Jun 2017 00:28:32 +0200 Subject: [PATCH 253/259] Update draw.c --- source/draw.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/draw.c b/source/draw.c index 3bb9206..89b6406 100644 --- a/source/draw.c +++ b/source/draw.c @@ -16,8 +16,6 @@ #ifdef ARM9 -extern struct fb fbs[2]; - u8 *gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16 *width, u16 *height) { //WARNING: width and height must stay inverted to simulate 3DSX version behavior! if (screen == GFX_TOP) { From fd641eef9c12a5282817f034e2117a6dc69b2419 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 10 Jun 2017 00:29:35 +0200 Subject: [PATCH 254/259] Update main.c --- source/main.c | 69 ++++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/source/main.c b/source/main.c index 908c9b1..3d3d015 100644 --- a/source/main.c +++ b/source/main.c @@ -67,6 +67,15 @@ int main() { *(u32 *) 0x10000020 = 0; *(u32 *) 0x10000020 = 0x340; + // Setup framebuffers: + // May be corrupted if screen were not initialized or if framebuffers were pushed on arguments + fbs[0].top_left = (u8 *)*PTR_TOP_SCREEN; + fbs[1].top_left = (u8 *)*PTR_TOP_SCREEN; + fbs[0].top_right = (u8 *)*PTR_TOP_RIGHT_SCREEN; + fbs[1].top_right = (u8 *)*PTR_TOP_RIGHT_SCREEN; + fbs[0].bottom = (u8 *)*PTR_BOT_SCREEN; + fbs[1].bottom = (u8 *)*PTR_BOT_SCREEN; + // Code inspired from Luma3DS u16 launchedPath[4]; if ((magicWord & 0xFFFF) == 0xBEEF && argc >= 1) @@ -74,6 +83,32 @@ int main() { u32 i; for(i = 0; i < 4 && argv[0][i] != 0; i++) launchedPath[i] = argv[0][i]; + + // Framebuffers management + if(argc >= 2) + { + u8 **fb = (u8 **)(void *)argv[1]; + fbs[0].top_left = fb[0]; + fbs[0].top_right = fb[1]; + fbs[0].bottom = fb[2]; + + if (argc >= 4) + { + fbs[1].top_left = fb[3]; + fbs[1].top_right = fb[4]; + fbs[1].bottom = fb[5]; + } + else + { + fbs[1].top_left = fbs[0].top_left; + fbs[1].top_right = fbs[0].top_right; + fbs[1].bottom = fbs[0].bottom; + } + + *PTR_TOP_SCREEN = fbs[0].top_left; + *PTR_TOP_RIGHT_SCREEN = fbs[0].top_right; + *PTR_BOT_SCREEN = fbs[0].bottom; + } } else if (magicWord == 0xBABE && argc == 2) { @@ -85,40 +120,6 @@ int main() { else launchedPath[0] = 0; - // Framebuffers management - if(argc >= 2) - { - u8 **fb = (u8 **)(void *)argv[1]; - fbs[0].top_left = fb[0]; - fbs[0].top_right = fb[1]; - fbs[0].bottom = fb[2]; - - if (argc >= 4) - { - fbs[1].top_left = fb[3]; - fbs[1].top_right = fb[4]; - fbs[1].bottom = fb[5]; - } - else - { - fbs[1].top_left = fbs[0].top_left; - fbs[1].top_right = fbs[0].top_right; - fbs[1].bottom = fbs[0].bottom; - } - - *PTR_TOP_SCREEN = fbs[0].top_left; - *PTR_BOT_SCREEN = fbs[0].bottom; - } - else - { - fbs[0].top_left = (u8 *)0x18300000; - fbs[1].top_left = (u8 *)0x18300000; - fbs[0].top_right = (u8 *)0x18300000; - fbs[1].top_right = (u8 *)0x18300000; - fbs[0].bottom = (u8 *)0x18346500; - fbs[1].bottom = (u8 *)0x18346500; - } - bool loadedFromSD = (memcmp(launchedPath, "n\0a\0n\0d\0", 8) != 0); initFileSystems(loadedFromSD); #else From 363ba13ed2404685fe6332becd49e98fe51069aa Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 10 Jun 2017 00:30:02 +0200 Subject: [PATCH 255/259] Update memory.h --- source/memory.h | 1 + 1 file changed, 1 insertion(+) diff --git a/source/memory.h b/source/memory.h index 8a69f7c..154f993 100644 --- a/source/memory.h +++ b/source/memory.h @@ -6,6 +6,7 @@ #define CTRBOOTMANAGER_MEMORY_H #define PTR_TOP_SCREEN (void**)(0x23FFFE00) +#define PTR_TOP_RIGHT_SCREEN (void**)(0x23FFFE04) #define PTR_BOT_SCREEN (void**)(0x23FFFE08) #define PTR_TOP_SCREEN_BUF (u8*)(0x25000000) #define PTR_BOT_SCREEN_BUF (u8*)(0x25046500) From 3395b4b259eab4d9ec2a92509402bd7f0237b2bc Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 10 Jun 2017 00:30:37 +0200 Subject: [PATCH 256/259] Update menu_config.c --- source/menu_config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/menu_config.c b/source/menu_config.c index 22ee904..b217f96 100644 --- a/source/menu_config.c +++ b/source/menu_config.c @@ -360,9 +360,9 @@ Do it at your own risk!!!"; } #ifdef ARM9 - drawInfo("CtrBootManager9 v2.5.1"); + drawInfo("CtrBootManager9 v2.5.2"); #else - drawInfo("CtrBootManager v2.5.1"); + drawInfo("CtrBootManager v2.5.2"); #endif swapFrameBuffers(); From ed28cb0b3aab8b8b5394228323ed0b339fe9eb50 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 10 Jun 2017 00:31:22 +0200 Subject: [PATCH 257/259] Update screen.c --- source/arm9/source/screen.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/source/arm9/source/screen.c b/source/arm9/source/screen.c index 4ff7a4d..77b1ca1 100644 --- a/source/arm9/source/screen.c +++ b/source/arm9/source/screen.c @@ -44,8 +44,6 @@ vu32 *arm11Entry = (u32 *)0x1FFFFFF8; } }*/ -const u32 brightness[BRIGHTNESS_COUNT] = {0x5F, 0x4C, 0x39, 0x26}; - void initScreens(u8 brightnessLevel) { if(PDN_GPU_CNT == 1) @@ -61,10 +59,20 @@ void initScreens(u8 brightnessLevel) //Turn on backlight i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A); + + // Setup arguments for FIRM launch + fbs[0].top_left = (u8 *)0x18300000; + fbs[1].top_left = (u8 *)0x18400000; + fbs[0].top_right = (u8 *)0x18300000; + fbs[1].top_right = (u8 *)0x18400000; + fbs[0].bottom = (u8 *)0x18346500; + fbs[1].bottom = (u8 *)0x18446500; } } -/*void updateBrightness(u8 brightnessLevel) +/*const u32 brightness[BRIGHTNESS_COUNT] = {0x5F, 0x4C, 0x39, 0x26}; + +void updateBrightness(u8 brightnessLevel) { static int brightnessValue; brightnessValue = brightness[brightnessLevel%BRIGHTNESS_COUNT]; From e7d3866724e08a1afa927014d3d315b41bd85e68 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 10 Jun 2017 00:32:09 +0200 Subject: [PATCH 258/259] Create changelog.txt --- changelog.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.txt b/changelog.txt index 07f4adb..aa88173 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +2.5.2 + +Fix crash when booted from A9LH or B9S v1.2 (due to framebuffers always gotten from arguments) + 2.5.1 Boot9Strap v1.2 support From 419f925a2e3ef581d5a7a2834af446cfdf38e257 Mon Sep 17 00:00:00 2001 From: OperationNT414C Date: Sat, 10 Jun 2017 00:32:42 +0200 Subject: [PATCH 259/259] Update changelog.txt --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index aa88173..f695c56 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,6 @@ 2.5.2 -Fix crash when booted from A9LH or B9S v1.2 (due to framebuffers always gotten from arguments) +Fix crash when booted from A9LH or B9S v1.0 (due to framebuffers always gotten from arguments) 2.5.1