First commit of the AuReiNand rewrite!

- Gotten rid of the patched FIRMs, AuReiNand now finds and loads all the FIRMs from CTRNAND by default. If you are booting an emuNAND, the FIRMs will be loaded from its CTRNAND. This also applies to AGB and TWL FIRM, and allows for a very fast boot with no firmware files on the SD card.
- If for some reason (like using NTR) you do not want to use the CTRNAND FIRM, you can place a firmware.bin in the aurei folder and it will be loaded just for the default NAND.
- The way AuReiNand works has changed. Now you can specify to autoboot SysNAND or not, and a NAND is no more tied to a FIRM (since 9.0 FIRM is autodetected). If you press nothing the default NAND is booted with its own FIRM, L boots the non-default NAND with its own FIRM, R boots EmuNAND with the SysNAND FIRM if you picked "Updated SysNAND", and vice-versa.
- In order for AuReiNand to handle FIRM reboots, the .bin path needs to be hardcoded in the program. The default is /arm9loaderhax.bin (the AuReiNand.dat is also supported for 9.0 people). A PC tool was written to make changing the path easier.
- Bug fixes and stuff I forgot.
- Gelex is a saint.
This commit is contained in:
Aurora 2016-04-11 05:15:44 +02:00
parent 4180261f1f
commit 7dbded99a2
29 changed files with 6452 additions and 5880 deletions

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
out out
build build
loader/build loader/build
screeninit/build
injector/build injector/build
*.bin *.bin
*.3dsx *.3dsx

View File

@ -42,6 +42,9 @@ ninjhax: $(dir_out)/3ds/$(name)
.PHONY: release .PHONY: release
release: $(dir_out)/$(name).zip release: $(dir_out)/$(name).zip
.PHONY: pathchanger
pathchanger: $(dir_out)/pathchanger
.PHONY: clean .PHONY: clean
clean: clean:
@$(MAKE) $(FLAGS) -C $(dir_mset) clean @$(MAKE) $(FLAGS) -C $(dir_mset) clean
@ -54,6 +57,9 @@ clean:
$(dir_out): $(dir_out):
@mkdir -p "$(dir_out)/aurei/payloads" @mkdir -p "$(dir_out)/aurei/payloads"
$(dir_out)/pathchanger: $(dir_out)
@cc pathchanger/pathchanger.c -o out/pathchanger
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out) $(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher @$(MAKE) $(FLAGS) -C $(dir_mset) launcher
@dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144 @dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
@ -108,9 +114,9 @@ $(dir_build)/%.o: $(dir_source)/%.s
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.c $(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.c
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(COMPILE.c) -mthumb -mthumb-interwork -Wno-unused-function $(OUTPUT_OPTION) $< $(COMPILE.c) -Wno-unused-function $(OUTPUT_OPTION) $<
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.s $(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.s
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(COMPILE.s) -mthumb -mthumb-interwork $(OUTPUT_OPTION) $< $(COMPILE.s) $(OUTPUT_OPTION) $<
include $(call rwildcard, $(dir_build), *.d) include $(call rwildcard, $(dir_build), *.d)

View File

@ -187,18 +187,18 @@ void patchCode(u64 progId, u8 *code, u32 size)
case 0x0004001000027000LL: // KOR MSET case 0x0004001000027000LL: // KOR MSET
case 0x0004001000028000LL: // TWN MSET case 0x0004001000028000LL: // TWN MSET
{ {
if(R_SUCCEEDED(loadConfig()) && ((config >> 5) & 1)) if(R_SUCCEEDED(loadConfig()) && ((config >> 4) & 1))
{ {
static const u16 verPattern[] = u"Ver."; static const u16 verPattern[] = u"Ver.";
const u32 currentFirm = ((config >> 12) & 1); const u32 currentNand = ((config >> 16) & 3);
const u32 currentNand = ((config >> 13) & 3); const u32 matchingFirm = ((config >> 18) & 1) == (currentNand != 0);
//Patch Ver. string //Patch Ver. string
patchMemory(code, size, patchMemory(code, size,
verPattern, verPattern,
sizeof(verPattern) - sizeof(u16), 0, sizeof(verPattern) - sizeof(u16), 0,
currentNand ? ((currentNand == 1) ? ((currentFirm == 1) ? u" Emu" : u"Emu9") : u"Emu2") : !currentNand ? ((matchingFirm) ? u" Sys" : u"SysA") :
((currentFirm == 1) ? u" Sys" : u"Sys9"), ((currentNand == 1) ? (matchingFirm ? u" Emu" : u"EmuA") : ((matchingFirm) ? u"Emu2" : u"Em2A")),
sizeof(verPattern) - sizeof(u16), 1 sizeof(verPattern) - sizeof(u16), 1
); );
} }

View File

@ -1,7 +1,7 @@
.arm.little .arm.little
firm_addr equ 0x24000000 ; Temporary location where we'll load the FIRM to payload_addr equ 0x23F00000 ; Brahma payload address.
firm_maxsize equ 0x200000 ; Random value that's bigger than any of the currently known firm's sizes. payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
.create "reboot.bin", 0 .create "reboot.bin", 0
.arm .arm
@ -21,80 +21,43 @@ firm_maxsize equ 0x200000 ; Random value that's bigger than any of the currentl
cmp r0, r2 cmp r0, r2
bne pxi_wait_recv bne pxi_wait_recv
; Convert 2 bytes of the path string mov r4, #0
; This will be the method of getting the lower 2 bytes of the title ID adr r1, bin_fname
; until someone bothers figuring out where the value is derived from. b open_payload
mov r0, #0 ; Result
add r1, sp, #0x3A8 - 0x70
add r1, #0x22 ; The significant bytes
mov r2, #4 ; Maximum loops (amount of bytes * 2)
hex_string_to_int_loop:
ldr r3, [r1], #2 ; 2 because it's a utf-16 string.
and r3, #0xFF
; Check if it"s a number
cmp r3, #'0'
blo hex_string_to_int_end
sub r3, #'0'
cmp r3, #9
bls hex_string_to_int_calc
; Check if it"s a capital letter
cmp r3, #'A' - '0'
blo hex_string_to_int_end
sub r3, #'A' - '0' - 0xA ; Make the correct value: 0xF >= al >= 0xA
cmp r3, #0xF
bls hex_string_to_int_calc
; Incorrect value: x > "A"
bhi hex_string_to_int_end
hex_string_to_int_calc:
orr r0, r3, r0, lsl #4
subs r2, #1
bne hex_string_to_int_loop
hex_string_to_int_end:
; Get the FIRM path
cmp r0, #0x0002 ; NATIVE_FIRM
adreq r1, firm_fname
beq load_firm
ldr r5, =0x0102 ; TWL_FIRM
cmp r0, r5
adreq r1, twlfirm_fname
beq load_firm
ldr r5, =0x0202 ; AGB_FIRM
cmp r0, r5
adreq r1, agbfirm_fname
beq load_firm
bne fallback ; TODO: Stubbed
fallback: fallback:
; Fallback: Load specified FIRM from exefs mov r4, #1
add r1, sp, #0x3A8-0x70 ; Location of exefs string. adr r1, dat_fname
b load_firm
load_firm: open_payload:
; Open file ; Open file
add r0, r7, #8 add r0, r7, #8
mov r2, #1 mov r2, #1
ldr r6, [fopen] ldr r6, [fopen]
orr r6, 1 orr r6, 1
blx r6 blx r6
cmp r0, #0
bne fallback ; If the .bin is not found, try the .dat.
cmp r0, #0 ; Check if we were able to load the FIRM read_payload:
bne fallback ; Otherwise, try again with the FIRM from exefs.
; This will loop indefinitely if the exefs FIRM fails to load, but whatever.
; Read file ; Read file
mov r0, r7 mov r0, r7
adr r1, bytes_read adr r1, bytes_read
mov r2, firm_addr ldr r2, =payload_addr
mov r3, firm_maxsize cmp r4, #0
movne r3, #0x12000 ; Skip the first 0x12000 bytes.
moveq r3, payload_maxsize
ldr r6, [sp, #0x3A8-0x198] ldr r6, [sp, #0x3A8-0x198]
ldr r6, [r6, #0x28] ldr r6, [r6, #0x28]
blx r6 blx r6
cmp r4, #0
movne r4, #0
bne read_payload ; Go read the real payload.
add r0, sp, #0x3A8 - 0x70
ldr r0, [r0, #0x27]
ldr r1, =payload_addr + 4
str r0, [r1] ; Copy the last digits of the wanted firm to the 5th byte of the payload.
; Set kernel state ; Set kernel state
mov r0, #0 mov r0, #0
@ -115,13 +78,9 @@ firm_maxsize equ 0x200000 ; Random value that's bigger than any of the currentl
bytes_read: .word 0 bytes_read: .word 0
fopen: .ascii "OPEN" fopen: .ascii "OPEN"
.pool .pool
firm_fname: .dcw "sdmc:/aurei/patched_firmware_sys.bin" bin_fname: .dcw "sdmc:/arm9loaderhax.bin"
.word 0 .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
.pool dat_fname: .dcw "sdmc:/AuReiNand.dat"
twlfirm_fname: .dcw "sdmc:/aurei/patched_firmware_twl.bin"
.word 0
.pool
agbfirm_fname: .dcw "sdmc:/aurei/patched_firmware_agb.bin"
.word 0 .word 0
.align 4 .align 4
@ -157,23 +116,6 @@ agbfirm_fname: .dcw "sdmc:/aurei/patched_firmware_agb.bin"
mcr p15, 0, r1, c2, c0, 1 ; icacheable mcr p15, 0, r1, c2, c0, 1 ; icacheable
mcr p15, 0, r2, c3, c0, 0 ; write bufferable mcr p15, 0, r2, c3, c0, 0 ; write bufferable
; Copy the firmware
mov r4, firm_addr
add r5, r4, #0x40 ; Start of loop
add r6, r5, #0x30 * 3 ; End of loop (scan 4 entries)
copy_firm_loop:
ldr r0, [r5]
cmp r0, #0
addne r0, r4 ; src
ldrne r1, [r5, #4] ; dest
ldrne r2, [r5, #8] ; size
blne memcpy32
cmp r5, r6
addlo r5, #0x30
blo copy_firm_loop
; Flush cache ; Flush cache
mov r2, #0 mov r2, #0
mov r1, r2 mov r1, r2
@ -197,22 +139,10 @@ agbfirm_fname: .dcw "sdmc:/aurei/patched_firmware_agb.bin"
mcr p15, 0, r1, c7, c5, 0 ; flush dcache mcr p15, 0, r1, c7, c5, 0 ; flush dcache
mcr p15, 0, r1, c7, c6, 0 ; flush icache mcr p15, 0, r1, c7, c6, 0 ; flush icache
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
mov r0, firm_addr
; Boot FIRM ; Jump to payload
mov r1, #0x1FFFFFFC ldr r0, =payload_addr
ldr r2, [r0, #8] ; arm11 entry
str r2, [r1]
ldr r0, [r0, #0xC] ; arm9 entry
bx r0 bx r0
.pool
memcpy32: ; memcpy32(void *src, void *dst, unsigned int size) .pool
add r2, r0
memcpy32_loop:
ldmia r0!, {r3}
stmia r1!, {r3}
cmp r0, r2
blo memcpy32_loop
bx lr
.close .close

98
pathchanger/pathchanger.c Normal file
View File

@ -0,0 +1,98 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef uint8_t u8;
static u8 *memsearch(u8 *startPos, const void *pattern, int size, int patternSize)
{
const u8 *patternc = (const u8 *)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;
}
static int fsize(FILE *fp)
{
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
rewind(fp);
return size;
}
static void error(FILE *payload, const char *message)
{
fclose(payload);
printf("%s, are you sure you're using an AuReiNand payload?\n", message);
exit(0);
}
int main(int argc, char **argv)
{
if(argc == 1)
{
printf("Usage: %s <AuReiNand payload path>\n", argv[0]);
exit(0);
}
FILE *payload;
size_t size;
payload = fopen(argv[1], "rb+");
size = fsize(payload);
if(size > 0x20000)
error(payload, "The input file is too large");
u8 *buffer = (u8 *)malloc(size);
fread(buffer, 1, size, payload);
u8 pattern[] = {'s', 0, 'd', 0, 'm', 0, 'c', 0, ':', 0, '/', 0};
u8 *found = memsearch(buffer, pattern, size, sizeof(pattern));
if(found == NULL)
{
free(buffer);
error(payload, "Pattern not found");
}
u8 input[37] = {0};
u8 payloadname[2 * sizeof(input)] = {0};
printf("Enter the payload's path (37 characters max): ");
scanf("%37s", input);
unsigned int i;
for (i = 0; i < sizeof(input); i++)
payloadname[2 * i] = input[i];
memcpy(found + 12, payloadname, sizeof(payloadname));
rewind(payload);
fwrite(buffer, 1, size, payload);
free(buffer);
fclose(payload);
exit(0);
}

View File

@ -12,7 +12,7 @@
#include "i2c.h" #include "i2c.h"
#include "buttons.h" #include "buttons.h"
void configureCFW(const char *configPath, const char *patchedFirms[]) void configureCFW(const char *configPath)
{ {
initScreens(); initScreens();
@ -20,10 +20,9 @@ void configureCFW(const char *configPath, const char *patchedFirms[])
drawString("Press A to select, START to save and reboot", 10, 30, COLOR_WHITE); drawString("Press A to select, START to save and reboot", 10, 30, COLOR_WHITE);
const char *optionsText[] = { "Screen-init brightness: 4( ) 3( ) 2( ) 1( )", const char *optionsText[] = { "Screen-init brightness: 4( ) 3( ) 2( ) 1( )",
"( ) Autoboot SysNAND",
"( ) Updated SysNAND mode (A9LH-only)", "( ) Updated SysNAND mode (A9LH-only)",
"( ) Use pre-patched FIRMs",
"( ) Force A9LH detection", "( ) Force A9LH detection",
"( ) Use 9.0 FIRM as default",
"( ) Use second EmuNAND as default", "( ) Use second EmuNAND as default",
"( ) Show current NAND in System Settings", "( ) Show current NAND in System Settings",
"( ) Show GBA boot screen in patched AGB_FIRM", "( ) Show GBA boot screen in patched AGB_FIRM",
@ -37,8 +36,8 @@ void configureCFW(const char *configPath, const char *patchedFirms[])
} options[optionsAmount]; } options[optionsAmount];
//Parse the existing configuration //Parse the existing configuration
options[0].enabled = CONFIG(10, 3); options[0].enabled = CONFIG(14, 3);
for(u32 i = optionsAmount; i; i--) for(u32 i = optionsAmount - 1; i; i--)
options[i].enabled = CONFIG((i - 1), 1); options[i].enabled = CONFIG((i - 1), 1);
//Pre-select the first configuration option //Pre-select the first configuration option
@ -55,7 +54,9 @@ void configureCFW(const char *configPath, const char *patchedFirms[])
//Display all the normal options in white, brightness will be displayed later //Display all the normal options in white, brightness will be displayed later
for(u32 i = 1; i < optionsAmount; i++) for(u32 i = 1; i < optionsAmount; i++)
{ {
options[i].posY = drawString(optionsText[i], 10, options[i - 1].posY + SPACING_Y + (!(1 - i) * 7), COLOR_WHITE); static int endPos = 59;
options[i].posY = endPos + SPACING_Y;
endPos = drawString(optionsText[i], 10, options[i].posY, COLOR_WHITE);
if(options[i].enabled) drawCharacter(selected, 10 + SPACING_X, options[i].posY, COLOR_WHITE); if(options[i].enabled) drawCharacter(selected, 10 + SPACING_X, options[i].posY, COLOR_WHITE);
} }
@ -129,18 +130,12 @@ void configureCFW(const char *configPath, const char *patchedFirms[])
if(pressed == BUTTON_START) break; if(pressed == BUTTON_START) break;
} }
//If the user has been using A9LH and the "Updated SysNAND" setting changed, delete the patched 9.0 FIRM
if(CONFIG(16, 1) && (CONFIG(0, 1) != options[1].enabled)) fileDelete(patchedFirms[3]);
//If the "Show GBA boot screen in patched AGB_FIRM" setting changed, delete the patched AGB_FIRM
if(CONFIG(6, 1) != options[7].enabled) fileDelete(patchedFirms[5]);
//Preserve the last-used boot options (last 12 bits) //Preserve the last-used boot options (last 12 bits)
config &= 0xFFF000; config &= 0xFF0000;
//Parse and write the new configuration //Parse and write the new configuration
config |= options[0].enabled << 10; config |= options[0].enabled << 14;
for(u32 i = optionsAmount; i; i--) for(u32 i = optionsAmount - 1; i; i--)
config |= options[i].enabled << (i - 1); config |= options[i].enabled << (i - 1);
fileWrite(&config, configPath, 3); fileWrite(&config, configPath, 3);

View File

@ -11,6 +11,6 @@
#define CFG_BOOTENV (*(vu32 *)0x10010000) #define CFG_BOOTENV (*(vu32 *)0x10010000)
#define CONFIG(a, b) ((config >> a) & b) #define CONFIG(a, b) ((config >> a) & b)
u32 config; extern u32 config;
void configureCFW(const char *configPath, const char *patchedFirms[]); void configureCFW(const char *configPath);

View File

@ -229,47 +229,154 @@ static void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode,
} }
} }
static void sha_wait_idle()
{
while(*REG_SHA_CNT & 1);
}
static 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);
}
/**************************************************************** /****************************************************************
* Nand/FIRM Crypto stuff * Nand/FIRM Crypto stuff
****************************************************************/ ****************************************************************/
//Nand key#2 (0x12C10) static u8 nandCTR[0x10],
static const u8 key2[0x10] = { nandSlot;
0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0
};
//Get Nand CTR key static u32 fatStart;
static void getNandCTR(u8 *buf, u32 console)
//Initialize the CTRNAND crypto
void ctrNandInit(void)
{ {
u8 *addr = (console ? (u8 *)0x080D8BBC : (u8 *)0x080D797C) + 0x0F; u8 nandCid[0x10];
for(u8 keyLen = 0x10; keyLen; keyLen--) u8 shaSum[0x20];
*(buf++) = *(addr--);
sdmmc_get_cid(1, (u32 *)nandCid);
sha(shaSum, nandCid, 0x10, SHA_256_MODE);
memcpy(nandCTR, shaSum, 0x10);
if(console)
{
u8 keyY0x5[0x10] = {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;
}
} }
//Read firm0 from NAND and write to buffer //Read and decrypt from the selected CTRNAND
void nandFirm0(u8 *outbuf, u32 size, u32 console) u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
{ {
u8 CTR[0x10]; u8 tmpCTR[0x10];
getNandCTR(CTR, console); memcpy(tmpCTR, nandCTR, 0x10);
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
sdmmc_nand_readsectors(0x0B130000 / 0x200, size / 0x200, outbuf); //Read
u32 result;
aes_advctr(CTR, 0x0B130000/0x10, AES_INPUT_BE | AES_INPUT_NORMAL); if(!firmSource)
aes_use_keyslot(0x06); result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf);
aes(outbuf, outbuf, size / AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); else
{
sector += emuOffset;
result = sdmmc_sdcard_readsectors(sector + fatStart, sectorCount, outbuf);
} }
//Decrypts the N3DS arm9bin //Decrypt
void decryptArm9Bin(u8 *arm9Section, u32 mode) aes_use_keyslot(nandSlot);
aes(outbuf, outbuf, (sectorCount * 0x200) / AES_BLOCK_SIZE, tmpCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
return result;
}
//Encrypt and write to the selected CTRNAND
u32 ctrNandWrite(u32 sector, u32 sectorCount, u8 *inbuf)
{
u8 tmpCTR[0x10];
memcpy(tmpCTR, nandCTR, 0x10);
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
//Encrypt
aes_use_keyslot(nandSlot);
aes(inbuf, inbuf, (sectorCount * 0x200) / AES_BLOCK_SIZE, tmpCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
//Write
if(!firmSource)
return sdmmc_nand_writesectors(sector + fatStart, sectorCount, inbuf);
sector += emuOffset;
return sdmmc_sdcard_writesectors(sector + fatStart, sectorCount, inbuf);
}
//Decrypt a FIRM ExeFS
void decryptExeFs(u8 *inbuf)
{
u32 exeFsOffset = (u32)inbuf + *(u32 *)(inbuf + 0x1A0) * 0x200;
u32 exeFsSize = *(u32 *)(inbuf + 0x1A4) * 0x200;
u8 ncchCTR[0x10];
memset(ncchCTR, 0, 0x10);
for(u32 i=0; i<8; i++)
ncchCTR[7-i] = *(inbuf + 0x108 + i);
ncchCTR[8] = 2;
aes_setkey(0x2C, inbuf, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setiv(ncchCTR, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x2C);
aes(inbuf - 0x200, (void *)exeFsOffset, exeFsSize/AES_BLOCK_SIZE, ncchCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
}
//ARM9Loader replacement
void arm9Loader(u8 *arm9Section, u32 mode)
{ {
//Firm keys //Firm keys
u8 keyY[0x10]; u8 keyY[0x10];
u8 CTR[0x10]; u8 arm9BinCTR[0x10];
u8 slot = mode ? 0x16 : 0x15; u8 arm9BinSlot = mode ? 0x16 : 0x15;
//Setup keys needed for arm9bin decryption //Setup keys needed for arm9bin decryption
memcpy(keyY, arm9Section + 0x10, 0x10); memcpy(keyY, arm9Section + 0x10, 0x10);
memcpy(CTR, arm9Section + 0x20, 0x10); memcpy(arm9BinCTR, arm9Section + 0x20, 0x10);
//Calculate the size of the ARM9 binary //Calculate the size of the ARM9 binary
u32 size = 0; u32 size = 0;
@ -279,31 +386,30 @@ void decryptArm9Bin(u8 *arm9Section, u32 mode)
if(mode) if(mode)
{ {
const u8 key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
u8 keyX[0x10]; u8 keyX[0x10];
//Set 0x11 to key2 for the arm9bin and misc keys //Set 0x11 to key2 for the arm9bin and misc keys
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x11); aes_use_keyslot(0x11);
aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0); aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(slot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
} }
aes_setkey(slot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(arm9BinSlot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setiv(CTR, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setiv(arm9BinCTR, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(slot); aes_use_keyslot(arm9BinSlot);
//Decrypt arm9bin //Decrypt arm9bin
aes(arm9Section + 0x800, arm9Section + 0x800, size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); aes(arm9Section + 0x800, arm9Section + 0x800, size/AES_BLOCK_SIZE, arm9BinCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
}
//Sets the N3DS 9.6 KeyXs //Set >=9.6 KeyXs
void setKeyXs(u8 *arm9Section) if(mode)
{ {
u8 *keyData = arm9Section + 0x89814; u8 *keyData = arm9Section + 0x89814;
u8 *decKey = keyData + 0x10; u8 *decKey = keyData + 0x10;
//Set keys 0x19..0x1F keyXs //Set keys 0x19..0x1F keyXs
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x11); aes_use_keyslot(0x11);
for(u8 slot = 0x19; slot < 0x20; slot++) for(u8 slot = 0x19; slot < 0x20; slot++)
{ {
@ -312,3 +418,4 @@ void setKeyXs(u8 *arm9Section)
*(keyData + 0xF) += 1; *(keyData + 0xF) += 1;
} }
} }
}

View File

@ -53,7 +53,38 @@
#define AES_KEYX 1 #define AES_KEYX 1
#define AES_KEYY 2 #define AES_KEYY 2
//NAND/FIRM stuff /**************************SHA****************************/
void nandFirm0(u8 *outbuf, u32 size, u32 console); #define REG_SHA_CNT ((vu32 *)0x1000A000)
void decryptArm9Bin(u8 *arm9Section, u32 mode); #define REG_SHA_BLKCNT ((vu32 *)0x1000A004)
void setKeyXs(u8 *arm9Section); #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)
extern u32 emuOffset, console, firmSource;
void ctrNandInit(void);
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
u32 ctrNandWrite(u32 sector, u32 sectorCount, u8 *inbuf);
void decryptExeFs(u8 *inbuf);
void arm9Loader(u8 *arm9Section, u32 mode);

View File

@ -8,7 +8,7 @@
#include "memory.h" #include "memory.h"
#include "fatfs/sdmmc/sdmmc.h" #include "fatfs/sdmmc/sdmmc.h"
u32 getEmunandSect(u32 *off, u32 *head, u32 *emuNAND) void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND)
{ {
u8 *const temp = (u8 *)0x24300000; u8 *const temp = (u8 *)0x24300000;
@ -40,13 +40,9 @@ u32 getEmunandSect(u32 *off, u32 *head, u32 *emuNAND)
{ {
(*emuNAND)--; (*emuNAND)--;
if(*emuNAND) getEmunandSect(off, head, emuNAND); if(*emuNAND) getEmunandSect(off, head, emuNAND);
return 0;
} }
} }
} }
return 1;
} }
u32 getSDMMC(u8 *pos, u32 size) u32 getSDMMC(u8 *pos, u32 size)

View File

@ -10,7 +10,7 @@
#define NCSD_MAGIC (0x4453434E) #define NCSD_MAGIC (0x4453434E)
u32 getEmunandSect(u32 *off, u32 *head, u32 *emuNAND); void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND);
u32 getSDMMC(u8 *pos, u32 size); u32 getSDMMC(u8 *pos, u32 size);
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff); void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff);
u32 *getMPU(u8 *pos, u32 size); u32 *getMPU(u8 *pos, u32 size);

View File

@ -10,6 +10,9 @@
#include "diskio.h" /* FatFs lower layer API */ #include "diskio.h" /* FatFs lower layer API */
#include "sdmmc/sdmmc.h" #include "sdmmc/sdmmc.h"
/* Definitions of physical drive number for each media */
#define SDCARD 0
#define CTRNAND 1
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Get Drive Status */ /* Get Drive Status */
@ -34,7 +37,16 @@ DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */ BYTE pdrv /* Physical drive nmuber to identify the drive */
) )
{ {
switch(pdrv)
{
case SDCARD:
sdmmc_sdcard_init(); sdmmc_sdcard_init();
break;
case CTRNAND:
ctrNandInit();
break;
}
return RES_OK; return RES_OK;
} }
@ -52,8 +64,16 @@ DRESULT disk_read (
UINT count /* Number of sectors to read */ UINT count /* Number of sectors to read */
) )
{ {
if (sdmmc_sdcard_readsectors(sector, count, buff)) { switch(pdrv)
{
case SDCARD:
if(sdmmc_sdcard_readsectors(sector, count, (BYTE *)buff))
return RES_PARERR; return RES_PARERR;
break;
case CTRNAND:
if(ctrNandRead(sector, count, (BYTE *)buff))
return RES_PARERR;
break;
} }
return RES_OK; return RES_OK;
@ -74,8 +94,16 @@ DRESULT disk_write (
UINT count /* Number of sectors to write */ UINT count /* Number of sectors to write */
) )
{ {
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) { switch(pdrv)
{
case SDCARD:
if(sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff))
return RES_PARERR; return RES_PARERR;
break;
case CTRNAND:
if(ctrNandWrite(sector, count, (BYTE *)buff))
return RES_PARERR;
break;
} }
return RES_OK; return RES_OK;

550
source/fatfs/ff.c Normal file → Executable file
View File

@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - FAT file system module R0.11 (C)ChaN, 2015 / FatFs - FAT file system module R0.11a (C)ChaN, 2015 /
/-----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ FatFs module is a free software that opened under license policy of / FatFs module is a free software that opened under license policy of
/ following conditions. / following conditions.
@ -26,7 +26,7 @@
---------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
#if _FATFS != 32020 /* Revision ID */ #if _FATFS != 64180 /* Revision ID */
#error Wrong include file (ff.h). #error Wrong include file (ff.h).
#endif #endif
@ -83,7 +83,7 @@ typedef struct {
/* DBCS code ranges and SBCS extend character conversion table */ /* DBCS code ranges and SBCS upper conversion tables */
#if _CODE_PAGE == 932 /* Japanese Shift-JIS */ #if _CODE_PAGE == 932 /* Japanese Shift-JIS */
#define _DF1S 0x81 /* DBC 1st byte range 1 start */ #define _DF1S 0x81 /* DBC 1st byte range 1 start */
@ -121,211 +121,192 @@ typedef struct {
#define _DS2S 0xA1 #define _DS2S 0xA1
#define _DS2E 0xFE #define _DS2E 0xFE
#elif _CODE_PAGE == 437 /* U.S. (OEM) */ #elif _CODE_PAGE == 437 /* U.S. */
#define _DF1S 0 #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, \ #define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
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, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
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,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
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}*/ 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 #elif _CODE_PAGE == 720 /* Arabic */
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 _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, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
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, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
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, \ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
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} 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) */ #elif _CODE_PAGE == 737 /* Greek */
#define _DF1S 0 #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, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
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, \ 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
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, \ 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \
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} 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 == 775 /* Baltic (OEM) */ #elif _CODE_PAGE == 771 /* KBL */
#define _DF1S 0 #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, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
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, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
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, \ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
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} 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 == 850 /* Multilingual Latin 1 (OEM) */ #elif _CODE_PAGE == 775 /* Baltic */
#define _DF1S 0 #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, \ #define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \
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, \ 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
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, \ 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
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} 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 == 852 /* Latin 2 (OEM) */ #elif _CODE_PAGE == 850 /* Latin 1 */
#define _DF1S 0 #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, \ #define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \
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, \ 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \
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, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
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} 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 == 855 /* Cyrillic (OEM) */ #elif _CODE_PAGE == 852 /* Latin 2 */
#define _DF1S 0 #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, \ #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \
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, \ 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \
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, \ 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \
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} 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 == 857 /* Turkish (OEM) */ #elif _CODE_PAGE == 855 /* Cyrillic */
#define _DF1S 0 #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, \ #define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \
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, \ 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
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, \ 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \
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} 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 == 858 /* Multilingual Latin 1 + Euro (OEM) */ #elif _CODE_PAGE == 857 /* Turkish */
#define _DF1S 0 #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, \ #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \
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, \ 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
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, \ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
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} 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 == 862 /* Hebrew (OEM) */ #elif _CODE_PAGE == 860 /* Portuguese */
#define _DF1S 0 #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, \ #define _EXCVT {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \
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, \ 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
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, \ 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
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} 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) */ #elif _CODE_PAGE == 861 /* Icelandic */
#define _DF1S 0 #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, \ #define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \
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, \ 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
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, \ 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
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} 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 == 874 /* Thai (OEM, Windows) */ #elif _CODE_PAGE == 862 /* Hebrew */
#define _DF1S 0 #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, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
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, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
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,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
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} 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) */ #elif _CODE_PAGE == 863 /* Canadian-French */
#define _DF1S 0 #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, \ #define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,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, \ 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \
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, \ 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
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} 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 == 1251 /* Cyrillic (Windows) */ #elif _CODE_PAGE == 864 /* Arabic */
#define _DF1S 0 #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, \ #define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,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, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
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,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,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} 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 == 1252 /* Latin 1 (Windows) */ #elif _CODE_PAGE == 865 /* Nordic */
#define _DF1S 0 #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, \ #define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
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, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
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,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
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} 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 == 1253 /* Greek (Windows) */ #elif _CODE_PAGE == 866 /* Russian */
#define _DF1S 0 #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, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
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, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
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, \ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
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} 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 == 1254 /* Turkish (Windows) */ #elif _CODE_PAGE == 869 /* Greek 2 */
#define _DF1S 0 #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, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
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, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \
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, \ 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
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} 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, \
#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \
#define _DF1S 0 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \
#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, \ 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF}
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 _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 _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 _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}
#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ #elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */
#if _USE_LFN #if _USE_LFN
@ -377,12 +358,12 @@ WCHAR ff_wtoupper(WCHAR chr)
/* FAT sub-type boundaries (Differ from specs but correct for real DOS/Windows) */ /* 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_FAT16 4086U /* Minimum number of clusters of FAT16 */
#define MIN_FAT32 65526U /* Minimum number of clusters as FAT32 */ #define MIN_FAT32 65526U /* Minimum number of clusters of FAT32 */
/* FatFs refers the members in the FAT structures as byte array instead of /* 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 */ / different platforms */
#define BS_jmpBoot 0 /* x86 jump instruction (3) */ #define BS_jmpBoot 0 /* x86 jump instruction (3) */
@ -399,7 +380,8 @@ WCHAR ff_wtoupper(WCHAR chr)
#define BPB_NumHeads 26 /* Number of heads (2) */ #define BPB_NumHeads 26 /* Number of heads (2) */
#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */ #define BPB_HiddSec 28 /* Number of special hidden sectors (4) */
#define BPB_TotSec32 32 /* Volume size [sector] (4) */ #define BPB_TotSec32 32 /* Volume size [sector] (4) */
#define BS_DrvNum 36 /* Physical drive number (2) */ #define BS_DrvNum 36 /* Physical drive number (1) */
#define BS_NTres 37 /* Error flag (1) */
#define BS_BootSig 38 /* Extended boot signature (1) */ #define BS_BootSig 38 /* Extended boot signature (1) */
#define BS_VolID 39 /* Volume serial number (4) */ #define BS_VolID 39 /* Volume serial number (4) */
#define BS_VolLab 43 /* Volume label (8) */ #define BS_VolLab 43 /* Volume label (8) */
@ -410,7 +392,8 @@ WCHAR ff_wtoupper(WCHAR chr)
#define BPB_RootClus 44 /* Root directory first cluster (4) */ #define BPB_RootClus 44 /* Root directory first cluster (4) */
#define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */ #define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */
#define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */ #define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */
#define BS_DrvNum32 64 /* Physical drive number (2) */ #define BS_DrvNum32 64 /* Physical drive number (1) */
#define BS_NTres32 65 /* Error flag (1) */
#define BS_BootSig32 66 /* Extended boot signature (1) */ #define BS_BootSig32 66 /* Extended boot signature (1) */
#define BS_VolID32 67 /* Volume serial number (4) */ #define BS_VolID32 67 /* Volume serial number (4) */
#define BS_VolLab32 71 /* Volume label (8) */ #define BS_VolLab32 71 /* Volume label (8) */
@ -438,7 +421,7 @@ WCHAR ff_wtoupper(WCHAR chr)
#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */ #define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */
#define LDIR_Attr 11 /* LFN attribute (1) */ #define LDIR_Attr 11 /* LFN attribute (1) */
#define LDIR_Type 12 /* LFN type (1) */ #define LDIR_Type 12 /* LFN type (1) */
#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */ #define LDIR_Chksum 13 /* Checksum of corresponding SFN entry */
#define LDIR_FstClusLO 26 /* Must be zero (0) */ #define LDIR_FstClusLO 26 /* Must be zero (0) */
#define SZ_DIRE 32 /* Size of a directory entry */ #define SZ_DIRE 32 /* Size of a directory entry */
#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ #define LLEF 0x40 /* Last long entry flag in LDIR_Ord */
@ -448,12 +431,15 @@ WCHAR ff_wtoupper(WCHAR chr)
/*------------------------------------------------------------*/ /*--------------------------------------------------------------------------
/* Module private work area */
/*------------------------------------------------------------*/ 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.
/* 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 not compliance with ANSI-C standard.
*/ */
#if _VOLUMES < 1 || _VOLUMES > 9 #if _VOLUMES < 1 || _VOLUMES > 9
@ -497,7 +483,7 @@ static WCHAR LfnBuf[_MAX_LFN + 1];
#endif #endif
#ifdef _EXCVT #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 #endif
@ -711,7 +697,7 @@ void clear_lock ( /* Clear lock entries of the volume */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY #if !_FS_READONLY
static static
FRESULT sync_window ( FRESULT sync_window ( /* FR_OK:succeeded, !=0:error */
FATFS* fs /* File system object */ FATFS* fs /* File system object */
) )
{ {
@ -740,7 +726,7 @@ FRESULT sync_window (
static static
FRESULT move_window ( FRESULT move_window ( /* FR_OK(0):succeeded, !=0:error */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD sector /* Sector number to make appearance in the fs->win[] */ DWORD sector /* Sector number to make appearance in the fs->win[] */
) )
@ -771,7 +757,7 @@ FRESULT move_window (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY #if !_FS_READONLY
static static
FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */ FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */
FATFS* fs /* File system object */ FATFS* fs /* File system object */
) )
{ {
@ -780,16 +766,16 @@ FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */
res = sync_window(fs); res = sync_window(fs);
if (res == FR_OK) { if (res == FR_OK) {
/* Update FSINFO sector if needed */ /* Update FSInfo sector if needed */
if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) {
/* Create FSINFO structure */ /* Create FSInfo structure */
mem_set(fs->win, 0, SS(fs)); mem_set(fs->win, 0, SS(fs));
ST_WORD(fs->win + BS_55AA, 0xAA55); ST_WORD(fs->win + BS_55AA, 0xAA55);
ST_DWORD(fs->win + FSI_LeadSig, 0x41615252); ST_DWORD(fs->win + FSI_LeadSig, 0x41615252);
ST_DWORD(fs->win + FSI_StrucSig, 0x61417272); ST_DWORD(fs->win + FSI_StrucSig, 0x61417272);
ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust); ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust);
ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust); ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust);
/* Write it into the FSINFO sector */ /* Write it into the FSInfo sector */
fs->winsect = fs->volbase + 1; fs->winsect = fs->volbase + 1;
disk_write(fs->drv, fs->win, fs->winsect, 1); disk_write(fs->drv, fs->win, fs->winsect, 1);
fs->fsi_flag = 0; fs->fsi_flag = 0;
@ -811,7 +797,7 @@ FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Hidden API for hacks and disk tools */ /* Hidden API for hacks and disk tools */
static DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ DWORD clust2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst /* Cluster# to be converted */ DWORD clst /* Cluster# to be converted */
) )
@ -829,7 +815,7 @@ static DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Hidden API for hacks and disk tools */ /* Hidden API for hacks and disk tools */
static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status */ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst /* FAT index number (cluster number) to get the value */ DWORD clst /* FAT index number (cluster number) to get the value */
) )
@ -839,7 +825,7 @@ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF
DWORD val; DWORD val;
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 */ val = 1; /* Internal error */
} else { } else {
@ -884,7 +870,7 @@ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF
/* Hidden API for hacks and disk tools */ /* Hidden API for hacks and disk tools */
#if !_FS_READONLY #if !_FS_READONLY
static FRESULT put_fat ( FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst, /* FAT index number (cluster number) to be changed */ DWORD clst, /* FAT index number (cluster number) to be changed */
DWORD val /* New value to be set to the entry */ DWORD val /* New value to be set to the entry */
@ -895,7 +881,7 @@ static FRESULT put_fat (
FRESULT res; FRESULT res;
if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */
res = FR_INT_ERR; res = FR_INT_ERR;
} else { } else {
@ -948,7 +934,7 @@ static FRESULT put_fat (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY #if !_FS_READONLY
static static
FRESULT remove_chain ( FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst /* Cluster# to remove a chain from */ DWORD clst /* Cluster# to remove a chain from */
) )
@ -959,7 +945,7 @@ FRESULT remove_chain (
DWORD scl = clst, ecl = clst, rt[2]; DWORD scl = clst, ecl = clst, rt[2];
#endif #endif
if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */
res = FR_INT_ERR; res = FR_INT_ERR;
} else { } else {
@ -1003,7 +989,7 @@ FRESULT remove_chain (
static static
DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst /* Cluster# to stretch. 0 means create a new chain. */ DWORD clst /* Cluster# to stretch, 0:Create a new chain */
) )
{ {
DWORD cs, ncl, scl; DWORD cs, ncl, scl;
@ -1091,7 +1077,7 @@ DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
FRESULT dir_sdi ( FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */
DIR* dp, /* Pointer to directory object */ DIR* dp, /* Pointer to directory object */
UINT idx /* Index of directory table */ UINT idx /* Index of directory table */
) )
@ -1139,7 +1125,7 @@ FRESULT dir_sdi (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static 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 */ DIR* dp, /* Pointer to the directory object */
int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ int stretch /* 0: Do not stretch table, 1: Stretch table if needed */
) )
@ -1210,7 +1196,7 @@ FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could
#if !_FS_READONLY #if !_FS_READONLY
static static
FRESULT dir_alloc ( FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */
DIR* dp, /* Pointer to the directory object */ DIR* dp, /* Pointer to the directory object */
UINT nent /* Number of contiguous entries to allocate (1-21) */ UINT nent /* Number of contiguous entries to allocate (1-21) */
) )
@ -1246,9 +1232,9 @@ FRESULT dir_alloc (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
DWORD ld_clust ( DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */
FATFS* fs, /* Pointer to the fs object */ FATFS* fs, /* Pointer to the fs object */
BYTE* dir /* Pointer to the directory entry */ const BYTE* dir /* Pointer to the SFN entry */
) )
{ {
DWORD cl; DWORD cl;
@ -1264,7 +1250,7 @@ DWORD ld_clust (
#if !_FS_READONLY #if !_FS_READONLY
static static
void st_clust ( void st_clust (
BYTE* dir, /* Pointer to the directory entry */ BYTE* dir, /* Pointer to the SFN entry */
DWORD cl /* Value to be set */ DWORD cl /* Value to be set */
) )
{ {
@ -1285,27 +1271,29 @@ const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN char
static static
int cmp_lfn ( /* 1:Matched, 0:Not matched */ int cmp_lfn ( /* 1:matched, 0:not matched */
WCHAR* lfnbuf, /* Pointer to the LFN to be compared */ WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */
BYTE* dir /* Pointer to the directory entry containing a part of LFN */ BYTE* dir /* Pointer to the directory entry containing the part of LFN */
) )
{ {
UINT i, s; UINT i, s;
WCHAR wc, uc; WCHAR wc, uc;
i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Get offset in the LFN buffer */ if (LD_WORD(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */
s = 0; wc = 1;
do { i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
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 */
wc = ff_wtoupper(uc); /* Convert it to upper case */ uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character */
if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */ if (wc) {
if (i >= _MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) /* Compare it */
return 0; /* Not matched */ return 0; /* Not matched */
wc = uc;
} else { } 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 */ if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) /* Last segment matched but different length */
return 0; return 0;
@ -1314,47 +1302,47 @@ int cmp_lfn ( /* 1:Matched, 0:Not matched */
} }
#if _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2
static static
int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */
WCHAR* lfnbuf, /* Pointer to the Unicode-LFN buffer */ WCHAR* lfnbuf, /* Pointer to the LFN working buffer */
BYTE* dir /* Pointer to the directory entry */ BYTE* dir /* Pointer to the LFN entry */
) )
{ {
UINT i, s; UINT i, s;
WCHAR wc, uc; 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 */ i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
s = 0; wc = 1; for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
do { uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character */
uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */ if (wc) {
if (wc) { /* Last character has not been processed */
if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
lfnbuf[i++] = wc = uc; /* Store it */ lfnbuf[i++] = wc = uc; /* Store it */
} else { } else {
if (uc != 0xFFFF) return 0; /* Check filler */ 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 (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */
if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
lfnbuf[i] = 0; lfnbuf[i] = 0;
} }
return 1; return 1; /* The part of LFN is valid */
} }
#endif
#if !_FS_READONLY #if !_FS_READONLY
static static
void fit_lfn ( void fit_lfn (
const WCHAR* lfnbuf, /* Pointer to the LFN buffer */ const WCHAR* lfnbuf, /* Pointer to the LFN working buffer */
BYTE* dir, /* Pointer to the directory entry */ BYTE* dir, /* Pointer to the LFN entry to be processed */
BYTE ord, /* LFN order (1-20) */ BYTE ord, /* LFN order (1-20) */
BYTE sum /* SFN sum */ BYTE sum /* Checksum of the corresponding SFN */
) )
{ {
UINT i, s; UINT i, s;
@ -1366,7 +1354,7 @@ void fit_lfn (
dir[LDIR_Type] = 0; 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; s = wc = 0;
do { do {
if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */ if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */
@ -1386,7 +1374,7 @@ void fit_lfn (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Create numbered name */ /* Create numbered name */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if _USE_LFN && !_FS_READONLY #if _USE_LFN
static static
void gen_numname ( void gen_numname (
BYTE* dst, /* Pointer to the buffer to store numbered SFN */ BYTE* dst, /* Pointer to the buffer to store numbered SFN */
@ -1443,7 +1431,7 @@ void gen_numname (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Calculate sum of an SFN */ /* Calculate checksum of an SFN entry */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if _USE_LFN #if _USE_LFN
static static
@ -1467,7 +1455,7 @@ BYTE sum_sfn (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
FRESULT dir_find ( FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
DIR* dp /* Pointer to the directory object linked to the file name */ DIR* dp /* Pointer to the directory object linked to the file name */
) )
{ {
@ -1587,7 +1575,7 @@ FRESULT dir_read (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY #if !_FS_READONLY
static 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 */ DIR* dp /* Target directory with object name to be created */
) )
{ {
@ -1627,7 +1615,7 @@ FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many
if (res == FR_OK && --nent) { /* Set LFN entry if needed */ if (res == FR_OK && --nent) { /* Set LFN entry if needed */
res = dir_sdi(dp, dp->index - nent); res = dir_sdi(dp, dp->index - nent);
if (res == FR_OK) { 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 */ do { /* Store LFN entries in bottom first */
res = move_window(dp->fs, dp->sect); res = move_window(dp->fs, dp->sect);
if (res != FR_OK) break; if (res != FR_OK) break;
@ -1665,7 +1653,7 @@ FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY && !_FS_MINIMIZE #if !_FS_READONLY && !_FS_MINIMIZE
static 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 */ DIR* dp /* Directory object pointing the entry to be removed */
) )
{ {
@ -1804,7 +1792,7 @@ WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */
static static
int pattern_matching ( /* Return value: 0:mismatched, 1:matched */ int pattern_matching ( /* 0:mismatched, 1:matched */
const TCHAR* pat, /* Matching pattern */ const TCHAR* pat, /* Matching pattern */
const TCHAR* nam, /* String to be tested */ const TCHAR* nam, /* String to be tested */
int skip, /* Number of pre-skip chars (number of ?s) */ int skip, /* Number of pre-skip chars (number of ?s) */
@ -1848,11 +1836,11 @@ 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 static
FRESULT create_name ( FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */
DIR* dp, /* Pointer to the directory object */ DIR* dp, /* Pointer to the directory object */
const TCHAR** path /* Pointer to pointer to the segment in the path string */ const TCHAR** path /* Pointer to pointer to the segment in the path string */
) )
@ -1890,22 +1878,21 @@ FRESULT create_name (
*path = &p[si]; /* Return pointer to the next segment */ *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 path */
#if _FS_RPATH #if _FS_RPATH
if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */ if ((di == 1 && lfn[di - 1] == '.') ||
(di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot entry? */
lfn[di] = 0; 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] = (i < di) ? '.' : ' ';
dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ dp->fn[i] = cf | NS_DOT; /* This is a dot entry */
return FR_OK; return FR_OK;
} }
#endif #endif
while (di) { /* Strip trailing spaces and dots */ while (di) { /* Snip off trailing spaces and dots if exist */
w = lfn[di - 1]; w = lfn[di - 1];
if (w != ' ' && w != '.') break; if (w != ' ' && w != '.') break;
di--; di--;
} }
if (!di) return FR_INVALID_NAME; /* Reject nul string */ if (!di) return FR_INVALID_NAME; /* Reject nul string */
lfn[di] = 0; /* LFN is created */ lfn[di] = 0; /* LFN is created */
/* Create SFN in directory form */ /* Create SFN in directory form */
@ -1942,7 +1929,7 @@ FRESULT create_name (
cf |= NS_LFN; /* Force create LFN entry */ 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) { if (i >= ni - 1) {
cf |= NS_LOSS | NS_LFN; i = ni; continue; cf |= NS_LOSS | NS_LFN; i = ni; continue;
} }
@ -1963,7 +1950,7 @@ FRESULT create_name (
dp->fn[i++] = (BYTE)w; 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 (ni == 8) b <<= 2;
if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */ if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */
@ -1984,7 +1971,7 @@ FRESULT create_name (
const char *p; const char *p;
/* Create file name in directory form */ /* Create file name in directory form */
for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Skip duplicated separator */
sfn = dp->fn; sfn = dp->fn;
mem_set(sfn, ' ', 11); mem_set(sfn, ' ', 11);
si = i = b = 0; ni = 8; si = i = b = 0; ni = 8;
@ -2019,7 +2006,7 @@ FRESULT create_name (
#endif #endif
#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 */ d = (BYTE)p[si++]; /* Get 2nd byte */
if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */ if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
return FR_INVALID_NAME; return FR_INVALID_NAME;
@ -2185,7 +2172,7 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static 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:Valid FAT-BS, 1:Valid BS but not FAT, 2:Not a BS, 3:Disk error */
FATFS* fs, /* File system object */ 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 check if it is an FAT boot record or not */
) )
@ -2343,7 +2330,7 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
/* Get fsinfo if available */ /* Get fsinfo if available */
fs->fsi_flag = 0x80; fs->fsi_flag = 0x80;
#if (_FS_NOFSINFO & 3) != 3 #if (_FS_NOFSINFO & 3) != 3
if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo is 1 */ if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo == 1 */
&& LD_WORD(fs->win + BPB_FSInfo) == 1 && LD_WORD(fs->win + BPB_FSInfo) == 1
&& move_window(fs, bsect + 1) == FR_OK) && move_window(fs, bsect + 1) == FR_OK)
{ {
@ -2389,14 +2376,11 @@ FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
FIL *fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/DIR structure is identical */ 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) if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id || (disk_status(fil->fs->drv) & STA_NOINIT))
return FR_INVALID_OBJECT; return FR_INVALID_OBJECT;
ENTER_FF(fil->fs); /* Lock file system */ ENTER_FF(fil->fs); /* Lock file system */
if (disk_status(fil->fs->drv) & STA_NOINIT)
return FR_NOT_READY;
return FR_OK; return FR_OK;
} }
@ -2407,7 +2391,7 @@ FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
Public Functions Public Functions
--------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
@ -2522,12 +2506,13 @@ FRESULT f_open (
} }
} }
if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
dw = GET_FATTIME(); /* Created time */ dw = GET_FATTIME();
ST_DWORD(dir + DIR_CrtTime, dw); ST_DWORD(dir + DIR_CrtTime, dw);/* Set created time */
ST_DWORD(dir + DIR_WrtTime, dw);/* Set modified time */
dir[DIR_Attr] = 0; /* Reset attribute */ dir[DIR_Attr] = 0; /* Reset attribute */
ST_DWORD(dir + DIR_FileSize, 0);/* size = 0 */ ST_DWORD(dir + DIR_FileSize, 0);/* Reset file size */
cl = ld_clust(dj.fs, dir); /* Get start cluster */ cl = ld_clust(dj.fs, dir); /* Get cluster chain */
st_clust(dir, 0); /* cluster = 0 */ st_clust(dir, 0); /* Reset cluster */
dj.fs->wflag = 1; dj.fs->wflag = 1;
if (cl) { /* Remove the cluster chain if exist */ if (cl) { /* Remove the cluster chain if exist */
dw = dj.fs->winsect; dw = dj.fs->winsect;
@ -2540,7 +2525,7 @@ FRESULT f_open (
} }
} }
else { /* Open an existing file */ else { /* Open an existing file */
if (res == FR_OK) { /* Follow succeeded */ if (res == FR_OK) { /* Following succeeded */
if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */ if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */
res = FR_NO_FILE; res = FR_NO_FILE;
} else { } else {
@ -2832,10 +2817,9 @@ FRESULT f_sync (
res = validate(fp); /* Check validity of the object */ res = validate(fp); /* Check validity of the object */
if (res == FR_OK) { if (res == FR_OK) {
if (fp->flag & FA__WRITTEN) { /* Has the file been written? */ if (fp->flag & FA__WRITTEN) { /* Is there any change to the file? */
/* Write-back dirty buffer */
#if !_FS_TINY #if !_FS_TINY
if (fp->flag & FA__DIRTY) { if (fp->flag & FA__DIRTY) { /* Write-back cached data if needed */
if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
LEAVE_FF(fp->fs, FR_DISK_ERR); LEAVE_FF(fp->fs, FR_DISK_ERR);
fp->flag &= ~FA__DIRTY; fp->flag &= ~FA__DIRTY;
@ -2848,7 +2832,7 @@ FRESULT f_sync (
dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */ ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */
st_clust(dir, fp->sclust); /* Update start cluster */ st_clust(dir, fp->sclust); /* Update start cluster */
tm = GET_FATTIME(); /* Update updated time */ tm = GET_FATTIME(); /* Update modified time */
ST_DWORD(dir + DIR_WrtTime, tm); ST_DWORD(dir + DIR_WrtTime, tm);
ST_WORD(dir + DIR_LstAccDate, 0); ST_WORD(dir + DIR_LstAccDate, 0);
fp->flag &= ~FA__WRITTEN; fp->flag &= ~FA__WRITTEN;
@ -3425,7 +3409,7 @@ FRESULT f_getfree (
{ {
FRESULT res; FRESULT res;
FATFS *fs; FATFS *fs;
DWORD n, clst, sect, stat; DWORD nfree, clst, sect, stat;
UINT i; UINT i;
BYTE fat, *p; BYTE fat, *p;
@ -3440,18 +3424,17 @@ FRESULT f_getfree (
} else { } else {
/* Get number of free clusters */ /* Get number of free clusters */
fat = fs->fs_type; fat = fs->fs_type;
n = 0; nfree = 0;
if (fat == FS_FAT12) { if (fat == FS_FAT12) { /* Sector unalighed entries: Search FAT via regular routine. */
clst = 2; clst = 2;
do { do {
stat = get_fat(fs, clst); stat = get_fat(fs, clst);
if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
if (stat == 1) { res = FR_INT_ERR; break; } if (stat == 1) { res = FR_INT_ERR; break; }
if (stat == 0) n++; if (stat == 0) nfree++;
} while (++clst < fs->n_fatent); } while (++clst < fs->n_fatent);
} else { } else { /* Sector alighed entries: Accelerate the FAT search. */
clst = fs->n_fatent; clst = fs->n_fatent; sect = fs->fatbase;
sect = fs->fatbase;
i = 0; p = 0; i = 0; p = 0;
do { do {
if (!i) { if (!i) {
@ -3461,17 +3444,17 @@ FRESULT f_getfree (
i = SS(fs); i = SS(fs);
} }
if (fat == FS_FAT16) { if (fat == FS_FAT16) {
if (LD_WORD(p) == 0) n++; if (LD_WORD(p) == 0) nfree++;
p += 2; i -= 2; p += 2; i -= 2;
} else { } else {
if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++; if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) nfree++;
p += 4; i -= 4; p += 4; i -= 4;
} }
} while (--clst); } while (--clst);
} }
fs->free_clust = n; fs->free_clust = nfree; /* free_clust is valid */
fs->fsi_flag |= 1; fs->fsi_flag |= 1; /* FSInfo is to be updated */
*nclst = n; *nclst = nfree; /* Return the free clusters */
} }
} }
LEAVE_FF(fs, res); LEAVE_FF(fs, res);
@ -3695,8 +3678,7 @@ FRESULT f_chmod (
DEFINE_NAMEBUF; DEFINE_NAMEBUF;
/* Get logical drive number */ res = find_volume(&dj.fs, &path, 1); /* Get logical drive number */
res = find_volume(&dj.fs, &path, 1);
if (res == FR_OK) { if (res == FR_OK) {
INIT_BUF(dj); INIT_BUF(dj);
res = follow_path(&dj, path); /* Follow the file path */ res = follow_path(&dj, path); /* Follow the file path */
@ -4263,7 +4245,7 @@ FRESULT f_mkfs (
ST_WORD(tbl + BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ 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 */ if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */
return FR_DISK_ERR; 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); disk_write(pdrv, tbl, b_vol + 6, 1);
/* Initialize FAT area */ /* Initialize FAT area */

6
source/fatfs/ff.h Normal file → Executable file
View File

@ -1,5 +1,5 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - FAT file system module include R0.11 (C)ChaN, 2015 / FatFs - FAT file system module include R0.11a (C)ChaN, 2015
/----------------------------------------------------------------------------/ /----------------------------------------------------------------------------/
/ FatFs module is a free software that opened under license policy of / FatFs module is a free software that opened under license policy of
/ following conditions. / following conditions.
@ -17,7 +17,7 @@
#ifndef _FATFS #ifndef _FATFS
#define _FATFS 32020 /* Revision ID */ #define _FATFS 64180 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -200,7 +200,7 @@ typedef enum {
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ 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_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_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 */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
} FRESULT; } FRESULT;

49
source/fatfs/ffconf.h Normal file → Executable file
View File

@ -1,21 +1,13 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015 / FatFs - FAT file system module configuration file R0.11a (C)ChaN, 2015
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FFCONF 32020 /* Revision ID */ #define _FFCONF 64180 /* 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 #define _FS_READONLY 0
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) /* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(), / Read-only configuration removes writing API functions, f_write(), f_sync(),
@ -23,7 +15,7 @@
/ and optional writing functions as well. */ / and optional writing functions as well. */
#define _FS_MINIMIZE 0 #define _FS_MINIMIZE 1
/* This option defines minimization level to remove some basic API functions. /* This option defines minimization level to remove some basic API functions.
/ /
/ 0: All basic functions are enabled. / 0: All basic functions are enabled.
@ -77,19 +69,24 @@
/ 437 - U.S. / 437 - U.S.
/ 720 - Arabic / 720 - Arabic
/ 737 - Greek / 737 - Greek
/ 771 - KBL
/ 775 - Baltic / 775 - Baltic
/ 850 - Multilingual Latin 1 / 850 - Latin 1
/ 852 - Latin 2 / 852 - Latin 2
/ 855 - Cyrillic / 855 - Cyrillic
/ 857 - Turkish / 857 - Turkish
/ 858 - Multilingual Latin 1 + Euro / 860 - Portuguese
/ 861 - Icelandic
/ 862 - Hebrew / 862 - Hebrew
/ 863 - Canadian French
/ 864 - Arabic
/ 865 - Nordic
/ 866 - Russian / 866 - Russian
/ 874 - Thai / 869 - Greek 2
/ 932 - Japanese Shift_JIS (DBCS) / 932 - Japanese (DBCS)
/ 936 - Simplified Chinese GBK (DBCS) / 936 - Simplified Chinese (DBCS)
/ 949 - Korean (DBCS) / 949 - Korean (DBCS)
/ 950 - Traditional Chinese Big5 (DBCS) / 950 - Traditional Chinese (DBCS)
*/ */
@ -115,7 +112,7 @@
/ to 1. This option also affects behavior of string I/O functions. */ / to 1. This option also affects behavior of string I/O functions. */
#define _STRF_ENCODE 0 #define _STRF_ENCODE 3
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to /* When _LFN_UNICODE is 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(). / be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
/ /
@ -141,7 +138,7 @@
/ Drive/Volume Configurations / Drive/Volume Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _VOLUMES 1 #define _VOLUMES 2
/* Number of volumes (logical drives) to be used. */ /* Number of volumes (logical drives) to be used. */
@ -195,8 +192,16 @@
/ System Configurations / 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_NORTC 1 #define _FS_NORTC 1
#define _NORTC_MON 2 #define _NORTC_MON 1
#define _NORTC_MDAY 1 #define _NORTC_MDAY 1
#define _NORTC_YEAR 2015 #define _NORTC_YEAR 2015
/* The _FS_NORTC option switches timestamp feature. If the system does not have /* The _FS_NORTC option switches timestamp feature. If the system does not have
@ -253,7 +258,7 @@
/ * Byte order on the memory is little-endian. / * 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. / 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. / Following table shows allowable settings of some type of processors.
/ /
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2 / ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1 / Cortex-M3 0 *3 Z80 0/1 V850ES 0/1

10
source/fatfs/integer.h Normal file → Executable file
View File

@ -5,26 +5,26 @@
#ifndef _FF_INTEGER #ifndef _FF_INTEGER
#define _FF_INTEGER #define _FF_INTEGER
#ifdef _WIN32 /* FatFs development platform */ #ifdef _WIN32 /* Development platform */
#include <windows.h> #include <windows.h>
#include <tchar.h> #include <tchar.h>
#else /* Embedded platform */ #else /* Embedded platform */
/* This type MUST be 8 bit */ /* This type MUST be 8-bit */
typedef unsigned char BYTE; typedef unsigned char BYTE;
/* These types MUST be 16 bit */ /* These types MUST be 16-bit */
typedef short SHORT; typedef short SHORT;
typedef unsigned short WORD; typedef unsigned short WORD;
typedef unsigned short WCHAR; typedef unsigned short WCHAR;
/* These types MUST be 16 bit or 32 bit */ /* These types MUST be 16-bit or 32-bit */
typedef int INT; typedef int INT;
typedef unsigned int UINT; typedef unsigned int UINT;
/* These types MUST be 32 bit */ /* These types MUST be 32-bit */
typedef long LONG; typedef long LONG;
typedef unsigned long DWORD; typedef unsigned long DWORD;

348
source/fatfs/option/ccsbcs.c Executable file
View File

@ -0,0 +1,348 @@
/*------------------------------------------------------------------------*/
/* 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 */
)
{
static const WCHAR lower[] = { /* Lower case characters to be converted */
/* Latin Supplement */ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
/* Latin Extended-A */ 0x101,0x103,0x105,0x107,0x109,0x10B,0x10D,0x10F,0x111,0x113,0x115,0x117,0x119,0x11B,0x11D,0x11F,0x121,0x123,0x125,0x127,0x129,0x12B,0x12D,0x12F,0x131,0x133,0x135,0x137,0x13A,0x13C,0x13E,0x140,0x142,0x144,0x146,0x148,0x14B,0x14D,0x14F,0x151,0x153,0x155,0x157,0x159,0x15B,0x15D,0x15F,0x161,0x163,0x165,0x167,0x169,0x16B,0x16D,0x16F,0x171,0x173,0x175,0x177,0x17A,0x17C,0x17E,
/* Latin Extended-B */ 0x183,0x185,0x188,0x18C,0x192,0x199,0x1A1,0x1A3,0x1A8,0x1AD,0x1B0,0x1B4,0x1B6,0x1B9,0x1BD,0x1C6,0x1C9,0x1CC,0x1CE,0x1D0,0x1D2,0x1D4,0x1D6,0x1D8,0x1DA,0x1DC,0x1DD,0x1DF,0x1E1,0x1E3,0x1E5,0x1E7,0x1E9,0x1EB,0x1ED,0x1EF,0x1F3,0x1F5,0x1FB,0x1FD,0x1FF,0x201,0x203,0x205,0x207,0x209,0x20B,0x20D,0x20F,0x211,0x213,0x215,0x217,
/* Greek, Coptic */ 0x3B1,0x3B2,0x3B3,0x3B4,0x3B5,0x3B6,0x3B7,0x3B8,0x3B9,0x3BA,0x3BB,0x3BC,0x3BD,0x3BE,0x3BF,0x3C0,0x3C1,0x3C3,0x3C4,0x3C5,0x3C6,0x3C7,0x3C8,0x3C9,0x3CA,0x3CB,0x3CC,0x3CD,0x3CE,0x3E3,0x3E5,0x3E7,0x3E9,0x3EB,
/* Cyrillic */ 0x430,0x431,0x432,0x433,0x434,0x435,0x436,0x437,0x438,0x439,0x43A,0x43B,0x43C,0x43D,0x43E,0x43F,0x440,0x441,0x442,0x443,0x444,0x445,0x446,0x447,0x448,0x449,0x44A,0x44B,0x44C,0x44D,0x44E,0x44F,0x452,0x453,0x454,0x455,0x456,0x457,0x458,0x459,0x45A,0x45B,0x45C,0x45E,0x45F,0x461,0x463,0x465,0x467,0x469,0x46B,0x46D,0x46F,0x471,0x473,0x475,0x477,0x479,0x47B,0x47D,0x47F,0x481,0x491,0x493,0x495,0x497,0x499,0x49B,0x49D,0x49F,0x4A1,0x4A3,0x4A5,0x4A7,0x4A9,0x4AB,0x4AD,0x4AF,0x4B1,0x4B3,0x4B5,0x4B7,0x4B9,0x4BB,0x4BD,0x4BF,0x4C2,0x4C4,0x4C8,0x4D1,0x4D3,0x4D5,0x4D7,0x4D9,0x4DB,0x4DD,0x4DF,0x4E1,0x4E3,0x4E5,0x4E7,0x4E9,0x4EB,0x4ED,0x4EF,0x4F1,0x4F3,0x4F5,0x4F9,
/* Armenian */ 0x561,0x562,0x563,0x564,0x565,0x566,0x567,0x568,0x569,0x56A,0x56B,0x56C,0x56D,0x56E,0x56F,0x570,0x571,0x572,0x573,0x574,0x575,0x576,0x577,0x578,0x579,0x57A,0x57B,0x57C,0x57D,0x57E,0x57F,0x580,0x581,0x582,0x583,0x584,0x585,0x586,
/* Latin Extended Additional */ 0x1E01,0x1E03,0x1E05,0x1E07,0x1E09,0x1E0B,0x1E0D,0x1E0F,0x1E11,0x1E13,0x1E15,0x1E17,0x1E19,0x1E1B,0x1E1D,0x1E1F,0x1E21,0x1E23,0x1E25,0x1E27,0x1E29,0x1E2B,0x1E2D,0x1E2F,0x1E31,0x1E33,0x1E35,0x1E37,0x1E39,0x1E3B,0x1E3D,0x1E3F,0x1E41,0x1E43,0x1E45,0x1E47,0x1E49,0x1E4B,0x1E4D,0x1E4F,0x1E51,0x1E53,0x1E55,0x1E57,0x1E59,0x1E5B,0x1E5D,0x1E5F,0x1E61,0x1E63,0x1E65,0x1E67,0x1E69,0x1E6B,0x1E6D,0x1E6F,0x1E71,0x1E73,0x1E75,0x1E77,0x1E79,0x1E7B,0x1E7D,0x1E7F,0x1E81,0x1E83,0x1E85,0x1E87,0x1E89,0x1E8B,0x1E8D,0x1E8F,0x1E91,0x1E93,0x1E95,0x1E97,0x1E99,0x1E9B,0x1E9D,0x1E9F,0x1EA1,0x1EA3,0x1EA5,0x1EA7,0x1EA9,0x1EAB,0x1EAD,0x1EAF,0x1EB1,0x1EB3,0x1EB5,0x1EB7,0x1EB9,0x1EBB,0x1EBD,0x1EBF,0x1EC1,0x1EC3,0x1EC5,0x1EC7,0x1EC9,0x1ECB,0x1ECD,0x1ECF,0x1ED1,0x1ED3,0x1ED5,0x1ED7,0x1ED9,0x1EDB,0x1EDD,0x1EDF,0x1EE1,0x1EE3,0x1EE5,0x1EE7,0x1EE9,0x1EEB,0x1EED,0x1EEF,0x1EF1,0x1EF3,0x1EF5,0x1EF7,0x1EF9,
/* Number forms */ 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,0x217A,0x217B,0x217C,0x217D,0x217E,0x217F,
/* Full-width */ 0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,0xFF58,0xFF59,0xFF5A
};
static const WCHAR upper[] = { /* Upper case characters correspond to lower[] */
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x178,
0x100,0x102,0x104,0x106,0x108,0x10A,0x10C,0x10E,0x110,0x112,0x114,0x116,0x118,0x11A,0x11C,0x11E,0x120,0x122,0x124,0x126,0x128,0x12A,0x12C,0x12E,0x130,0x132,0x134,0x136,0x139,0x13B,0x13D,0x13F,0x141,0x143,0x145,0x147,0x14A,0x14C,0x14E,0x150,0x152,0x154,0x156,0x158,0x15A,0x15C,0x15E,0x160,0x162,0x164,0x166,0x168,0x16A,0x16C,0x16E,0x170,0x172,0x174,0x176,0x179,0x17B,0x17D,
0x182,0x184,0x187,0x18B,0x191,0x198,0x1A0,0x1A2,0x1A7,0x1AC,0x1AF,0x1B3,0x1B5,0x1B8,0x1BC,0x1C4,0x1C7,0x1CA,0x1CD,0x1CF,0x1D1,0x1D3,0x1D5,0x1D7,0x1D9,0x1DB,0x18E,0x1DE,0x1E0,0x1E2,0x1E4,0x1E6,0x1E8,0x1EA,0x1EC,0x1EE,0x1F1,0x1F4,0x1FA,0x1FC,0x1FE,0x200,0x202,0x204,0x206,0x208,0x20A,0x20C,0x20E,0x210,0x212,0x214,0x216,
0x391,0x392,0x393,0x394,0x395,0x396,0x397,0x398,0x399,0x39A,0x39B,0x39C,0x39D,0x39E,0x39F,0x3A0,0x3A1,0x3A3,0x3A4,0x3A5,0x3A6,0x3A7,0x3A8,0x3A9,0x3AA,0x3AB,0x38C,0x38E,0x38F,0x3E2,0x3E4,0x3E6,0x3E8,0x3EA,
0x410,0x411,0x412,0x413,0x414,0x415,0x416,0x417,0x418,0x419,0x41A,0x41B,0x41C,0x41D,0x41E,0x41F,0x420,0x421,0x422,0x423,0x424,0x425,0x426,0x427,0x428,0x429,0x42A,0x42B,0x42C,0x42D,0x42E,0x42F,0x402,0x403,0x404,0x405,0x406,0x407,0x408,0x409,0x40A,0x40B,0x40C,0x40E,0x40F,0x460,0x462,0x464,0x466,0x468,0x46A,0x46C,0x46E,0x470,0x472,0x474,0x476,0x478,0x47A,0x47C,0x47E,0x480,0x490,0x492,0x494,0x496,0x498,0x49A,0x49C,0x49E,0x4A0,0x4A2,0x4A4,0x4A6,0x4A8,0x4AA,0x4AC,0x4AE,0x4B0,0x4B2,0x4B4,0x4B6,0x4B8,0x4BA,0x4BC,0x4BE,0x4C1,0x4C3,0x5C7,0x4D0,0x4D2,0x4D4,0x4D6,0x4D8,0x4DA,0x4DC,0x4DE,0x4E0,0x4E2,0x4E4,0x4E6,0x4E8,0x4EA,0x4EC,0x4EE,0x4F0,0x4F2,0x4F4,0x4F8,
0x531,0x532,0x533,0x534,0x535,0x536,0x537,0x538,0x539,0x53A,0x53B,0x53C,0x53D,0x53E,0x53F,0x540,0x541,0x542,0x543,0x544,0x545,0x546,0x547,0x548,0x549,0x54A,0x54B,0x54C,0x54D,0x54E,0x54F,0x550,0x551,0x552,0x553,0x554,0x555,0x556,
0x1E00,0x1E02,0x1E04,0x1E06,0x1E08,0x1E0A,0x1E0C,0x1E0E,0x1E10,0x1E12,0x1E14,0x1E16,0x1E18,0x1E1A,0x1E1C,0x1E1E,0x1E20,0x1E22,0x1E24,0x1E26,0x1E28,0x1E2A,0x1E2C,0x1E2E,0x1E30,0x1E32,0x1E34,0x1E36,0x1E38,0x1E3A,0x1E3C,0x1E3E,0x1E40,0x1E42,0x1E44,0x1E46,0x1E48,0x1E4A,0x1E4C,0x1E4E,0x1E50,0x1E52,0x1E54,0x1E56,0x1E58,0x1E5A,0x1E5C,0x1E5E,0x1E60,0x1E62,0x1E64,0x1E66,0x1E68,0x1E6A,0x1E6C,0x1E6E,0x1E70,0x1E72,0x1E74,0x1E76,0x1E78,0x1E7A,0x1E7C,0x1E7E,0x1E80,0x1E82,0x1E84,0x1E86,0x1E88,0x1E8A,0x1E8C,0x1E8E,0x1E90,0x1E92,0x1E94,0x1E96,0x1E98,0x1E9A,0x1E9C,0x1E9E,0x1EA0,0x1EA2,0x1EA4,0x1EA6,0x1EA8,0x1EAA,0x1EAC,0x1EAE,0x1EB0,0x1EB2,0x1EB4,0x1EB6,0x1EB8,0x1EBA,0x1EBC,0x1EBE,0x1EC0,0x1EC2,0x1EC4,0x1EC6,0x1EC8,0x1ECA,0x1ECC,0x1ECE,0x1ED0,0x1ED2,0x1ED4,0x1ED6,0x1ED8,0x1EDA,0x1EDC,0x1EDE,0x1EE0,0x1EE2,0x1EE4,0x1EE6,0x1EE8,0x1EEA,0x1EEC,0x1EEE,0x1EF0,0x1EF2,0x1EF4,0x1EF6,0x1EF8,
0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216A,0x216B,0x216C,0x216D,0x216E,0x216F,
0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,0xFF39,0xFF3A
};
UINT i, n, hi, li;
if (chr < 0x80) { /* ASCII characters (acceleration) */
if (chr >= 0x61 && chr <= 0x7A) chr -= 0x20;
} else { /* Non ASCII characters (table search) */
n = 12; li = 0; hi = sizeof lower / sizeof lower[0];
do {
i = li + (hi - li) / 2;
if (chr == lower[i]) break;
if (chr > lower[i]) li = i; else hi = i;
} while (--n);
if (n) chr = upper[i];
}
return chr;
}

View File

@ -2,3 +2,4 @@
#include <stdbool.h> #include <stdbool.h>
#include "../../types.h" #include "../../types.h"
#include "../../crypto.h"

View File

@ -402,3 +402,44 @@ int sdmmc_sdcard_init()
return result | SD_Init(); return result | 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;
}

View File

@ -122,6 +122,7 @@ int sdmmc_sdcard_init();
u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out); u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
u32 sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in); u32 sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in);
mmcdevice *getMMCDevice(int drive); mmcdevice *getMMCDevice(int drive);
int sdmmc_get_cid( int isNand, uint32_t *info);
u32 sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out); u32 sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
u32 sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, vu8 *in); u32 sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, vu8 *in);

View File

@ -18,46 +18,36 @@
#include "buttons.h" #include "buttons.h"
#include "../build/patches.h" #include "../build/patches.h"
//FIRM patches version
#define PATCH_VER 4
static firmHeader *const firm = (firmHeader *)0x24000000; static firmHeader *const firm = (firmHeader *)0x24000000;
static const firmSectionHeader *section; static const firmSectionHeader *section;
static u8 *arm9Section;
static const char *patchedFirms[] = { "/aurei/patched_firmware_sys.bin", static const char *firmFolders[3][2] = {{ "00000002", "20000002" },
"/aurei/patched_firmware_emu.bin", { "00000102", "20000102" },
"/aurei/patched_firmware_em2.bin", { "00000202", "20000202" }};
"/aurei/patched_firmware90.bin", u32 config,
"/aurei/patched_firmware_twl.bin",
"/aurei/patched_firmware_agb.bin" };
u32 config;
static u32 firmSize,
console, console,
mode,
emuNAND,
a9lhSetup,
selectedFirm,
usePatchedFirm,
emuOffset, emuOffset,
emuHeader; firmSource;
void setupCFW(void) void main(void)
{ {
//Determine if booting with A9LH u32 bootType,
u32 a9lhBoot = !PDN_SPI_CNT ? 1 : 0; firmType,
nandType,
//Retrieve the last booted FIRM a9lhInstalled,
u32 previousFirm = CFG_BOOTENV; updatedSys,
needConfig,
newConfig,
emuHeader;
//Detect the console being used //Detect the console being used
console = (PDN_MPCORE_CFG == 1) ? 0 : 1; console = (PDN_MPCORE_CFG == 1) ? 0 : 1;
//Get pressed buttons //Mount filesystems. CTRNAND will be mounted only if/when needed
u32 pressed = HID_PAD; mountFs();
//Attempt to read the configuration file //Attempt to read the configuration file
const char configPath[] = "/aurei/config.bin"; const char configPath[] = "/aurei/config.bin";
u32 needConfig;
if(fileRead(&config, configPath, 3)) needConfig = 1; if(fileRead(&config, configPath, 3)) needConfig = 1;
else else
{ {
@ -65,26 +55,54 @@ void setupCFW(void)
needConfig = 2; needConfig = 2;
} }
//Determine if A9LH is installed and the user has an updated sysNAND //Determine if this is a firmlaunch boot
u32 updatedSys; if(*(vu8 *)0x23F00005)
{
bootType = 1;
//'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
firmType = *(vu8 *)0x23F00005 - 0x2F;
nandType = CONFIG(16, 3);
firmSource = CONFIG(18, 1);
a9lhInstalled = CONFIG(19, 1);
updatedSys = (a9lhInstalled && CONFIG(1, 1)) ? 1 : 0;
}
else
{
bootType = 0;
firmType = 1;
//Determine if booting with A9LH
u32 a9lhBoot = !PDN_SPI_CNT ? 1 : 0;
//Retrieve the last booted FIRM
u32 previousFirm = CFG_BOOTENV;
//Get pressed buttons
u32 pressed = HID_PAD;
//Determine if we need to autoboot sysNAND
u32 autoBootSys = CONFIG(0, 1);
//Determine if A9LH is installed and the user has an updated sysNAND
if(a9lhBoot || CONFIG(2, 1)) if(a9lhBoot || CONFIG(2, 1))
{ {
if(pressed == SAFE_MODE) if(pressed == SAFE_MODE)
error("Using Safe Mode would brick you, or remove A9LH!"); error("Using Safe Mode would brick you, or remove A9LH!");
a9lhSetup = 1; a9lhInstalled = 1;
//Check setting for > 9.2 sysNAND //Check setting for > 9.2 sysNAND
updatedSys = CONFIG(0, 1); updatedSys = CONFIG(1, 1);
} }
else else
{ {
a9lhSetup = 0; a9lhInstalled = 0;
updatedSys = 0; updatedSys = 0;
} }
u32 tempConfig = (PATCH_VER << 17) | (a9lhSetup << 16); newConfig = a9lhInstalled << 19;
/* If booting with A9LH, it's a MCU reboot and a previous configuration exists, /* If booting with A9LH, it's a MCU reboot and a previous configuration exists,
try to force boot options */ try to force boot options */
@ -93,19 +111,19 @@ void setupCFW(void)
//Always force a sysNAND boot when quitting AGB_FIRM //Always force a sysNAND boot when quitting AGB_FIRM
if(previousFirm == 7) if(previousFirm == 7)
{ {
mode = updatedSys ? 1 : CONFIG(12, 1); nandType = 0;
emuNAND = 0; firmSource = updatedSys ? 0 : CONFIG(18, 1);
needConfig = 0; needConfig = 0;
//Flag to prevent multiple boot options-forcing //Flag to prevent multiple boot options-forcing
tempConfig |= 1 << 15; newConfig |= 1 << 20;
} }
/* Else, force the last used boot options unless a payload button or A/L/R are pressed /* Else, force the last used boot options unless a payload button or A/L/R are pressed
or the no-forcing flag is set */ or the no-forcing flag is set */
else if(!(pressed & OVERRIDE_BUTTONS) && !CONFIG(15, 1)) else if(!(pressed & OVERRIDE_BUTTONS) && !CONFIG(20, 1))
{ {
mode = CONFIG(12, 1); nandType = CONFIG(16, 3);
emuNAND = CONFIG(13, 3); firmSource = CONFIG(18, 1);
needConfig = 0; needConfig = 0;
} }
} }
@ -121,187 +139,147 @@ void setupCFW(void)
//If no configuration file exists or SELECT is held, load configuration menu //If no configuration file exists or SELECT is held, load configuration menu
if(needConfig == 2 || (pressed & BUTTON_SELECT)) if(needConfig == 2 || (pressed & BUTTON_SELECT))
configureCFW(configPath, patchedFirms); configureCFW(configPath);
//If screens are inited or the corresponding option is set, load splash screen //If screens are inited or the corresponding option is set, load splash screen
if(PDN_GPU_CNT != 1 || CONFIG(7, 1)) loadSplash(); if(PDN_GPU_CNT != 1 || CONFIG(6, 1)) loadSplash();
/* If L is pressed, or L or R are not pressed when it is the default FIRM, //Determine if we need to boot an emuNAND or sysNAND
boot 9.0 FIRM */ nandType = (pressed & BUTTON_L1) ? autoBootSys : ((pressed & BUTTON_R1) ? updatedSys : !autoBootSys);
mode = CONFIG(3, 1) ? ((!(pressed & BUTTON_L1R1)) ? 0 : 1) :
((pressed & BUTTON_L1) ? 0 : 1);
/* If L or R aren't pressed on a 9.0/9.2 sysNAND, or the 9.0 FIRM is selected /* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
or R is pressed on a > 9.2 sysNAND, boot emuNAND */ or vice-versa, boot the second emuNAND */
if((updatedSys && (!mode || (pressed & BUTTON_R1))) || (!updatedSys && mode && !(pressed & BUTTON_R1))) if(nandType && ((!(pressed & BUTTON_B)) == CONFIG(3, 1))) nandType++;
//Determine the NAND we should take the FIRM from
firmSource = (pressed & BUTTON_R1) ? !nandType : (nandType != 0);
}
}
//If we need to boot emuNAND, make sure it exists
if(nandType)
{ {
/* If not 9.0 FIRM and the second emuNAND is set as default and B isn't pressed, or vice-versa, getEmunandSect(&emuOffset, &emuHeader, &nandType);
attempt to boot it */ if(!nandType) firmSource = 0;
emuNAND = (mode && ((!(pressed & BUTTON_B)) == CONFIG(4, 1))) ? 2 : 1;
}
else emuNAND = 0;
/* If tha FIRM patches version is different or user switched to/from A9LH,
delete all patched FIRMs */
if((tempConfig & 0xFF0000) != (config & 0xFF0000))
deleteFirms(patchedFirms, sizeof(patchedFirms) / sizeof(char *));
} }
u32 usePatchedFirmSet = CONFIG(1, 1); //Same if we're using emuNAND as the FIRM source
else if(firmSource)
getEmunandSect(&emuOffset, &emuHeader, &firmSource);
while(1) if(!bootType)
{ {
/* Determine which patched FIRM we need to write or attempt to use (if any). newConfig |= (nandType << 16) | (firmSource << 18);
Patched 9.0 FIRM is only needed if "Use pre-patched FIRMs" is set */
selectedFirm = mode ? (emuNAND ? (emuNAND == 1 ? 2 : 3) : 1) :
(usePatchedFirmSet ? 4 : 0);
//If "Use pre-patched FIRMs" is set and the appropriate FIRM exists, use it
if(usePatchedFirmSet && fileExists(patchedFirms[selectedFirm - 1]))
usePatchedFirm = 1;
/* If the user is booting EmuNAND but the chosen one is not found,
force 9.6/10.x FIRM and re-detect the patched FIRMs */
else if(emuNAND && !getEmunandSect(&emuOffset, &emuHeader, &emuNAND))
{
mode = 1;
continue;
}
break;
}
tempConfig |= (emuNAND << 13) | (mode << 12);
/* If the boot configuration is different from previously, overwrite it. /* If the boot configuration is different from previously, overwrite it.
Just the no-forcing flag being set is not enough */ Just the no-forcing flag being set is not enough */
if((tempConfig & 0xFF7000) != (config & 0xFFF000)) if((newConfig & 0xEF0000) != (config & 0xFF0000))
{ {
//Preserve user settings (first 12 bits) //Preserve user settings (first 2 bytes)
tempConfig |= config & 0xFFF; newConfig |= config & 0xFFFF;
fileWrite(&tempConfig, configPath, 3); fileWrite(&newConfig, configPath, 3);
} }
} }
loadFirm(firmType, firmType == 1 && (nandType == 2 || updatedSys == !nandType));
if(firmType == 1) patchNativeFirm(firmType, nandType, emuHeader, a9lhInstalled);
else patchTwlAgbFirm(firmType);
launchFirm(bootType);
}
//Load FIRM into FCRAM //Load FIRM into FCRAM
void loadFirm(void) static inline void loadFirm(u32 firmType, u32 externalFirm)
{ {
//If not using an A9LH setup or the patched FIRM, load 9.0 FIRM from NAND u32 firmSize;
if(!usePatchedFirm && !a9lhSetup && !mode)
{
//Read FIRM from NAND and write to FCRAM
firmSize = console ? 0xF2000 : 0xE9000;
nandFirm0((u8 *)firm, firmSize, console);
//Check for correct decryption
if(memcmp(firm, "FIRM", 4) != 0)
error("Couldn't decrypt NAND FIRM0 (O3DS not on 9.x?)");
}
//Load FIRM from SD
else
{
const char *path = usePatchedFirm ? patchedFirms[selectedFirm - 1] :
(mode ? "/aurei/firmware.bin" : "/aurei/firmware90.bin");
firmSize = fileSize(path);
if(!firmSize) error(mode ? "aurei/firmware.bin doesn't exist" :
"aurei/firmware90.bin doesn't exist");
fileRead(firm, path, firmSize);
}
section = firm->section; section = firm->section;
if(externalFirm)
{
const char *path = "/aurei/firmware.bin";
firmSize = fileSize(path);
if(firmSize)
{
fileRead(firm, path, firmSize);
//Check that the loaded FIRM matches the console //Check that the loaded FIRM matches the console
if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68)) if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68))
error(mode ? "aurei/firmware.bin doesn't match this console,\nor it's encrypted" : error("aurei/firmware.bin doesn't match this console,\nor it's encrypted");
"aurei/firmware90.bin doesn't match this console,\nor it's encrypted"); }
}
else firmSize = 0;
arm9Section = (u8 *)firm + section[2].offset; if(!firmSize)
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
if(console && !usePatchedFirm)
{ {
decryptArm9Bin(arm9Section, mode); firmRead((u8 *)firm, firmFolders[firmType - 1][console]);
firm->arm9Entry = (u8 *)0x801B01C; decryptExeFs((u8 *)firm);
} }
} }
static inline void patchTwlAgb(u32 whichFirm) static inline void patchNativeFirm(u32 firmType, u32 nandType, u32 emuHeader, u32 a9lhInstalled)
{ {
static firmHeader *const twlAgbFirm = (firmHeader *)0x25000000; u8 *arm9Section = (u8 *)firm + section[2].offset;
const char *path = whichFirm ? "/aurei/firmware_agb.bin" : "/aurei/firmware_twl.bin";
u32 size = fileSize(path);
//Skip patching if the file doesn't exist
if(!size) return;
fileRead(twlAgbFirm, path, size);
static const firmSectionHeader *twlAgbSection = twlAgbFirm->section;
//Check that the loaded FIRM matches the console
if((((u32)twlAgbSection[3].address >> 8) & 0xFF) != (console ? 0x60 : 0x68))
error(whichFirm ? "aurei/firmware_agb.bin doesn't match this\nconsole, or it's encrypted" :
"aurei/firmware_twl.bin doesn't match this\nconsole, or it's encrypted");
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
if(console) if(console)
{ {
decryptArm9Bin((u8 *)twlAgbFirm + twlAgbSection[3].offset, 0); //Determine if we're booting the 9.0 FIRM
twlAgbFirm->arm9Entry = (u8 *)0x801301C; if(arm9Section[0x51] == 0xFF) firmType--;
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
arm9Loader((u8 *)firm + section[2].offset, firmType);
firm->arm9Entry = (u8 *)0x801B01C;
} }
else
static const patchData twlPatches[] = {
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
{{0x173A0E, 0x17474A}, { .type1 = 0x2001 }, 1},
{{0x174802, 0x17553E}, { .type1 = 0x2000 }, 2},
{{0x174964, 0x1756A0}, { .type1 = 0x2000 }, 2},
{{0x174D52, 0x175A8E}, { .type1 = 0x2001 }, 2},
{{0x174D5E, 0x175A9A}, { .type1 = 0x2001 }, 2},
{{0x174D6A, 0x175AA6}, { .type1 = 0x2001 }, 2},
{{0x174E56, 0x175B92}, { .type1 = 0x2001 }, 1},
{{0x174E58, 0x175B94}, { .type1 = 0x4770 }, 1}
},
agbPatches[] = {
{{0x9D2A8, 0x9DF64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
{{0xD7A12, 0xD8B8A}, { .type1 = 0xEF26 }, 1}
};
/* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
if the matching option was enabled (keep it as last) */
u32 numPatches = whichFirm ? (sizeof(agbPatches) / sizeof(patchData) - !CONFIG(6, 1)) :
(sizeof(twlPatches) / sizeof(patchData));
const patchData *patches = whichFirm ? agbPatches : twlPatches;
//Patch
for(u32 i = 0; i < numPatches; i++)
{ {
switch(patches[i].type) //Determine if we're booting the 9.0 FIRM
{ u8 firm90Hash[0x10] = {0x27, 0x2D, 0xFE, 0xEB, 0xAF, 0x3F, 0x6B, 0x3B, 0xF5, 0xDE, 0x4C, 0x41, 0xDE, 0x95, 0x27, 0x6A};
case 0: if(memcmp(section[2].hash, firm90Hash, 0x10) == 0) firmType--;
memcpy((u8 *)twlAgbFirm + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
break;
case 2:
*(u16 *)((u8 *)twlAgbFirm + patches[i].offset[console] + 2) = 0;
case 1:
*(u16 *)((u8 *)twlAgbFirm + patches[i].offset[console]) = patches[i].patch.type1;
break;
}
} }
fileWrite(twlAgbFirm, whichFirm ? patchedFirms[5] : patchedFirms[4], size); if(firmType == 1 || nandType)
{
//Find the Process9 NCCH location
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
//Apply emuNAND patches
if(nandType) patchEmuNAND(arm9Section, proc9Offset, emuHeader);
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax
if(firmType == 1) patchReboots(arm9Section, proc9Offset);
} }
//NAND redirection //Apply FIRM0/1 writes patches on sysNAND to protect A9LH
static inline void patchEmuNAND(u8 *proc9Offset) if(a9lhInstalled && !nandType)
{ {
//Copy emuNAND code u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
*writeOffset = writeBlock[0];
*(writeOffset + 1) = writeBlock[1];
}
//Apply signature checks patches
u32 sigOffset,
sigOffset2;
getSigChecks(arm9Section, section[2].size, &sigOffset, &sigOffset2);
*(u16 *)sigOffset = sigPatch[0];
*(u16 *)sigOffset2 = sigPatch[0];
*((u16 *)sigOffset2 + 1) = sigPatch[1];
//Replace the FIRM loader with the injector
injectLoader();
}
static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader)
{
//Copy nandType code
void *emuCodeOffset = getEmuCode(proc9Offset); void *emuCodeOffset = getEmuCode(proc9Offset);
memcpy(emuCodeOffset, emunand, emunand_size); memcpy(emuCodeOffset, emunand, emunand_size);
//Add the data of the found emuNAND //Add the data of the found nandType
u32 *pos_offset = (u32 *)memsearch(emuCodeOffset, "NAND", emunand_size, 4); u32 *pos_offset = (u32 *)memsearch(emuCodeOffset, "NAND", emunand_size, 4);
u32 *pos_header = (u32 *)memsearch(emuCodeOffset, "NCSD", emunand_size, 4); u32 *pos_header = (u32 *)memsearch(emuCodeOffset, "NCSD", emunand_size, 4);
*pos_offset = emuOffset; *pos_offset = emuOffset;
@ -334,7 +312,7 @@ static inline void patchEmuNAND(u8 *proc9Offset)
*(mpuOffset + 9) = mpuPatch[2]; *(mpuOffset + 9) = mpuPatch[2];
} }
static inline void patchReboots(u8 *proc9Offset) static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset)
{ {
//Calculate offset for the firmlaunch code //Calculate offset for the firmlaunch code
void *rebootOffset = getReboot(arm9Section, section[2].size); void *rebootOffset = getReboot(arm9Section, section[2].size);
@ -348,13 +326,6 @@ static inline void patchReboots(u8 *proc9Offset)
//Put the fOpen offset in the right location //Put the fOpen offset in the right location
u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4); u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4);
*pos_fopen = fOpenOffset; *pos_fopen = fOpenOffset;
//Patch path for emuNAND-patched FIRM
if(emuNAND)
{
void *pos_path = memsearch(rebootOffset, L"sy", reboot_size, 4);
memcpy(pos_path, emuNAND == 1 ? L"emu" : L"em2", 5);
}
} }
static inline void injectLoader(void) static inline void injectLoader(void)
@ -376,71 +347,70 @@ static inline void injectLoader(void)
} }
} }
//Patches static inline void patchTwlAgbFirm(u32 firmType)
void patchFirm(void)
{ {
if(mode) //On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
if(console)
{ {
//Only patch AGB_FIRM/TWL_FIRM if the patched ones don't already exist arm9Loader((u8 *)firm + section[3].offset, 0);
if(!fileExists(patchedFirms[4])) patchTwlAgb(0); firm->arm9Entry = (u8 *)0x801301C;
if(!fileExists(patchedFirms[5])) patchTwlAgb(1);
} }
//Skip patching static const patchData twlPatches[] = {
if(usePatchedFirm) return; {{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
{{0x173A0E, 0x17474A}, { .type1 = 0x2001 }, 1},
{{0x174802, 0x17553E}, { .type1 = 0x2000 }, 2},
{{0x174964, 0x1756A0}, { .type1 = 0x2000 }, 2},
{{0x174D52, 0x175A8E}, { .type1 = 0x2001 }, 2},
{{0x174D5E, 0x175A9A}, { .type1 = 0x2001 }, 2},
{{0x174D6A, 0x175AA6}, { .type1 = 0x2001 }, 2},
{{0x174E56, 0x175B92}, { .type1 = 0x2001 }, 1},
{{0x174E58, 0x175B94}, { .type1 = 0x4770 }, 1}
},
agbPatches[] = {
{{0x9D2A8, 0x9DF64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
{{0xD7A12, 0xD8B8A}, { .type1 = 0xEF26 }, 1}
};
if(mode || emuNAND) /* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
if the matching option was enabled (keep it as last) */
u32 numPatches = firmType == 2 ? (sizeof(twlPatches) / sizeof(patchData)) : (sizeof(agbPatches) / sizeof(patchData) - !CONFIG(5, 1));
const patchData *patches = firmType == 2 ? twlPatches : agbPatches;
//Patch
for(u32 i = 0; i < numPatches; i++)
{ {
//Find the Process9 NCCH location switch(patches[i].type)
u8 *proc9Offset = getProc9(arm9Section, section[2].size); {
case 0:
//Apply emuNAND patches memcpy((u8 *)firm + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
if(emuNAND) patchEmuNAND(proc9Offset); break;
case 2:
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax *(u16 *)((u8 *)firm + patches[i].offset[console] + 2) = 0;
if(mode) patchReboots(proc9Offset); case 1:
*(u16 *)((u8 *)firm + patches[i].offset[console]) = patches[i].patch.type1;
break;
}
}
} }
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH static inline void launchFirm(u32 bootType)
if(a9lhSetup && !emuNAND)
{ {
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
*writeOffset = writeBlock[0];
*(writeOffset + 1) = writeBlock[1];
}
//Apply signature checks patches
u32 sigOffset,
sigOffset2;
getSigChecks(arm9Section, section[2].size, &sigOffset, &sigOffset2);
*(u16 *)sigOffset = sigPatch[0];
*(u16 *)sigOffset2 = sigPatch[0];
*((u16 *)sigOffset2 + 1) = sigPatch[1];
//Replace the FIRM loader with the injector
injectLoader();
//Write patched FIRM to SD if needed
if(selectedFirm)
if(!fileWrite(firm, patchedFirms[selectedFirm - 1], firmSize))
error("Couldn't write the patched FIRM (no free space?)");
}
void launchFirm(void)
{
if(console && mode) setKeyXs(arm9Section);
//Copy firm partitions to respective memory locations //Copy firm partitions to respective memory locations
memcpy(section[0].address, (u8 *)firm + section[0].offset, section[0].size); for(u32 i = 0; i < 4 && section[i].size; i++)
memcpy(section[1].address, (u8 *)firm + section[1].offset, section[1].size); memcpy(section[i].address, (u8 *)firm + section[i].offset, section[i].size);
memcpy(section[2].address, arm9Section, section[2].size);
//Fixes N3DS 3D //Determine the ARM11 entry to use
vu32 *arm11;
if(bootType) arm11 = (u32 *)0x1FFFFFFC;
else
{
deinitScreens(); deinitScreens();
arm11 = (u32 *)0x1FFFFFF8;
}
//Set ARM11 kernel entrypoint //Set ARM11 kernel entrypoint
*(vu32 *)0x1FFFFFF8 = (u32)firm->arm11Entry; *arm11 = (u32)firm->arm11Entry;
//Final jump to arm9 kernel //Final jump to arm9 kernel
((void (*)())firm->arm9Entry)(); ((void (*)())firm->arm9Entry)();

View File

@ -38,7 +38,10 @@ typedef struct patchData {
u32 type; u32 type;
} patchData; } patchData;
void setupCFW(void); static inline void loadFirm(u32 firmType, u32 externalFirm);
void loadFirm(void); static inline void patchNativeFirm(u32 firmType, u32 emuNAND, u32 emuHeader, u32 a9lhSetup);
void patchFirm(void); static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader);
void launchFirm(void); static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset);
static inline void injectLoader(void);
static inline void patchTwlAgbFirm(u32 firmType);
static inline void launchFirm(u32 bootType);

View File

@ -5,13 +5,16 @@
*/ */
#include "fs.h" #include "fs.h"
#include "memory.h"
#include "fatfs/ff.h" #include "fatfs/ff.h"
static FATFS fs; static FATFS sdFs,
nandFs;
u32 mountSD(void) u32 mountFs(void)
{ {
if(f_mount(&fs, "0:", 1) != FR_OK) return 0; if(f_mount(&sdFs, "0:", 1) != FR_OK) return 0;
f_mount(&nandFs, "1:", 0);
return 1; return 1;
} }
@ -68,7 +71,58 @@ u32 fileExists(const char *path)
return exists; return exists;
} }
void fileDelete(const char *path) void firmRead(u8 *dest, const char *firmFolder)
{ {
f_unlink(path); char path[48] = "1:/title/00040138/00000000/content";
memcpy(&path[18], firmFolder, 8);
DIR dir;
FILINFO info = { .lfname = NULL };
f_opendir(&dir, path);
u32 id = 0;
//Parse the target directory
while(f_readdir(&dir, &info) == FR_OK)
{
//We've parsed the whole folder
if(!info.fname[0]) break;
//Not a cxi
if(info.fname[9] != 'a' && info.fname[9] != 'A') continue;
//Convert the .app name to an integer
u32 tempId = 0;
for(char *tmp = info.fname; (*tmp) != '.'; tmp++)
{
if((*tmp) > '9') tempId = (tempId << 4) + ((*tmp) - 'A') + 9;
else tempId = (tempId << 4) + (*tmp) - '0';
}
//Found a newer cxi
if(tempId > id) id = tempId;
}
f_closedir(&dir);
//Complete the string with the .app name
memcpy(&path[34], "/00000000.app", 14);
//Last digit of the .app
u32 i = 42;
//Convert back the .app name from integer to array
while(id > 15)
{
u32 remainder = (id % 16);
if(remainder > 9) path[i] = remainder - 9 + 'A';
else path[i] = remainder + '0';
id /= 16;
i--;
}
if(id > 9) path[i] = id - 9 + 'A';
else path[i] = id + '0';
fileRead(dest, path, 0);
} }

View File

@ -8,9 +8,9 @@
#include "types.h" #include "types.h"
u32 mountSD(void); u32 mountFs(void);
u32 fileRead(void *dest, const char *path, u32 size); u32 fileRead(void *dest, const char *path, u32 size);
u32 fileWrite(const void *buffer, const char *path, u32 size); u32 fileWrite(const void *buffer, const char *path, u32 size);
u32 fileSize(const char *path); u32 fileSize(const char *path);
u32 fileExists(const char *path); u32 fileExists(const char *path);
void fileDelete(const char *path); void firmRead(u8 *dest, const char *firmFolder);

View File

@ -1,19 +0,0 @@
/*
* main.c
* by Reisyukaku / Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*
* Minimalist CFW for (N)3DS
*/
#include "fs.h"
#include "firm.h"
void main(void)
{
mountSD();
setupCFW();
loadFirm();
patchFirm();
launchFirm();
}

View File

@ -16,7 +16,7 @@
#define SCREENINIT_ADDRESS 0x24F03000 #define SCREENINIT_ADDRESS 0x24F03000
static vu32 *const arm11 = (u32 *)0x1FFFFFF8; vu32 *arm11Entry = (u32 *)0x1FFFFFF8;
void deinitScreens(void) void deinitScreens(void)
{ {
@ -26,7 +26,7 @@ void deinitScreens(void)
__asm(".word 0xF10C01C0"); __asm(".word 0xF10C01C0");
//Clear ARM11 entry offset //Clear ARM11 entry offset
*arm11 = 0; *arm11Entry = 0;
//Shutdown LCDs //Shutdown LCDs
*(vu32 *)0x10202A44 = 0; *(vu32 *)0x10202A44 = 0;
@ -34,16 +34,16 @@ void deinitScreens(void)
*(vu32 *)0x10202014 = 0; *(vu32 *)0x10202014 = 0;
//Wait for the entry to be set //Wait for the entry to be set
while(!*arm11); while(!*arm11Entry);
//Jump to it //Jump to it
((void (*)())*arm11)(); ((void (*)())*arm11Entry)();
} }
if(PDN_GPU_CNT != 1) if(PDN_GPU_CNT != 1)
{ {
*arm11 = (u32)ARM11; *arm11Entry = (u32)ARM11;
while(*arm11); while(*arm11Entry);
} }
} }
@ -54,10 +54,10 @@ void initScreens(void)
memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size); memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size);
//Write brightness level for the stub to pick up //Write brightness level for the stub to pick up
*(vu32 *)(SCREENINIT_ADDRESS + 8) = CONFIG(10, 3); *(vu32 *)(SCREENINIT_ADDRESS + 8) = CONFIG(14, 3);
*arm11 = SCREENINIT_ADDRESS; *arm11Entry = SCREENINIT_ADDRESS;
while(*arm11); while(*arm11Entry);
//Turn on backlight //Turn on backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A); i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);

View File

@ -2,15 +2,20 @@
.align 4 .align 4
.global _start .global _start
_start: _start:
b start
.word 0
start:
@ Change the stack pointer @ Change the stack pointer
mov sp, #0x27000000 mov sp, #0x27000000
@ Give read/write access to all the memory regions @ Give read/write access to all the memory regions
ldr r0, =0x33333333 ldr r5, =0x33333333
mcr p15, 0, r0, c5, c0, 2 @ write data access mcr p15, 0, r5, c5, c0, 2 @ write data access
mcr p15, 0, r0, c5, c0, 3 @ write instruction access mcr p15, 0, r5, c5, c0, 3 @ write instruction access
@ Set MPU permissions and cache settings @ Sets MPU permissions and cache settings
ldr r0, =0xFFFF001D @ ffff0000 32k ldr r0, =0xFFFF001D @ ffff0000 32k
ldr r1, =0x01FF801D @ 01ff8000 32k ldr r1, =0x01FF801D @ 01ff8000 32k
ldr r2, =0x08000027 @ 08000000 1M ldr r2, =0x08000027 @ 08000000 1M
@ -28,16 +33,16 @@ _start:
mcr p15, 0, r6, c6, c6, 0 mcr p15, 0, r6, c6, c6, 0
mcr p15, 0, r7, c6, c7, 0 mcr p15, 0, r7, c6, c7, 0
mov r0, #0x25 mov r0, #0x25
mcr p15, 0, r0, c2, c0, 0 @ data cacheable mcr p15, 0, r0, c3, c0, 0 @ Write bufferable 0, 2, 5
mcr p15, 0, r0, c2, c0, 1 @ instruction cacheable mcr p15, 0, r0, c2, c0, 0 @ Data cacheable 0, 2, 5
mcr p15, 0, r0, c3, c0, 0 @ data bufferable mcr p15, 0, r0, c2, c0, 1 @ Inst cacheable 0, 2, 5
@ Enable caches @ Enable caches
mrc p15, 0, r0, c1, c0, 0 @ read control register mrc p15, 0, r4, c1, c0, 0 @ read control register
orr r0, r0, #(1<<12) @ - instruction cache enable orr r4, r4, #(1<<12) @ - instruction cache enable
orr r0, r0, #(1<<2) @ - data cache enable orr r4, r4, #(1<<2) @ - data cache enable
orr r0, r0, #(1<<0) @ - mpu enable orr r4, r4, #(1<<0) @ - mpu enable
mcr p15, 0, r0, c1, c0, 0 @ write control register mcr p15, 0, r4, c1, c0, 0 @ write control register
@ Flush caches @ Flush caches
mov r0, #0 mov r0, #0

View File

@ -7,7 +7,6 @@
#include "utils.h" #include "utils.h"
#include "screeninit.h" #include "screeninit.h"
#include "draw.h" #include "draw.h"
#include "fs.h"
#include "i2c.h" #include "i2c.h"
#include "buttons.h" #include "buttons.h"
@ -37,15 +36,6 @@ u32 waitInput(void)
return key; return key;
} }
void deleteFirms(const char *firmPaths[], u32 firms)
{
while(firms)
{
fileDelete(firmPaths[firms - 1]);
firms--;
}
}
void error(const char *message) void error(const char *message)
{ {
initScreens(); initScreens();

View File

@ -9,5 +9,4 @@
#include "types.h" #include "types.h"
u32 waitInput(void); u32 waitInput(void);
void deleteFirms(const char *firmPaths[], u32 firms);
void error(const char *message); void error(const char *message);