From ef3a1bc2e6e7510ba781f96b480e17fc8e580738 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sat, 12 Mar 2022 14:13:01 +0800 Subject: [PATCH 01/25] Remove old ctrtool source code. --- ctrtool/LICENSE | 22 - ctrtool/Makefile | 32 - ctrtool/aes_keygen.c | 100 -- ctrtool/aes_keygen.h | 8 - ctrtool/cia.c | 317 ----- ctrtool/cia.h | 72 - ctrtool/ctr.c | 357 ----- ctrtool/ctr.h | 149 --- ctrtool/ctrtool.sln | 20 - ctrtool/ctrtool.vcproj | 442 ------- ctrtool/ctrtool.vcxproj | 164 --- ctrtool/ctrtool.vcxproj.filters | 225 ---- ctrtool/cwav.c | 1003 -------------- ctrtool/cwav.h | 205 --- ctrtool/exefs.c | 342 ----- ctrtool/exefs.h | 61 - ctrtool/exheader.c | 704 ---------- ctrtool/exheader.h | 202 --- ctrtool/filepath.c | 90 -- ctrtool/filepath.h | 20 - ctrtool/firm.c | 257 ---- ctrtool/firm.h | 57 - ctrtool/info.h | 16 - ctrtool/ivfc.c | 247 ---- ctrtool/ivfc.h | 78 -- ctrtool/keyset.cpp | 395 ------ ctrtool/keyset.h | 96 -- ctrtool/lzss.c | 195 --- ctrtool/lzss.h | 26 - ctrtool/main.c | 488 ------- ctrtool/ncch.c | 880 ------------- ctrtool/ncch.h | 113 -- ctrtool/ncsd.c | 165 --- ctrtool/ncsd.h | 57 - ctrtool/oschar.c | 210 --- ctrtool/oschar.h | 95 -- ctrtool/polarssl/aes.c | 1164 ---------------- ctrtool/polarssl/aes.h | 139 -- ctrtool/polarssl/bignum.c | 2038 ----------------------------- ctrtool/polarssl/bignum.h | 533 -------- ctrtool/polarssl/bn_mul.h | 736 ----------- ctrtool/polarssl/config.h | 336 ----- ctrtool/polarssl/padlock.h | 98 -- ctrtool/polarssl/rsa.c | 823 ------------ ctrtool/polarssl/rsa.h | 353 ----- ctrtool/polarssl/sha2.c | 702 ---------- ctrtool/polarssl/sha2.h | 155 --- ctrtool/romfs.c | 406 ------ ctrtool/romfs.h | 99 -- ctrtool/settings.c | 314 ----- ctrtool/settings.h | 81 -- ctrtool/stream.c | 138 -- ctrtool/stream.h | 45 - ctrtool/syscalls.c | 171 --- ctrtool/syscalls.h | 19 - ctrtool/tik.c | 127 -- ctrtool/tik.h | 64 - ctrtool/tinyxml/tinystr.cpp | 111 -- ctrtool/tinyxml/tinystr.h | 305 ----- ctrtool/tinyxml/tinyxml.cpp | 1886 -------------------------- ctrtool/tinyxml/tinyxml.h | 1805 ------------------------- ctrtool/tinyxml/tinyxmlerror.cpp | 52 - ctrtool/tinyxml/tinyxmlparser.cpp | 1638 ----------------------- ctrtool/tmd.c | 180 --- ctrtool/tmd.h | 103 -- ctrtool/types.h | 44 - ctrtool/utils.c | 239 ---- ctrtool/utils.h | 59 - ctrtool/windows/getopt.c | 1047 --------------- ctrtool/windows/getopt.h | 172 --- ctrtool/windows/getopt1.c | 188 --- 71 files changed, 24280 deletions(-) delete mode 100644 ctrtool/LICENSE delete mode 100644 ctrtool/Makefile delete mode 100644 ctrtool/aes_keygen.c delete mode 100644 ctrtool/aes_keygen.h delete mode 100644 ctrtool/cia.c delete mode 100644 ctrtool/cia.h delete mode 100644 ctrtool/ctr.c delete mode 100644 ctrtool/ctr.h delete mode 100644 ctrtool/ctrtool.sln delete mode 100644 ctrtool/ctrtool.vcproj delete mode 100644 ctrtool/ctrtool.vcxproj delete mode 100644 ctrtool/ctrtool.vcxproj.filters delete mode 100644 ctrtool/cwav.c delete mode 100644 ctrtool/cwav.h delete mode 100644 ctrtool/exefs.c delete mode 100644 ctrtool/exefs.h delete mode 100644 ctrtool/exheader.c delete mode 100644 ctrtool/exheader.h delete mode 100644 ctrtool/filepath.c delete mode 100644 ctrtool/filepath.h delete mode 100644 ctrtool/firm.c delete mode 100644 ctrtool/firm.h delete mode 100644 ctrtool/info.h delete mode 100644 ctrtool/ivfc.c delete mode 100644 ctrtool/ivfc.h delete mode 100644 ctrtool/keyset.cpp delete mode 100644 ctrtool/keyset.h delete mode 100644 ctrtool/lzss.c delete mode 100644 ctrtool/lzss.h delete mode 100644 ctrtool/main.c delete mode 100644 ctrtool/ncch.c delete mode 100644 ctrtool/ncch.h delete mode 100644 ctrtool/ncsd.c delete mode 100644 ctrtool/ncsd.h delete mode 100644 ctrtool/oschar.c delete mode 100644 ctrtool/oschar.h delete mode 100644 ctrtool/polarssl/aes.c delete mode 100644 ctrtool/polarssl/aes.h delete mode 100644 ctrtool/polarssl/bignum.c delete mode 100644 ctrtool/polarssl/bignum.h delete mode 100644 ctrtool/polarssl/bn_mul.h delete mode 100644 ctrtool/polarssl/config.h delete mode 100644 ctrtool/polarssl/padlock.h delete mode 100644 ctrtool/polarssl/rsa.c delete mode 100644 ctrtool/polarssl/rsa.h delete mode 100644 ctrtool/polarssl/sha2.c delete mode 100644 ctrtool/polarssl/sha2.h delete mode 100644 ctrtool/romfs.c delete mode 100644 ctrtool/romfs.h delete mode 100644 ctrtool/settings.c delete mode 100644 ctrtool/settings.h delete mode 100644 ctrtool/stream.c delete mode 100644 ctrtool/stream.h delete mode 100644 ctrtool/syscalls.c delete mode 100644 ctrtool/syscalls.h delete mode 100644 ctrtool/tik.c delete mode 100644 ctrtool/tik.h delete mode 100644 ctrtool/tinyxml/tinystr.cpp delete mode 100644 ctrtool/tinyxml/tinystr.h delete mode 100644 ctrtool/tinyxml/tinyxml.cpp delete mode 100644 ctrtool/tinyxml/tinyxml.h delete mode 100644 ctrtool/tinyxml/tinyxmlerror.cpp delete mode 100644 ctrtool/tinyxml/tinyxmlparser.cpp delete mode 100644 ctrtool/tmd.c delete mode 100644 ctrtool/tmd.h delete mode 100644 ctrtool/types.h delete mode 100644 ctrtool/utils.c delete mode 100644 ctrtool/utils.h delete mode 100644 ctrtool/windows/getopt.c delete mode 100644 ctrtool/windows/getopt.h delete mode 100644 ctrtool/windows/getopt1.c diff --git a/ctrtool/LICENSE b/ctrtool/LICENSE deleted file mode 100644 index 3768595..0000000 --- a/ctrtool/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) 2012 neimod -Copyright (c) 2014 3DSGuy - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/ctrtool/Makefile b/ctrtool/Makefile deleted file mode 100644 index cd515a4..0000000 --- a/ctrtool/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# Sources -SRC_DIR = . polarssl tinyxml -OBJS = $(foreach dir,$(SRC_DIR),$(subst .c,.o,$(wildcard $(dir)/*.c))) $(foreach dir,$(SRC_DIR),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) - -# Compiler Settings -OUTPUT = ctrtool -CXXFLAGS = -I. -CFLAGS = -O2 -Wall -Wno-unused-variable -Wno-unused-result -I. -std=c11 -CC = gcc -CXX = g++ -SYS := $(shell gcc -dumpmachine) -ifneq (, $(findstring linux, $(SYS))) - # Linux - CFLAGS += -Wno-unused-but-set-variable -else ifneq (, $(findstring cygwin, $(SYS))) - # Cygwin - CFLAGS += -Wno-unused-but-set-variable -DUSE_FILE32API - LIBS += -liconv -static-libgcc -static-libstdc++ -else ifneq (, $(findstring darwin, $(SYS))) - # OS X - LIBS += -liconv -else - #Windows Build CFG - CFLAGS += -Wno-unused-but-set-variable - LIBS += -static-libgcc -static-libstdc++ -static -lpthread -endif - -main: $(OBJS) - $(CXX) -o $(OUTPUT) $(OBJS) $(LIBS) - -clean: - rm -rf $(OUTPUT) $(OBJS) diff --git a/ctrtool/aes_keygen.c b/ctrtool/aes_keygen.c deleted file mode 100644 index eb81bdf..0000000 --- a/ctrtool/aes_keygen.c +++ /dev/null @@ -1,100 +0,0 @@ -#include "aes_keygen.h" - -// 128bit wrap-around math -int32_t wrap_index(int32_t i) -{ - return i < 0 ? ((i % 16) + 16) % 16 : (i > 15 ? i % 16 : i); -} - -void n128_rrot(const uint8_t *in, uint32_t rot, uint8_t *out) -{ - uint32_t bit_shift, byte_shift; - - rot = rot % 128; - byte_shift = rot / 8; - bit_shift = rot % 8; - - for (int32_t i = 0; i < 16; i++) { - out[i] = (in[wrap_index(i - byte_shift)] >> bit_shift) | (in[wrap_index(i - byte_shift - 1)] << (8 - bit_shift)); - } - -} - -void n128_lrot(const uint8_t *in, uint32_t rot, uint8_t *out) -{ - uint32_t bit_shift, byte_shift; - - rot = rot % 128; - byte_shift = rot / 8; - bit_shift = rot % 8; - - for (int32_t i = 0; i < 16; i++) { - out[i] = (in[wrap_index(i + byte_shift)] << bit_shift) | (in[wrap_index(i + byte_shift + 1)] >> (8 - bit_shift)); - } -} - -/* out = a + b -*/ -void n128_add(const uint8_t *a, const uint8_t *b, uint8_t *out) -{ - uint8_t carry = 0; - uint32_t sum = 0; - - for (int i = 15; i >= 0; i--) { - sum = a[i] + b[i] + carry; - carry = sum >> 8; - out[i] = sum & 0xff; - } -} - -/* out = a - b -*/ -void n128_sub(const uint8_t *a, const uint8_t *b, uint8_t *out) -{ - uint8_t carry = 0; - uint32_t sum = 0; - - for (int i = 15; i >= 0; i--) { - sum = a[i] - (b[i] + carry); - - // check to see if anything was borrowed from next byte - if (a[i] < (b[i] + carry)) { - sum += 0x100; - carry = 1; - } - else { - carry = 0; - } - - // set value - out[i] = sum & 0xff; - } -} - -void n128_xor(const uint8_t *a, const uint8_t *b, uint8_t *out) -{ - for (int i = 0; i < 16; i++) { - out[i] = a[i] ^ b[i]; - } -} - -// keygen algorithm -void ctr_aes_keygen(const uint8_t *x, const uint8_t *y, uint8_t *key) -{ - static const uint8_t KEYGEN_CONST[16] = { 0x1F, 0xF9, 0xE9, 0xAA, 0xC5, 0xFE, 0x04, 0x08, 0x02, 0x45, 0x91, 0xDC, 0x5D, 0x52, 0x76, 0x8A }; - - // overall algo: - // key = (((x <<< 2) ^ y) + KEYGEN_CONST) >>> 41 - uint8_t x_rot[16], key_xy[16], key_xyc[16]; - - // x_rot = x <<< 2 - n128_lrot(x, 2, x_rot); - - // key_xy = x_rot ^ y - n128_xor(x_rot, y, key_xy); - - // key_xyc = key_xy + KEYGEN_CONST - n128_add(key_xy, KEYGEN_CONST, key_xyc); - - n128_rrot(key_xyc, 41, key); -} \ No newline at end of file diff --git a/ctrtool/aes_keygen.h b/ctrtool/aes_keygen.h deleted file mode 100644 index dae87a3..0000000 --- a/ctrtool/aes_keygen.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include - -/* - AES Key generator for the Nintendo 3DS (CTR) Consoles -*/ - -void ctr_aes_keygen(const uint8_t *x, const uint8_t *y, uint8_t *key); diff --git a/ctrtool/cia.c b/ctrtool/cia.c deleted file mode 100644 index 85b16b8..0000000 --- a/ctrtool/cia.c +++ /dev/null @@ -1,317 +0,0 @@ -#include -#include -#include -#include "types.h" -#include "utils.h" -#include "cia.h" -#include - - -void cia_init(cia_context* ctx) -{ - memset(ctx, 0, sizeof(cia_context)); - - tik_init(&ctx->tik); - tmd_init(&ctx->tmd); -} - -void cia_set_file(cia_context* ctx, FILE* file) -{ - ctx->file = file; -} - -void cia_set_offset(cia_context* ctx, u64 offset) -{ - ctx->offset = offset; -} - -void cia_set_size(cia_context* ctx, u64 size) -{ - ctx->size = size; -} - - -void cia_set_usersettings(cia_context* ctx, settings* usersettings) -{ - ctx->usersettings = usersettings; -} - - -void cia_save(cia_context* ctx, u32 type, u32 flags) -{ - u64 offset; - u64 size; - u16 contentflags; - u16 contentindex; - u8 docrypto; - filepath* path = 0; - ctr_tmd_body *body; - ctr_tmd_contentchunk *chunk; - unsigned int i; - char tmpname[255]; - - switch(type) - { - case CIATYPE_CERTS: - offset = ctx->offsetcerts; - size = ctx->sizecert; - path = settings_get_certs_path(ctx->usersettings); - break; - - case CIATYPE_TIK: - offset = ctx->offsettik; - size = ctx->sizetik; - path = settings_get_tik_path(ctx->usersettings); - break; - - case CIATYPE_TMD: - offset = ctx->offsettmd; - size = ctx->sizetmd; - path = settings_get_tmd_path(ctx->usersettings); - break; - - case CIATYPE_CONTENT: - offset = ctx->offsetcontent; - size = ctx->sizecontent; - path = settings_get_content_path(ctx->usersettings); - - break; - - case CIATYPE_META: - offset = ctx->offsetmeta; - size = ctx->sizemeta; - path = settings_get_meta_path(ctx->usersettings);; - break; - - default: - fprintf(stderr, "Error, unknown CIA type specified\n"); - return; - break; - } - - if (path == 0 || path->valid == 0) - return; - - switch(type) - { - case CIATYPE_CERTS: fprintf(stdout, "Saving certs to %s\n", path->pathname); break; - case CIATYPE_TIK: fprintf(stdout, "Saving tik to %s\n", path->pathname); break; - case CIATYPE_TMD: fprintf(stdout, "Saving tmd to %s\n", path->pathname); break; - case CIATYPE_CONTENT: - - body = tmd_get_body(&ctx->tmd); - chunk = (ctr_tmd_contentchunk*)(body->contentinfo + (sizeof(ctr_tmd_contentinfo) * TMD_MAX_CONTENTS)); - - for(i = 0; i < getbe16(body->contentcount); i++) { - contentflags = getbe16(chunk->type); - contentindex = getbe16(chunk->index); - docrypto = (contentflags & 1) && !(flags & PlainFlag); - - if(ctx->header.contentindex[contentindex >> 3] & (0x80 >> (contentindex & 7))) { - sprintf(tmpname, "%s.%04x.%08x", path->pathname, contentindex, getbe32(chunk->id)); - fprintf(stdout, "Saving content #%04x to %s\n", contentindex, tmpname); - - if(docrypto) // Decrypt if needed - { - ctx->iv[0] = (contentindex >> 8) & 0xff; - ctx->iv[1] = contentindex & 0xff; - - ctr_init_cbc_decrypt(&ctx->aes, ctx->titlekey, ctx->iv); - } - - cia_save_blob(ctx, tmpname, offset, getbe64(chunk->size) & 0xffffffff, docrypto); - - offset += getbe64(chunk->size) & 0xffffffff; - } - chunk++; - } - - memset(ctx->iv, 0, 16); - - return; - break; - - case CIATYPE_META: fprintf(stdout, "Saving meta to %s\n", path->pathname); break; - } - - cia_save_blob(ctx, path->pathname, offset, size, 0); -} - -void cia_save_blob(cia_context *ctx, char *out_path, u64 offset, u64 size, int do_cbc) -{ - FILE *fout = 0; - u8 buffer[16*1024]; - - fseeko64(ctx->file, ctx->offset + offset, SEEK_SET); - - fout = fopen(out_path, "wb"); - if (fout == NULL) - { - fprintf(stdout, "Error opening out file %s\n", out_path); - goto clean; - } - - while(size) - { - u32 max = sizeof(buffer); - if (max > size) - max = (u32) size; - - if (max != fread(buffer, 1, max, ctx->file)) - { - fprintf(stdout, "Error reading file\n"); - goto clean; - } - - if (do_cbc == 1) - ctr_decrypt_cbc(&ctx->aes, buffer, buffer, max); - - if (max != fwrite(buffer, 1, max, fout)) - { - fprintf(stdout, "Error writing file\n"); - goto clean; - } - - size -= max; - } - -clean: - if (fout) - fclose(fout); -} - - -void cia_process(cia_context* ctx, u32 actions) -{ - fseeko64(ctx->file, 0, SEEK_SET); - - if (fread(&ctx->header, 1, sizeof(ctr_ciaheader), ctx->file) != sizeof(ctr_ciaheader)) - { - fprintf(stderr, "Error reading CIA header\n"); - goto clean; - } - - ctx->sizeheader = getle32(ctx->header.headersize); - ctx->sizecert = getle32(ctx->header.certsize); - ctx->sizetik = getle32(ctx->header.ticketsize); - ctx->sizetmd = getle32(ctx->header.tmdsize); - ctx->sizecontent = getle64(ctx->header.contentsize); - ctx->sizemeta = getle32(ctx->header.metasize); - - ctx->offsetcerts = align(ctx->sizeheader, 64); - ctx->offsettik = align((u32) (ctx->offsetcerts + ctx->sizecert), 64); - ctx->offsettmd = align((u32) (ctx->offsettik + ctx->sizetik), 64); - ctx->offsetcontent = align((u32) (ctx->offsettmd + ctx->sizetmd), 64); - ctx->offsetmeta = align64(ctx->offsetcontent + ctx->sizecontent, 64); - - if (actions & InfoFlag) - cia_print(ctx); - - - tik_set_file(&ctx->tik, ctx->file); - tik_set_offset(&ctx->tik, ctx->offsettik); - tik_set_size(&ctx->tik, ctx->sizetik); - tik_set_usersettings(&ctx->tik, ctx->usersettings); - - tik_process(&ctx->tik, actions); - memset(ctx->iv, 0, 16); - - if (tik_get_titlekey(&ctx->tik)) - memcpy(ctx->titlekey, tik_get_titlekey(&ctx->tik), 16); - else if (settings_get_title_key(ctx->usersettings)) - memcpy(ctx->titlekey, settings_get_title_key(ctx->usersettings), 16); - - tmd_set_file(&ctx->tmd, ctx->file); - tmd_set_offset(&ctx->tmd, ctx->offsettmd); - tmd_set_size(&ctx->tmd, ctx->sizetmd); - tmd_set_usersettings(&ctx->tmd, ctx->usersettings); - tmd_process(&ctx->tmd, (actions & ~InfoFlag)); - - if (actions & VerifyFlag) - { - cia_verify_contents(ctx, actions); - } - - if (actions & InfoFlag || actions & VerifyFlag) - tmd_print(&ctx->tmd); - - if (actions & ExtractFlag) - { - cia_save(ctx, CIATYPE_CERTS, actions); - cia_save(ctx, CIATYPE_TMD, actions); - cia_save(ctx, CIATYPE_TIK, actions); - cia_save(ctx, CIATYPE_META, actions); - cia_save(ctx, CIATYPE_CONTENT, actions); - } - -clean: - return; -} - -void cia_verify_contents(cia_context *ctx, u32 actions) -{ - u16 contentflags; - u16 contentindex; - ctr_tmd_body *body; - ctr_tmd_contentchunk *chunk; - u8 *verify_buf; - u32 content_size=0; - unsigned i; - - // verify TMD content hashes, requires decryption .. - body = tmd_get_body(&ctx->tmd); - chunk = (ctr_tmd_contentchunk*)(body->contentinfo + (sizeof(ctr_tmd_contentinfo) * TMD_MAX_CONTENTS)); - - fseeko64(ctx->file, ctx->offset + ctx->offsetcontent, SEEK_SET); - for(i = 0; i < getbe16(body->contentcount); i++) - { - contentindex = getbe16(chunk->index); - - if(ctx->header.contentindex[contentindex >> 3] & (0x80 >> (contentindex & 7))) - { - content_size = getbe64(chunk->size) & 0xffffffff; - - contentflags = getbe16(chunk->type); - - verify_buf = malloc(content_size); - fread(verify_buf, content_size, 1, ctx->file); - - if(contentflags & 1 && !(actions & PlainFlag)) // Decrypt if needed - { - ctx->iv[0] = (contentindex >> 8) & 0xff; - ctx->iv[1] = contentindex & 0xff; - - ctr_init_cbc_decrypt(&ctx->aes, ctx->titlekey, ctx->iv); - - ctr_decrypt_cbc(&ctx->aes, verify_buf, verify_buf, content_size); - } - - if (ctr_sha_256_verify(verify_buf, content_size, chunk->hash) == Good) - ctx->tmd.content_hash_stat[i] = 1; - else - ctx->tmd.content_hash_stat[i] = 2; - - free(verify_buf); - } - chunk++; - } -} - -void cia_print(cia_context* ctx) -{ - ctr_ciaheader* header = &ctx->header; - - fprintf(stdout, "Header size 0x%08x\n", getle32(header->headersize)); - fprintf(stdout, "Type %04x\n", getle16(header->type)); - fprintf(stdout, "Version %04x\n", getle16(header->version)); - fprintf(stdout, "Certificates offset: 0x%"PRIx64"\n", ctx->offsetcerts); - fprintf(stdout, "Certificates size: 0x%x\n", ctx->sizecert); - fprintf(stdout, "Ticket offset: 0x%"PRIx64"\n", ctx->offsettik); - fprintf(stdout, "Ticket size 0x%x\n", ctx->sizetik); - fprintf(stdout, "TMD offset: 0x%"PRIx64"\n", ctx->offsettmd); - fprintf(stdout, "TMD size: 0x%x\n", ctx->sizetmd); - fprintf(stdout, "Meta offset: 0x%"PRIx64"\n", ctx->offsetmeta); - fprintf(stdout, "Meta size: 0x%x\n", ctx->sizemeta); - fprintf(stdout, "Content offset: 0x%"PRIx64"\n", ctx->offsetcontent); - fprintf(stdout, "Content size: 0x%"PRIx64"\n", ctx->sizecontent); -} diff --git a/ctrtool/cia.h b/ctrtool/cia.h deleted file mode 100644 index 52b0152..0000000 --- a/ctrtool/cia.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef _CIA_H_ -#define _CIA_H_ - -#include "types.h" -#include "filepath.h" -#include "tik.h" -#include "tmd.h" -#include "ctr.h" -#include "settings.h" - -typedef enum -{ - CIATYPE_CERTS, - CIATYPE_TMD, - CIATYPE_TIK, - CIATYPE_CONTENT, - CIATYPE_META, -} cia_types; - -typedef struct -{ - u8 headersize[4]; - u8 type[2]; - u8 version[2]; - u8 certsize[4]; - u8 ticketsize[4]; - u8 tmdsize[4]; - u8 metasize[4]; - u8 contentsize[8]; - u8 contentindex[0x2000]; -} ctr_ciaheader; - -typedef struct -{ - FILE* file; - u64 offset; - u64 size; - u8 titlekey[16]; - u8 iv[16]; - ctr_ciaheader header; - ctr_aes_context aes; - settings* usersettings; - - tik_context tik; - tmd_context tmd; - - u32 sizeheader; - u32 sizecert; - u32 sizetik; - u32 sizetmd; - u64 sizecontent; - u32 sizemeta; - - u64 offsetcerts; - u64 offsettik; - u64 offsettmd; - u64 offsetcontent; - u64 offsetmeta; -} cia_context; - -void cia_init(cia_context* ctx); -void cia_set_file(cia_context* ctx, FILE* file); -void cia_set_offset(cia_context* ctx, u64 offset); -void cia_set_size(cia_context* ctx, u64 size); -void cia_set_usersettings(cia_context* ctx, settings* usersettings); -void cia_print(cia_context* ctx); -void cia_save(cia_context* ctx, u32 type, u32 flags); -void cia_process(cia_context* ctx, u32 actions); -void cia_save_blob(cia_context *ctx, char *out_path, u64 offset, u64 size, int do_cbc); -void cia_verify_contents(cia_context *ctx, u32 actions); - -#endif // _CIA_H_ diff --git a/ctrtool/ctr.c b/ctrtool/ctr.c deleted file mode 100644 index 54cfc0f..0000000 --- a/ctrtool/ctr.c +++ /dev/null @@ -1,357 +0,0 @@ -#include -#include -#include -#include - -#include "ctr.h" -#include "utils.h" - - -void ctr_set_iv( ctr_aes_context* ctx, - u8 iv[16] ) -{ - memcpy(ctx->iv, iv, 16); -} - -void ctr_add_counter( ctr_aes_context* ctx, - u32 block_num ) -{ - u32 ctr[4]; - ctr[3] = getbe32(&ctx->ctr[0]); - ctr[2] = getbe32(&ctx->ctr[4]); - ctr[1] = getbe32(&ctx->ctr[8]); - ctr[0] = getbe32(&ctx->ctr[12]); - - for (u32 i = 0; i < 4; i++) { - u64 total = ctr[i] + block_num; - // if there wasn't a wrap around, add the two together and exit - if (total <= 0xffffffff) { - ctr[i] += block_num; - break; - } - - // add the difference - ctr[i] = (u32)(total - 0x100000000); - // carry to next word - block_num = (u32)(total >> 32); - } - - putbe32(ctx->ctr + 0x00, ctr[3]); - putbe32(ctx->ctr + 0x04, ctr[2]); - putbe32(ctx->ctr + 0x08, ctr[1]); - putbe32(ctx->ctr + 0x0C, ctr[0]); -} - -void ctr_set_counter( ctr_aes_context* ctx, - u8 ctr[16] ) -{ - memcpy(ctx->ctr, ctr, 16); -} - - -void ctr_init_key(ctr_aes_context* ctx, - u8 key[16]) -{ - aes_setkey_enc(&ctx->aes, key, 128); -} - -void ctr_init_counter( ctr_aes_context* ctx, - u8 ctr[16] ) -{ - ctr_set_counter(ctx, ctr); -} - - -void ctr_crypt_counter_block( ctr_aes_context* ctx, - u8 input[16], - u8 output[16] ) -{ - int i; - u8 stream[16]; - - - aes_crypt_ecb(&ctx->aes, AES_ENCRYPT, ctx->ctr, stream); - - - if (input) - { - for(i=0; i<16; i++) - { - output[i] = stream[i] ^ input[i]; - } - } - else - { - for(i=0; i<16; i++) - output[i] = stream[i]; - } - - ctr_add_counter(ctx, 1); -} - - -void ctr_crypt_counter( ctr_aes_context* ctx, - u8* input, - u8* output, - u32 size ) -{ - u8 stream[16]; - u32 i; - - while(size >= 16) - { - ctr_crypt_counter_block(ctx, input, output); - - if (input) - input += 16; - if (output) - output += 16; - - size -= 16; - } - - if (size) - { - memset(stream, 0, 16); - ctr_crypt_counter_block(ctx, stream, stream); - - if (input) - { - for(i=0; iaes, key, 128); - ctr_set_iv(ctx, iv); -} - -void ctr_init_cbc_decrypt( ctr_aes_context* ctx, - u8 key[16], - u8 iv[16] ) -{ - aes_setkey_dec(&ctx->aes, key, 128); - ctr_set_iv(ctx, iv); -} - -void ctr_encrypt_cbc( ctr_aes_context* ctx, - u8* input, - u8* output, - u32 size ) -{ - aes_crypt_cbc(&ctx->aes, AES_ENCRYPT, size, ctx->iv, input, output); -} - -void ctr_decrypt_cbc( ctr_aes_context* ctx, - u8* input, - u8* output, - u32 size ) -{ - aes_crypt_cbc(&ctx->aes, AES_DECRYPT, size, ctx->iv, input, output); -} - -void ctr_sha_256( const u8* data, - u32 size, - u8 hash[0x20] ) -{ - sha2(data, size, hash, 0); -} - -int ctr_sha_256_verify( const u8* data, - u32 size, - const u8 checkhash[0x20] ) -{ - u8 hash[0x20]; - - sha2(data, size, hash, 0); - - if (memcmp(hash, checkhash, 0x20) == 0) - return Good; - else - return Fail; -} - -void ctr_sha_256_init( ctr_sha256_context* ctx ) -{ - sha2_starts(&ctx->sha, 0); -} - -void ctr_sha_256_update( ctr_sha256_context* ctx, - const u8* data, - u32 size ) -{ - sha2_update(&ctx->sha, data, size); -} - - -void ctr_sha_256_finish( ctr_sha256_context* ctx, - u8 hash[0x20] ) -{ - sha2_finish(&ctx->sha, hash); -} - - -void ctr_rsa_init_key_pubmodulus(rsakey2048* key, u8 modulus[0x100]) -{ - u8 exponent[3] = {0x01, 0x00, 0x01}; - - ctr_rsa_init_key_pub(key, modulus, exponent); -} - -void ctr_rsa_init_key_pub(rsakey2048* key, u8 modulus[0x100], u8 exponent[3]) -{ - key->keytype = RSAKEY_PUB; - memcpy(key->n, modulus, 0x100); - memcpy(key->e, exponent, 3); -} - -int ctr_rsa_init(ctr_rsa_context* ctx, rsakey2048* key) -{ - rsa_init(&ctx->rsa, RSA_PKCS_V15, 0); - ctx->rsa.len = 0x100; - - if (key->keytype == RSAKEY_INVALID) - goto clean; - - if (mpi_read_binary(&ctx->rsa.N, key->n, sizeof(key->n))) - goto clean; - if (mpi_read_binary(&ctx->rsa.E, key->e, sizeof(key->e))) - goto clean; - if (rsa_check_pubkey(&ctx->rsa)) - goto clean; - - if (key->keytype == RSAKEY_PRIV) - { - if (mpi_read_binary(&ctx->rsa.D, key->d, sizeof(key->d))) - goto clean; - if (mpi_read_binary(&ctx->rsa.P, key->p, sizeof(key->p))) - goto clean; - if (mpi_read_binary(&ctx->rsa.Q, key->q, sizeof(key->q))) - goto clean; - if (mpi_read_binary(&ctx->rsa.DP, key->dp, sizeof(key->dp))) - goto clean; - if (mpi_read_binary(&ctx->rsa.DQ, key->dq, sizeof(key->dq))) - goto clean; - if (mpi_read_binary(&ctx->rsa.QP, key->qp, sizeof(key->qp))) - goto clean; - if (rsa_check_privkey(&ctx->rsa)) - goto clean; - } - - return 1; -clean: - return 0; -} - -int ctr_rsa_verify_hash(const u8 signature[0x100], const u8 hash[0x20], rsakey2048* key) -{ - ctr_rsa_context ctx; - u32 result; -// u8 output[0x100]; - - if (key->keytype == RSAKEY_INVALID) - return Fail; - - ctr_rsa_init(&ctx, key); -// memset(output, 0, 0x100); -// result = ctr_rsa_public(signature, output, key); -// printf("Result = %d\n", result); -// memdump(stdout, "output: ", output, 0x100); - - result = rsa_pkcs1_verify(&ctx.rsa, RSA_PUBLIC, SIG_RSA_SHA256, 0x20, hash, (u8*)signature); - - ctr_rsa_free(&ctx); - - if (result == 0) - return Good; - else - return Fail; -} - - -int ctr_rsa_sign_hash(const u8 hash[0x20], u8 signature[0x100], rsakey2048* key) -{ - ctr_rsa_context ctx; - u32 result; - - ctr_rsa_init(&ctx, key); - - result = rsa_pkcs1_verify(&ctx.rsa, RSA_PUBLIC, SIG_RSA_SHA256, 0x20, hash, (u8*)signature); - result = rsa_pkcs1_sign(&ctx.rsa, RSA_PRIVATE, SIG_RSA_SHA256, 0x20, hash, signature); - - ctr_rsa_free(&ctx); - - if (result == 0) - return 1; - else - return 0; -} - -int ctr_rsa_public(const u8 signature[0x100], u8 output[0x100], rsakey2048* key) -{ - ctr_rsa_context ctx; - u32 result; - - ctr_rsa_init(&ctx, key); - - result = rsa_public(&ctx.rsa, signature, output); - - ctr_rsa_free(&ctx); - - if (result == 0) - return 1; - else - return 0; -} - - -void ctr_rsa_free(ctr_rsa_context* ctx) -{ - rsa_free(&ctx->rsa); -} - -/* - * Generate DP, DQ, QP based on private key - */ -#if 0 -static int ctr_rsa_key_init(ctr_rsa_context* ctx ) -{ - int ret; - mpi P1, Q1; - - mpi_init( &P1, &Q1, NULL ); - - MPI_CHK( mpi_sub_int( &P1, &ctx->rsa.P, 1 ) ); - MPI_CHK( mpi_sub_int( &Q1, &ctx->rsa.Q, 1 ) ); - - /* - * DP = D mod (P - 1) - * DQ = D mod (Q - 1) - * QP = Q^-1 mod P - */ - MPI_CHK( mpi_mod_mpi( &ctx->rsa.DP, &ctx->rsa.D, &P1 ) ); - MPI_CHK( mpi_mod_mpi( &ctx->rsa.DQ, &ctx->rsa.D, &Q1 ) ); - MPI_CHK( mpi_inv_mod( &ctx->rsa.QP, &ctx->rsa.Q, &ctx->rsa.P ) ); - -cleanup: - - mpi_free(&Q1, &P1, NULL ); - - if( ret != 0 ) - { - rsa_free( &ctx->rsa ); - return( POLARSSL_ERR_RSA_KEY_GEN_FAILED | ret ); - } - - return( 0 ); -} -#endif \ No newline at end of file diff --git a/ctrtool/ctr.h b/ctrtool/ctr.h deleted file mode 100644 index 48b61e5..0000000 --- a/ctrtool/ctr.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef _CTR_H_ -#define _CTR_H_ - -#include "polarssl/aes.h" -#include "polarssl/rsa.h" -#include "polarssl/sha2.h" -#include "types.h" -#include "keyset.h" - -#define MAGIC_NCCH 0x4843434E -#define MAGIC_NCSD 0x4453434E -#define MAGIC_FIRM 0x4D524946 -#define MAGIC_CWAV 0x56415743 -#define MAGIC_IVFC 0x43465649 - -#define SIZE_128MB (128 * 1024 * 1024) - -typedef enum -{ - FILETYPE_UNKNOWN = 0, - FILETYPE_CCI, - FILETYPE_CXI, - FILETYPE_CIA, - FILETYPE_EXHEADER, - FILETYPE_TMD, - FILETYPE_LZSS, - FILETYPE_FIRM, - FILETYPE_CWAV, - FILETYPE_EXEFS, - FILETYPE_ROMFS -} ctr_filetypes; - -typedef struct -{ - u8 ctr[16]; - u8 iv[16]; - aes_context aes; -} ctr_aes_context; - -typedef struct -{ - rsa_context rsa; -} ctr_rsa_context; - -typedef struct -{ - sha2_context sha; -} ctr_sha256_context; - - -#ifdef __cplusplus -extern "C" { -#endif - -void ctr_set_iv( ctr_aes_context* ctx, - u8 iv[16] ); - -void ctr_add_counter( ctr_aes_context* ctx, - u32 block_num ); - -void ctr_set_counter( ctr_aes_context* ctx, - u8 ctr[16] ); - -void ctr_init_key(ctr_aes_context* ctx, - u8 key[16]); - - -void ctr_init_counter( ctr_aes_context* ctx, - u8 ctr[16] ); - - -void ctr_crypt_counter_block( ctr_aes_context* ctx, - u8 input[16], - u8 output[16] ); - - -void ctr_crypt_counter( ctr_aes_context* ctx, - u8* input, - u8* output, - u32 size ); - - -void ctr_init_cbc_encrypt( ctr_aes_context* ctx, - u8 key[16], - u8 iv[16] ); - -void ctr_init_cbc_decrypt( ctr_aes_context* ctx, - u8 key[16], - u8 iv[16] ); - -void ctr_encrypt_cbc( ctr_aes_context* ctx, - u8* input, - u8* output, - u32 size ); - -void ctr_decrypt_cbc( ctr_aes_context* ctx, - u8* input, - u8* output, - u32 size ); - -void ctr_rsa_init_key_pubmodulus( rsakey2048* key, - u8 modulus[0x100] ); - -void ctr_rsa_init_key_pub( rsakey2048* key, - u8 modulus[0x100], - u8 exponent[3] ); - -int ctr_rsa_init( ctr_rsa_context* ctx, - rsakey2048* key ); - - -void ctr_rsa_free( ctr_rsa_context* ctx ); - -int ctr_rsa_verify_hash( const u8 signature[0x100], - const u8 hash[0x20], - rsakey2048* key); - -int ctr_rsa_sign_hash( const u8 hash[0x20], - u8 signature[0x100], - rsakey2048* key ); - -int ctr_rsa_public( const u8 signature[0x100], - u8 output[0x100], - rsakey2048* key ); - -void ctr_sha_256( const u8* data, - u32 size, - u8 hash[0x20] ); - -int ctr_sha_256_verify( const u8* data, - u32 size, - const u8 checkhash[0x20] ); - - -void ctr_sha_256_init( ctr_sha256_context* ctx ); - -void ctr_sha_256_update( ctr_sha256_context* ctx, - const u8* data, - u32 size ); - - -void ctr_sha_256_finish( ctr_sha256_context* ctx, - u8 hash[0x20] ); - -#ifdef __cplusplus -} -#endif - -#endif // _CTR_H_ diff --git a/ctrtool/ctrtool.sln b/ctrtool/ctrtool.sln deleted file mode 100644 index ab9464c..0000000 --- a/ctrtool/ctrtool.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ctrtool", "ctrtool.vcxproj", "{96F5CA15-30DA-4DF5-9DFF-523D58D38001}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {96F5CA15-30DA-4DF5-9DFF-523D58D38001}.Debug|Win32.ActiveCfg = Debug|Win32 - {96F5CA15-30DA-4DF5-9DFF-523D58D38001}.Debug|Win32.Build.0 = Debug|Win32 - {96F5CA15-30DA-4DF5-9DFF-523D58D38001}.Release|Win32.ActiveCfg = Release|Win32 - {96F5CA15-30DA-4DF5-9DFF-523D58D38001}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/ctrtool/ctrtool.vcproj b/ctrtool/ctrtool.vcproj deleted file mode 100644 index d3e8b0d..0000000 --- a/ctrtool/ctrtool.vcproj +++ /dev/null @@ -1,442 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ctrtool/ctrtool.vcxproj b/ctrtool/ctrtool.vcxproj deleted file mode 100644 index 21abef9..0000000 --- a/ctrtool/ctrtool.vcxproj +++ /dev/null @@ -1,164 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {96F5CA15-30DA-4DF5-9DFF-523D58D38001} - ctrtooltje - Win32Proj - - - - Application - v140 - Unicode - true - - - Application - v140 - Unicode - - - - - - - - - - - - - <_ProjectFileVersion>11.0.50727.1 - - - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - true - - - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - - - - Disabled - windows;.;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - Level3 - EditAndContinue - 4996;%(DisableSpecificWarnings) - false - - - true - Console - MachineX86 - - - - - MaxSpeed - true - windows;.;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - MultiThreaded - true - - Level3 - ProgramDatabase - - - true - Console - true - true - MachineX86 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ctrtool/ctrtool.vcxproj.filters b/ctrtool/ctrtool.vcxproj.filters deleted file mode 100644 index 8f0b392..0000000 --- a/ctrtool/ctrtool.vcxproj.filters +++ /dev/null @@ -1,225 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {dfec7c2d-ac92-481f-a1eb-732b0669b7d1} - - - {dd509a5e-b804-4879-b0b7-876718c9621a} - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {d16b9918-7159-4a81-a0b7-521c2b2f8a30} - - - {492dc50f-e790-426b-b991-86306ad69fd4} - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files\polarssl - - - Source Files\polarssl - - - Source Files\polarssl - - - Source Files\polarssl - - - Source Files\tinyxml - - - Source Files\tinyxml - - - Source Files\tinyxml - - - Source Files\tinyxml - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files\polarssl - - - Header Files\polarssl - - - Header Files\polarssl - - - Header Files\polarssl - - - Header Files\polarssl - - - Header Files\polarssl - - - Header Files\tinyxml - - - Header Files\tinyxml - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/ctrtool/cwav.c b/ctrtool/cwav.c deleted file mode 100644 index cfe39d8..0000000 --- a/ctrtool/cwav.c +++ /dev/null @@ -1,1003 +0,0 @@ -#include -#include -#include - -#include "types.h" -#include "cwav.h" -#include "utils.h" -#include "stream.h" - -#define BUFFERSIZE (4*1024) -#define SAMPLECOUNT 1024 - -static const int ima_adpcm_step_table[89] = { - 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, - 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, - 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, - 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, - 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, - 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, - 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, - 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, - 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 -}; - -static const int ima_adpcm_index_table[16] = { - -1, -1, -1, -1, 2, 4, 6, 8, - -1, -1, -1, -1, 2, 4, 6, 8 -}; - -void cwav_init(cwav_context* ctx) -{ - memset(ctx, 0, sizeof(cwav_context)); -} - -void cwav_set_file(cwav_context* ctx, FILE* file) -{ - ctx->file = file; -} - -void cwav_set_offset(cwav_context* ctx, u64 offset) -{ - ctx->offset = offset; -} - -void cwav_set_size(cwav_context* ctx, u64 size) -{ - ctx->size = size; -} - -void cwav_set_usersettings(cwav_context* ctx, settings* usersettings) -{ - ctx->usersettings = usersettings; -} - -void cwav_process(cwav_context* ctx, u32 actions) -{ - u32 i; - u32 infoheaderoffset; - - fseeko64(ctx->file, ctx->offset, SEEK_SET); - fread(&ctx->header, 1, sizeof(cwav_header), ctx->file); - - infoheaderoffset = getle32(ctx->header.infoblockref.offset); - - fseeko64(ctx->file, ctx->offset + infoheaderoffset, SEEK_SET); - fread(&ctx->infoheader, 1, sizeof(cwav_infoheader), ctx->file); - - ctx->channelcount = getle32(ctx->infoheader.channelcount); - if (ctx->channelcount) - { - ctx->channel = malloc(ctx->channelcount * sizeof(cwav_channel)); - - for(i=0; ichannelcount; i++) - { - fread(&ctx->channel[i].inforef, sizeof(cwav_reference), 1, ctx->file); - } - - for(i=0; ichannelcount; i++) - { - u32 channeloffset = infoheaderoffset + 0x1C + getle32(ctx->channel[i].inforef.offset); - - fseeko64(ctx->file, ctx->offset + channeloffset, SEEK_SET); - fread(&ctx->channel[i].info, sizeof(cwav_channelinfo), 1, ctx->file); - - if (ctx->infoheader.encoding == CWAV_ENCODING_DSPADPCM) - { - if (getle16(ctx->channel[i].info.codecref.idtype) == 0x300) - { - u32 codecoffset = channeloffset + getle32(ctx->channel[i].info.codecref.offset); - - fseeko64(ctx->file, ctx->offset + codecoffset, SEEK_SET); - fread(&ctx->channel[i].infodspadpcm, sizeof(cwav_dspadpcminfo), 1, ctx->file); - } - } - else if (ctx->infoheader.encoding == CWAV_ENCODING_IMAADPCM) - { - if (getle16(ctx->channel[i].info.codecref.idtype) == 0x301) - { - u32 codecoffset = channeloffset + getle32(ctx->channel[i].info.codecref.offset); - - fseeko64(ctx->file, ctx->offset + codecoffset, SEEK_SET); - fread(&ctx->channel[i].infoimaadpcm, sizeof(cwav_imaadpcminfo), 1, ctx->file); - } - } - } - } - - - if (actions & InfoFlag) - { - cwav_print(ctx); - } - - if (actions & ExtractFlag) - { - filepath* path = settings_get_wav_path(ctx->usersettings); - - if (path && path->valid) - cwav_save_to_wav(ctx, path->pathname); - } - - - free(ctx->channel); -} - - -void cwav_write_wav_header(cwav_context* ctx, stream_out_context* outstreamctx, u32 size) -{ - wav_pcm_header header; - u32 samplerate = getle32(ctx->infoheader.samplerate); - u32 channelcount = ctx->channelcount; - - - putle32(header.chunkid, 0x46464952); - putle32(header.chunksize, 36 + size); - putle32(header.format, 0x45564157); - putle32(header.subchunk1id, 0x20746d66); - putle32(header.subchunk1size, 16); - putle16(header.audioformat, 1); - putle16(header.numchannels, channelcount); - putle32(header.samplerate, samplerate); - putle32(header.byterate, samplerate * channelcount * 2); - putle16(header.blockalign, channelcount * 2); - putle16(header.bitspersample, 16); - - putle32(header.subchunk2id, 0x61746164); - putle32(header.subchunk2size, size); - - stream_out_buffer(outstreamctx, &header, sizeof(wav_pcm_header)); -} - -int cwav_dspadpcm_decode_to_wav(cwav_context* ctx, stream_out_context* outstreamctx) -{ - u32 s, c, i; - int result = 0; - cwav_dspadpcmstate state; - u32 loopcount = settings_get_cwav_loopcount(ctx->usersettings); - - cwav_dspadpcm_init(&state); - - if (0 == cwav_dspadpcm_allocate(&state, ctx)) - goto clean; - - for(i=0; i<1+loopcount; i++) - { - int isloop = (i != 0); - - if (0 == cwav_dspadpcm_setup(&state, ctx, isloop)) - goto clean; - - while(1) - { - if (0 == cwav_dspadpcm_decode(&state, ctx)) - goto clean; - - if (state.samplecountavailable == 0) - break; - - for(s=0; schannelcount; c++) - { - s16 sampledata = state.channelstate[c].samplebuffer[s]; - - if (!stream_out_byte(outstreamctx, 0xFF & sampledata) || !stream_out_byte(outstreamctx, 0xFF & (sampledata>>8))) - { - fprintf(stderr, "Error writing output stream\n"); - goto clean; - } - } - } - } - } - - result = 1; - -clean: - cwav_dspadpcm_destroy(&state); - - return result; -} - - -int cwav_imaadpcm_decode_to_wav(cwav_context* ctx, stream_out_context* outstreamctx) -{ - u32 s, c, i; - int result = 0; - cwav_imaadpcmstate state; - u32 loopcount = settings_get_cwav_loopcount(ctx->usersettings); - - - cwav_imaadpcm_init(&state); - if (0 == cwav_imaadpcm_allocate(&state, ctx)) - goto clean; - - for(i=0; i<1+loopcount; i++) - { - int isloop = (i != 0); - - if (0 == cwav_imaadpcm_setup(&state, ctx, isloop)) - goto clean; - - while(1) - { - if (0 == cwav_imaadpcm_decode(&state, ctx)) - goto clean; - - if (state.samplecountavailable == 0) - break; - - for(s=0; schannelcount; c++) - { - s16 sampledata = state.channelstate[c].samplebuffer[s]; - - if (!stream_out_byte(outstreamctx, 0xFF & sampledata) || !stream_out_byte(outstreamctx, 0xFF & (sampledata>>8))) - { - fprintf(stderr, "Error writing output stream\n"); - goto clean; - } - } - } - } - } - - result = 1; - -clean: - cwav_imaadpcm_destroy(&state); - - return result; -} - - -int cwav_pcm_decode_to_wav(cwav_context* ctx, stream_out_context* outstreamctx) -{ - u32 s, c, i; - int result = 0; - cwav_pcmstate state; - u32 loopcount = settings_get_cwav_loopcount(ctx->usersettings); - - - cwav_pcm_init(&state); - - - if (0 == cwav_pcm_allocate(&state, ctx)) - goto clean; - - for(i=0; i<1+loopcount; i++) - { - int isloop = (i != 0); - - if (0 == cwav_pcm_setup(&state, ctx, isloop)) - goto clean; - - while(1) - { - if (0 == cwav_pcm_decode(&state, ctx)) - goto clean; - - if (state.samplecountavailable == 0) - break; - - for(s=0; schannelcount; c++) - { - s16 sampledata = state.channelstate[c].samplebuffer[s]; - - if (!stream_out_byte(outstreamctx, 0xFF & sampledata) || !stream_out_byte(outstreamctx, 0xFF & (sampledata>>8))) - { - fprintf(stderr, "Error writing output stream\n"); - goto clean; - } - } - } - } - } - - result = 1; - -clean: - cwav_pcm_destroy(&state); - - return result; -} - -int cwav_save_to_wav(cwav_context* ctx, const char* filepath) -{ - u32 startposition = 0; - u32 endposition = 0; - int result = 0; - FILE* outfile = 0; - stream_out_context outstreamctx; - - - stream_out_init(&outstreamctx); - - if (ctx->channelcount == 0) - goto clean; - - fprintf(stdout, "Saving sound data to %s...\n", filepath); - outfile = fopen(filepath, "wb"); - if (!outfile) - { - fprintf(stderr, "Error could not open file %s for writing.\n", filepath); - goto clean; - } - - stream_out_allocate(&outstreamctx, BUFFERSIZE, outfile); - stream_out_skip(&outstreamctx, sizeof(wav_pcm_header)); - stream_out_position(&outstreamctx, &startposition); - - if (ctx->infoheader.encoding == CWAV_ENCODING_DSPADPCM) - result = cwav_dspadpcm_decode_to_wav(ctx, &outstreamctx); - else if (ctx->infoheader.encoding == CWAV_ENCODING_IMAADPCM) - result = cwav_imaadpcm_decode_to_wav(ctx, &outstreamctx); - else if (ctx->infoheader.encoding == CWAV_ENCODING_PCM16) - result = cwav_pcm_decode_to_wav(ctx, &outstreamctx); - else if (ctx->infoheader.encoding == CWAV_ENCODING_PCM8) - result = cwav_pcm_decode_to_wav(ctx, &outstreamctx); - - if (!result) - goto clean; - - stream_out_position(&outstreamctx, &endposition); - - stream_out_seek(&outstreamctx, 0); - cwav_write_wav_header(ctx, &outstreamctx, endposition-startposition); - stream_out_flush(&outstreamctx); - result = 1; - -clean: - stream_out_destroy(&outstreamctx); - - if (outfile) - fclose(outfile); - - return result; -} - -void cwav_dspadpcm_init(cwav_dspadpcmstate* state) -{ - memset(state, 0, sizeof(cwav_dspadpcmstate)); -} - -int cwav_dspadpcm_allocate(cwav_dspadpcmstate* state, cwav_context* ctx) -{ - u32 channelcount = ctx->channelcount; - - - state->samplebuffer = malloc(sizeof(s16) * SAMPLECOUNT * channelcount); - state->channelstate = malloc(sizeof(cwav_dspadpcmchannelstate) * channelcount); - state->samplecountcapacity = SAMPLECOUNT; - state->samplecountavailable = 0; - state->samplecountremaining = 0; - - if (ctx->channel == 0) - return 0; - - if (state->samplebuffer == 0 || state->channelstate == 0) - { - fprintf(stderr, "Error allocating memory\n"); - return 0; - } - - return 1; -} - -int cwav_dspadpcm_setup(cwav_dspadpcmstate* state, cwav_context* ctx, int isloop) -{ - u32 channelcount = ctx->channelcount; - u32 i; - u32 startoffset = 0; - - - if (ctx->channel == 0) - return 0; - - if (state->samplebuffer == 0 || state->channelstate == 0) - return 0; - - state->samplecountavailable = 0; - - if (isloop) - { - state->samplecountremaining = getle32(ctx->infoheader.loopend) - getle32(ctx->infoheader.loopstart); - - startoffset = getle32(ctx->infoheader.loopstart) * 8 / 14; - } - else - { - state->samplecountremaining = getle32(ctx->infoheader.loopend); - startoffset = 0; - } - - - - for(i=0; ichannel[i]; - cwav_dspadpcminfo* adpcminfo = &adpcmchannel->infodspadpcm; - - if (getle16(adpcmchannel->info.codecref.idtype) != 0x300) - { - fprintf(stderr, "Error, not DSP-ADPCM format.\n"); - return 0; - } - - state->channelstate[i].samplebuffer = state->samplebuffer + SAMPLECOUNT * i; - state->channelstate[i].sampleoffset = (u32) (ctx->offset + getle32(adpcmchannel->info.sampleref.offset) + getle32(ctx->header.datablockref.offset) + 8 + startoffset); - if (isloop) - { - state->channelstate[i].yn1 = getle16(adpcminfo->loopyn1); - state->channelstate[i].yn2 = getle16(adpcminfo->loopyn2); - } - else - { - state->channelstate[i].yn1 = getle16(adpcminfo->yn1); - state->channelstate[i].yn2 = getle16(adpcminfo->yn2); - } - stream_in_allocate(&state->channelstate[i].instreamctx, BUFFERSIZE, ctx->file); - stream_in_seek(&state->channelstate[i].instreamctx, state->channelstate[i].sampleoffset); - } - - return 1; -} - -// decode dsp-adpcm to pcm signed 16-bit -int cwav_dspadpcm_decode(cwav_dspadpcmstate* state, cwav_context* ctx) -{ - u32 i, c; - u32 maxsamplecount; - u32 channelcount = ctx->channelcount; - - if (ctx->channel == 0 || state->samplebuffer == 0 || state->channelstate == 0) - return 0; - - - state->samplecountavailable = 0; - if (state->samplecountremaining <= 0) - { - return 1; - } - - while(state->samplecountremaining > 0) - { - u32 samplecountavailable = state->samplecountcapacity - state->samplecountavailable; - - if (state->samplecountremaining < 14) - maxsamplecount = state->samplecountremaining; - else - maxsamplecount = 14; - - if (samplecountavailable < maxsamplecount) - break; - - for(c=0; cchannelstate[c]; - - s16* samplebuffer = channelstate->samplebuffer + state->samplecountavailable; - stream_in_context* instreamctx = &channelstate->instreamctx; - s16 yn1 = channelstate->yn1; - s16 yn2 = channelstate->yn2; - cwav_channel* adpcmchannel = &ctx->channel[c]; - cwav_dspadpcminfo* adpcminfo = &adpcmchannel->infodspadpcm; - - u8 data; - u8 lonibble; - u8 hinibble; - s16 coef1; - s16 coef2; - u32 shift; - s16 table[14]; - - stream_in_reseek(instreamctx); - - - if (0 == stream_in_byte(instreamctx, &data)) - { - fprintf(stderr, "Error reading input stream\n"); - return 1; - } - - lonibble = data & 0xF; - hinibble = data>>4; - - coef1 = getle16(adpcminfo->coef[hinibble*2+0]); - coef2 = getle16(adpcminfo->coef[hinibble*2+1]); - shift = 17 - lonibble; - - for(i=0; i<7; i++) - { - stream_in_byte(instreamctx, &data); - table[i*2+0] = data>>4; - table[i*2+1] = data & 0xF; - } - - - for(i=0; i> shift; - - s32 prediction = (yn1 * coef1 + yn2 * coef2 + xshifted + 0x400)>>11; - - if (prediction < -0x8000) - prediction = -0x8000; - if (prediction > 0x7FFF) - prediction = 0x7FFF; - - yn2 = yn1; - yn1 = prediction; - - samplebuffer[i] = prediction; - } - - channelstate->yn1 = yn1; - channelstate->yn2 = yn2; - } - - state->samplecountremaining -= maxsamplecount; - state->samplecountavailable += maxsamplecount; - } - - return 1; -} - -void cwav_dspadpcm_destroy(cwav_dspadpcmstate* state) -{ - free(state->channelstate); - free(state->samplebuffer); - - state->channelstate = 0; - state->samplebuffer = 0; -} - -void cwav_imaadpcm_init(cwav_imaadpcmstate* state) -{ - memset(state, 0, sizeof(cwav_imaadpcmstate)); -} - - -int cwav_imaadpcm_allocate(cwav_imaadpcmstate* state, cwav_context* ctx) -{ - u32 channelcount = ctx->channelcount; - - - state->samplebuffer = malloc(sizeof(s16) * SAMPLECOUNT * channelcount); - state->channelstate = malloc(sizeof(cwav_imaadpcmchannelstate) * channelcount); - state->samplecountcapacity = SAMPLECOUNT; - state->samplecountavailable = 0; - state->samplecountremaining = 0; - - if (ctx->channel == 0) - return 0; - - if (state->samplebuffer == 0 || state->channelstate == 0) - { - fprintf(stderr, "Error allocating memory\n"); - return 0; - } - - return 1; -} - -int cwav_imaadpcm_setup(cwav_imaadpcmstate* state, cwav_context* ctx, int isloop) -{ - u32 channelcount = ctx->channelcount; - u32 i; - u32 startoffset = 0; - - - if (ctx->channel == 0) - return 0; - - if (state->samplebuffer == 0 || state->channelstate == 0) - { - fprintf(stderr, "Error allocating memory\n"); - return 0; - } - - state->samplecountavailable = 0; - if (isloop) - { - state->samplecountremaining = getle32(ctx->infoheader.loopend) - getle32(ctx->infoheader.loopstart); - - startoffset = getle32(ctx->infoheader.loopstart) / 2; - } - else - { - state->samplecountremaining = getle32(ctx->infoheader.loopend); - startoffset = 0; - } - - for(i=0; ichannel[i]; - cwav_imaadpcminfo* adpcminfo = &adpcmchannel->infoimaadpcm; - - if (getle16(adpcmchannel->info.codecref.idtype) != 0x301) - { - fprintf(stderr, "Error, not IMA-ADPCM format.\n"); - return 0; - } - - state->channelstate[i].samplebuffer = state->samplebuffer + SAMPLECOUNT * i; - state->channelstate[i].sampleoffset = (u32) (ctx->offset + getle32(adpcmchannel->info.sampleref.offset) + getle32(ctx->header.datablockref.offset) + 8 + startoffset); - if (isloop) - { - state->channelstate[i].data = getle16(adpcminfo->loopdata); - state->channelstate[i].tableindex = adpcminfo->looptableindex; - } - else - { - state->channelstate[i].data = getle16(adpcminfo->data); - state->channelstate[i].tableindex = adpcminfo->tableindex; - } - stream_in_allocate(&state->channelstate[i].instreamctx, BUFFERSIZE, ctx->file); - stream_in_seek(&state->channelstate[i].instreamctx, state->channelstate[i].sampleoffset); - } - - return 1; -} - -u8 cwav_imaadpcm_clamp_tableindex(u8 tableindex, int inc) -{ - int unclamped = tableindex + inc; - - if (unclamped < 0) - unclamped = 0; - if (unclamped > 88) - unclamped = 88; - - return unclamped; -} - -// decode ima-adpcm to pcm signed 16-bit -int cwav_imaadpcm_decode(cwav_imaadpcmstate* state, cwav_context* ctx) -{ - u32 i, c; - u32 maxsamplecount; - u32 channelcount = ctx->channelcount; - - if (ctx->channel == 0 || state->samplebuffer == 0 || state->channelstate == 0) - return 0; - - - state->samplecountavailable = 0; - if (state->samplecountremaining <= 0) - { - return 1; - } - - while(state->samplecountremaining > 0) - { - u32 samplecountavailable = state->samplecountcapacity - state->samplecountavailable; - - if (state->samplecountremaining < 2) - maxsamplecount = state->samplecountremaining; - else - maxsamplecount = 2; - - if (samplecountavailable < maxsamplecount) - break; - - for(c=0; cchannelstate[c]; - - s16* samplebuffer = channelstate->samplebuffer + state->samplecountavailable; - stream_in_context* instreamctx = &channelstate->instreamctx; - s16 prediction = channelstate->data; - u8 tableindex = channelstate->tableindex; - cwav_channel* adpcmchannel = &ctx->channel[c]; - cwav_imaadpcminfo* adpcminfo = &adpcmchannel->infoimaadpcm; - u8 data; - - - stream_in_reseek(instreamctx); - - - if (0 == stream_in_byte(instreamctx, &data)) - { - fprintf(stderr, "Error reading input stream\n"); - return 1; - } - - - for(i=0; i 0x7FFF) - prediction = 0x7FFF; - - samplebuffer[i] = prediction; - data >>= 4; - } - - channelstate->data = prediction; - channelstate->tableindex = tableindex; - } - - state->samplecountremaining -= maxsamplecount; - state->samplecountavailable += maxsamplecount; - } - - return 1; -} - -void cwav_imaadpcm_destroy(cwav_imaadpcmstate* state) -{ - free(state->channelstate); - free(state->samplebuffer); - - state->channelstate = 0; - state->samplebuffer = 0; -} - - -void cwav_pcm_init(cwav_pcmstate* state) -{ - memset(state, 0, sizeof(cwav_pcmstate)); -} - -int cwav_pcm_allocate(cwav_pcmstate* state, cwav_context* ctx) -{ - u32 channelcount = ctx->channelcount; - - - state->samplebuffer = malloc(sizeof(s16) * SAMPLECOUNT * channelcount); - state->channelstate = malloc(sizeof(cwav_pcmchannelstate) * channelcount); - state->samplecountcapacity = SAMPLECOUNT; - state->samplecountavailable = 0; - state->samplecountremaining = 0; - - if (ctx->channel == 0) - return 0; - - if (state->samplebuffer == 0 || state->channelstate == 0) - { - fprintf(stderr, "Error allocating memory\n"); - return 0; - } - - return 1; -} - -int cwav_pcm_setup(cwav_pcmstate* state, cwav_context* ctx, int isloop) -{ - u32 channelcount = ctx->channelcount; - u32 i; - u32 startoffset = 0; - - - if (ctx->channel == 0) - return 0; - - if (state->samplebuffer == 0 || state->channelstate == 0) - { - fprintf(stderr, "Error allocating memory\n"); - return 0; - } - - state->samplecountavailable = 0; - state->samplecountcapacity = SAMPLECOUNT; - if (isloop) - { - state->samplecountremaining = getle32(ctx->infoheader.loopend) - getle32(ctx->infoheader.loopstart); - - if (ctx->infoheader.encoding == CWAV_ENCODING_PCM8) - startoffset = getle32(ctx->infoheader.loopstart); - else if (ctx->infoheader.encoding == CWAV_ENCODING_PCM16) - startoffset = getle32(ctx->infoheader.loopstart) * 2; - else - startoffset = 0; - } - else - { - state->samplecountremaining = getle32(ctx->infoheader.loopend); - startoffset = 0; - } - - for(i=0; ichannel[i]; - - state->channelstate[i].samplebuffer = state->samplebuffer + SAMPLECOUNT * i; - state->channelstate[i].sampleoffset = (u32) (ctx->offset + getle32(pcmchannel->info.sampleref.offset) + getle32(ctx->header.datablockref.offset) + 8 + startoffset); - stream_in_allocate(&state->channelstate[i].instreamctx, BUFFERSIZE, ctx->file); - stream_in_seek(&state->channelstate[i].instreamctx, state->channelstate[i].sampleoffset); - } - - return 1; -} - -// decode pcm to pcm signed 16-bit -int cwav_pcm_decode(cwav_pcmstate* state, cwav_context* ctx) -{ - u32 i, c; - u32 maxsamplecount; - u32 channelcount = ctx->channelcount; - - if (ctx->channel == 0 || state->samplebuffer == 0 || state->channelstate == 0) - return 0; - - - state->samplecountavailable = 0; - if (state->samplecountremaining <= 0) - { - return 1; - } - - while(state->samplecountremaining > 0) - { - u32 samplecountavailable = state->samplecountcapacity - state->samplecountavailable; - - if (state->samplecountremaining < 1) - maxsamplecount = state->samplecountremaining; - else - maxsamplecount = 1; - - if (samplecountavailable < maxsamplecount) - break; - - for(c=0; cchannelstate[c]; - - s16* samplebuffer = channelstate->samplebuffer + state->samplecountavailable; - stream_in_context* instreamctx = &channelstate->instreamctx; - cwav_channel* pcmchannel = &ctx->channel[c]; - - - stream_in_reseek(instreamctx); - - for(i=0; iinfoheader.encoding == CWAV_ENCODING_PCM16) - { - if (0 == stream_in_byte(instreamctx, &datalo) || 0 == stream_in_byte(instreamctx, &datahi)) - { - fprintf(stderr, "Error reading input stream\n"); - return 1; - } - samplebuffer[i] = (datahi << 8) | datalo; - } - else if (ctx->infoheader.encoding == CWAV_ENCODING_PCM8) - { - if (0 == stream_in_byte(instreamctx, &datahi)) - { - fprintf(stderr, "Error reading input stream\n"); - return 1; - } - samplebuffer[i] = (datahi << 8); - } - } - } - - state->samplecountremaining -= maxsamplecount; - state->samplecountavailable += maxsamplecount; - } - - return 1; -} - -void cwav_pcm_destroy(cwav_pcmstate* state) -{ - free(state->channelstate); - free(state->samplebuffer); - - state->channelstate = 0; - state->samplebuffer = 0; -} - -const char* cwav_encoding_string(u8 encoding) -{ - switch(encoding) - { - case CWAV_ENCODING_DSPADPCM: return "DSP-ADPCM"; - case CWAV_ENCODING_IMAADPCM: return "IMA-ADPCM"; - case CWAV_ENCODING_PCM8: return "PCM8"; - case CWAV_ENCODING_PCM16: return "PCM16"; - default: return "UNKNOWN"; - } -} - -void cwav_print(cwav_context* ctx) -{ - cwav_header* header = &ctx->header; - cwav_infoheader* infoheader = &ctx->infoheader; - u32 i; - u32 infoheaderoffset = (u32) (ctx->offset + getle32(ctx->header.infoblockref.offset)); - u32 channelcount = getle32(infoheader->channelcount); - - fprintf(stdout, "Header: %c%c%c%c\n", header->magic[0], header->magic[1], header->magic[2], header->magic[3]); - fprintf(stdout, "Byte order mark: 0x%04X\n", getle16(header->byteordermark)); - fprintf(stdout, "Header size: 0x%04X\n", getle16(header->headersize)); - fprintf(stdout, "Version: 0x%08X\n", getle32(header->version)); - fprintf(stdout, "Total size: 0x%08X\n", getle32(header->totalsize)); - fprintf(stdout, "Data blocks: 0x%04X\n", getle16(header->datablocks)); - fprintf(stdout, "Info block idtype: 0x%04X\n", getle16(header->infoblockref.idtype)); - fprintf(stdout, "Info block offset: 0x%08X\n", getle32(header->infoblockref.offset)); - fprintf(stdout, "Info block size: 0x%08X\n", getle32(header->infoblockref.size)); - fprintf(stdout, "Data block idtype: 0x%04X\n", getle16(header->datablockref.idtype)); - fprintf(stdout, "Data block offset: 0x%08X\n", getle32(header->datablockref.offset)); - fprintf(stdout, "Data block size: 0x%08X\n", getle32(header->datablockref.size)); - fprintf(stdout, "\n"); - fprintf(stdout, "Header: %c%c%c%c\n", infoheader->magic[0], infoheader->magic[1], infoheader->magic[2], infoheader->magic[3]); - fprintf(stdout, "Size: 0x%08X\n", getle32(infoheader->size)); - fprintf(stdout, "Encoding: 0x%02X (%s)\n", infoheader->encoding, cwav_encoding_string(infoheader->encoding)); - fprintf(stdout, "Looped: 0x%02X\n", infoheader->looped); - fprintf(stdout, "Samplerate: %d\n", getle32(infoheader->samplerate)); - fprintf(stdout, "Loop start: 0x%08X\n", getle32(infoheader->loopstart)); - fprintf(stdout, "Loop end: 0x%08X\n", getle32(infoheader->loopend)); - fprintf(stdout, "Channels: %d\n", channelcount); - if (ctx->channel != 0) - { - for(i=0; ichannel[i].inforef.offset); - u32 codecoffset = channeloffset + getle32(ctx->channel[i].info.codecref.offset); - u32 sampleoffset = (u32) (ctx->offset + getle32(ctx->channel[i].info.sampleref.offset) + getle32(ctx->header.datablockref.offset) + 8); - - fprintf(stdout, "Channel %d:\n", i); - fprintf(stdout, " > Channel ref idtype: 0x%04X\n", getle16(ctx->channel[i].inforef.idtype)); - fprintf(stdout, " > Channel ref offset: 0x%08X\n", channeloffset); - fprintf(stdout, " > Sample ref idtype: 0x%04X\n", getle16(ctx->channel[i].info.sampleref.idtype)); - fprintf(stdout, " > Sample ref offset: 0x%08X\n", sampleoffset); - fprintf(stdout, " > Codec ref idtype: 0x%04X\n", getle16(ctx->channel[i].info.codecref.idtype)); - fprintf(stdout, " > Codec ref offset: 0x%08X\n", codecoffset); - - -#ifdef CWAV_CODEC_PRINT - if (ctx->infoheader.encoding == CWAV_ENCODING_DSPADPCM && getle16(ctx->channel[i].info.codecref.idtype) == 0x300) - { - u32 j; - - for(j=0; j<16; j++) - fprintf(stdout, " > Adpcm coef %02d: 0x%04X\n", j, getle16(ctx->channel[i].infodspadpcm.coef[j])); - fprintf(stdout, " > Adpcm scale: 0x%04X\n", getle16(ctx->channel[i].infodspadpcm.scale)); - fprintf(stdout, " > Adpcm yn1: 0x%04X\n", getle16(ctx->channel[i].infodspadpcm.yn1)); - fprintf(stdout, " > Adpcm yn2: 0x%04X\n", getle16(ctx->channel[i].infodspadpcm.yn2)); - fprintf(stdout, " > Adpcm loop scale: 0x%04X\n", getle16(ctx->channel[i].infodspadpcm.loopscale)); - fprintf(stdout, " > Adpcm loop yn1: 0x%04X\n", getle16(ctx->channel[i].infodspadpcm.loopyn1)); - fprintf(stdout, " > Adpcm loop yn2: 0x%04X\n", getle16(ctx->channel[i].infodspadpcm.loopyn2)); - } - - if (ctx->infoheader.encoding == CWAV_ENCODING_IMAADPCM && getle16(ctx->channel[i].info.codecref.idtype) == 0x301) - { - fprintf(stdout, " > Adpcm data: 0x%04X\n", getle16(ctx->channel[i].infoimaadpcm.data)); - fprintf(stdout, " > Adpcm tblindex: 0x%02X\n", ctx->channel[i].infoimaadpcm.tableindex); - fprintf(stdout, " > Adpcm loopdata: 0x%04X\n", getle16(ctx->channel[i].infoimaadpcm.loopdata)); - fprintf(stdout, " > Adpcm looptblindex: 0x%02X\n", ctx->channel[i].infoimaadpcm.looptableindex); - } -#endif - } - } -} diff --git a/ctrtool/cwav.h b/ctrtool/cwav.h deleted file mode 100644 index 180f4b0..0000000 --- a/ctrtool/cwav.h +++ /dev/null @@ -1,205 +0,0 @@ -#ifndef _CWAV_H_ -#define _CWAV_H_ - -#include -#include "types.h" -#include "settings.h" -#include "stream.h" - -#define CWAV_ENCODING_PCM8 0 -#define CWAV_ENCODING_PCM16 1 -#define CWAV_ENCODING_DSPADPCM 2 -#define CWAV_ENCODING_IMAADPCM 3 - -typedef struct -{ - u8 idtype[2]; - u8 padding[2]; - u8 offset[4]; -} cwav_reference; - -typedef struct -{ - u8 idtype[2]; - u8 padding[2]; - u8 offset[4]; - u8 size[4]; -} cwav_sizedreference; - - -typedef struct -{ - u8 magic[4]; - u8 byteordermark[2]; - u8 headersize[2]; - u8 version[4]; - u8 totalsize[4]; - u8 datablocks[2]; - u8 reserved[2]; - cwav_sizedreference infoblockref; - cwav_sizedreference datablockref; -} cwav_header; - -typedef struct -{ - u8 magic[4]; - u8 size[4]; - u8 encoding; - u8 looped; - u8 padding[2]; - u8 samplerate[4]; - u8 loopstart[4]; - u8 loopend[4]; - u8 reserved[4]; - u8 channelcount[4]; -} cwav_infoheader; - -typedef struct -{ - cwav_reference sampleref; - cwav_reference codecref; - u8 reserved[4]; -} cwav_channelinfo; - -typedef struct -{ - u8 coef[16][2]; - u8 scale[2]; - u8 yn1[2]; - u8 yn2[2]; - u8 loopscale[2]; - u8 loopyn1[2]; - u8 loopyn2[2]; -} cwav_dspadpcminfo; - -typedef struct -{ - u8 data[2]; - u8 tableindex; - u8 padding; - u8 loopdata[2]; - u8 looptableindex; - u8 looppadding; -} cwav_imaadpcminfo; - - -typedef struct -{ - s16 yn1; - s16 yn2; - u32 sampleoffset; - s16* samplebuffer; - stream_in_context instreamctx; -} cwav_dspadpcmchannelstate; - -typedef struct -{ - cwav_dspadpcmchannelstate* channelstate; - s16* samplebuffer; - u32 samplecountavailable; - u32 samplecountcapacity; - u32 samplecountremaining; -} cwav_dspadpcmstate; - -typedef struct -{ - s16 data; - u8 tableindex; - u32 sampleoffset; - s16* samplebuffer; - stream_in_context instreamctx; -} cwav_imaadpcmchannelstate; - -typedef struct -{ - cwav_imaadpcmchannelstate* channelstate; - s16* samplebuffer; - u32 samplecountavailable; - u32 samplecountcapacity; - u32 samplecountremaining; -} cwav_imaadpcmstate; - -typedef struct -{ - u32 sampleoffset; - s16* samplebuffer; - stream_in_context instreamctx; -} cwav_pcmchannelstate; - -typedef struct -{ - cwav_pcmchannelstate* channelstate; - s16* samplebuffer; - u32 samplecountavailable; - u32 samplecountcapacity; - u32 samplecountremaining; -} cwav_pcmstate; - - -typedef struct -{ - cwav_reference inforef; - cwav_channelinfo info; - cwav_dspadpcminfo infodspadpcm; - cwav_imaadpcminfo infoimaadpcm; -} cwav_channel; - -typedef struct -{ - u8 chunkid[4]; - u8 chunksize[4]; - u8 format[4]; - u8 subchunk1id[4]; - u8 subchunk1size[4]; - u8 audioformat[2]; - u8 numchannels[2]; - u8 samplerate[4]; - u8 byterate[4]; - u8 blockalign[2]; - u8 bitspersample[2]; - u8 subchunk2id[4]; - u8 subchunk2size[4]; -} wav_pcm_header; - -typedef struct -{ - FILE* file; - settings* usersettings; - u64 offset; - u64 size; - u32 channelcount; - cwav_header header; - cwav_infoheader infoheader; - cwav_channel* channel; -} cwav_context; - -void cwav_init(cwav_context* ctx); -void cwav_set_file(cwav_context* ctx, FILE* file); -void cwav_set_offset(cwav_context* ctx, u64 offset); -void cwav_set_size(cwav_context* ctx, u64 size); -void cwav_set_usersettings(cwav_context* ctx, settings* usersettings); -void cwav_process(cwav_context* ctx, u32 actions); -void cwav_dspadpcm_init(cwav_dspadpcmstate* state); -int cwav_dspadpcm_allocate(cwav_dspadpcmstate* state, cwav_context* ctx); -int cwav_dspadpcm_setup(cwav_dspadpcmstate* state, cwav_context* ctx, int isloop); -int cwav_dspadpcm_decode(cwav_dspadpcmstate* state, cwav_context* ctx); -int cwav_dspadpcm_decode_to_wav(cwav_context* ctx, stream_out_context* outstreamctx); -void cwav_dspadpcm_destroy(cwav_dspadpcmstate* state); -void cwav_imaadpcm_init(cwav_imaadpcmstate* state); -int cwav_imaadpcm_allocate(cwav_imaadpcmstate* state, cwav_context* ctx); -int cwav_imaadpcm_setup(cwav_imaadpcmstate* state, cwav_context* ctx, int isloop); -int cwav_imaadpcm_decode(cwav_imaadpcmstate* state, cwav_context* ctx); -int cwav_imaadpcm_decode_to_wav(cwav_context* ctx, stream_out_context* outstreamctx); -u8 cwav_imaadpcm_clamp_tableindex(u8 tableindex, int inc); -void cwav_imaadpcm_destroy(cwav_imaadpcmstate* state); -void cwav_pcm_init(cwav_pcmstate* state); -int cwav_pcm_allocate(cwav_pcmstate* state, cwav_context* ctx); -int cwav_pcm_setup(cwav_pcmstate* state, cwav_context* ctx, int isloop); -int cwav_pcm_decode(cwav_pcmstate* state, cwav_context* ctx); -int cwav_pcm_decode_to_wav(cwav_context* ctx, stream_out_context* outstreamctx); -void cwav_pcm_destroy(cwav_pcmstate* state); -void cwav_write_wav_header(cwav_context* ctx, stream_out_context* outstreamctx, u32 size); -int cwav_save_to_wav(cwav_context* ctx, const char* filepath); -void cwav_print(cwav_context* ctx); - -#endif // _CWAV_H_ diff --git a/ctrtool/exefs.c b/ctrtool/exefs.c deleted file mode 100644 index 465bc8b..0000000 --- a/ctrtool/exefs.c +++ /dev/null @@ -1,342 +0,0 @@ -#include -#include -#include - -#include "types.h" -#include "exefs.h" -#include "utils.h" -#include "ncch.h" -#include "lzss.h" - -void exefs_init(exefs_context* ctx) -{ - memset(ctx, 0, sizeof(exefs_context)); -} - -void exefs_set_file(exefs_context* ctx, FILE* file) -{ - ctx->file = file; -} - -void exefs_set_offset(exefs_context* ctx, u64 offset) -{ - ctx->offset = offset; -} - -void exefs_set_size(exefs_context* ctx, u64 size) -{ - ctx->size = size; -} - -void exefs_set_usersettings(exefs_context* ctx, settings* usersettings) -{ - ctx->usersettings = usersettings; -} - -void exefs_set_titleid(exefs_context* ctx, u8 titleid[8]) -{ - memcpy(ctx->titleid, titleid, 8); -} - -void exefs_set_compressedflag(exefs_context* ctx, int compressedflag) -{ - ctx->compressedflag = compressedflag; -} - -void exefs_set_encrypted(exefs_context* ctx, u32 encrypted) -{ - ctx->encrypted = encrypted; -} - -void exefs_set_keys(exefs_context* ctx, u8 key0[16], u8 key1[16]) -{ - memcpy(ctx->key[0], key0, 16); - memcpy(ctx->key[1], key1, 16); -} - -void exefs_set_counter(exefs_context* ctx, u8 counter[16]) -{ - memcpy(ctx->counter, counter, 16); -} - -void exefs_save(exefs_context* ctx, u32 index, u32 flags) -{ - exefs_sectionheader* section = (exefs_sectionheader*)(ctx->header.section + index); - char outfname[MAX_PATH]; - char name[64]; - u32 offset; - u32 size; - FILE* fout; - u32 compressedsize = 0; - u32 decompressedsize = 0; - u8* compressedbuffer = 0; - u8* decompressedbuffer = 0; - filepath* dirpath = 0; - - // determine offset/size of target - offset = getle32(section->offset) + sizeof(exefs_header); - size = getle32(section->size); - dirpath = settings_get_exefs_dir_path(ctx->usersettings); - - if (size == 0 || dirpath == 0 || dirpath->valid == 0) - return; - - if (size >= ctx->size) - { - fprintf(stderr, "Error, ExeFS section %d size invalid\n", index); - return; - } - - // create new file - memset(name, 0, sizeof(name)); - memcpy(name, section->name, 8); - - - memcpy(outfname, dirpath->pathname, MAX_PATH); - strcat(outfname, "/"); - - if (name[0] == '.') - strcat(outfname, name+1); - else - strcat(outfname, name); - strcat(outfname, ".bin"); - - fout = fopen(outfname, "wb"); - - if (fout == 0) - { - fprintf(stderr, "Error, failed to create file %s\n", outfname); - goto clean; - } - - // seek in source file to location of target data - fseeko64(ctx->file, ctx->offset + offset, SEEK_SET); - - // do decryption prep - if (ctx->encrypted) - { - // setup aes counter - ctr_init_counter(&ctx->aes, ctx->counter); - ctr_add_counter(&ctx->aes, offset / 0x10); - - // setup key - if (strncmp((const char*)section->name, "icon", 8) == 0 || strncmp((const char*)section->name, "banner", 8) == 0) - ctr_init_key(&ctx->aes, ctx->key[0]); - else - ctr_init_key(&ctx->aes, ctx->key[1]); - } - - // if this is file0, and compression is set or forced: decompress section - if (index == 0 && (ctx->compressedflag || (flags & DecompressCodeFlag)) && ((flags & RawFlag) == 0)) - { - fprintf(stdout, "Decompressing section %s to %s...\n", name, outfname); - - compressedsize = size; - compressedbuffer = malloc(compressedsize); - - if (compressedbuffer == 0) - { - fprintf(stdout, "Error allocating memory\n"); - goto clean; - } - if (compressedsize != fread(compressedbuffer, 1, compressedsize, ctx->file)) - { - fprintf(stdout, "Error reading input file\n"); - goto clean; - } - - // decrypt if required - if (ctx->encrypted) - ctr_crypt_counter(&ctx->aes, compressedbuffer, compressedbuffer, compressedsize); - - - decompressedsize = lzss_get_decompressed_size(compressedbuffer, compressedsize); - decompressedbuffer = malloc(decompressedsize); - if (decompressedbuffer == 0) - { - fprintf(stdout, "Error allocating memory\n"); - goto clean; - } - - if (0 == lzss_decompress(compressedbuffer, compressedsize, decompressedbuffer, decompressedsize)) - goto clean; - - if (decompressedsize != fwrite(decompressedbuffer, 1, decompressedsize, fout)) - { - fprintf(stdout, "Error writing output file\n"); - goto clean; - } - } - else - { - u8 buffer[16 * 1024]; - - fprintf(stdout, "Saving section %s to %s...\n", name, outfname); - - while(size) - { - u32 max = sizeof(buffer); - if (max > size) - max = size; - - if (max != fread(buffer, 1, max, ctx->file)) - { - fprintf(stdout, "Error reading input file\n"); - goto clean; - } - - if (ctx->encrypted) - ctr_crypt_counter(&ctx->aes, buffer, buffer, max); - - if (max != fwrite(buffer, 1, max, fout)) - { - fprintf(stdout, "Error writing output file\n"); - goto clean; - } - - size -= max; - } - } - -clean: - if (fout) - fclose(fout); - free(compressedbuffer); - free(decompressedbuffer); - return; -} - -void exefs_read_header(exefs_context* ctx, u32 flags) -{ - fseeko64(ctx->file, ctx->offset, SEEK_SET); - fread(&ctx->header, 1, sizeof(exefs_header), ctx->file); - - if (ctx->encrypted) { - ctr_init_key(&ctx->aes, ctx->key[0]); - ctr_init_counter(&ctx->aes, ctx->counter); - ctr_crypt_counter(&ctx->aes, (u8*)&ctx->header, (u8*)&ctx->header, sizeof(exefs_header)); - } - -} - -void exefs_calculate_hash(exefs_context* ctx, u8 hash[32]) -{ - ctr_sha_256((const u8*)&ctx->header, sizeof(exefs_header), hash); -} - -void exefs_process(exefs_context* ctx, u32 actions) -{ - u32 i; - - exefs_read_header(ctx, actions); - - if (actions & VerifyFlag) - { - for(i=0; i<8; i++) - ctx->hashcheck[i] = exefs_verify(ctx, i, actions)? Good : Fail; - } - - if (actions & InfoFlag) - { - exefs_print(ctx); - } - - if (actions & ExtractFlag) - { - filepath* dirpath = settings_get_exefs_dir_path(ctx->usersettings); - - if (dirpath && dirpath->valid) - { - makedir(dirpath->pathname); - for(i=0; i<8; i++) - exefs_save(ctx, i, actions); - } - } -} - -int exefs_verify(exefs_context* ctx, u32 index, u32 flags) -{ - exefs_sectionheader* section = (exefs_sectionheader*)(ctx->header.section + index); - u32 offset; - u32 size; - u8 buffer[16 * 1024]; - u8 hash[0x20]; - - - offset = getle32(section->offset) + sizeof(exefs_header); - size = getle32(section->size); - - if (size == 0) - return 0; - - fseeko64(ctx->file, ctx->offset + offset, SEEK_SET); - if (strncmp((const char*)section->name, "icon", 8) == 0 || strncmp((const char*)section->name, "banner", 8) == 0) - ctr_init_key(&ctx->aes, ctx->key[0]); - else - ctr_init_key(&ctx->aes, ctx->key[1]); - ctr_init_counter(&ctx->aes, ctx->counter); - ctr_add_counter(&ctx->aes, offset / 0x10); - - ctr_sha_256_init(&ctx->sha); - - while(size) - { - u32 max = sizeof(buffer); - if (max > size) - max = size; - - if (max != fread(buffer, 1, max, ctx->file)) - { - fprintf(stdout, "Error reading input file\n"); - goto clean; - } - - if (ctx->encrypted) - ctr_crypt_counter(&ctx->aes, buffer, buffer, max); - - ctr_sha_256_update(&ctx->sha, buffer, max); - - size -= max; - } - - ctr_sha_256_finish(&ctx->sha, hash); - - if (memcmp(hash, ctx->header.hashes[7-index], 0x20) == 0) - return 1; -clean: - return 0; -} - -void exefs_print(exefs_context* ctx) -{ - u32 i; - char sectname[9]; - u32 sectoffset; - u32 sectsize; - - fprintf(stdout, "\nExeFS:\n"); - for(i=0; iheader.section + i); - - - memset(sectname, 0, sizeof(sectname)); - memcpy(sectname, section->name, 8); - - sectoffset = getle32(section->offset); - sectsize = getle32(section->size); - - if (sectsize) - { - fprintf(stdout, "Section name: %s\n", sectname); - fprintf(stdout, "Section offset: 0x%08x\n", sectoffset + 0x200); - fprintf(stdout, "Section size: 0x%08x\n", sectsize); - if (ctx->hashcheck[i] == Good) - memdump(stdout, "Section hash (GOOD): ", ctx->header.hashes[7-i], 0x20); - else if (ctx->hashcheck[i] == Fail) - memdump(stdout, "Section hash (FAIL): ", ctx->header.hashes[7-i], 0x20); - else - memdump(stdout, "Section hash: ", ctx->header.hashes[7-i], 0x20); - } - } -} diff --git a/ctrtool/exefs.h b/ctrtool/exefs.h deleted file mode 100644 index fd6e8f0..0000000 --- a/ctrtool/exefs.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef _EXEFS_H_ -#define _EXEFS_H_ - -#include "types.h" -#include "info.h" -#include "ctr.h" -#include "filepath.h" -#include "settings.h" - -#define EXEFS_SECTION_NUM 8 - -typedef struct -{ - u8 name[8]; - u8 offset[4]; - u8 size[4]; -} exefs_sectionheader; - - -typedef struct -{ - exefs_sectionheader section[EXEFS_SECTION_NUM]; - u8 reserved[0x80]; - u8 hashes[EXEFS_SECTION_NUM][0x20]; -} exefs_header; - -typedef struct -{ - FILE* file; - settings* usersettings; - u8 titleid[8]; - u8 counter[16]; - u8 key[2][16]; - u64 offset; - u64 size; - exefs_header header; - ctr_aes_context aes; - ctr_sha256_context sha; - int hashcheck[EXEFS_SECTION_NUM]; - int compressedflag; - int encrypted; -} exefs_context; - -void exefs_init(exefs_context* ctx); -void exefs_set_file(exefs_context* ctx, FILE* file); -void exefs_set_offset(exefs_context* ctx, u64 offset); -void exefs_set_size(exefs_context* ctx, u64 size); -void exefs_set_usersettings(exefs_context* ctx, settings* usersettings); -void exefs_set_titleid(exefs_context* ctx, u8 titleid[8]); -void exefs_set_counter(exefs_context* ctx, u8 counter[16]); -void exefs_set_compressedflag(exefs_context* ctx, int compressedflag); -void exefs_set_keys(exefs_context* ctx, u8 key[16], u8 special_key[16]); -void exefs_set_encrypted(exefs_context* ctx, u32 encrypted); -void exefs_read_header(exefs_context* ctx, u32 flags); -void exefs_calculate_hash(exefs_context* ctx, u8 hash[32]); -void exefs_process(exefs_context* ctx, u32 actions); -void exefs_print(exefs_context* ctx); -void exefs_save(exefs_context* ctx, u32 index, u32 flags); -int exefs_verify(exefs_context* ctx, u32 index, u32 flags); -void exefs_determine_key(exefs_context* ctx, u32 actions); -#endif // _EXEFS_H_ diff --git a/ctrtool/exheader.c b/ctrtool/exheader.c deleted file mode 100644 index 86609d8..0000000 --- a/ctrtool/exheader.c +++ /dev/null @@ -1,704 +0,0 @@ -#include -#include -#include - -#include "types.h" -#include "exheader.h" -#include "utils.h" -#include "ncch.h" -#include "syscalls.h" -#include - -void exheader_init(exheader_context* ctx) -{ - memset(ctx, 0, sizeof(exheader_context)); -} - -void exheader_set_file(exheader_context* ctx, FILE* file) -{ - ctx->file = file; -} - -void exheader_set_offset(exheader_context* ctx, u64 offset) -{ - ctx->offset = offset; -} - -void exheader_set_size(exheader_context* ctx, u64 size) -{ - ctx->size = size; -} - -void exheader_set_usersettings(exheader_context* ctx, settings* usersettings) -{ - ctx->usersettings = usersettings; -} - -void exheader_set_titleid(exheader_context* ctx, u8 titleid[8]) -{ - memcpy(ctx->titleid, titleid, 8); -} - -void exheader_set_programid(exheader_context* ctx, u8 programid[8]) -{ - memcpy(ctx->programid, programid, 8); -} - -void exheader_set_hash(exheader_context* ctx, u8 hash[32]) -{ - memcpy(ctx->hash, hash, 32); -} - -void exheader_set_counter(exheader_context* ctx, u8 counter[16]) -{ - memcpy(ctx->counter, counter, 16); -} - -int exheader_get_compressedflag(exheader_context* ctx) -{ - return ctx->compressedflag; -} - -void exheader_set_encrypted(exheader_context* ctx, u32 encrypted) -{ - ctx->encrypted = encrypted; -} - -void exheader_set_key(exheader_context* ctx, u8 key[16]) -{ - memcpy(ctx->key, key, 16); -} - - -void exheader_read(exheader_context* ctx, u32 actions) -{ - if (ctx->haveread == 0) - { - fseeko64(ctx->file, ctx->offset, SEEK_SET); - fread(&ctx->header, 1, sizeof(exheader_header), ctx->file); - - ctr_init_key(&ctx->aes, ctx->key); - ctr_init_counter(&ctx->aes, ctx->counter); - if (ctx->encrypted) - ctr_crypt_counter(&ctx->aes, (u8*)&ctx->header, (u8*)&ctx->header, sizeof(exheader_header)); - - ctx->haveread = 1; - } -} - -int exheader_hash_valid(exheader_context* ctx) -{ - u8 hash[32]; - ctr_sha_256((u8*)&ctx->header, 0x400, hash); - - if(memcmp(ctx->hash,hash,0x20)){ - fprintf(stderr, "Error, exheader hash mismatch. Wrong key?\n"); - return 0; - } - - return 1; -} - -int exheader_programid_valid(exheader_context* ctx) -{ - if (!settings_get_ignore_programid(ctx->usersettings)) - { - if (memcmp(ctx->header.arm11systemlocalcaps.programid, ctx->programid, 8)) - { - fprintf(stderr, "Error, program id mismatch. Wrong key?\n"); - return 0; - } - } - - return 1; -} - -void exheader_deserialise_arm11localcaps_permissions(exheader_arm11systemlocalcaps_deserialised *caps, const exheader_arm11systemlocalcaps *arm11) -{ - int i; - - memset(caps, 0, sizeof(exheader_arm11systemlocalcaps_deserialised)); - - memcpy(caps->program_id, arm11->programid, 8); - caps->core_version = getle32(arm11->coreversion); - - caps->enable_l2_cache = (arm11->flag[0] >> 0) & 1; - caps->new3ds_cpu_speed = (arm11->flag[0] >> 1) & 1; - caps->new3ds_systemmode = (arm11->flag[1] >> 0) & 15; - - caps->ideal_processor = (arm11->flag[2] >> 0) & 3; - caps->affinity_mask = (arm11->flag[2] >> 2) & 3; - caps->old3ds_systemmode = (arm11->flag[2] >> 4) & 15; - - caps->priority = (s8)arm11->flag[3]; - - // storage info - if (arm11->storageinfo.otherattributes & 2) { - caps->extdata_id = 0; - for (i = 0; i < 3; i++) - caps->other_user_saveid[i] = 0; - caps->use_other_variation_savedata = 0; - - for (i = 0; i < 3; i++) - caps->accessible_saveid[i] = 0xfffff & (getle64(arm11->storageinfo.accessibleuniqueids) >> 20 * (2 - i)); - for (i = 0; i < 3; i++) - caps->accessible_saveid[i+3] = 0xfffff & (getle64(arm11->storageinfo.extsavedataid) >> 20 * (2 - i)); - } - else { - caps->extdata_id = getle64(arm11->storageinfo.extsavedataid); - for (i = 0; i < 3; i++) - caps->other_user_saveid[i] = 0xfffff & (getle64(arm11->storageinfo.accessibleuniqueids) >> 20 * (2 - i)); - caps->use_other_variation_savedata = (getle64(arm11->storageinfo.accessibleuniqueids) >> 60) & 1; - - for (i = 0; i < 6; i++) - caps->accessible_saveid[i] = 0; - } - - caps->system_saveid[0] = getle32(arm11->storageinfo.systemsavedataid); - caps->system_saveid[1] = getle32(arm11->storageinfo.systemsavedataid + 4); - caps->accessinfo = getle64(arm11->storageinfo.accessinfo) & ~((u64)0xff00000000000000); - - // Service Access Control - for (i = 0; i < 34; i++) - strncpy(caps->service_access_control[i], (char*)arm11->serviceaccesscontrol[i], 8); - - caps->resource_limit_category = arm11->resourcelimitcategory; -} - -int exheader_process(exheader_context* ctx, u32 actions) -{ - exheader_read(ctx, actions); - - if (ctx->header.codesetinfo.flags.flag & 1) - ctx->compressedflag = 1; - - exheader_deserialise_arm11localcaps_permissions(&ctx->system_local_caps, &ctx->header.arm11systemlocalcaps); - - if (actions & VerifyFlag) - exheader_verify(ctx); - - if (actions & InfoFlag) - exheader_print(ctx, actions); - - return 1; -} - -void exheader_print_arm9accesscontrol(exheader_context* ctx) -{ - unsigned int i; - unsigned int flags[15*8]; - - fprintf(stdout, "ARM9 Desc. version: 0x%X\n", ctx->header.arm9accesscontrol.descversion); - - for(i=0; i<15*8; i++) - { - if (ctx->header.arm9accesscontrol.descriptors[i/8] & (1<<(i&7))) - flags[i] = 1; - else - flags[i] = 0; - } - - fprintf(stdout, "Mount NAND fs: %s\n", flags[0]? "YES" : "NO"); - fprintf(stdout, "Mount NAND RO write fs: %s\n", flags[1]? "YES" : "NO"); - fprintf(stdout, "Mount NAND TWL fs: %s\n", flags[2]? "YES" : "NO"); - fprintf(stdout, "Mount NAND W fs: %s\n", flags[3]? "YES" : "NO"); - fprintf(stdout, "Mount CARD SPI fs: %s\n", flags[4]? "YES" : "NO"); - fprintf(stdout, "Use SDIF3: %s\n", flags[5]? "YES" : "NO"); - fprintf(stdout, "Create seed: %s\n", flags[6]? "YES" : "NO"); - fprintf(stdout, "Use CARD SPI: %s\n", flags[7]? "YES" : "NO"); - fprintf(stdout, "SD Application: %s\n", flags[8]? "YES" : "NO"); - fprintf(stdout, "Use Direct SDMC: %s\n", flags[9]? "YES" : "NO"); - - for(i=10; i<15*8; i++) - { - if (flags[i]) - fprintf(stdout, "Unknown flag: %d\n", i); - } -} - -void exheader_print_arm11kernelcapabilities(exheader_context* ctx, u32 actions) -{ - unsigned int i, j; - unsigned int systemcallmask[8]; - unsigned int unknowndescriptor[28]; - unsigned int svccount = 0; - unsigned int svcmask = 0; - unsigned int interrupt[0x80]; - unsigned int interruptcount = 0; - - memset(systemcallmask, 0, sizeof(systemcallmask)); - memset(interrupt, 0, sizeof(interrupt)); - - for(i=0; i<28; i++) - { - unsigned int descriptor = getle32(ctx->header.arm11kernelcaps.descriptors[i]); - - unknowndescriptor[i] = 0; - - if ((descriptor & (0x1f<<27)) == (0x1e<<27)) - systemcallmask[(descriptor>>24) & 7] = descriptor & 0x00FFFFFF; - else if ((descriptor & (0x7f<<25)) == (0x7e<<25)) - fprintf(stdout, "Kernel release version: %d.%d\n", (descriptor>>8)&0xFF, (descriptor>>0)&0xFF); - else if ((descriptor & (0xf<<28)) == (0xe<<28)) - { - for(j=0; j<4; j++) - interrupt[(descriptor >> (j*7)) & 0x7F] = 1; - } - else if ((descriptor & (0xff<<24)) == (0xfe<<24)) - fprintf(stdout, "Handle table size: 0x%X\n", descriptor & 0x3FF); - else if ((descriptor & (0xfff<<20)) == (0xffe<<20)) - fprintf(stdout, "Mapping IO address: 0x%X (%s)\n", (descriptor & 0xFFFFF)<<12, (descriptor&(1<<20))?"RO":"RW"); - else if ((descriptor & (0x7ff<<21)) == (0x7fc<<21)) - fprintf(stdout, "Mapping static address: 0x%X (%s)\n", (descriptor & 0x1FFFFF)<<12, (descriptor&(1<<20))?"RO":"RW"); - else if ((descriptor & (0x1ff<<23)) == (0x1fe<<23)) - { - unsigned int memorytype = (descriptor>>8)&15; - fprintf(stdout, "Kernel flags: \n"); - fprintf(stdout, " > Allow debug: %s\n", (descriptor&(1<<0))?"YES":"NO"); - fprintf(stdout, " > Force debug: %s\n", (descriptor&(1<<1))?"YES":"NO"); - fprintf(stdout, " > Allow non-alphanum: %s\n", (descriptor&(1<<2))?"YES":"NO"); - fprintf(stdout, " > Shared page writing: %s\n", (descriptor&(1<<3))?"YES":"NO"); - fprintf(stdout, " > Privilege priority: %s\n", (descriptor&(1<<4))?"YES":"NO"); - fprintf(stdout, " > Allow main() args: %s\n", (descriptor&(1<<5))?"YES":"NO"); - fprintf(stdout, " > Shared device mem: %s\n", (descriptor&(1<<6))?"YES":"NO"); - fprintf(stdout, " > Runnable on sleep: %s\n", (descriptor&(1<<7))?"YES":"NO"); - fprintf(stdout, " > Special memory: %s\n", (descriptor&(1<<12))?"YES":"NO"); - fprintf(stdout, " > Access Core 2: %s\n", (descriptor&(1<<13))?"YES":"NO"); - - - switch(memorytype) - { - case 1: fprintf(stdout, " > Memory type: APPLICATION\n"); break; - case 2: fprintf(stdout, " > Memory type: SYSTEM\n"); break; - case 3: fprintf(stdout, " > Memory type: BASE\n"); break; - default: fprintf(stdout, " > Memory type: Unknown (%d)\n", memorytype); break; - } - } - else if (descriptor != 0xFFFFFFFF) - unknowndescriptor[i] = 1; - } - - fprintf(stdout, "Allowed systemcalls: "); - if(!(actions & ShowSyscallsFlag)) - { - for(i=0; i<8; i++) - { - for(j=0; j<24; j++) - { - svcmask = systemcallmask[i]; - - if (svcmask & (1< 0x%02X %s\n", svcid, svcname); - } - } - } - } - - fprintf(stdout, "Allowed interrupts: "); - for(i=0; i<0x7F; i++) - { - if (interrupt[i]) - { - if (interruptcount == 0) - { - fprintf(stdout, "0x%02X", i); - } - else if ( (interruptcount & 7) == 0) - { - fprintf(stdout, " "); - fprintf(stdout, "0x%02X", i); - } - else - { - fprintf(stdout, ", 0x%02X", i); - } - - interruptcount++; - if ( (interruptcount & 7) == 0) - { - fprintf(stdout, "\n"); - } - } - } - if (interruptcount & 7) - fprintf(stdout, "\n"); - if (interruptcount == 0) - fprintf(stdout, "none\n"); - - for(i=0; i<28; i++) - { - unsigned int descriptor = getle32(ctx->header.arm11kernelcaps.descriptors[i]); - - if (unknowndescriptor[i]) - fprintf(stdout, "Unknown descriptor: %08X\n", descriptor); - } -} - -char* exheader_print_accessinfobit(u32 bit, char *str) -{ - switch(bit) - { - case 0 : - sprintf(str,"Category System Application"); - break; - case 1 : - sprintf(str,"Category Hardware Check"); - break; - case 2 : - sprintf(str,"Category File System Tool"); - break; - case 3 : - sprintf(str,"Debug"); - break; - case 4 : - sprintf(str,"TWL Card Backup"); - break; - case 5 : - sprintf(str,"TWL Nand Data"); - break; - case 6 : - sprintf(str,"BOSS"); - break; - case 7 : - sprintf(str,"Direct SDMC"); - break; - case 8 : - sprintf(str,"Core"); - break; - case 9 : - sprintf(str,"CTR NAND RO"); - break; - case 10 : - sprintf(str,"CTR NAND RW"); - break; - case 11 : - sprintf(str,"CTR NAND RO (Write Access)"); - break; - case 12 : - sprintf(str,"Category System Settings"); - break; - case 13 : - sprintf(str,"CARD BOARD"); - break; - case 14 : - sprintf(str,"Export Import IVS"); - break; - case 15 : - sprintf(str,"Direct SDMC (Write Only)"); - break; - case 16 : - sprintf(str,"Switch Cleanup"); - break; - case 17 : - sprintf(str,"Save Data Move"); - break; - case 18 : - sprintf(str,"Shop"); - break; - case 19 : - sprintf(str,"Shell"); - break; - case 20 : - sprintf(str,"Category HomeMenu"); - break; - case 21 : - sprintf(str,"Seed DB"); - break; - default : - sprintf(str,"Bit %d (unknown)",bit); - break; - } - - return str; -} - -void exheader_print_arm11accessinfo(exheader_context* ctx) -{ - char str[100]; - u64 i, bit; - for(i = 0; i < 56; i++) - { - bit = ((u64)1 << i); - if((ctx->system_local_caps.accessinfo & bit) == bit) - fprintf(stdout, " > %s\n",exheader_print_accessinfobit((u32)i,str)); - } -} - -void exheader_print_arm11storageinfo(exheader_context* ctx) -{ - u32 i; - - fprintf(stdout, "Ext savedata id: 0x%"PRIx64"\n",ctx->system_local_caps.extdata_id); - for(i = 0; i < 2; i++) - fprintf(stdout, "System savedata id %d: 0x%x %s\n",i+1, ctx->system_local_caps.system_saveid[i],exheader_getvalidstring(ctx->validsystemsaveID[i])); - for(i = 0; i < 3; i++) - fprintf(stdout, "OtherUserSaveDataId%d: 0x%x\n",i+1, ctx->system_local_caps.other_user_saveid[i]); - fprintf(stdout, "Accessible Savedata Ids:\n"); - for(i = 0; i < 6; i++) - { - if(ctx->system_local_caps.accessible_saveid[i] != 0x00000) - fprintf(stdout, " > 0x%05x\n", ctx->system_local_caps.accessible_saveid[i]); - } - - fprintf(stdout, "Other Variation Saves: %s\n", ctx->system_local_caps.use_other_variation_savedata ? "Accessible" : "Inaccessible"); - fprintf(stdout, "Access info: 0x%"PRIx64" %s\n", ctx->system_local_caps.accessinfo,exheader_getvalidstring(ctx->validaccessinfo)); - exheader_print_arm11accessinfo(ctx); -} - -int exheader_signature_verify(exheader_context* ctx, rsakey2048* key) -{ - u8 hash[0x20]; - - ctr_sha_256(ctx->header.accessdesc.ncchpubkeymodulus, 0x300, hash); - return ctr_rsa_verify_hash(ctx->header.accessdesc.signature, hash, key); -} - -void exheader_verify(exheader_context* ctx) -{ - unsigned int i, j; - exheader_arm11systemlocalcaps_deserialised accessdesc; - - exheader_deserialise_arm11localcaps_permissions(&accessdesc, &ctx->header.accessdesc.arm11systemlocalcaps); - - ctx->validsystemsaveID[0] = Good; - ctx->validsystemsaveID[1] = Good; - ctx->validaccessinfo = Good; - ctx->validcoreversion = Good; - ctx->validprogramid = Good; - ctx->validpriority = Good; - ctx->validaffinitymask = Good; - ctx->valididealprocessor = Good; - ctx->validold3dssystemmode = Good; - ctx->validnew3dssystemmode = Good; - ctx->validenablel2cache = Good; - ctx->validnew3dscpuspeed = Good; - ctx->validservicecontrol = Good; - - for(i=0; i<8; i++) - { - if (ctx->system_local_caps.program_id[i] == accessdesc.program_id[i] || accessdesc.program_id[i] == 0xFF) - continue; - ctx->validprogramid = Fail; - break; - } - - if (ctx->system_local_caps.core_version != accessdesc.core_version) - ctx->validcoreversion = Fail; - - if (ctx->system_local_caps.priority < accessdesc.priority) - ctx->validpriority = Fail; - - if((1<system_local_caps.ideal_processor & accessdesc.ideal_processor) == 0) - ctx->valididealprocessor = Fail; - - if (ctx->system_local_caps.affinity_mask & ~accessdesc.affinity_mask) - ctx->validaffinitymask = Fail; - - if (ctx->system_local_caps.old3ds_systemmode > accessdesc.old3ds_systemmode) - ctx->validold3dssystemmode = Fail; - - if (ctx->system_local_caps.new3ds_systemmode > accessdesc.new3ds_systemmode) - ctx->validnew3dssystemmode = Fail; - - if (ctx->system_local_caps.enable_l2_cache != accessdesc.enable_l2_cache) - ctx->validenablel2cache = Fail; - - if (ctx->system_local_caps.new3ds_cpu_speed != accessdesc.new3ds_cpu_speed) - ctx->validnew3dscpuspeed = Fail; - - - - - // Storage Info Verify - if(ctx->system_local_caps.system_saveid[0] & ~accessdesc.system_saveid[0]) - ctx->validsystemsaveID[0] = Fail; - if(ctx->system_local_caps.system_saveid[1] & ~accessdesc.system_saveid[1]) - ctx->validsystemsaveID[1] = Fail; - - - if (ctx->system_local_caps.accessinfo & ~accessdesc.accessinfo) - ctx->validaccessinfo = Fail; - - // Service Access Control - for (i = 0; i < 34; i++) { - if (strlen(ctx->system_local_caps.service_access_control[i]) == 0) - continue; - - for (j = 0; j < 34; j++) { - if (strcmp(ctx->system_local_caps.service_access_control[i], accessdesc.service_access_control[j]) == 0) - break; - } - - if (strcmp(ctx->system_local_caps.service_access_control[i], accessdesc.service_access_control[j]) == 0) - continue; - - ctx->validservicecontrol = Fail; - } - - if (ctx->usersettings) - ctx->validsignature = exheader_signature_verify(ctx, &ctx->usersettings->keys.ncchdescrsakey); -} - -const char* exheader_getvalidstring(int valid) -{ - if (valid == 0) - return ""; - else if (valid == 1) - return "(GOOD)"; - else - return "(FAIL)"; -} - -const char* exheader_getsystemmodestring(u8 systemmode) -{ - switch (systemmode) - { - case (sysmode_64MB) : - return "64MB"; - case (sysmode_96MB) : - return "96MB"; - case (sysmode_80MB) : - return "80MB"; - case (sysmode_72MB) : - return "72MB"; - case (sysmode_32MB) : - return "32MB"; - default: - return "Unknown"; - } -} - -const char* exheader_getsystemmodeextstring(u8 systemmodeext, u8 systemmode) -{ - switch (systemmodeext) - { - case (sysmode_ext_LEGACY) : - return exheader_getsystemmodestring(systemmode); - case (sysmode_ext_124MB) : - return "124MB"; - case (sysmode_ext_178MB) : - return "178MB"; - default: - return "124MB"; - } -} - - -void exheader_print(exheader_context* ctx, u32 actions) -{ - u32 i; - u64 savedatasize = getle64(ctx->header.systeminfo.savedatasize); - exheader_codesetinfo* codesetinfo = &ctx->header.codesetinfo; - - - fprintf(stdout, "\nExtended header:\n"); - if (ctx->validsignature == Unchecked) - memdump(stdout, "Signature: ", ctx->header.accessdesc.signature, 0x100); - else if (ctx->validsignature == Good) - memdump(stdout, "Signature (GOOD): ", ctx->header.accessdesc.signature, 0x100); - else if (ctx->validsignature == Fail) - memdump(stdout, "Signature (FAIL): ", ctx->header.accessdesc.signature, 0x100); - printf("\n"); - memdump(stdout, "NCCH Hdr RSA Modulus: ", ctx->header.accessdesc.ncchpubkeymodulus, 0x100); - fprintf(stdout, "Name: %.8s\n", codesetinfo->name); - fprintf(stdout, "Flag: %02X ", codesetinfo->flags.flag); - if (codesetinfo->flags.flag & 1) - fprintf(stdout, "[compressed]"); - if (codesetinfo->flags.flag & 2) - fprintf(stdout, "[sd app]"); - fprintf(stdout, "\n"); - fprintf(stdout, "Remaster version: %04X\n", getle16(codesetinfo->flags.remasterversion)); - - fprintf(stdout, "Code text address: 0x%08X\n", getle32(codesetinfo->text.address)); - fprintf(stdout, "Code text size: 0x%08X\n", getle32(codesetinfo->text.codesize)); - fprintf(stdout, "Code text max pages: 0x%08X (0x%08X)\n", getle32(codesetinfo->text.nummaxpages), getle32(codesetinfo->text.nummaxpages)*0x1000); - fprintf(stdout, "Code ro address: 0x%08X\n", getle32(codesetinfo->ro.address)); - fprintf(stdout, "Code ro size: 0x%08X\n", getle32(codesetinfo->ro.codesize)); - fprintf(stdout, "Code ro max pages: 0x%08X (0x%08X)\n", getle32(codesetinfo->ro.nummaxpages), getle32(codesetinfo->ro.nummaxpages)*0x1000); - fprintf(stdout, "Code data address: 0x%08X\n", getle32(codesetinfo->data.address)); - fprintf(stdout, "Code data size: 0x%08X\n", getle32(codesetinfo->data.codesize)); - fprintf(stdout, "Code data max pages: 0x%08X (0x%08X)\n", getle32(codesetinfo->data.nummaxpages), getle32(codesetinfo->data.nummaxpages)*0x1000); - fprintf(stdout, "Code bss size: 0x%08X\n", getle32(codesetinfo->bsssize)); - fprintf(stdout, "Code stack size: 0x%08X\n", getle32(codesetinfo->stacksize)); - - for(i=0; i<0x30; i++) - { - if (getle64(ctx->header.deplist.programid[i]) != 0x0000000000000000UL) - fprintf(stdout, "Dependency: %016"PRIx64"\n", getle64(ctx->header.deplist.programid[i])); - } - if(savedatasize < sizeKB) - fprintf(stdout, "Savedata size: 0x%"PRIx64"\n", savedatasize); - else if(savedatasize < sizeMB) - fprintf(stdout, "Savedata size: %"PRIu64"K\n", savedatasize/sizeKB); - else - fprintf(stdout, "Savedata size: %"PRIu64"M\n", savedatasize/sizeMB); - fprintf(stdout, "Jump id: %016"PRIx64"\n", getle64(ctx->header.systeminfo.jumpid)); - - fprintf(stdout, "Program id: %016"PRIx64" %s\n", getle64(ctx->header.arm11systemlocalcaps.programid), exheader_getvalidstring(ctx->validprogramid)); - fprintf(stdout, "Core version: 0x%X\n", getle32(ctx->header.arm11systemlocalcaps.coreversion)); - fprintf(stdout, "System mode: %s %s\n", exheader_getsystemmodestring(ctx->system_local_caps.old3ds_systemmode), exheader_getvalidstring(ctx->validold3dssystemmode)); - fprintf(stdout, "System mode (New3DS): %s %s\n", exheader_getsystemmodeextstring(ctx->system_local_caps.new3ds_systemmode, ctx->system_local_caps.old3ds_systemmode), exheader_getvalidstring(ctx->validnew3dssystemmode)); - fprintf(stdout, "CPU Speed (New3DS): %s %s\n", ctx->system_local_caps.new3ds_cpu_speed? "804MHz" : "268MHz", exheader_getvalidstring(ctx->validnew3dscpuspeed)); - fprintf(stdout, "Enable L2 Cache: %s %s\n", ctx->system_local_caps.enable_l2_cache ? "YES" : "NO", exheader_getvalidstring(ctx->validnew3dscpuspeed)); - fprintf(stdout, "Ideal processor: %d %s\n", ctx->system_local_caps.ideal_processor, exheader_getvalidstring(ctx->valididealprocessor)); - fprintf(stdout, "Affinity mask: %d %s\n", ctx->system_local_caps.affinity_mask, exheader_getvalidstring(ctx->validaffinitymask)); - fprintf(stdout, "Main thread priority: %d %s\n", ctx->system_local_caps.priority, exheader_getvalidstring(ctx->validpriority)); - // print resource limit descriptor too? currently mostly zeroes... - exheader_print_arm11storageinfo(ctx); - exheader_print_arm11kernelcapabilities(ctx, actions); - exheader_print_arm9accesscontrol(ctx); - - fprintf(stdout, "Service access: %s\n", exheader_getvalidstring(ctx->validservicecontrol)); - for(i=0; i<34; i++) - { - if (strlen(ctx->system_local_caps.service_access_control[i]) > 0) - fprintf(stdout, " > %s\n", ctx->system_local_caps.service_access_control[i]); - } - fprintf(stdout, "Reslimit category: %02X\n", ctx->header.arm11systemlocalcaps.resourcelimitcategory); -} diff --git a/ctrtool/exheader.h b/ctrtool/exheader.h deleted file mode 100644 index 7f4ce49..0000000 --- a/ctrtool/exheader.h +++ /dev/null @@ -1,202 +0,0 @@ -#ifndef _EXHEADER_H_ -#define _EXHEADER_H_ - -#include -#include "types.h" -#include "ctr.h" -#include "settings.h" - -typedef enum -{ - sysmode_64MB, - sysmode_UNK, - sysmode_96MB, - sysmode_80MB, - sysmode_72MB, - sysmode_32MB, -} exheader_systemmode; - -typedef enum -{ - sysmode_ext_LEGACY, - sysmode_ext_124MB, - sysmode_ext_178MB, -} exheader_systemmodeext; - -typedef struct -{ - u8 reserved[5]; - u8 flag; - u8 remasterversion[2]; -} exheader_systeminfoflags; - -typedef struct -{ - u8 address[4]; - u8 nummaxpages[4]; - u8 codesize[4]; -} exheader_codesegmentinfo; - -typedef struct -{ - u8 name[8]; - exheader_systeminfoflags flags; - exheader_codesegmentinfo text; - u8 stacksize[4]; - exheader_codesegmentinfo ro; - u8 reserved[4]; - exheader_codesegmentinfo data; - u8 bsssize[4]; -} exheader_codesetinfo; - -typedef struct -{ - u8 programid[0x30][8]; -} exheader_dependencylist; - -typedef struct -{ - u8 savedatasize[8]; - u8 jumpid[8]; - u8 reserved2[0x30]; -} exheader_systeminfo; - -typedef struct -{ - u8 extsavedataid[8]; - u8 systemsavedataid[8]; - u8 accessibleuniqueids[8]; - u8 accessinfo[7]; - u8 otherattributes; -} exheader_storageinfo; - -typedef struct -{ - u8 programid[8]; - u8 coreversion[4]; - u8 flag[4]; - u8 resourcelimitdescriptor[0x10][2]; - exheader_storageinfo storageinfo; - u8 serviceaccesscontrol[34][8]; - u8 reserved[0xf]; - u8 resourcelimitcategory; -} exheader_arm11systemlocalcaps; - -typedef struct -{ - u8 program_id[8]; - u32 core_version; - - // flag - u8 enable_l2_cache; - u8 new3ds_cpu_speed; - u8 new3ds_systemmode; - u8 ideal_processor; - u8 affinity_mask; - u8 old3ds_systemmode; - s8 priority; - - // storageinfo - u64 extdata_id; - u32 other_user_saveid[3]; - u8 use_other_variation_savedata; - u32 accessible_saveid[6]; - u32 system_saveid[2]; - u64 accessinfo; - - - char service_access_control[34][10]; - u8 resource_limit_category; -} exheader_arm11systemlocalcaps_deserialised; - -typedef struct -{ - u8 descriptors[28][4]; - u8 reserved[0x10]; -} exheader_arm11kernelcapabilities; - -typedef struct -{ - u8 descriptors[15]; - u8 descversion; -} exheader_arm9accesscontrol; - -typedef struct -{ - // systemcontrol info { - // coreinfo { - exheader_codesetinfo codesetinfo; - exheader_dependencylist deplist; - // } - exheader_systeminfo systeminfo; - // } - // accesscontrolinfo { - exheader_arm11systemlocalcaps arm11systemlocalcaps; - exheader_arm11kernelcapabilities arm11kernelcaps; - exheader_arm9accesscontrol arm9accesscontrol; - // } - struct { - u8 signature[0x100]; - u8 ncchpubkeymodulus[0x100]; - exheader_arm11systemlocalcaps arm11systemlocalcaps; - exheader_arm11kernelcapabilities arm11kernelcaps; - exheader_arm9accesscontrol arm9accesscontrol; - } accessdesc; -} exheader_header; - -typedef struct -{ - int haveread; - FILE* file; - settings* usersettings; - u8 titleid[8]; - u8 programid[8]; - u8 hash[32]; - u8 counter[16]; - u8 key[16]; - u64 offset; - u64 size; - exheader_header header; - - exheader_arm11systemlocalcaps_deserialised system_local_caps; - - ctr_aes_context aes; - ctr_rsa_context rsa; - int compressedflag; - int encrypted; - int validprogramid; - int validpriority; - int validaffinitymask; - int valididealprocessor; - int validold3dssystemmode; - int validnew3dssystemmode; - int validenablel2cache; - int validnew3dscpuspeed; - int validcoreversion; - int validsystemsaveID[2]; - int validaccessinfo; - int validservicecontrol; - int validsignature; -} exheader_context; - -void exheader_init(exheader_context* ctx); -void exheader_set_file(exheader_context* ctx, FILE* file); -void exheader_set_offset(exheader_context* ctx, u64 offset); -void exheader_set_size(exheader_context* ctx, u64 size); -void exheader_set_titleid(exheader_context* ctx, u8 titleid[8]); -void exheader_set_counter(exheader_context* ctx, u8 counter[16]); -void exheader_set_programid(exheader_context* ctx, u8 programid[8]); -void exheader_set_hash(exheader_context* ctx, u8 hash[32]); -void exheader_set_encrypted(exheader_context* ctx, u32 encrypted); -void exheader_set_key(exheader_context* ctx, u8 key[16]); -void exheader_set_usersettings(exheader_context* ctx, settings* usersettings); -int exheader_get_compressedflag(exheader_context* ctx); -void exheader_read(exheader_context* ctx, u32 actions); -int exheader_process(exheader_context* ctx, u32 actions); -const char* exheader_getvalidstring(int valid); -void exheader_print(exheader_context* ctx, u32 actions); -void exheader_verify(exheader_context* ctx); -int exheader_hash_valid(exheader_context* ctx); -int exheader_programid_valid(exheader_context* ctx); - -#endif // _EXHEADER_H_ diff --git a/ctrtool/filepath.c b/ctrtool/filepath.c deleted file mode 100644 index 366bb65..0000000 --- a/ctrtool/filepath.c +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include -#include - -#include "types.h" -#include "filepath.h" - -void filepath_init(filepath* fpath) -{ - fpath->valid = 0; -} - -void filepath_copy(filepath* fpath, filepath* copy) -{ - if (copy != 0 && copy->valid) - memcpy(fpath, copy, sizeof(filepath)); - else - memset(fpath, 0, sizeof(filepath)); -} - -void filepath_append_utf16(filepath* fpath, const u8* name) -{ - u32 size; - - - if (fpath->valid == 0) - return; - - size = strlen(fpath->pathname); - - if (size > 0 && size < (MAX_PATH-1)) - { - if (fpath->pathname[size-1] != PATH_SEPERATOR) - fpath->pathname[size++] = PATH_SEPERATOR; - } - - while(size < (MAX_PATH-1)) - { - u8 lo = *name++; - u8 hi = *name++; - u16 code = (hi<<8) | lo; - - if (code == 0) - break; - - // convert non-ANSI to '#', because unicode support is too much work - if (code > 0x7F) - code = '#'; - - fpath->pathname[size++] = (char) code; - } - - fpath->pathname[size] = 0; - - if (size >= (MAX_PATH-1)) - fpath->valid = 0; -} - -void filepath_append(filepath* fpath, const char* format, ...) -{ - char tmppath[MAX_PATH]; - va_list args; - - if (fpath->valid == 0) - return; - - memset(tmppath, 0, MAX_PATH); - - va_start(args, format); - vsprintf(tmppath, format, args); - va_end(args); - - strcat(fpath->pathname, "/"); - strcat(fpath->pathname, tmppath); -} - -void filepath_set(filepath* fpath, const char* path) -{ - fpath->valid = 1; - memset(fpath->pathname, 0, MAX_PATH); - strncpy(fpath->pathname, path, MAX_PATH); -} - -const char* filepath_get(filepath* fpath) -{ - if (fpath->valid == 0) - return 0; - else - return fpath->pathname; -} diff --git a/ctrtool/filepath.h b/ctrtool/filepath.h deleted file mode 100644 index 9f6d72c..0000000 --- a/ctrtool/filepath.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _FILEPATH_H_ -#define _FILEPATH_H_ - -#include "types.h" -#include "utils.h" - -typedef struct -{ - char pathname[MAX_PATH]; - int valid; -} filepath; - -void filepath_init(filepath* fpath); -void filepath_copy(filepath* fpath, filepath* copy); -void filepath_append_utf16(filepath* fpath, const u8* name); -void filepath_append(filepath* fpath, const char* format, ...); -void filepath_set(filepath* fpath, const char* path); -const char* filepath_get(filepath* fpath); - -#endif // _FILEPATH_H_ diff --git a/ctrtool/firm.c b/ctrtool/firm.c deleted file mode 100644 index 491f4a7..0000000 --- a/ctrtool/firm.c +++ /dev/null @@ -1,257 +0,0 @@ -#include -#include -#include - -#include "types.h" -#include "firm.h" -#include "utils.h" - -void firm_init(firm_context* ctx) -{ - memset(ctx, 0, sizeof(firm_context)); -} - -void firm_set_file(firm_context* ctx, FILE* file) -{ - ctx->file = file; -} - -void firm_set_offset(firm_context* ctx, u64 offset) -{ - ctx->offset = offset; -} - -void firm_set_size(firm_context* ctx, u32 size) -{ - ctx->size = size; -} - -void firm_set_usersettings(firm_context* ctx, settings* usersettings) -{ - ctx->usersettings = usersettings; -} - -void firm_save(firm_context* ctx, u32 index, u32 flags) -{ - firm_sectionheader* section = (firm_sectionheader*)(ctx->header.section + index); - u32 offset; - u32 size; - u32 address; - FILE* fout; - filepath outpath; - u8 buffer[16 * 1024]; - - - offset = getle32(section->offset); - size = getle32(section->size); - address = getle32(section->address); - filepath_copy(&outpath, settings_get_firm_dir_path(ctx->usersettings)); - filepath_append(&outpath, "firm_%d_%08X.bin", index, address); - - if (size == 0 || outpath.valid == 0) - return; - - if (size >= ctx->size) - { - fprintf(stderr, "Error, firm section %d size invalid\n", index); - return; - } - - fout = fopen(outpath.pathname, "wb"); - if (fout == 0) - { - fprintf(stderr, "Error, failed to create file %s\n", outpath.pathname); - goto clean; - } - - - - fseeko64(ctx->file, ctx->offset + offset, SEEK_SET); - fprintf(stdout, "Saving section %d to %s...\n", index, outpath.pathname); - - while(size) - { - u32 max = sizeof(buffer); - if (max > size) - max = size; - - if (max != fread(buffer, 1, max, ctx->file)) - { - fprintf(stdout, "Error reading input file\n"); - goto clean; - } - - if (max != fwrite(buffer, 1, max, fout)) - { - fprintf(stdout, "Error writing output file\n"); - goto clean; - } - - size -= max; - } - - -clean: - return; -} - - -void firm_process(firm_context* ctx, u32 actions) -{ - u32 i; - - fseeko64(ctx->file, ctx->offset, SEEK_SET); - fread(&ctx->header, 1, sizeof(firm_header), ctx->file); - - if (getle32(ctx->header.magic) != MAGIC_FIRM) - { - fprintf(stdout, "Error, FIRM segment corrupted\n"); - return; - } - - - if (actions & VerifyFlag) - { - firm_verify(ctx, actions); - firm_signature_verify(ctx); - } - - if (actions & InfoFlag) - { - firm_print(ctx); - } - - if (actions & ExtractFlag) - { - filepath* dirpath = settings_get_firm_dir_path(ctx->usersettings); - - if (dirpath && dirpath->valid) - { - makedir(dirpath->pathname); - for(i=0; i<4; i++) - firm_save(ctx, i, actions); - } - } -} - -int firm_verify(firm_context* ctx, u32 flags) -{ - unsigned int i; - u32 offset; - u32 size; - u8 buffer[16 * 1024]; - u8 hash[0x20]; - - - for(i=0; i<4; i++) - { - firm_sectionheader* section = (firm_sectionheader*)(ctx->header.section + i); - - - offset = getle32(section->offset); - size = getle32(section->size); - - if (size == 0) - return 0; - - fseeko64(ctx->file, ctx->offset + offset, SEEK_SET); - - ctr_sha_256_init(&ctx->sha); - - while(size) - { - u32 max = sizeof(buffer); - if (max > size) - max = size; - - if (max != fread(buffer, 1, max, ctx->file)) - { - fprintf(stdout, "Error reading input file\n"); - goto clean; - } - - ctr_sha_256_update(&ctx->sha, buffer, max); - - size -= max; - } - - ctr_sha_256_finish(&ctx->sha, hash); - - - if (memcmp(hash, section->hash, 0x20) == 0) - ctx->hashcheck[i] = Good; - else - ctx->hashcheck[i] = Fail; - } - - -clean: - return 0; -} - - -void firm_signature_verify(firm_context* ctx) -{ - u8 hash[0x20]; - - if (ctx->usersettings) - { - ctr_sha_256(ctx->header.magic, 0x100, hash); - ctx->headersigcheck = ctr_rsa_verify_hash(ctx->header.signature, hash, &ctx->usersettings->keys.firmrsakey); - } -} - - -void firm_print(firm_context* ctx) -{ - u32 i; - u32 address; - u32 copyMethod; - u32 offset; - u32 size; - u32 priority = getle32(ctx->header.priority); - u32 entrypointarm11 = getle32(ctx->header.entrypointarm11); - u32 entrypointarm9 = getle32(ctx->header.entrypointarm9); - - fprintf(stdout, "\nFIRM:\n"); - if (ctx->headersigcheck == Unchecked) - memdump(stdout, "Signature: ", ctx->header.signature, 0x100); - else if (ctx->headersigcheck == Good) - memdump(stdout, "Signature (GOOD): ", ctx->header.signature, 0x100); - else - memdump(stdout, "Signature (FAIL): ", ctx->header.signature, 0x100); - - fprintf(stdout, "\n"); - fprintf(stdout, "Priority: %u\n", priority); - fprintf(stdout, "Entrypoint ARM9: 0x%08X\n", entrypointarm9); - fprintf(stdout, "Entrypoint ARM11: 0x%08X\n", entrypointarm11); - fprintf(stdout, "\n"); - - - for(i=0; i<4; i++) - { - firm_sectionheader* section = (firm_sectionheader*)(ctx->header.section + i); - - - offset = getle32(section->offset); - size = getle32(section->size); - address = getle32(section->address); - copyMethod = getle32(section->copyMethod); - - if (size) - { - fprintf(stdout, "Section %d \n", i); - fprintf(stdout, " Copy Method: %s\n", copyMethod==0 ? "NDMA" : copyMethod==1 ? "XDMA" : - copyMethod==2 ? "memcpy" : "UNKNOWN"); - fprintf(stdout, " Address: 0x%08X\n", address); - fprintf(stdout, " Offset: 0x%08X\n", offset); - fprintf(stdout, " Size: 0x%08X\n", size); - if (ctx->hashcheck[i] == Good) - memdump(stdout, " Hash (GOOD): ", section->hash, 0x20); - else if (ctx->hashcheck[i] == Fail) - memdump(stdout, " Hash (FAIL): ", section->hash, 0x20); - else - memdump(stdout, " Hash: ", section->hash, 0x20); - } - } -} diff --git a/ctrtool/firm.h b/ctrtool/firm.h deleted file mode 100644 index 5d1ebbc..0000000 --- a/ctrtool/firm.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef _FIRM_H_ -#define _FIRM_H_ - -#include "types.h" -#include "info.h" -#include "ctr.h" -#include "filepath.h" -#include "settings.h" - - -typedef struct -{ - u8 offset[4]; - u8 address[4]; - u8 size[4]; - u8 copyMethod[4]; - u8 hash[32]; -} firm_sectionheader; - - - - -typedef struct -{ - u8 magic[4]; - u8 priority[4]; - u8 entrypointarm11[4]; - u8 entrypointarm9[4]; - u8 reserved1[0x30]; - firm_sectionheader section[4]; - u8 signature[0x100]; -} firm_header; - -typedef struct -{ - FILE* file; - settings* usersettings; - u64 offset; - u32 size; - firm_header header; - ctr_sha256_context sha; - int hashcheck[4]; - int headersigcheck; -} firm_context; - -void firm_init(firm_context* ctx); -void firm_set_file(firm_context* ctx, FILE* file); -void firm_set_offset(firm_context* ctx, u64 offset); -void firm_set_size(firm_context* ctx, u32 size); -void firm_set_usersettings(firm_context* ctx, settings* usersettings); -void firm_process(firm_context* ctx, u32 actions); -void firm_print(firm_context* ctx); -void firm_save(firm_context* ctx, u32 index, u32 flags); -int firm_verify(firm_context* ctx, u32 flags); -void firm_signature_verify(firm_context* ctx); - -#endif // _FIRM_H_ diff --git a/ctrtool/info.h b/ctrtool/info.h deleted file mode 100644 index fac4117..0000000 --- a/ctrtool/info.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _INFO_H_ -#define _INFO_H_ - -#include "types.h" -#include "keyset.h" - -typedef struct -{ - FILE* file; - keyset* keys; - u32 offset; - const u8* blob; - u32 blobsize; -} infocontext; - -#endif // _INFO_H_ diff --git a/ctrtool/ivfc.c b/ctrtool/ivfc.c deleted file mode 100644 index 4a77a67..0000000 --- a/ctrtool/ivfc.c +++ /dev/null @@ -1,247 +0,0 @@ -#include -#include -#include -#include "types.h" -#include "utils.h" -#include "ivfc.h" -#include "ctr.h" - -void ivfc_init(ivfc_context* ctx) -{ - memset(ctx, 0, sizeof(ivfc_context)); -} - -void ivfc_set_usersettings(ivfc_context* ctx, settings* usersettings) -{ - ctx->usersettings = usersettings; -} - -void ivfc_set_offset(ivfc_context* ctx, u64 offset) -{ - ctx->offset = offset; -} - -void ivfc_set_size(ivfc_context* ctx, u64 size) -{ - ctx->size = size; -} - -void ivfc_set_file(ivfc_context* ctx, FILE* file) -{ - ctx->file = file; -} - -void ivfc_set_encrypted(ivfc_context* ctx, u32 encrypted) -{ - ctx->encrypted = encrypted; -} - -void ivfc_set_key(ivfc_context* ctx, u8 key[16]) -{ - ctr_init_key(&ctx->aes, key); -} - -void ivfc_set_counter(ivfc_context* ctx, u8 counter[16]) -{ - memcpy(ctx->counter, counter, 16); -} - -void ivfc_fseek(ivfc_context* ctx, u64 offset) -{ - u64 data_pos = offset - ctx->offset; - fseeko64(ctx->file, offset, SEEK_SET); - - if (ctx->encrypted) { - //printf("start fseek encrypted prep\n"); - ctr_init_counter(&ctx->aes, ctx->counter); - //printf("middle fseek encrypted prep\n"); - ctr_add_counter(&ctx->aes, (u32)(data_pos / 0x10)); - //printf("finish fseek encrypted prep\n"); - } -} - -size_t ivfc_fread(ivfc_context* ctx, void* buffer, size_t size, size_t count) -{ - size_t read; - if ((read = fread(buffer, size, count, ctx->file)) != count) { - //printf("ivfc_fread() fail\n"); - return read; - } - if (ctx->encrypted) { - ctr_crypt_counter(&ctx->aes, buffer, buffer, size*read); - } - return read; -} - - -void ivfc_process(ivfc_context* ctx, u32 actions) -{ - ivfc_fseek(ctx, ctx->offset); - ivfc_fread(ctx, &ctx->header, 1, sizeof(ivfc_header)); - - if (getle32(ctx->header.magic) != MAGIC_IVFC) - { - fprintf(stdout, "Error, IVFC segment corrupted\n"); - return; - } - - if (getle32(ctx->header.id) == 0x10000) - { - ctx->levelcount = 3; - - ctx->level[2].hashblocksize = 1 << getle32(ctx->header.level3.blocksize); - ctx->level[1].hashblocksize = 1 << getle32(ctx->header.level2.blocksize); - ctx->level[0].hashblocksize = 1 << getle32(ctx->header.level1.blocksize); - - ctx->bodyoffset = align64(IVFC_HEADER_SIZE + getle32(ctx->header.masterhashsize), ctx->level[2].hashblocksize); - ctx->bodysize = getle64(ctx->header.level3.hashdatasize); - - ctx->level[2].dataoffset = ctx->bodyoffset; - ctx->level[2].datasize = align64(ctx->bodysize, ctx->level[2].hashblocksize); - - ctx->level[0].dataoffset = ctx->level[2].dataoffset + ctx->level[2].datasize; - ctx->level[0].datasize = align64(getle64(ctx->header.level1.hashdatasize), ctx->level[0].hashblocksize); - - ctx->level[1].dataoffset = ctx->level[0].dataoffset + ctx->level[0].datasize; - ctx->level[1].datasize = align64(getle64(ctx->header.level2.hashdatasize), ctx->level[1].hashblocksize); - - ctx->level[0].hashoffset = IVFC_HEADER_SIZE; - ctx->level[1].hashoffset = ctx->level[0].dataoffset; - ctx->level[2].hashoffset = ctx->level[1].dataoffset; - } - - if (actions & VerifyFlag) - ivfc_verify(ctx, actions); - - if (actions & InfoFlag) - ivfc_print(ctx); - -} - -void ivfc_verify(ivfc_context* ctx, u32 flags) -{ - u32 i, j; - u32 blockcount; - - for(i=0; ilevelcount; i++) - { - ivfc_level* level = ctx->level + i; - - level->hashcheck = Fail; - } - - // Import IVFC level hashes - uint8_t *levelhash[IVFC_MAX_LEVEL] = { NULL }; - - for (i=0; ilevelcount; i++) - { - blockcount = (u32)(ctx->level[i].datasize / ctx->level[i].hashblocksize); - u32 read_size = align(blockcount * 0x20, ctx->level[i].hashblocksize); - levelhash[i] = malloc(read_size); - ivfc_read(ctx, ctx->level[i].hashoffset, read_size, levelhash[i]); - } - - // Verify blocks - for (i=0; ilevelcount; i++) - { - blockcount = (u32) (ctx->level[i].datasize / ctx->level[i].hashblocksize); - if (ctx->level[i].datasize % ctx->level[i].hashblocksize != 0) - { - fprintf(stderr, "Error, IVFC block size mismatch\n"); - return; - } - - ctx->level[i].hashcheck = Good; - - for (j=0; jlevel[i].hashblocksize * j, ctx->level[i].hashblocksize, calchash); - } - // a data level - else { - ivfc_read(ctx, ctx->level[i].dataoffset + j * ctx->level[i].hashblocksize, ctx->level[i].hashblocksize, ctx->buffer); - ctr_sha_256(ctx->buffer, (u32)ctx->level[i].hashblocksize, calchash); - } - - if (memcmp(calchash, levelhash[i] + 0x20 * j, 0x20) != 0) { - ctx->level[i].hashcheck = Fail; - } - - } - } - - // Free level hashes - for (int i = 0; i < 3; i++) { - free(levelhash[i]); - } -} - -void ivfc_read(ivfc_context* ctx, u64 offset, u64 size, u8* buffer) -{ - if ( (offset > ctx->size) || (offset+size > ctx->size) ) - { - fprintf(stderr, "Error, IVFC offset out of range (offset=0x%08"PRIx64", size=0x%08"PRIx64")\n", offset, size); - return; - } - - ivfc_fseek(ctx, ctx->offset + offset); - if (size != ivfc_fread(ctx, buffer, 1, (size_t) size)) - { - fprintf(stderr, "Error, IVFC could not read file\n"); - return; - } -} - -void ivfc_hash(ivfc_context* ctx, u64 offset, u64 size, u8* hash) -{ - if (size > IVFC_MAX_BUFFERSIZE) - { - fprintf(stderr, "Error, IVFC hash block size too big.\n"); - return; - } - - ivfc_read(ctx, offset, size, ctx->buffer); - - ctr_sha_256(ctx->buffer, (u32) size, hash); -} - -void ivfc_print(ivfc_context* ctx) -{ - u32 i; - ivfc_header* header = &ctx->header; - - fprintf(stdout, "\nIVFC:\n"); - - fprintf(stdout, "Header: %.4s\n", header->magic); - fprintf(stdout, "Id: %08x\n", getle32(header->id)); - - for(i=0; ilevelcount; i++) - { - ivfc_level* level = ctx->level + i; - - fprintf(stdout, "\n"); - if (level->hashcheck == Unchecked) - fprintf(stdout, "Level %d: \n", i); - else - fprintf(stdout, "Level %d (%s): \n", i, level->hashcheck == Good? "GOOD" : "FAIL"); - fprintf(stdout, " Data offset: 0x%08"PRIx64"\n", ctx->offset + level->dataoffset); - fprintf(stdout, " Data size: 0x%08"PRIx64"\n", level->datasize); - fprintf(stdout, " Hash offset: 0x%08"PRIx64"\n", ctx->offset + level->hashoffset); - fprintf(stdout, " Hash block size: 0x%08x\n", level->hashblocksize); - } -} - -u64 ivfc_get_body_offset(ivfc_context* ctx) -{ - return ctx->bodyoffset; -} - -u64 ivfc_get_body_size(ivfc_context* ctx) -{ - return ctx->bodysize; -} - diff --git a/ctrtool/ivfc.h b/ctrtool/ivfc.h deleted file mode 100644 index 67b5c7e..0000000 --- a/ctrtool/ivfc.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef __IVFC_H__ -#define __IVFC_H__ - -#include "types.h" -#include "ctr.h" -#include "settings.h" - -#define IVFC_HEADER_SIZE 0x60 -#define IVFC_MAX_LEVEL 4 -#define IVFC_MAX_BUFFERSIZE 0x4000 - -typedef struct -{ - u8 logicaloffset[8]; - u8 hashdatasize[8]; - u8 blocksize[4]; - u8 reserved[4]; -} ivfc_levelheader; - -typedef struct -{ - u64 dataoffset; - u64 datasize; - u64 hashoffset; - u32 hashblocksize; - int hashcheck; -} ivfc_level; - -typedef struct -{ - u8 magic[4]; - u8 id[4]; - u8 masterhashsize[4]; - ivfc_levelheader level1; - ivfc_levelheader level2; - ivfc_levelheader level3; - u8 reserved[4]; - u8 optionalsize[4]; -} ivfc_header; - -typedef struct -{ - FILE* file; - u64 offset; - u64 size; - settings* usersettings; - u8 counter[16]; - ctr_aes_context aes; - int encrypted; - - ivfc_header header; - - u32 levelcount; - ivfc_level level[IVFC_MAX_LEVEL]; - u64 bodyoffset; - u64 bodysize; - u8 buffer[IVFC_MAX_BUFFERSIZE]; -} ivfc_context; - -void ivfc_init(ivfc_context* ctx); -void ivfc_process(ivfc_context* ctx, u32 actions); -void ivfc_set_offset(ivfc_context* ctx, u64 offset); -void ivfc_set_size(ivfc_context* ctx, u64 size); -void ivfc_set_file(ivfc_context* ctx, FILE* file); -void ivfc_set_usersettings(ivfc_context* ctx, settings* usersettings); -void ivfc_set_encrypted(ivfc_context* ctx, u32 encrypted); -void ivfc_set_key(ivfc_context* ctx, u8 key[16]); -void ivfc_set_counter(ivfc_context* ctx, u8 counter[16]); -void ivfc_fseek(ivfc_context* ctx, u64 offset); -size_t ivfc_fread(ivfc_context* ctx, void* buffer, size_t size, size_t count); - -void ivfc_verify(ivfc_context* ctx, u32 flags); -void ivfc_print(ivfc_context* ctx); - -void ivfc_read(ivfc_context* ctx, u64 offset, u64 size, u8* buffer); -void ivfc_hash(ivfc_context* ctx, u64 offset, u64 size, u8* hash); - -#endif // __IVFC_H__ diff --git a/ctrtool/keyset.cpp b/ctrtool/keyset.cpp deleted file mode 100644 index b4e6763..0000000 --- a/ctrtool/keyset.cpp +++ /dev/null @@ -1,395 +0,0 @@ -#include -#include "keyset.h" -#include "utils.h" -#include "tinyxml/tinyxml.h" - -static void keyset_set_key128(key128* key, unsigned char* keydata); -static void keyset_parse_key128(key128* key, char* keytext, int keylen); -static int keyset_parse_key(const char* text, unsigned int textlen, unsigned char* key, unsigned int size, int* valid); -static int keyset_load_rsakey2048(TiXmlElement* elem, rsakey2048* key); -static int keyset_load_key128(TiXmlHandle node, key128* key); -static int keyset_load_key(TiXmlHandle node, unsigned char* key, unsigned int maxsize, int* valid); - -static int ishex(char c) -{ - if (c >= '0' && c <= '9') - return 1; - if (c >= 'A' && c <= 'F') - return 1; - if (c >= 'a' && c <= 'f') - return 1; - return 0; - -} - -static unsigned char hextobin(char c) -{ - if (c >= '0' && c <= '9') - return c-'0'; - if (c >= 'A' && c <= 'F') - return c-'A'+0xA; - if (c >= 'a' && c <= 'f') - return c-'a'+0xA; - return 0; -} - -void keyset_init(keyset* keys, u32 actions) -{ - const key128 defaultkeys_retail[] = { - // fixed system key - unknown if used/correct? - {{0x52, 0x7c, 0xe6, 0x30, 0xa9, 0xca, 0x30, 0x5f, 0x36, 0x96, 0xf3, 0xcd, 0xe9, 0x54, 0x19, 0x4b}, 1}, - // NCCH 0x2c keyX - {{0xb9, 0x8e, 0x95, 0xce, 0xca, 0x3e, 0x4d, 0x17, 0x1f, 0x76, 0xa9, 0x4d, 0xe9, 0x34, 0xc0, 0x53}, 1}, - // NCCH 0x25 keyX 7.x - {{0xce, 0xe7, 0xd8, 0xab, 0x30, 0xc0, 0x0d, 0xae, 0x85, 0x0e, 0xf5, 0xe3, 0x82, 0xac, 0x5a, 0xf3}, 1}, - // NCCH 0x18 keyX N9.3 - {{0x82, 0xe9, 0xc9, 0xbe, 0xbf, 0xb8, 0xbd, 0xb8, 0x75, 0xec, 0xc0, 0xa0, 0x7d, 0x47, 0x43, 0x74}, 1}, - // NCCH 0x1B keyX N9.6 - {{0x45, 0xad, 0x04, 0x95, 0x39, 0x92, 0xc7, 0xc8, 0x93, 0x72, 0x4a, 0x9a, 0x7b, 0xce, 0x61, 0x82}, 1}, - // common key index0 (application) - {{0x64, 0xC5, 0xFD, 0x55, 0xDD, 0x3A, 0xD9, 0x88, 0x32, 0x5B, 0xAA, 0xEC, 0x52, 0x43, 0xDB, 0x98}, 1}, - // common key index1 (system) - {{0x4A, 0xAA, 0x3D, 0x0E, 0x27, 0xD4, 0xD7, 0x28, 0xD0, 0xB1, 0xB4, 0x33, 0xF0, 0xF9, 0xCB, 0xC8}, 1}, - // common key index2 - {{0xFB, 0xB0, 0xEF, 0x8C, 0xDB, 0xB0, 0xD8, 0xE4, 0x53, 0xCD, 0x99, 0x34, 0x43, 0x71, 0x69, 0x7F}, 1}, - // common key index3 - {{0x25, 0x95, 0x9B, 0x7A, 0xD0, 0x40, 0x9F, 0x72, 0x68, 0x41, 0x98, 0xBA, 0x2E, 0xCD, 0x7D, 0xC6}, 1}, - // common key index4 - {{0x7A, 0xDA, 0x22, 0xCA, 0xFF, 0xC4, 0x76, 0xCC, 0x82, 0x97, 0xA0, 0xC7, 0xCE, 0xEE, 0xEE, 0xBE}, 1}, - // common key index5 - {{0xA5, 0x05, 0x1C, 0xA1, 0xB3, 0x7D, 0xCF, 0x3A, 0xFB, 0xCF, 0x8C, 0xC1, 0xED, 0xD9, 0xCE, 0x02}, 1}, - }; - const key128 defaultkeys_dev[] = { - // fixed system key - {{0x52, 0x7c, 0xe6, 0x30, 0xa9, 0xca, 0x30, 0x5f, 0x36, 0x96, 0xf3, 0xcd, 0xe9, 0x54, 0x19, 0x4b}, 1}, - // NCCH 0x2c keyX - {{0x51, 0x02, 0x07, 0x51, 0x55, 0x07, 0xcb, 0xb1, 0x8e, 0x24, 0x3d, 0xcb, 0x85, 0xe2, 0x3a, 0x1d}, 1}, - // NCCH 0x25 keyX 7.x - {{0x81, 0x90, 0x7a, 0x4b, 0x6f, 0x1b, 0x47, 0x32, 0x3a, 0x67, 0x79, 0x74, 0xce, 0x4a, 0xd7, 0x1b}, 1}, - // NCCH 0x18 keyX N9.3 - {{0x30, 0x4b, 0xf1, 0x46, 0x83, 0x72, 0xee, 0x64, 0x11, 0x5e, 0xbd, 0x40, 0x93, 0xd8, 0x42, 0x76}, 1}, - // NCCH 0x1B keyX N9.6 - {{0x6c, 0x8b, 0x29, 0x44, 0xa0, 0x72, 0x60, 0x35, 0xf9, 0x41, 0xdf, 0xc0, 0x18, 0x52, 0x4f, 0xb6}, 1}, - // common key index0 - {{0x55, 0xA3, 0xF8, 0x72, 0xBD, 0xC8, 0x0C, 0x55, 0x5A, 0x65, 0x43, 0x81, 0x13, 0x9E, 0x15, 0x3B}, 1}, - // common key index1 - {{0x44, 0x34, 0xED, 0x14, 0x82, 0x0C, 0xA1, 0xEB, 0xAB, 0x82, 0xC1, 0x6E, 0x7B, 0xEF, 0x0C, 0x25}, 1}, - // common key index2 - {{0xF6, 0x2E, 0x3F, 0x95, 0x8E, 0x28, 0xA2, 0x1F, 0x28, 0x9E, 0xEC, 0x71, 0xA8, 0x66, 0x29, 0xDC}, 1}, - // common key index3 - {{0x2B, 0x49, 0xCB, 0x6F, 0x99, 0x98, 0xD9, 0xAD, 0x94, 0xF2, 0xED, 0xE7, 0xB5, 0xDA, 0x3E, 0x27}, 1}, - // common key index4 - {{0x75, 0x05, 0x52, 0xBF, 0xAA, 0x1C, 0x04, 0x07, 0x55, 0xC8, 0xD5, 0x9A, 0x55, 0xF9, 0xAD, 0x1F}, 1}, - // common key index5 - {{0xAA, 0xDA, 0x4C, 0xA8, 0xF6, 0xE5, 0xA9, 0x77, 0xE0, 0xA0, 0xF9, 0xE4, 0x76, 0xCF, 0x0D, 0x63}, 1}, - }; - - memset(keys, 0, sizeof(keyset)); - - if (actions & PlainFlag) - return; - - // select keyset - const key128* default_keys = (actions & DevFlag)? defaultkeys_dev : defaultkeys_retail; - - u32 key_index = 0; - // set ncch keys - memcpy(&keys->ncchfixedsystemkey, &default_keys[key_index++], sizeof(key128)); - memcpy(&keys->ncchkeyX_old, &default_keys[key_index++], sizeof(key128)); - memcpy(&keys->ncchkeyX_seven, &default_keys[key_index++], sizeof(key128)); - memcpy(&keys->ncchkeyX_ninethree, &default_keys[key_index++], sizeof(key128)); - memcpy(&keys->ncchkeyX_ninesix, &default_keys[key_index++], sizeof(key128)); - - // set common keys - for (u32 i = 0; i < COMMONKEY_NUM; i++) - { - memcpy(&keys->commonkey[i], &default_keys[key_index++], sizeof(key128)); - } - -} - -int keyset_load_key(TiXmlHandle node, unsigned char* key, unsigned int size, int* valid) -{ - TiXmlElement* elem = node.ToElement(); - - if (valid) - *valid = 0; - - if (!elem) - return 0; - - const char* text = elem->GetText(); - unsigned int textlen = strlen(text); - - int status = keyset_parse_key(text, textlen, key, size, valid); - - if (status == KEY_ERR_LEN_MISMATCH) - { - fprintf(stderr, "Error size mismatch for key \"%s/%s\"\n", elem->Parent()->Value(), elem->Value()); - return 0; - } - - return 1; -} - - -int keyset_parse_key(const char* text, unsigned int textlen, unsigned char* key, unsigned int size, int* valid) -{ - unsigned int i, j; - unsigned int hexcount = 0; - - - if (valid) - *valid = 0; - - for(i=0; idata, sizeof(key->data), &key->valid); -} - -int keyset_load_rsakey2048(TiXmlHandle node, rsakey2048* key) -{ - key->keytype = RSAKEY_INVALID; - - if (!keyset_load_key(node.FirstChild("N"), key->n, sizeof(key->n), 0)) - goto clean; - if (!keyset_load_key(node.FirstChild("E"), key->e, sizeof(key->e), 0)) - goto clean; - key->keytype = RSAKEY_PUB; - - if (!keyset_load_key(node.FirstChild("D"), key->d, sizeof(key->d), 0)) - goto clean; - if (!keyset_load_key(node.FirstChild("P"), key->p, sizeof(key->p), 0)) - goto clean; - if (!keyset_load_key(node.FirstChild("Q"), key->q, sizeof(key->q), 0)) - goto clean; - if (!keyset_load_key(node.FirstChild("DP"), key->dp, sizeof(key->dp), 0)) - goto clean; - if (!keyset_load_key(node.FirstChild("DQ"), key->dq, sizeof(key->dq), 0)) - goto clean; - if (!keyset_load_key(node.FirstChild("QP"), key->qp, sizeof(key->qp), 0)) - goto clean; - - key->keytype = RSAKEY_PRIV; -clean: - return (key->keytype != RSAKEY_INVALID); -} - -int keyset_load(keyset* keys, const char* fname, int verbose) -{ - TiXmlDocument doc(fname); - bool loadOkay = doc.LoadFile(); - - if (!loadOkay) - { - if (verbose) - fprintf(stderr, "Could not load keyset file \"%s\", error: %s.\n", fname, doc.ErrorDesc() ); - - return 0; - } - - TiXmlHandle root = doc.FirstChild("document"); - - keyset_load_rsakey2048(root.FirstChild("ncsdrsakey"), &keys->ncsdrsakey); - keyset_load_rsakey2048(root.FirstChild("ncchrsakey"), &keys->ncchrsakey); - keyset_load_rsakey2048(root.FirstChild("ncchdescrsakey"), &keys->ncchdescrsakey); - keyset_load_rsakey2048(root.FirstChild("firmrsakey"), &keys->firmrsakey); - /* - keyset_load_key128(root.FirstChild("ncchfixedsystemkey"), &keys->ncchfixedsystemkey); - keyset_load_key128(root.FirstChild("ncchkeyxold"), &keys->ncchkeyX_old); - keyset_load_key128(root.FirstChild("ncchkeyxseven"), &keys->ncchkeyX_seven); - keyset_load_key128(root.FirstChild("ncchkeyxninethree"), &keys->ncchkeyX_ninethree); - keyset_load_key128(root.FirstChild("ncchkeyxninesix"), &keys->ncchkeyX_ninesix); - */ - - return 1; -} - - -void keyset_merge(keyset* keys, keyset* src) -{ -#define COPY_IF_VALID(v) do {\ - if (src->v.valid && !keys->v.valid)\ - keyset_set_key128(&keys->v, src->v.data);\ -} while (0) - - // todo complete key copy - /* COPY_IF_VALID(commonkey[0]); */ - //if () - for (size_t i = 0; i < COMMONKEY_NUM; i++) - { - COPY_IF_VALID(commonkey[i]); - } - COPY_IF_VALID(titlekey); - COPY_IF_VALID(seed_fallback); - COPY_IF_VALID(ncchfixedsystemkey); - COPY_IF_VALID(ncchkeyX_old); - COPY_IF_VALID(ncchkeyX_seven); - COPY_IF_VALID(ncchkeyX_ninethree); - COPY_IF_VALID(ncchkeyX_ninesix); - if (src->seed_num > 0) - { - keys->seed_num = src->seed_num; - keys->seed_db = (seeddb_entry*)calloc(keys->seed_num, sizeof(seeddb_entry)); - memcpy(keys->seed_db, src->seed_db, keys->seed_num * sizeof(seeddb_entry)); - } - -#undef COPY_IF_VALID -} - -void keyset_set_key128(key128* key, unsigned char* keydata) -{ - memcpy(key->data, keydata, 16); - key->valid = 1; -} - -void keyset_parse_key128(key128* key, char* keytext, int keylen) -{ - keyset_parse_key(keytext, keylen, key->data, 16, &key->valid); -} - -void keyset_parse_titlekey(keyset* keys, char* keytext, int keylen) -{ - keyset_parse_key128(&keys->titlekey, keytext, keylen); -} - -void keyset_parse_ncchkeyX_old(keyset* keys, char* keytext, int keylen) -{ - keyset_parse_key128(&keys->ncchkeyX_old, keytext, keylen); -} - -void keyset_parse_ncchfixedsystemkey(keyset* keys, char* keytext, int keylen) -{ - keyset_parse_key128(&keys->ncchfixedsystemkey, keytext, keylen); -} - -void keyset_parse_ncchkeyX_seven(keyset* keys, char* keytext, int keylen) -{ - keyset_parse_key128(&keys->ncchkeyX_seven, keytext, keylen); -} - -void keyset_parse_ncchkeyX_ninethree(keyset* keys, char* keytext, int keylen) -{ - keyset_parse_key128(&keys->ncchkeyX_ninethree, keytext, keylen); -} - -void keyset_parse_ncchkeyX_ninesix(keyset* keys, char* keytext, int keylen) -{ - keyset_parse_key128(&keys->ncchkeyX_ninesix, keytext, keylen); -} - -void keyset_parse_seeddb(keyset* keys, char* path) -{ - //keyset_parse_key128(&keys->seed, keytext, keylen); - FILE* fp = fopen(path, "rb"); - if (fp == NULL) - { - printf("[ERROR] Failed to load SeedDB (failed to open file)\n"); - return; - } - - seeddb_header hdr; - fread(&hdr, sizeof(seeddb_header), 1, fp); - - keys->seed_num = getle32(hdr.n_entries); - for (u32 i = 0; i < 0xC; i++) - { - if (hdr.padding[i] != 0x00) - { - printf("[ERROR] SeedDB is corrupt. (padding malformed)\n"); - return; - } - } - - keys->seed_db = (seeddb_entry*)calloc(keys->seed_num, sizeof(seeddb_entry)); - fread(keys->seed_db, keys->seed_num * sizeof(seeddb_entry), 1, fp); -} - -void keyset_parse_seed_fallback(keyset* keys, char* keytext, int keylen) -{ - keyset_parse_key128(&keys->seed_fallback, keytext, keylen); -} - - -void keyset_dump_rsakey(rsakey2048* key, const char* keytitle) -{ - if (key->keytype == RSAKEY_INVALID) - return; - - - fprintf(stdout, "%s\n", keytitle); - - memdump(stdout, "Modulus: ", key->n, 256); - memdump(stdout, "Exponent: ", key->e, 3); - - if (key->keytype == RSAKEY_PRIV) - { - memdump(stdout, "P: ", key->p, 128); - memdump(stdout, "Q: ", key->q, 128); - } - fprintf(stdout, "\n"); -} - -void keyset_dump_key128(key128* key, const char* keytitle) -{ - if (key->valid) - { - fprintf(stdout, "%s\n", keytitle); - memdump(stdout, "", key->data, 16); - fprintf(stdout, "\n"); - } -} - -void keyset_dump(keyset* keys) -{ -#define DUMP_KEY(n, s) do {\ - keyset_dump_key128(&keys->n, (s));\ -} while(0) - fprintf(stdout, "Current keyset: \n"); - DUMP_KEY(ncchkeyX_old, "NCCH OLD KEYX"); - DUMP_KEY(ncchkeyX_seven, "NCCH 7.0 KEYX"); - DUMP_KEY(ncchkeyX_ninethree, "NCCH N9.3 KEYX"); - DUMP_KEY(ncchkeyX_ninesix, "NCCH N9.6 KEYX"); - DUMP_KEY(ncchfixedsystemkey, "NCCH FIXEDSYSTEMKEY"); -#undef DUMP_KEY - - keyset_dump_rsakey(&keys->ncsdrsakey, "NCSD RSA KEY"); - keyset_dump_rsakey(&keys->ncchdescrsakey, "NCCH DESC RSA KEY"); - - fprintf(stdout, "\n"); -} - diff --git a/ctrtool/keyset.h b/ctrtool/keyset.h deleted file mode 100644 index 4d9235d..0000000 --- a/ctrtool/keyset.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef _KEYSET_H_ -#define _KEYSET_H_ - -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define COMMONKEY_NUM 6 - -typedef enum -{ - KEY_ERR_LEN_MISMATCH, - KEY_ERR_INVALID_NODE, - KEY_OK -} keystatus; - -typedef enum -{ - RSAKEY_INVALID, - RSAKEY_PRIV, - RSAKEY_PUB -} rsakeytype; - -typedef struct -{ - u8 title_id[8]; - u8 seed[0x10]; - u8 padding[0x8]; -} seeddb_entry; - -typedef struct -{ - u8 n_entries[4]; - u8 padding[0xC]; -} seeddb_header; - - -typedef struct -{ - unsigned char n[256]; - unsigned char e[3]; - unsigned char d[256]; - unsigned char p[128]; - unsigned char q[128]; - unsigned char dp[128]; - unsigned char dq[128]; - unsigned char qp[128]; - rsakeytype keytype; -} rsakey2048; - -typedef struct -{ - unsigned char data[16]; - int valid; -} key128; - -typedef struct -{ - u32 seed_num; - seeddb_entry* seed_db; - - key128 commonkey[COMMONKEY_NUM]; - key128 titlekey; - key128 seed_fallback; - key128 ncchfixedsystemkey; - key128 ncchkeyX_old; - key128 ncchkeyX_seven; - key128 ncchkeyX_ninethree; - key128 ncchkeyX_ninesix; - rsakey2048 ncsdrsakey; - rsakey2048 ncchrsakey; - rsakey2048 ncchdescrsakey; - rsakey2048 firmrsakey; -} keyset; - -void keyset_init(keyset* keys, u32 actions); -int keyset_load(keyset* keys, const char* fname, int verbose); -void keyset_merge(keyset* keys, keyset* src); -void keyset_parse_titlekey(keyset* keys, char* keytext, int keylen); -void keyset_parse_ncchkeyX_old(keyset* keys, char* keytext, int keylen); -void keyset_parse_ncchfixedsystemkey(keyset* keys, char* keytext, int keylen); -void keyset_parse_ncchkeyX_seven(keyset* keys, char* keytext, int keylen); -void keyset_parse_ncchkeyX_ninethree(keyset* keys, char* keytext, int keylen); -void keyset_parse_ncchkeyX_ninesix(keyset* keys, char* keytext, int keylen); -void keyset_parse_seeddb(keyset* keys, char* path); -void keyset_parse_seed_fallback(keyset* keys, char* keytext, int keylen); -void keyset_dump(keyset* keys); - -#ifdef __cplusplus -} -#endif - - -#endif // _KEYSET_H_ diff --git a/ctrtool/lzss.c b/ctrtool/lzss.c deleted file mode 100644 index 1a853a5..0000000 --- a/ctrtool/lzss.c +++ /dev/null @@ -1,195 +0,0 @@ -#include -#include -#include -#include "types.h" -#include "utils.h" -#include "lzss.h" - -void lzss_init(lzss_context* ctx) -{ - memset(ctx, 0, sizeof(lzss_context)); -} - -void lzss_set_usersettings(lzss_context* ctx, settings* usersettings) -{ - ctx->usersettings = usersettings; -} - -void lzss_set_offset(lzss_context* ctx, u32 offset) -{ - ctx->offset = offset; -} - -void lzss_set_size(lzss_context* ctx, u32 size) -{ - ctx->size = size; -} - -void lzss_set_file(lzss_context* ctx, FILE* file) -{ - ctx->file = file; -} - - -void lzss_process(lzss_context* ctx, u32 actions) -{ - unsigned int compressedsize; - unsigned char* compressedbuffer = 0; - unsigned int decompressedsize; - unsigned char* decompressedbuffer = 0; - FILE* fout = 0; - - - fseeko64(ctx->file, ctx->offset, SEEK_SET); - - - if (actions & ExtractFlag) - { - - filepath* path = settings_get_lzss_path(ctx->usersettings); - - if (path == 0 || path->valid == 0) - goto clean; - - fout = fopen(path->pathname, "wb"); - if (0 == fout) - { - fprintf(stdout, "Error opening out file %s\n", path->pathname); - goto clean; - } - compressedsize = ctx->size; - compressedbuffer = malloc(compressedsize); - if (1 != fread(compressedbuffer, compressedsize, 1, ctx->file)) - { - fprintf(stdout, "Error read input file\n"); - goto clean; - } - - decompressedsize = lzss_get_decompressed_size(compressedbuffer, compressedsize); - decompressedbuffer = malloc(decompressedsize); - - printf("Compressed: %d\n", compressedsize); - printf("Decompressed: %d\n", decompressedsize); - - if (decompressedbuffer == 0) - { - fprintf(stdout, "Error allocating memory\n"); - goto clean; - } - - if (0 == lzss_decompress(compressedbuffer, compressedsize, decompressedbuffer, decompressedsize)) - goto clean; - - printf("Saving decompressed lzss blob to %s...\n", path->pathname); - if (decompressedsize != fwrite(decompressedbuffer, 1, decompressedsize, fout)) - { - fprintf(stdout, "Error writing output file\n"); - goto clean; - } - } - -clean: - free(decompressedbuffer); - free(compressedbuffer); - if (fout) - fclose(fout); -} - - -u32 lzss_get_decompressed_size(u8* compressed, u32 compressedsize) -{ - u8* footer = compressed + compressedsize - 8; - - //u32 buffertopandbottom = getle32(footer+0); - u32 originalbottom = getle32(footer+4); - - return originalbottom + compressedsize; -} - -int lzss_decompress(u8* compressed, u32 compressedsize, u8* decompressed, u32 decompressedsize) -{ - u8* footer = compressed + compressedsize - 8; - u32 buffertopandbottom = getle32(footer+0); - //u32 originalbottom = getle32(footer+4); - u32 i, j; - u32 out = decompressedsize; - u32 index = compressedsize - ((buffertopandbottom>>24)&0xFF); - u32 segmentoffset; - u32 segmentsize; - u8 control; - u32 stopindex = compressedsize - (buffertopandbottom&0xFFFFFF); - - memset(decompressed, 0, decompressedsize); - memcpy(decompressed, compressed, compressedsize); - - - while(index > stopindex) - { - control = compressed[--index]; - - - for(i=0; i<8; i++) - { - if (index <= stopindex) - break; - - if (index <= 0) - break; - - if (out <= 0) - break; - - if (control & 0x80) - { - if (index < 2) - { - fprintf(stderr, "Error, compression out of bounds\n"); - goto clean; - } - - index -= 2; - - segmentoffset = compressed[index] | (compressed[index+1]<<8); - segmentsize = ((segmentoffset >> 12)&15)+3; - segmentoffset &= 0x0FFF; - segmentoffset += 2; - - - if (out < segmentsize) - { - fprintf(stderr, "Error, compression out of bounds\n"); - goto clean; - } - - for(j=0; j= decompressedsize) - { - fprintf(stderr, "Error, compression out of bounds\n"); - goto clean; - } - - data = decompressed[out+segmentoffset]; - decompressed[--out] = data; - } - } - else - { - if (out < 1) - { - fprintf(stderr, "Error, compression out of bounds\n"); - goto clean; - } - decompressed[--out] = compressed[--index]; - } - - control <<= 1; - } - } - - return 1; -clean: - return 0; -} diff --git a/ctrtool/lzss.h b/ctrtool/lzss.h deleted file mode 100644 index 64a5b2f..0000000 --- a/ctrtool/lzss.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _LZSS_H_ -#define _LZSS_H_ - -#include "types.h" -#include "settings.h" - -typedef struct -{ - FILE* file; - u32 offset; - u32 size; - settings* usersettings; -} lzss_context; - -void lzss_init(lzss_context* ctx); -void lzss_process(lzss_context* ctx, u32 actions); -void lzss_set_offset(lzss_context* ctx, u32 offset); -void lzss_set_size(lzss_context* ctx, u32 size); -void lzss_set_file(lzss_context* ctx, FILE* file); -void lzss_set_usersettings(lzss_context* ctx, settings* usersettings); - -u32 lzss_get_decompressed_size(u8* compressed, u32 compressedsize); -int lzss_decompress(u8* compressed, u32 compressedsize, u8* decompressed, u32 decompressedsize); - - -#endif // _LZSS_H_ diff --git a/ctrtool/main.c b/ctrtool/main.c deleted file mode 100644 index 1cbc04b..0000000 --- a/ctrtool/main.c +++ /dev/null @@ -1,488 +0,0 @@ -#include -#include -#include -#include -#include "utils.h" -#include "ctr.h" -#include "ncch.h" -#include "ncsd.h" -#include "cia.h" -#include "tmd.h" -#include "tik.h" -#include "lzss.h" -#include "keyset.h" -#include "exefs.h" -#include "info.h" -#include "settings.h" -#include "firm.h" -#include "cwav.h" -#include "romfs.h" - -enum cryptotype -{ - Plain, - CTR, - CBC -}; - - -typedef struct -{ - int actions; - u32 filetype; - FILE* infile; - u64 infilesize; - settings usersettings; -} toolcontext; - -static void usage(const char *argv0) -{ - fprintf(stderr, - "CTRTOOL v0.7 (c) neimod, 3DSGuy.\n" - "Built: %s %s\n" - "\n" - "Usage: %s [options...] \n" - "Options:\n" - " -i, --info Show file info.\n" - " This is the default action.\n" - " -x, --extract Extract data from file.\n" - " This is also the default action.\n" - " -p, --plain Extract data without decrypting.\n" - " -r, --raw Keep raw data, don't unpack.\n" - " -k, --keyset=file Specify keyset file.\n" - " -v, --verbose Give verbose output.\n" - " -y, --verify Verify hashes and signatures.\n" - " -d, --dev Decrypt with development keys instead of retail.\n" - " --unitsize=size Set media unit size (default 0x200).\n" -// " --commonkey=key Set common key.\n" - " --titlekey=key Set tik title key.\n" -// " --ncchkey=key Set ncch key.\n" -// " --ncchsyskey=key Set ncch fixed system key.\n" - " --seeddb=file Set seeddb for ncch seed crypto.\n" - " --seed=key Set specific seed for ncch seed crypto.\n" - " --showkeys Show the keys being used.\n" - " --showsyscalls Show system call names instead of numbers.\n" - " -t, --intype=type Specify input file type [ncsd, ncch, exheader, cia, tmd, lzss,\n" - " firm, cwav, exefs, romfs]\n" - "LZSS options:\n" - " --lzssout=file Specify lzss output file\n" - "CXI/CCI options:\n" - " -n, --ncch=index Specify NCCH partition index.\n" - " --exheader=file Specify Extended Header file path.\n" - " --logo=file Specify Logo file path.\n" - " --plainrgn=file Specify Plain region file path\n" - " --exefs=file Specify ExeFS file path.\n" - " --exefsdir=dir Specify ExeFS directory path.\n" - " --romfs=file Specify RomFS file path.\n" - " --romfsdir=dir Specify RomFS directory path.\n" - " --listromfs List files in RomFS.\n" - "CIA options:\n" - " --certs=file Specify Certificate chain file path.\n" - " --tik=file Specify Ticket file path.\n" - " --tmd=file Specify TMD file path.\n" - " --contents=file Specify Contents file path.\n" - " --meta=file Specify Meta file path.\n" - "FIRM options:\n" - " --firmdir=dir Specify Firm directory path.\n" - "CWAV options:\n" - " --wav=file Specify wav output file.\n" - " --wavloops=count Specify wav loop count, default 0.\n" - "EXEFS options:\n" - " --decompresscode Decompress .code section\n" - " (only needed when using raw EXEFS file)\n" - "\n", - __TIME__, __DATE__, argv0); - exit(1); -} - - -int main(int argc, char* argv[]) -{ - toolcontext ctx; - u8 magic[4]; - char infname[512]; - int c; - u32 ncchindex = 0; - char keysetfname[512] = "keys.xml"; - keyset tmpkeys; - unsigned int checkkeysetfile = 0; - - memset(&ctx, 0, sizeof(toolcontext)); - ctx.actions = InfoFlag | ExtractFlag; - ctx.filetype = FILETYPE_UNKNOWN; - - settings_init(&ctx.usersettings); - keyset_init(&tmpkeys, 0); - - - while (1) - { - int option_index; - static struct option long_options[] = - { - {"extract", 0, NULL, 'x'}, - {"plain", 0, NULL, 'p'}, - {"info", 0, NULL, 'i'}, - {"exefs", 1, NULL, 0}, - {"romfs", 1, NULL, 1}, - {"exheader", 1, NULL, 2}, - {"certs", 1, NULL, 3}, - {"tik", 1, NULL, 4}, - {"tmd", 1, NULL, 5}, - {"contents", 1, NULL, 6}, - {"meta", 1, NULL, 7}, - {"exefsdir", 1, NULL, 8}, - {"keyset", 1, NULL, 'k'}, - {"ncch", 1, NULL, 'n'}, - {"verbose", 0, NULL, 'v'}, - {"verify", 0, NULL, 'y'}, - {"raw", 0, NULL, 'r'}, - {"unitsize", 1, NULL, 9}, - {"showkeys", 0, NULL, 10}, - //{"commonkeyx", 1, NULL, 11}, - //{"ncchkeyxold", 1, NULL, 12}, - {"intype", 1, NULL, 't'}, - {"lzssout", 1, NULL, 13}, - {"firmdir", 1, NULL, 14}, - {"ncchsyskey", 1, NULL, 15}, - {"wav", 1, NULL, 16}, - {"romfsdir", 1, NULL, 17}, - {"listromfs", 0, NULL, 18}, - {"wavloops", 1, NULL, 19}, - {"logo", 1, NULL, 20}, - {"decompresscode", 0, NULL, 21}, - {"titlekey", 1, NULL, 22}, - {"plainrgn", 1, NULL, 23}, - {"showsyscalls", 0, NULL, 24}, - //{"ncchkeyxseven", 1, NULL, 25}, - //{"ncchkeyxninethree", 1, NULL, 26}, - //{"ncchkeyxninesix", 1, NULL, 27}, - {"seeddb", 1, NULL, 28}, - {"seed", 1, NULL, 29 }, - {NULL}, - }; - - c = getopt_long(argc, argv, "dryxivpk:n:t:", long_options, &option_index); - if (c == -1) - break; - - switch (c) - { - case 'x': - ctx.actions |= ExtractFlag; - break; - - case 'v': - ctx.actions |= VerboseFlag; - break; - - case 'y': - ctx.actions |= VerifyFlag; - break; - - case 'd': - ctx.actions |= DevFlag; - break; - - case 'p': - ctx.actions |= PlainFlag; - break; - - case 'r': - ctx.actions |= RawFlag; - break; - - case 'i': - ctx.actions |= InfoFlag; - break; - - case 'n': - ncchindex = strtoul(optarg, 0, 0); - break; - - case 'k': - strncpy(keysetfname, optarg, sizeof(keysetfname)); - checkkeysetfile = 1; - break; - - case 't': - if (!strcmp(optarg, "exheader")) - ctx.filetype = FILETYPE_EXHEADER; - else if (!strcmp(optarg, "ncch")) - ctx.filetype = FILETYPE_CXI; - else if (!strcmp(optarg, "ncsd")) - ctx.filetype = FILETYPE_CCI; - else if (!strcmp(optarg, "cia")) - ctx.filetype = FILETYPE_CIA; - else if (!strcmp(optarg, "tmd")) - ctx.filetype = FILETYPE_TMD; - else if (!strcmp(optarg, "lzss")) - ctx.filetype = FILETYPE_LZSS; - else if (!strcmp(optarg, "firm")) - ctx.filetype = FILETYPE_FIRM; - else if (!strcmp(optarg, "cwav")) - ctx.filetype = FILETYPE_CWAV; - else if (!strcmp(optarg, "exefs")) - ctx.filetype = FILETYPE_EXEFS; - else if (!strcmp(optarg, "romfs")) - ctx.filetype = FILETYPE_ROMFS; - break; - - case 0: settings_set_exefs_path(&ctx.usersettings, optarg); break; - case 1: settings_set_romfs_path(&ctx.usersettings, optarg); break; - case 2: settings_set_exheader_path(&ctx.usersettings, optarg); break; - case 3: settings_set_certs_path(&ctx.usersettings, optarg); break; - case 4: settings_set_tik_path(&ctx.usersettings, optarg); break; - case 5: settings_set_tmd_path(&ctx.usersettings, optarg); break; - case 6: settings_set_content_path(&ctx.usersettings, optarg); break; - case 7: settings_set_meta_path(&ctx.usersettings, optarg); break; - case 8: settings_set_exefs_dir_path(&ctx.usersettings, optarg); break; - case 9: settings_set_mediaunit_size(&ctx.usersettings, strtoul(optarg, 0, 0)); break; - case 10: ctx.actions |= ShowKeysFlag; break; - //case 11: keyset_parse_commonkeyX(&tmpkeys, optarg, strlen(optarg)); break; - //case 12: keyset_parse_ncchkeyX_old(&tmpkeys, optarg, strlen(optarg)); break; - case 13: settings_set_lzss_path(&ctx.usersettings, optarg); break; - case 14: settings_set_firm_dir_path(&ctx.usersettings, optarg); break; - //case 15: keyset_parse_ncchfixedsystemkey(&tmpkeys, optarg, strlen(optarg)); break; - case 16: settings_set_wav_path(&ctx.usersettings, optarg); break; - case 17: settings_set_romfs_dir_path(&ctx.usersettings, optarg); break; - case 18: settings_set_list_romfs_files(&ctx.usersettings, 1); break; - case 19: settings_set_cwav_loopcount(&ctx.usersettings, strtoul(optarg, 0, 0)); break; - case 20: settings_set_logo_path(&ctx.usersettings, optarg); break; - case 21: ctx.actions |= DecompressCodeFlag; break; - case 22: keyset_parse_titlekey(&tmpkeys, optarg, strlen(optarg)); break; - case 23: settings_set_plainrgn_path(&ctx.usersettings, optarg); break; - case 24: ctx.actions |= ShowSyscallsFlag; break; - //case 25: keyset_parse_ncchkeyX_seven(&tmpkeys, optarg, strlen(optarg)); break; - //case 26: keyset_parse_ncchkeyX_ninethree(&tmpkeys, optarg, strlen(optarg)); break; - //case 27: keyset_parse_ncchkeyX_ninesix(&tmpkeys, optarg, strlen(optarg)); break; - case 28: keyset_parse_seeddb(&tmpkeys, optarg); break; - case 29: keyset_parse_seed_fallback(&tmpkeys, optarg, strlen(optarg)); break; - - default: - usage(argv[0]); - } - } - - if (optind == argc - 1) - { - // Exactly one extra argument - an input file - strncpy(infname, argv[optind], sizeof(infname)); - } - else if ( (optind < argc) || (argc == 1) ) - { - // Too many extra args - usage(argv[0]); - } - - keyset_init(&ctx.usersettings.keys, ctx.actions); - keyset_load(&ctx.usersettings.keys, keysetfname, (ctx.actions & VerboseFlag) | checkkeysetfile); - keyset_merge(&ctx.usersettings.keys, &tmpkeys); - if (ctx.actions & ShowKeysFlag) - keyset_dump(&ctx.usersettings.keys); - - ctx.infilesize = _fsize(infname); - ctx.infile = fopen(infname, "rb"); - - if (ctx.infile == 0) - { - fprintf(stderr, "error: could not open input file!\n"); - return -1; - } - - if (ctx.filetype == FILETYPE_UNKNOWN) - { - fseeko64(ctx.infile, 0x100, SEEK_SET); - fread(&magic, 1, 4, ctx.infile); - - switch(getle32(magic)) - { - case MAGIC_NCCH: - ctx.filetype = FILETYPE_CXI; - break; - - case MAGIC_NCSD: - ctx.filetype = FILETYPE_CCI; - break; - - default: - break; - } - } - - if (ctx.filetype == FILETYPE_UNKNOWN) - { - fseeko64(ctx.infile, 0, SEEK_SET); - fread(magic, 1, 4, ctx.infile); - - switch(getle32(magic)) - { - case 0x2020: - ctx.filetype = FILETYPE_CIA; - break; - - case MAGIC_FIRM: - ctx.filetype = FILETYPE_FIRM; - break; - - case MAGIC_CWAV: - ctx.filetype = FILETYPE_CWAV; - break; - - case MAGIC_IVFC: - ctx.filetype = FILETYPE_ROMFS; // TODO: need to determine more here.. savegames use IVFC too, but is not ROMFS. - break; - } - } - - if (ctx.filetype == FILETYPE_UNKNOWN) - { - fprintf(stdout, "Unknown file\n"); - exit(1); - } - - - switch(ctx.filetype) - { - case FILETYPE_CCI: - { - ncsd_context ncsdctx; - - ncsd_init(&ncsdctx); - ncsd_set_file(&ncsdctx, ctx.infile); - ncsd_set_size(&ncsdctx, ctx.infilesize); - ncsd_set_ncch_index(&ncsdctx, ncchindex); - ncsd_set_usersettings(&ncsdctx, &ctx.usersettings); - ncsd_process(&ncsdctx, ctx.actions); - - break; - } - - case FILETYPE_FIRM: - { - firm_context firmctx; - - firm_init(&firmctx); - firm_set_file(&firmctx, ctx.infile); - firm_set_size(&firmctx, (u32) ctx.infilesize); - firm_set_usersettings(&firmctx, &ctx.usersettings); - firm_process(&firmctx, ctx.actions); - - break; - } - - case FILETYPE_CXI: - { - ncch_context ncchctx; - - ncch_init(&ncchctx); - ncch_set_file(&ncchctx, ctx.infile); - ncch_set_size(&ncchctx, ctx.infilesize); - ncch_set_usersettings(&ncchctx, &ctx.usersettings); - ncch_process(&ncchctx, ctx.actions); - - break; - } - - - case FILETYPE_CIA: - { - cia_context ciactx; - - cia_init(&ciactx); - cia_set_file(&ciactx, ctx.infile); - cia_set_size(&ciactx, ctx.infilesize); - cia_set_usersettings(&ciactx, &ctx.usersettings); - cia_process(&ciactx, ctx.actions); - - break; - } - - case FILETYPE_EXHEADER: - { - exheader_context exheaderctx; - - exheader_init(&exheaderctx); - exheader_set_file(&exheaderctx, ctx.infile); - exheader_set_size(&exheaderctx, ctx.infilesize); - settings_set_ignore_programid(&ctx.usersettings, 1); - - exheader_set_usersettings(&exheaderctx, &ctx.usersettings); - exheader_process(&exheaderctx, ctx.actions); - - break; - } - - case FILETYPE_TMD: - { - tmd_context tmdctx; - - tmd_init(&tmdctx); - tmd_set_file(&tmdctx, ctx.infile); - tmd_set_size(&tmdctx, (u32) ctx.infilesize); - tmd_set_usersettings(&tmdctx, &ctx.usersettings); - tmd_process(&tmdctx, ctx.actions); - - break; - } - - case FILETYPE_LZSS: - { - lzss_context lzssctx; - - lzss_init(&lzssctx); - lzss_set_file(&lzssctx, ctx.infile); - lzss_set_size(&lzssctx, (u32) ctx.infilesize); - lzss_set_usersettings(&lzssctx, &ctx.usersettings); - lzss_process(&lzssctx, ctx.actions); - - break; - } - - - case FILETYPE_CWAV: - { - cwav_context cwavctx; - - cwav_init(&cwavctx); - cwav_set_file(&cwavctx, ctx.infile); - cwav_set_size(&cwavctx, ctx.infilesize); - cwav_set_usersettings(&cwavctx, &ctx.usersettings); - cwav_process(&cwavctx, ctx.actions); - - break; - } - - case FILETYPE_EXEFS: - { - exefs_context exefsctx; - - exefs_init(&exefsctx); - exefs_set_file(&exefsctx, ctx.infile); - exefs_set_size(&exefsctx, ctx.infilesize); - exefs_set_usersettings(&exefsctx, &ctx.usersettings); - exefs_process(&exefsctx, ctx.actions); - - break; - } - - case FILETYPE_ROMFS: - { - romfs_context romfsctx; - - romfs_init(&romfsctx); - romfs_set_file(&romfsctx, ctx.infile); - romfs_set_size(&romfsctx, ctx.infilesize); - romfs_set_usersettings(&romfsctx, &ctx.usersettings); - romfs_set_encrypted(&romfsctx, 0); - romfs_process(&romfsctx, ctx.actions); - - break; - } - } - - if (ctx.infile) - fclose(ctx.infile); - - return 0; -} diff --git a/ctrtool/ncch.c b/ctrtool/ncch.c deleted file mode 100644 index a5516dd..0000000 --- a/ctrtool/ncch.c +++ /dev/null @@ -1,880 +0,0 @@ -#include -#include -#include -#include "types.h" -#include "ncch.h" -#include "utils.h" -#include "ctr.h" -#include "settings.h" -#include "aes_keygen.h" -#include - -static int programid_is_system(u8 programid[8]) -{ - u32 hiprogramid = getle32(programid+4); - - if ( ((hiprogramid >> 14) == 0x10) && (hiprogramid & 0x10) ) - return 1; - else - return 0; -} - - -void ncch_init(ncch_context* ctx) -{ - memset(ctx, 0, sizeof(ncch_context)); - exefs_init(&ctx->exefs); -} - -void ncch_set_usersettings(ncch_context* ctx, settings* usersettings) -{ - ctx->usersettings = usersettings; -} - -void ncch_set_offset(ncch_context* ctx, u64 offset) -{ - ctx->offset = offset; -} - -void ncch_set_size(ncch_context* ctx, u64 size) -{ - ctx->size = size; -} - -void ncch_set_file(ncch_context* ctx, FILE* file) -{ - ctx->file = file; -} - -void ncch_get_counter(ncch_context* ctx, u8 counter[16], u8 type) -{ - u32 version = getle16(ctx->header.version); - u32 mediaunitsize = (u32) ncch_get_mediaunit_size(ctx); - u8* titleid = ctx->header.titleid; - u32 i; - u64 x = 0; - - memset(counter, 0, 16); - - if (version == 2 || version == 0) - { - for(i=0; i<8; i++) - counter[i] = titleid[7-i]; - counter[8] = type; - } - else if (version == 1) - { - if (type == NCCHTYPE_EXHEADER) - x = 0x200; - else if (type == NCCHTYPE_EXEFS) - x = getle32(ctx->header.exefsoffset) * mediaunitsize; - else if (type == NCCHTYPE_ROMFS) - x = getle32(ctx->header.romfsoffset) * mediaunitsize; - - for(i=0; i<8; i++) - counter[i] = titleid[i]; - for(i=0; i<4; i++) - counter[12+i] = (u8) (x>>((3-i)*8)); - } -} - - -/* this is broken */ -int ncch_extract_prepare(ncch_context* ctx, u32 type, u32 flags) -{ - u64 offset = 0; - u64 size = 0; - u8 counter[16]; - - - switch(type) - { - case NCCHTYPE_EXEFS: - { - offset = ncch_get_exefs_offset(ctx); - size = ncch_get_exefs_size(ctx); - ctr_init_key(&ctx->aes, ctx->key[0]); - } - break; - - case NCCHTYPE_ROMFS: - { - offset = ncch_get_romfs_offset(ctx); - size = ncch_get_romfs_size(ctx); - ctr_init_key(&ctx->aes, ctx->key[1]); - } - break; - - case NCCHTYPE_EXHEADER: - { - offset = ncch_get_exheader_offset(ctx); - size = ncch_get_exheader_size(ctx) * 2; - ctr_init_key(&ctx->aes, ctx->key[0]); - } - break; - - case NCCHTYPE_LOGO: - { - offset = ncch_get_logo_offset(ctx); - size = ncch_get_logo_size(ctx); - } - break; - - case NCCHTYPE_PLAINRGN: - { - offset = ncch_get_plainrgn_offset(ctx); - size = ncch_get_plainrgn_size(ctx); - } - break; - - default: - { - fprintf(stderr, "Error invalid NCCH type\n"); - goto clean; - } - break; - } - - ctx->extractsize = size; - ctx->extractflags = flags; - fseeko64(ctx->file, offset, SEEK_SET); - ncch_get_counter(ctx, counter, type); - - ctr_init_counter(&ctx->aes, counter); - - return 1; - -clean: - return 0; -} - -int ncch_extract_buffer(ncch_context* ctx, u8* buffer, u32 buffersize, u32* outsize, u8 nocrypto) -{ - u32 read_len = buffersize; - - if (read_len > ctx->extractsize) - read_len = (u32) ctx->extractsize; - - *outsize = read_len; - - if (ctx->extractsize) - { - if (read_len != fread(buffer, 1, read_len, ctx->file)) - { - fprintf(stdout, "Error reading input file\n"); - goto clean; - } - - if (ctx->encrypted && !nocrypto) - ctr_crypt_counter(&ctx->aes, buffer, buffer, read_len); - - ctx->extractsize -= read_len; - } - - return 1; - -clean: - return 0; -} - -void ncch_save(ncch_context* ctx, u32 type, u32 flags) -{ - FILE* fout = 0; - filepath* path = 0; - u8 buffer[16*1024]; - exefs_header exefs_hdr; - - - if (0 == ncch_extract_prepare(ctx, type, flags)) - goto clean; - - switch(type) - { - case NCCHTYPE_EXEFS: path = settings_get_exefs_path(ctx->usersettings); break; - case NCCHTYPE_ROMFS: path = settings_get_romfs_path(ctx->usersettings); break; - case NCCHTYPE_EXHEADER: path = settings_get_exheader_path(ctx->usersettings); break; - case NCCHTYPE_LOGO: path = settings_get_logo_path(ctx->usersettings); break; - case NCCHTYPE_PLAINRGN: path = settings_get_plainrgn_path(ctx->usersettings); break; - } - - if (path == 0 || path->valid == 0) - goto clean; - - fout = fopen(path->pathname, "wb"); - if (0 == fout) - { - fprintf(stdout, "Error opening out file %s\n", path->pathname); - goto clean; - } - - switch(type) - { - case NCCHTYPE_EXEFS: fprintf(stdout, "Saving ExeFS...\n"); break; - case NCCHTYPE_ROMFS: fprintf(stdout, "Saving RomFS...\n"); break; - case NCCHTYPE_EXHEADER: fprintf(stdout, "Saving Extended Header...\n"); break; - case NCCHTYPE_LOGO: fprintf(stdout, "Saving Logo...\n"); break; - case NCCHTYPE_PLAINRGN: fprintf(stdout, "Saving Plain Region...\n"); break; - } - - // special crypto considerations for exefs when two keys are used - if (type == NCCHTYPE_EXEFS && ctx->header.flags[3] > 0 && ctx->encrypted) - { - u32 read_len; - - // read header - if (0 == ncch_extract_buffer(ctx, (u8*)&exefs_hdr, sizeof(exefs_hdr), &read_len, 0)) - goto clean; - - if (read_len != fwrite(&exefs_hdr, 1, read_len, fout)) - { - fprintf(stdout, "Error writing output file\n"); - goto clean; - } - - for (int i = 0; i < 8; i++) - { - - // get section size - u32 section_size = getle32(exefs_hdr.section[i].size); - u32 section_padding = align(section_size, 0x200)-section_size; - - // skip empty sections - if (section_size == 0) - continue; - - // select correct key - if (strncmp((char*)exefs_hdr.section[i].name, "icon", 8) == 0 || strncmp((char*)exefs_hdr.section[i].name, "banner", 8) == 0) - ctr_init_key(&ctx->aes, ctx->key[0]); - else - ctr_init_key(&ctx->aes, ctx->key[1]); - - // set counter - u8 ctr[16]; - ncch_get_counter(ctx, ctr, NCCHTYPE_EXEFS); - ctr_init_counter(&ctx->aes, ctr); - ctr_add_counter(&ctx->aes, (getle32(exefs_hdr.section[i].offset) + sizeof(exefs_header)) / 0x10); - - // extract data - while (section_size > 0) - { - read_len = sizeof(buffer); - if (read_len > section_size) - read_len = section_size; - - - if (read_len != fread(buffer, 1, read_len, ctx->file)) - { - fprintf(stdout, "Error reading input file\n"); - goto clean; - } - - ctr_crypt_counter(&ctx->aes, buffer, buffer, read_len); - - if (read_len != fwrite(buffer, 1, read_len, fout)) - { - fprintf(stdout, "Error writing output file\n"); - goto clean; - } - - - section_size -= read_len; - } - - // skip the padding - if (section_padding) - { - fseeko64(ctx->file, section_padding, SEEK_CUR); - memset(buffer, 0, section_padding); - if (section_padding != fwrite(buffer, 1, section_padding, fout)) - { - fprintf(stdout, "Error writing output file\n"); - goto clean; - } - - } - - ctx->extractsize -= section_size + section_padding; - } - } - else - { - while (1) - { - u32 read_len; - - if (0 == ncch_extract_buffer(ctx, buffer, sizeof(buffer), &read_len, (type == NCCHTYPE_LOGO || type == NCCHTYPE_PLAINRGN))) - goto clean; - - if (read_len == 0) - break; - - if (read_len != fwrite(buffer, 1, read_len, fout)) - { - fprintf(stdout, "Error writing output file\n"); - goto clean; - } - } - } - -clean: - if (fout) - fclose(fout); - return; -} - -void ncch_verify(ncch_context* ctx, u32 flags) -{ - u32 mediaunitsize = (u32) ncch_get_mediaunit_size(ctx); - u32 exefshashregionsize = getle32(ctx->header.exefshashregionsize) * mediaunitsize; - u32 romfshashregionsize = getle32(ctx->header.romfshashregionsize) * mediaunitsize; - u32 exheaderhashregionsize = getle32(ctx->header.extendedheadersize); - u32 logohashregionsize = getle32(ctx->header.logosize) * mediaunitsize; - u8* exefshashregion = 0; - u8* romfshashregion = 0; - u8* exheaderhashregion = 0; - u8* logohashregion = 0; - u8* tmphash = 0; - rsakey2048 ncchrsakey; - - if (exefshashregionsize >= SIZE_128MB || romfshashregionsize >= SIZE_128MB || exheaderhashregionsize >= SIZE_128MB || logohashregionsize >= SIZE_128MB) - goto clean; - - exefshashregion = malloc(exefshashregionsize); - romfshashregion = malloc(romfshashregionsize); - exheaderhashregion = malloc(exheaderhashregionsize); - logohashregion = malloc(logohashregionsize); - - - if (ctx->usersettings) - { - if ( (ctx->header.flags[5] & 3) == 1) - ctx->headersigcheck = ncch_signature_verify(ctx, &ctx->usersettings->keys.ncchrsakey); - else - { - ctr_rsa_init_key_pubmodulus(&ncchrsakey, ctx->exheader.header.accessdesc.ncchpubkeymodulus); - ctx->headersigcheck = ncch_signature_verify(ctx, &ncchrsakey); - } - } - - if (exefshashregionsize) - { - if (0 == ncch_extract_prepare(ctx, NCCHTYPE_EXEFS, flags)) - goto clean; - if (0 == ncch_extract_buffer(ctx, exefshashregion, exefshashregionsize, &exefshashregionsize,0)) - goto clean; - ctx->exefshashcheck = ctr_sha_256_verify(exefshashregion, exefshashregionsize, ctx->header.exefssuperblockhash); - } - if (romfshashregionsize) - { - if (0 == ncch_extract_prepare(ctx, NCCHTYPE_ROMFS, flags)) - goto clean; - if (0 == ncch_extract_buffer(ctx, romfshashregion, romfshashregionsize, &romfshashregionsize,0)) - goto clean; - ctx->romfshashcheck = ctr_sha_256_verify(romfshashregion, romfshashregionsize, ctx->header.romfssuperblockhash); - } - if (exheaderhashregionsize) - { - if (0 == ncch_extract_prepare(ctx, NCCHTYPE_EXHEADER, flags)) - goto clean; - if (0 == ncch_extract_buffer(ctx, exheaderhashregion, exheaderhashregionsize, &exheaderhashregionsize,0)) - goto clean; - ctx->exheaderhashcheck = ctr_sha_256_verify(exheaderhashregion, exheaderhashregionsize, ctx->header.extendedheaderhash); - } - if (logohashregionsize) - { - if (0 == ncch_extract_prepare(ctx, NCCHTYPE_LOGO, flags)) - goto clean; - if (0 == ncch_extract_buffer(ctx, logohashregion, logohashregionsize, &logohashregionsize,1)) - goto clean; - ctx->logohashcheck = ctr_sha_256_verify(logohashregion, logohashregionsize, ctx->header.logohash); - } - - - free(exefshashregion); - free(romfshashregion); - free(exheaderhashregion); - free(logohashregion); -clean: - return; -} - - -void ncch_process(ncch_context* ctx, u32 actions) -{ - u8 exheadercounter[16]; - u8 exefscounter[16]; - u8 romfscounter[16]; - int result = 1; - - - fseeko64(ctx->file, ctx->offset, SEEK_SET); - fread(&ctx->header, 1, 0x200, ctx->file); - - if (getle32(ctx->header.magic) != MAGIC_NCCH) - { - fprintf(stdout, "Error, NCCH segment corrupted\n"); - return; - } - - const u32 exheaderSize = getle32(ctx->header.extendedheadersize); - if (exheaderSize != 0x400 && exheaderSize != 0) - { - fprintf(stdout, "Error, exheader is 0x%02x bytes long, expected 0x400 or 0\n", getle32(ctx->header.extendedheadersize)); - return; - } - - ncch_determine_key(ctx, actions); - - ncch_get_counter(ctx, exheadercounter, NCCHTYPE_EXHEADER); - ncch_get_counter(ctx, exefscounter, NCCHTYPE_EXEFS); - ncch_get_counter(ctx, romfscounter, NCCHTYPE_ROMFS); - - if (actions & ShowKeysFlag) - { - fprintf(stdout, "Counter(s):\n"); - memdump(stdout, " exheader: ", exheadercounter, 0x10); - memdump(stdout, " ExeFS: ", exefscounter, 0x10); - memdump(stdout, " RomFS: ", romfscounter, 0x10); - } - - - exheader_set_file(&ctx->exheader, ctx->file); - exheader_set_offset(&ctx->exheader, ncch_get_exheader_offset(ctx) ); - exheader_set_size(&ctx->exheader, ncch_get_exheader_size(ctx) ); - exheader_set_usersettings(&ctx->exheader, ctx->usersettings); - exheader_set_titleid(&ctx->exheader, ctx->header.titleid); - exheader_set_programid(&ctx->exheader, ctx->header.programid); - exheader_set_hash(&ctx->exheader, ctx->header.extendedheaderhash); - exheader_set_counter(&ctx->exheader, exheadercounter); - exheader_set_key(&ctx->exheader, ctx->key[0]); - exheader_set_encrypted(&ctx->exheader, ctx->encrypted); - - exefs_set_file(&ctx->exefs, ctx->file); - exefs_set_offset(&ctx->exefs, ncch_get_exefs_offset(ctx) ); - exefs_set_size(&ctx->exefs, ncch_get_exefs_size(ctx) ); - exefs_set_titleid(&ctx->exefs, ctx->header.titleid); - exefs_set_usersettings(&ctx->exefs, ctx->usersettings); - exefs_set_counter(&ctx->exefs, exefscounter); - exefs_set_keys(&ctx->exefs, ctx->key[0], ctx->key[1]); - exefs_set_encrypted(&ctx->exefs, ctx->encrypted); - - romfs_set_file(&ctx->romfs, ctx->file); - romfs_set_offset(&ctx->romfs, ncch_get_romfs_offset(ctx)); - romfs_set_size(&ctx->romfs, ncch_get_romfs_size(ctx)); - romfs_set_usersettings(&ctx->romfs, ctx->usersettings); - romfs_set_counter(&ctx->romfs, romfscounter); - romfs_set_key(&ctx->romfs, ctx->key[1]); - romfs_set_encrypted(&ctx->romfs, ctx->encrypted); - - exheader_read(&ctx->exheader, actions); - - - if (actions & VerifyFlag) - ncch_verify(ctx, actions); - - if (actions & InfoFlag) - ncch_print(ctx); - - if (ctx->encrypted == NCCHCRYPTO_BROKEN) - { - fprintf(stderr, "Error, NCCH encryption broken.\n"); - return; - } - - if ((actions & ShowKeysFlag) && ctx->encrypted) - { - fprintf(stdout, "Using key(s):\n"); - if (ctx->encrypted == NCCHCRYPTO_FIXED) - { - memdump(stdout, " Key: ", ctx->key[0], 0x10); - } - else - { - memdump(stdout, " 0x2C: ", ctx->key[0], 0x10); - if (memcmp(ctx->key[0], ctx->key[1], 0x10) != 0) - { - fprintf(stdout, " special (%02x): ", ctx->header.flags[3]); - memdump(stdout, "", ctx->key[1], 0x10); - } - } - } - - if (actions & ExtractFlag) - { - ncch_save(ctx, NCCHTYPE_EXEFS, actions); - ncch_save(ctx, NCCHTYPE_ROMFS, actions); - ncch_save(ctx, NCCHTYPE_EXHEADER, actions); - ncch_save(ctx, NCCHTYPE_LOGO, actions); - ncch_save(ctx, NCCHTYPE_PLAINRGN, actions); - } - - - if (result && ncch_get_exheader_size(ctx)) - { - if (!exheader_hash_valid(&ctx->exheader)) - return; - - result = exheader_process(&ctx->exheader, actions); - } - - if (result && ncch_get_exefs_size(ctx)) - { - if(ncch_get_exheader_size(ctx)) - exefs_set_compressedflag(&ctx->exefs, exheader_get_compressedflag(&ctx->exheader)); - exefs_process(&ctx->exefs, actions); - } - - if (result && ncch_get_romfs_size(ctx)) - { - romfs_process(&ctx->romfs, actions); - } -} - -int ncch_signature_verify(ncch_context* ctx, rsakey2048* key) -{ - u8 hash[0x20]; - - ctr_sha_256(ctx->header.magic, 0x100, hash); - return ctr_rsa_verify_hash(ctx->header.signature, hash, key); -} - - -u64 ncch_get_exefs_offset(ncch_context* ctx) -{ - return ctx->offset + getle32(ctx->header.exefsoffset) * ncch_get_mediaunit_size(ctx); -} - -u64 ncch_get_exefs_size(ncch_context* ctx) -{ - return getle32(ctx->header.exefssize) * ncch_get_mediaunit_size(ctx); -} - -u64 ncch_get_romfs_offset(ncch_context* ctx) -{ - return ctx->offset + getle32(ctx->header.romfsoffset) * ncch_get_mediaunit_size(ctx); -} - -u64 ncch_get_romfs_size(ncch_context* ctx) -{ - return getle32(ctx->header.romfssize) * ncch_get_mediaunit_size(ctx); -} - -u64 ncch_get_exheader_offset(ncch_context* ctx) -{ - return ctx->offset + 0x200; -} - -u64 ncch_get_exheader_size(ncch_context* ctx) -{ - return getle32(ctx->header.extendedheadersize); -} - -u64 ncch_get_logo_offset(ncch_context* ctx) -{ - return ctx->offset + getle32(ctx->header.logooffset) * ncch_get_mediaunit_size(ctx); -} - -u64 ncch_get_logo_size(ncch_context* ctx) -{ - return getle32(ctx->header.logosize) * ncch_get_mediaunit_size(ctx); -} - -u64 ncch_get_plainrgn_offset(ncch_context* ctx) -{ - return ctx->offset + getle32(ctx->header.plainregionoffset) * ncch_get_mediaunit_size(ctx); -} - -u64 ncch_get_plainrgn_size(ncch_context* ctx) -{ - return getle32(ctx->header.plainregionsize) * ncch_get_mediaunit_size(ctx); -} - - -u64 ncch_get_mediaunit_size(ncch_context* ctx) -{ - unsigned int mediaunitsize = settings_get_mediaunit_size(ctx->usersettings); - - if (mediaunitsize == 0) - { - unsigned short version = getle16(ctx->header.version); - if (version == 1) - mediaunitsize = 1; - else if (version == 2 || version == 0) - mediaunitsize = 1 << (ctx->header.flags[6] + 9); - } - - return mediaunitsize; -} - - -void ncch_determine_key(ncch_context* ctx, u32 actions) -{ - u8 exheader_buffer[0x400]; - u8 seedbuf[0x20]; - u8* seed; - u8* keyX = NULL; - u8 hash[0x20] = {0}; - ctr_ncchheader* header = &ctx->header; - const u32 exheaderSize = getle32(header->extendedheadersize); - struct sNcchKeyslot - { - u8 x[0x10]; - u8 y[0x10]; - u8 key[0x10]; - } key[2]; - - - // Check if the NCCH is already decrypted, by checking if the exheader hash matches - // Otherwise, use determination rules - fseeko64(ctx->file, ncch_get_exheader_offset(ctx), SEEK_SET); - memset(exheader_buffer, 0, exheaderSize); - fread(exheader_buffer, 1, exheaderSize, ctx->file); - ctr_sha_256(exheader_buffer, exheaderSize, hash); - if (!memcmp(hash, header->extendedheaderhash, 32)) - { - // exheader hash matches, so probably decrypted - ctx->encrypted = NCCHCRYPTO_NONE; - if (!(header->flags[7] & 4)) - fprintf(stderr, "Warning, exheader is decrypted but the NCCH says it isn't.\n" - "This NCCH will likely break on console.\n"); - return; - } - - // if not plain flag set and not ncch unencrypted flag set - // determine the keys - if (!(actions & PlainFlag) && !(header->flags[7] & 4)) - { - // fixed key crypto - if (header->flags[7] & 1) - { - ctx->encrypted = NCCHCRYPTO_FIXED; - if (programid_is_system(header->programid)) - { - if (settings_get_ncch_fixedsystemkey(ctx->usersettings) == NULL) - { - fprintf(stderr, "Error, could not read system fixed key.\n"); - ctx->encrypted = NCCHCRYPTO_BROKEN; - return; - } - - memcpy(key[0].key, settings_get_ncch_fixedsystemkey(ctx->usersettings), 0x10); - } - else - { - memset(key[0].key, 0x00, 0x10); - } - - memcpy(key[1].key, key[0].key, 0x10); - } - // secure crypto - else - { - ctx->encrypted = NCCHCRYPTO_SECURE; - if (settings_get_ncchkeyX_old(ctx->usersettings) == NULL) - { - fprintf(stderr, "Error, could not read NCCH base keyX.\n"); - ctx->encrypted = NCCHCRYPTO_BROKEN; - return; - } - - // setup regular keyslot seeds (exheader, exefs:icon|banner) - memcpy(key[0].x, settings_get_ncchkeyX_old(ctx->usersettings), 0x10); - memcpy(key[0].y, header->signature, 0x10); - - // setup second keyslot seed (romfs, exefs:!(icon|banner)) - // - get keyX - - switch (header->flags[3]) - { - case(0): - keyX = settings_get_ncchkeyX_old(ctx->usersettings); - break; - case(1): - keyX = settings_get_ncchkeyX_seven(ctx->usersettings); - break; - case(10): - keyX = settings_get_ncchkeyX_ninethree(ctx->usersettings); - break; - case(11): - keyX = settings_get_ncchkeyX_ninesix(ctx->usersettings); - break; - default: - fprintf(stderr, "Warning, unknown NCCH crypto method.\n"); - ctx->encrypted = NCCHCRYPTO_BROKEN; - return; - } - - if (keyX == NULL) - { - fprintf(stderr, "Error, could not read NCCH keyX.\n"); - ctx->encrypted = NCCHCRYPTO_BROKEN; - return; - } - - memcpy(key[1].x, keyX, 0x10); - - // - get keyY - if (header->flags[7] & 0x20) - { - seed = settings_get_seed(ctx->usersettings, getle64(header->programid)); - if (!seed) - { - fprintf(stderr, "This title uses seed crypto, but no seed is set, unable to decrypt.\n" - "Use -p to avoid decryption or use --seeddb=dbfile or --seed=SEEDHERE.\n"); - ctx->encrypted = NCCHCRYPTO_BROKEN; - return; - } - - memcpy(seedbuf, seed, 0x10); - // Assumes running on little endian - memcpy(seedbuf + 0x10, header->programid, sizeof(header->programid)); - ctr_sha_256(seedbuf, 0x18, hash); - if (memcmp(hash, header->seedcheck, sizeof(header->seedcheck))) { - fprintf(stderr, "Seed check mismatch. (Got: %02x%02x%02x%02x, expected: %02x%02x%02x%02x)\n", - hash[0], hash[1], hash[2], hash[3], - header->seedcheck[0], header->seedcheck[1], header->seedcheck[2], header->seedcheck[3]); - ctx->encrypted = NCCHCRYPTO_BROKEN; - return; - } - - memcpy(seedbuf, header->signature, 0x10); - memcpy(seedbuf + 0x10, seed, 0x10); - ctr_sha_256(seedbuf, 0x20, hash); - memcpy(key[1].y, hash, 0x10); - } - else - { - memcpy(key[1].y, key[0].y, 0x10); - } - - - // generate keys - ctr_aes_keygen(key[0].x, key[0].y, key[0].key); - ctr_aes_keygen(key[1].x, key[1].y, key[1].key); - } - - // save keys - memcpy(ctx->key[0], key[0].key, 0x10); - memcpy(ctx->key[1], key[1].key, 0x10); - } - else - { - ctx->encrypted = NCCHCRYPTO_NONE; - } -} - -static const char* formtypetostring(unsigned char flags) -{ - unsigned char formtype = flags & 3; - - switch(formtype) - { - case 0: return "Not assigned"; - case 1: return "Simple content"; - case 2: return "Executable content without RomFS"; - case 3: return "Executable content"; - default: return "Unknown"; - } -} - -static const char* contenttypetostring(unsigned char flags) -{ - unsigned char contenttype = flags>>2; - - switch(contenttype) - { - case 0: return "Application"; - case 1: return "System Update"; - case 2: return "Manual"; - case 3: return "Child"; - case 4: return "Trial"; - case 5: return "Extended System Update"; - default: return "Unknown"; - } -} - -static const char* contentplatformtostring(unsigned char platform) -{ - switch (platform) - { - case 1: return "CTR"; - case 2: return "SNAKE"; - default: return "Unknown"; - } -} - - - -void ncch_print(ncch_context* ctx) -{ - ctr_ncchheader *header = &ctx->header; - u64 offset = ctx->offset; - u64 mediaunitsize = ncch_get_mediaunit_size(ctx); - - fprintf(stdout, "\nNCCH:\n"); - - fprintf(stdout, "Header: %.4s\n", header->magic); - if (ctx->headersigcheck == Unchecked) - memdump(stdout, "Signature: ", header->signature, 0x100); - else if (ctx->headersigcheck == Good) - memdump(stdout, "Signature (GOOD): ", header->signature, 0x100); - else - memdump(stdout, "Signature (FAIL): ", header->signature, 0x100); - fprintf(stdout, "Content size: 0x%08"PRIx64"\n", getle32(header->contentsize)*mediaunitsize); - fprintf(stdout, "Title id: %016"PRIx64"\n", getle64(header->titleid)); - fprintf(stdout, "Maker code: %.2s\n", header->makercode); - fprintf(stdout, "Version: %d\n", getle16(header->version)); - fprintf(stdout, "Title seed check: %08x\n", getle32(header->seedcheck)); - fprintf(stdout, "Program id: %016"PRIx64"\n", getle64(header->programid)); - if(ctx->logohashcheck == Unchecked) - memdump(stdout, "Logo hash: ", header->logohash, 0x20); - else if(ctx->logohashcheck == Good) - memdump(stdout, "Logo hash (GOOD): ", header->logohash, 0x20); - else - memdump(stdout, "Logo hash (FAIL): ", header->logohash, 0x20); - fprintf(stdout, "Product code: %.16s\n", header->productcode); - fprintf(stdout, "Exheader size: 0x%x\n", getle32(header->extendedheadersize)); - if (ctx->exheaderhashcheck == Unchecked) - memdump(stdout, "Exheader hash: ", header->extendedheaderhash, 0x20); - else if (ctx->exheaderhashcheck == Good) - memdump(stdout, "Exheader hash (GOOD): ", header->extendedheaderhash, 0x20); - else - memdump(stdout, "Exheader hash (FAIL): ", header->extendedheaderhash, 0x20); - fprintf(stdout, "Flags: %016"PRIx64"\n", getle64(header->flags)); - fprintf(stdout, " > Mediaunit size: 0x%x\n", (u32)mediaunitsize); - if (header->flags[7] & 4) - fprintf(stdout, " > Crypto key: None\n"); - else if (header->flags[7] & 1) - fprintf(stdout, " > Crypto key: %s\n", programid_is_system(header->programid)? "Fixed":"Zeros"); - else - fprintf(stdout, " > Crypto key: Secure (%d)%s\n", header->flags[3], header->flags[7] & 32? " (KeyY seeded)" : ""); - fprintf(stdout, " > Form type: %s\n", formtypetostring(header->flags[5])); - fprintf(stdout, " > Content type: %s\n", contenttypetostring(header->flags[5])); - fprintf(stdout, " > Content platform: %s\n", contentplatformtostring(header->flags[4])); - if (header->flags[7] & 2) - fprintf(stdout, " > No RomFS mount\n"); - - - fprintf(stdout, "Plain region offset: 0x%08"PRIx64"\n", getle32(header->plainregionsize)? offset+getle32(header->plainregionoffset)*mediaunitsize : 0); - fprintf(stdout, "Plain region size: 0x%08"PRIx64"\n", getle32(header->plainregionsize)*mediaunitsize); - fprintf(stdout, "Logo offset: 0x%08"PRIx64"\n", getle32(header->logosize)? offset+getle32(header->logooffset)*mediaunitsize : 0); - fprintf(stdout, "Logo size: 0x%08"PRIx64"\n", getle32(header->logosize)*mediaunitsize); - fprintf(stdout, "ExeFS offset: 0x%08"PRIx64"\n", getle32(header->exefssize)? offset+getle32(header->exefsoffset)*mediaunitsize : 0); - fprintf(stdout, "ExeFS size: 0x%08"PRIx64"\n", getle32(header->exefssize)*mediaunitsize); - fprintf(stdout, "ExeFS hash region size: 0x%08"PRIx64"\n", getle32(header->exefshashregionsize)*mediaunitsize); - fprintf(stdout, "RomFS offset: 0x%08"PRIx64"\n", getle32(header->romfssize)? offset+getle32(header->romfsoffset)*mediaunitsize : 0); - fprintf(stdout, "RomFS size: 0x%08"PRIx64"\n", getle32(header->romfssize)*mediaunitsize); - fprintf(stdout, "RomFS hash region size: 0x%08"PRIx64"\n", getle32(header->romfshashregionsize)*mediaunitsize); - if (ctx->exefshashcheck == Unchecked) - memdump(stdout, "ExeFS Hash: ", header->exefssuperblockhash, 0x20); - else if (ctx->exefshashcheck == Good) - memdump(stdout, "ExeFS Hash (GOOD): ", header->exefssuperblockhash, 0x20); - else - memdump(stdout, "ExeFS Hash (FAIL): ", header->exefssuperblockhash, 0x20); - if (ctx->romfshashcheck == Unchecked) - memdump(stdout, "RomFS Hash: ", header->romfssuperblockhash, 0x20); - else if (ctx->romfshashcheck == Good) - memdump(stdout, "RomFS Hash (GOOD): ", header->romfssuperblockhash, 0x20); - else - memdump(stdout, "RomFS Hash (FAIL): ", header->romfssuperblockhash, 0x20); -} diff --git a/ctrtool/ncch.h b/ctrtool/ncch.h deleted file mode 100644 index 94d2968..0000000 --- a/ctrtool/ncch.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef _NCCH_H_ -#define _NCCH_H_ - -#include -#include "types.h" -#include "keyset.h" -#include "filepath.h" -#include "ctr.h" -#include "exefs.h" -#include "romfs.h" -#include "exheader.h" -#include "settings.h" - -typedef enum -{ - NCCHTYPE_EXHEADER = 1, - NCCHTYPE_EXEFS = 2, - NCCHTYPE_ROMFS = 3, - NCCHTYPE_LOGO = 4, - NCCHTYPE_PLAINRGN = 5, -} ctr_ncchtypes; - -typedef enum -{ - NCCHCRYPTO_NONE = 0, //< already decrypted - NCCHCRYPTO_FIXED = 1, //< fixed key crypto, used for SDK-made application titles and very very old system titles - NCCHCRYPTO_SECURE = (1<<1), //< hardware generated key - NCCHCRYPTO_BROKEN = 0xFF //< Internal: failed to generate key, but encryption still used -} ctr_ncchcryptotype; - -typedef struct -{ - u8 signature[0x100]; - u8 magic[4]; - u8 contentsize[4]; - u8 titleid[8]; - u8 makercode[2]; - u8 version[2]; - u8 seedcheck[4]; - u8 programid[8]; - u8 reserved1[0x10]; - u8 logohash[0x20]; - u8 productcode[0x10]; - u8 extendedheaderhash[0x20]; - u8 extendedheadersize[4]; - u8 reserved2[4]; - u8 flags[8]; - u8 plainregionoffset[4]; - u8 plainregionsize[4]; - u8 logooffset[4]; - u8 logosize[4]; - u8 exefsoffset[4]; - u8 exefssize[4]; - u8 exefshashregionsize[4]; - u8 reserved4[4]; - u8 romfsoffset[4]; - u8 romfssize[4]; - u8 romfshashregionsize[4]; - u8 reserved5[4]; - u8 exefssuperblockhash[0x20]; - u8 romfssuperblockhash[0x20]; -} ctr_ncchheader; - - -typedef struct -{ - FILE* file; - u8 key[2][16]; - u8 seed[16]; - u32 encrypted; - u64 offset; - u64 size; - settings* usersettings; - ctr_ncchheader header; - ctr_aes_context aes; - exefs_context exefs; - romfs_context romfs; - exheader_context exheader; - int exefshashcheck; - int romfshashcheck; - int exheaderhashcheck; - int logohashcheck; - int headersigcheck; - u64 extractsize; - u32 extractflags; -} ncch_context; - -void ncch_init(ncch_context* ctx); -void ncch_process(ncch_context* ctx, u32 actions); -void ncch_set_offset(ncch_context* ctx, u64 offset); -void ncch_set_size(ncch_context* ctx, u64 size); -void ncch_set_file(ncch_context* ctx, FILE* file); -void ncch_set_usersettings(ncch_context* ctx, settings* usersettings); -u64 ncch_get_exefs_offset(ncch_context* ctx); -u64 ncch_get_exefs_size(ncch_context* ctx); -u64 ncch_get_romfs_offset(ncch_context* ctx); -u64 ncch_get_romfs_size(ncch_context* ctx); -u64 ncch_get_exheader_offset(ncch_context* ctx); -u64 ncch_get_exheader_size(ncch_context* ctx); -u64 ncch_get_logo_offset(ncch_context* ctx); -u64 ncch_get_logo_size(ncch_context* ctx); -u64 ncch_get_plainrgn_offset(ncch_context* ctx); -u64 ncch_get_plainrgn_size(ncch_context* ctx); -void ncch_print(ncch_context* ctx); -int ncch_signature_verify(ncch_context* ctx, rsakey2048* key); -void ncch_verify(ncch_context* ctx, u32 flags); -void ncch_save(ncch_context* ctx, u32 type, u32 flags); -int ncch_extract_prepare(ncch_context* ctx, u32 type, u32 flags); -int ncch_extract_buffer(ncch_context* ctx, u8* buffer, u32 buffersize, u32* outsize, u8 nocrypto); -u64 ncch_get_mediaunit_size(ncch_context* ctx); -void ncch_get_counter(ncch_context* ctx, u8 counter[16], u8 type); -void ncch_determine_key(ncch_context* ctx, u32 actions); -#endif // _NCCH_H_ diff --git a/ctrtool/ncsd.c b/ctrtool/ncsd.c deleted file mode 100644 index ab9fae8..0000000 --- a/ctrtool/ncsd.c +++ /dev/null @@ -1,165 +0,0 @@ -#include -#include - -#include "types.h" -#include "ncsd.h" -#include "utils.h" -#include "ctr.h" -#include - - -void ncsd_init(ncsd_context* ctx) -{ - memset(ctx, 0, sizeof(ncsd_context)); -} - -void ncsd_set_offset(ncsd_context* ctx, u64 offset) -{ - ctx->offset = offset; -} - -void ncsd_set_file(ncsd_context* ctx, FILE* file) -{ - ctx->file = file; -} - -void ncsd_set_size(ncsd_context* ctx, u64 size) -{ - ctx->size = size; -} - -void ncsd_set_ncch_index(ncsd_context* ctx, u32 ncch_index) -{ - ctx->ncch_index = ncch_index; -} - -void ncsd_set_usersettings(ncsd_context* ctx, settings* usersettings) -{ - ctx->usersettings = usersettings; -} - -int ncsd_signature_verify(const void* blob, rsakey2048* key) -{ - u8* message = (u8*)blob + 0x100; - u8* sig = (u8*)blob; - u8 hash[0x20]; - - ctr_sha_256(message, 0x100, hash); - return ctr_rsa_verify_hash(sig, hash, key); -} - -u64 ncsd_get_mediaunit_size(ncsd_context* ctx) -{ - unsigned int mediaunitsize = settings_get_mediaunit_size(ctx->usersettings); - - if (mediaunitsize == 0) - mediaunitsize = 1<<(9+ctx->header.flags[6]); - - return mediaunitsize; -} - -void ncsd_process(ncsd_context* ctx, u32 actions) -{ - fseeko64(ctx->file, ctx->offset, SEEK_SET); - fread(&ctx->header, 1, 0x200, ctx->file); - - if (getle32(ctx->header.magic) != MAGIC_NCSD) - { - fprintf(stdout, "Error, NCSD segment corrupted\n"); - return; - } - - - if (actions & VerifyFlag) - { - if (ctx->usersettings) - ctx->headersigcheck = ncsd_signature_verify(&ctx->header, &ctx->usersettings->keys.ncsdrsakey); - } - - if (actions & InfoFlag) - ncsd_print(ctx); - - if(ctx->ncch_index > 7 || ctx->header.partitiongeometry[ctx->ncch_index].size == 0) - { - fprintf(stderr," ERROR NCSD partition %d, does not exist\n",ctx->ncch_index); - return; - } - - ncch_set_file(&ctx->ncch, ctx->file); - ncch_set_offset(&ctx->ncch, ctx->header.partitiongeometry[ctx->ncch_index].offset * ncsd_get_mediaunit_size(ctx)); - ncch_set_size(&ctx->ncch, ctx->header.partitiongeometry[ctx->ncch_index].size * ncsd_get_mediaunit_size(ctx)); - ncch_set_usersettings(&ctx->ncch, ctx->usersettings); - ncch_process(&ctx->ncch, actions); -} - -const char* ncsd_print_mediatype(u8 type) -{ - switch(type) - { - case 0 : return "Internal Device"; - case 1 : return "Card1"; - case 2 : return "Card2"; - case 3 : return "Extended Device"; - default: return "Unknown"; - } -} - -const char* ncsd_print_carddevice(u8 type) -{ - switch(type) - { - case 1 : return "NorFlash"; - case 2 : return "None"; - case 3 : return "BT"; - default: return "Unknown"; - } -} - -void ncsd_print(ncsd_context* ctx) -{ - char magic[5]; - ctr_ncsdheader* header = &ctx->header; - unsigned int i; - unsigned int mediaunitsize = (unsigned int) ncsd_get_mediaunit_size(ctx); - - - memcpy(magic, header->magic, 4); - magic[4] = 0; - - fprintf(stdout, "Header: %s\n", magic); - if (ctx->headersigcheck == Unchecked) - memdump(stdout, "Signature: ", header->signature, 0x100); - else if (ctx->headersigcheck == Good) - memdump(stdout, "Signature (GOOD): ", header->signature, 0x100); - else - memdump(stdout, "Signature (FAIL): ", header->signature, 0x100); - fprintf(stdout, "Media size: 0x%08x\n", getle32(header->mediasize)); - fprintf(stdout, "Media id: %016"PRIx64"\n", getle64(header->mediaid)); - //memdump(stdout, "Partition FS type: ", header->partitionfstype, 8); - //memdump(stdout, "Partition crypt type: ", header->partitioncrypttype, 8); - //memdump(stdout, "Partition offset/size: ", header->partitionoffsetandsize, 0x40); - fprintf(stdout, "\n"); - for(i=0; i<8; i++) - { - u32 partitionoffset = header->partitiongeometry[i].offset * mediaunitsize; - u32 partitionsize = header->partitiongeometry[i].size * mediaunitsize; - - if (partitionsize != 0) - { - fprintf(stdout, "Partition %d \n", i); - memdump(stdout, " Id: ", header->titleid+i*8, 8); - fprintf(stdout, " Area: 0x%08X-0x%08X\n", partitionoffset, partitionoffset+partitionsize); - fprintf(stdout, " Filesystem: %02X\n", header->partitionfstype[i]); - fprintf(stdout, " Encryption: %02X\n", header->partitioncrypttype[i]); - fprintf(stdout, "\n"); - } - } - memdump(stdout, "Extended header hash: ", header->extendedheaderhash, 0x20); - memdump(stdout, "Additional header size: ", header->additionalheadersize, 4); - memdump(stdout, "Sector zero offset: ", header->sectorzerooffset, 4); - memdump(stdout, "Flags: ", header->flags, 8); - fprintf(stdout, " > Mediaunit size: 0x%X\n", mediaunitsize); - fprintf(stdout, " > Mediatype: %s\n", ncsd_print_mediatype(header->flags[5])); - fprintf(stdout, " > Card Device: %s\n", ncsd_print_carddevice(header->flags[3] | header->flags[7])); - -} diff --git a/ctrtool/ncsd.h b/ctrtool/ncsd.h deleted file mode 100644 index 2d6ee53..0000000 --- a/ctrtool/ncsd.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef _NCSD_H_ -#define _NCSD_H_ - -#include "types.h" -#include "keyset.h" -#include "settings.h" -#include "ncch.h" - -typedef struct -{ - u32 offset; - u32 size; -} ncsd_partition_geometry; - -typedef struct -{ - u8 signature[0x100]; - u8 magic[4]; - u8 mediasize[4]; - u8 mediaid[8]; - u8 partitionfstype[8]; - u8 partitioncrypttype[8]; - ncsd_partition_geometry partitiongeometry[8]; - u8 extendedheaderhash[0x20]; - u8 additionalheadersize[4]; - u8 sectorzerooffset[4]; - u8 flags[8]; - u8 titleid[0x40]; - u8 reserved[0x30]; -} ctr_ncsdheader; - - -typedef struct -{ - FILE* file; - u64 offset; - u64 size; - u32 ncch_index; - ctr_ncsdheader header; - settings* usersettings; - int headersigcheck; - ncch_context ncch; -} ncsd_context; - - -void ncsd_init(ncsd_context* ctx); -void ncsd_set_offset(ncsd_context* ctx, u64 offset); -void ncsd_set_size(ncsd_context* ctx, u64 size); -void ncsd_set_ncch_index(ncsd_context* ctx, u32 ncch_index); -void ncsd_set_file(ncsd_context* ctx, FILE* file); -void ncsd_set_usersettings(ncsd_context* ctx, settings* usersettings); -int ncsd_signature_verify(const void* blob, rsakey2048* key); -void ncsd_process(ncsd_context* ctx, u32 actions); -void ncsd_print(ncsd_context* ctx); -u64 ncsd_get_mediaunit_size(ncsd_context* ctx); - -#endif // _NCSD_H_ diff --git a/ctrtool/oschar.c b/ctrtool/oschar.c deleted file mode 100644 index ac8ddcc..0000000 --- a/ctrtool/oschar.c +++ /dev/null @@ -1,210 +0,0 @@ -#include -#ifndef _WIN32 -#ifndef __CYGWIN__ -#define LIBICONV_PLUG -#endif -#include -#endif -#include "oschar.h" - -int os_fstat(const oschar_t *path) -{ - struct _osstat st; - return os_stat(path, &st); -} - -uint64_t os_fsize(const oschar_t *path) -{ - struct _osstat st; - if (os_stat(path, &st) != 0) - return 0; - else - return st.st_size; -} - -int os_makedir(const oschar_t *dir) -{ -#ifdef _WIN32 - return _wmkdir(dir); -#else - return mkdir(dir, 0777); -#endif -} - -uint32_t utf16_strlen(const utf16char_t *str) -{ - uint32_t i; - for (i = 0; str[i] != 0x0; i++); - return i; -} - -void utf16_fputs(const utf16char_t *str, FILE *out) -{ - oschar_t *_str = os_CopyConvertUTF16Str(str); - os_fputs(_str, out); - free(_str); -} - -char* strcopy_8to8(const char *src) -{ - uint32_t src_len; - char *dst; - - if (!src) - return NULL; - - src_len = strlen(src); - - // Allocate memory for expanded string - dst = calloc(src_len + 1, sizeof(char)); - if (!dst) - return NULL; - - // Copy elements from src into dst - strncpy(dst, src, src_len); - - return dst; -} - -utf16char_t* strcopy_8to16(const char *src) -{ - uint32_t src_len, i; - utf16char_t *dst; - - if (!src) - return NULL; - - src_len = strlen(src); - - // Allocate memory for expanded string - dst = calloc(src_len + 1, sizeof(utf16char_t)); - if (!dst) - return NULL; - - // Copy elements from src into dst - for (i = 0; i < src_len; i++) - dst[i] = src[i]; - - return dst; -} - - -utf16char_t* strcopy_16to16(const utf16char_t *src) -{ - uint32_t src_len, i; - utf16char_t *dst; - - if (!src) - return NULL; - - src_len = utf16_strlen(src); - - // Allocate memory for expanded string - dst = calloc(src_len + 1, sizeof(utf16char_t)); - if (!dst) - return NULL; - - // Copy elements from src into dst - for (i = 0; i < src_len; i++) - dst[i] = src[i]; - - return dst; -} - -#ifndef _WIN32 -utf16char_t* strcopy_UTF8toUTF16(const char *src) -{ - uint32_t src_len, dst_len; - size_t in_bytes, out_bytes; - utf16char_t *dst; - char *in, *out; - - if (!src) - return NULL; - - src_len = strlen(src); - dst_len = src_len + 1; - - // Allocate memory for string - dst = calloc(dst_len, sizeof(utf16char_t)); - if (!dst) - return NULL; - - in = (char*)src; - out = (char*)dst; - in_bytes = src_len*sizeof(char); - out_bytes = dst_len*sizeof(utf16char_t); - - iconv_t cd = iconv_open("UTF-16LE", "UTF-8"); - iconv(cd, &in, &in_bytes, &out, &out_bytes); - iconv_close(cd); - return dst; -} - -char* strcopy_UTF16toUTF8(const utf16char_t *src) -{ - uint32_t src_len, dst_len; - size_t in_bytes, out_bytes; - char *dst; - char *in, *out; - - if (!src) - return NULL; - - src_len = utf16_strlen(src); - // UTF-8 can use up to 3 bytes per UTF-16 code unit, or four for a surrogate pair - dst_len = src_len * 3; - - // Allocate memory for string - dst = calloc(dst_len, sizeof(char)); - if (!dst) - return NULL; - - in = (char*)src; - out = (char*)dst; - in_bytes = src_len*sizeof(uint16_t); - out_bytes = dst_len*sizeof(char); - - iconv_t cd = iconv_open("UTF-8", "UTF-16LE"); - iconv(cd, &in, &in_bytes, &out, &out_bytes); - iconv_close(cd); - return dst; -} -#endif - -oschar_t* os_AppendToPath(const oschar_t *src, const oschar_t *add) -{ - uint32_t len; - oschar_t *new_path; - - len = os_strlen(src) + os_strlen(add) + 0x10; - new_path = calloc(len, sizeof(oschar_t)); - -#ifdef _WIN32 - _snwprintf(new_path, len, L"%s%c%s", src, OS_PATH_SEPARATOR, add); -#else - snprintf(new_path, len, "%s%c%s", src, OS_PATH_SEPARATOR, add); -#endif - - return new_path; -} - -oschar_t* os_AppendUTF16StrToPath(const oschar_t *src, const utf16char_t *add) -{ - uint32_t len; - oschar_t *new_path, *_add; - - _add = os_CopyConvertUTF16Str(add); - - len = os_strlen(src) + os_strlen(_add) + 0x10; - new_path = calloc(len, sizeof(oschar_t)); - -#ifdef _WIN32 - _snwprintf(new_path, len, L"%s%c%s", src, OS_PATH_SEPARATOR, _add); -#else - snprintf(new_path, len, "%s%c%s", src, OS_PATH_SEPARATOR, _add); -#endif - - free(_add); - return new_path; -} diff --git a/ctrtool/oschar.h b/ctrtool/oschar.h deleted file mode 100644 index 9c788b0..0000000 --- a/ctrtool/oschar.h +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once -#include -#include -#include -#include -#ifdef _WIN32 -#include -#endif - -// Nintendo uses UTF16-LE chars for extended ASCII support -typedef uint16_t utf16char_t; - -// Native OS char type for unicode support -#ifdef _WIN32 -typedef wchar_t oschar_t; // UTF16-LE -#else -typedef char oschar_t; // UTF8 -#endif - -// Simple redirect macros for functions and types -#ifdef _WIN32 -#define os_strlen wcslen -#define os_strcmp wcscmp -#define os_fputs fputws - -#define os_CopyStr strcopy_16to16 -#define os_CopyConvertCharStr strcopy_8to16 -#define os_CopyConvertUTF16Str strcopy_16to16 -#define utf16_CopyStr strcopy_16to16 -#define utf16_CopyConvertOsStr strcopy_16to16 - -#define _osdirent _wdirent -#define _OSDIR _WDIR -#define os_readdir _wreaddir -#define os_opendir _wopendir -#define os_closedir _wclosedir -#define os_chdir _wchdir - -#define _osstat _stat64 -#define os_stat _wstat64 - -#define os_fopen _wfopen -#define OS_MODE_READ L"rb" -#define OS_MODE_WRITE L"wb" -#define OS_MODE_EDIT L"rb+" -#define OS_PATH_SEPARATOR '\\' -#else -#define os_strlen strlen -#define os_strcmp strcmp -#define os_fputs fputs - -#define os_CopyStr strcopy_8to8 -#define os_CopyConvertUTF16Str strcopy_UTF16toUTF8 -#define os_CopyConvertCharStr strcopy_8to8 -#define utf16_CopyStr strcopy_16to16 -#define utf16_CopyConvertOsStr strcopy_UTF8toUTF16 - -#define _osdirent dirent -#define _OSDIR DIR -#define os_readdir readdir -#define os_opendir opendir -#define os_closedir closedir -#define os_chdir chdir - -#define _osstat stat -#define os_stat stat - -#define os_fopen fopen -#define OS_MODE_READ "rb" -#define OS_MODE_WRITE "wb" -#define OS_MODE_EDIT "rb+" -#define OS_PATH_SEPARATOR '/' -#endif - -/* File related */ -int os_fstat(const oschar_t* path); -uint64_t os_fsize(const oschar_t* path); -int os_makedir(const oschar_t *dir); - -/* UTF16 String property functions */ -uint32_t utf16_strlen(const utf16char_t* str); -void utf16_fputs(const utf16char_t *str, FILE *out); - -/* String Copy and Conversion */ -char* strcopy_8to8(const char *src); -utf16char_t* strcopy_8to16(const char *src); -utf16char_t* strcopy_16to16(const utf16char_t *src); -#ifndef _WIN32 -utf16char_t* strcopy_UTF8toUTF16(const char *src); -char* strcopy_UTF16toUTF8(const utf16char_t *src); -#endif - -/* String Append and Create */ -oschar_t* os_AppendToPath(const oschar_t *src, const oschar_t *add); -oschar_t* os_AppendUTF16StrToPath(const oschar_t *src, const utf16char_t *add); \ No newline at end of file diff --git a/ctrtool/polarssl/aes.c b/ctrtool/polarssl/aes.c deleted file mode 100644 index 45f74a6..0000000 --- a/ctrtool/polarssl/aes.c +++ /dev/null @@ -1,1164 +0,0 @@ -/* - * FIPS-197 compliant AES implementation - * - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. - * - * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf - * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf - */ - -#include "polarssl/config.h" - -#if defined(POLARSSL_AES_C) - -#include "polarssl/aes.h" -#include "polarssl/padlock.h" - -#include - -/* - * 32-bit integer manipulation macros (little endian) - */ -#ifndef GET_ULONG_LE -#define GET_ULONG_LE(n,b,i) \ -{ \ - (n) = ( (unsigned long) (b)[(i) ] ) \ - | ( (unsigned long) (b)[(i) + 1] << 8 ) \ - | ( (unsigned long) (b)[(i) + 2] << 16 ) \ - | ( (unsigned long) (b)[(i) + 3] << 24 ); \ -} -#endif - -#ifndef PUT_ULONG_LE -#define PUT_ULONG_LE(n,b,i) \ -{ \ - (b)[(i) ] = (unsigned char) ( (n) ); \ - (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ - (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ - (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ -} -#endif - -#if defined(POLARSSL_AES_ROM_TABLES) -/* - * Forward S-box - */ -static const unsigned char FSb[256] = -{ - 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, - 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, - 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, - 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, - 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, - 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, - 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, - 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, - 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, - 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, - 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, - 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, - 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, - 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, - 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, - 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, - 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, - 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, - 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, - 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, - 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, - 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, - 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, - 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, - 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, - 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, - 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, - 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, - 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, - 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, - 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, - 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 -}; - -/* - * Forward tables - */ -#define FT \ -\ - V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \ - V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \ - V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \ - V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \ - V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \ - V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \ - V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \ - V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \ - V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \ - V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \ - V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \ - V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \ - V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \ - V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \ - V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \ - V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \ - V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \ - V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \ - V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \ - V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \ - V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \ - V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \ - V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \ - V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \ - V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \ - V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \ - V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \ - V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \ - V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \ - V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \ - V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \ - V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \ - V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \ - V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \ - V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \ - V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \ - V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \ - V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \ - V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \ - V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \ - V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \ - V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \ - V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \ - V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \ - V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \ - V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \ - V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \ - V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \ - V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \ - V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \ - V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \ - V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \ - V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \ - V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \ - V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \ - V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \ - V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \ - V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \ - V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \ - V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \ - V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \ - V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \ - V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \ - V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C) - -#define V(a,b,c,d) 0x##a##b##c##d -static const unsigned long FT0[256] = { FT }; -#undef V - -#define V(a,b,c,d) 0x##b##c##d##a -static const unsigned long FT1[256] = { FT }; -#undef V - -#define V(a,b,c,d) 0x##c##d##a##b -static const unsigned long FT2[256] = { FT }; -#undef V - -#define V(a,b,c,d) 0x##d##a##b##c -static const unsigned long FT3[256] = { FT }; -#undef V - -#undef FT - -/* - * Reverse S-box - */ -static const unsigned char RSb[256] = -{ - 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, - 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, - 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, - 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, - 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, - 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, - 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, - 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, - 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, - 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, - 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, - 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, - 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, - 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, - 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, - 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, - 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, - 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, - 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, - 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, - 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, - 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, - 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, - 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, - 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, - 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, - 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, - 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, - 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, - 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, - 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D -}; - -/* - * Reverse tables - */ -#define RT \ -\ - V(50,A7,F4,51), V(53,65,41,7E), V(C3,A4,17,1A), V(96,5E,27,3A), \ - V(CB,6B,AB,3B), V(F1,45,9D,1F), V(AB,58,FA,AC), V(93,03,E3,4B), \ - V(55,FA,30,20), V(F6,6D,76,AD), V(91,76,CC,88), V(25,4C,02,F5), \ - V(FC,D7,E5,4F), V(D7,CB,2A,C5), V(80,44,35,26), V(8F,A3,62,B5), \ - V(49,5A,B1,DE), V(67,1B,BA,25), V(98,0E,EA,45), V(E1,C0,FE,5D), \ - V(02,75,2F,C3), V(12,F0,4C,81), V(A3,97,46,8D), V(C6,F9,D3,6B), \ - V(E7,5F,8F,03), V(95,9C,92,15), V(EB,7A,6D,BF), V(DA,59,52,95), \ - V(2D,83,BE,D4), V(D3,21,74,58), V(29,69,E0,49), V(44,C8,C9,8E), \ - V(6A,89,C2,75), V(78,79,8E,F4), V(6B,3E,58,99), V(DD,71,B9,27), \ - V(B6,4F,E1,BE), V(17,AD,88,F0), V(66,AC,20,C9), V(B4,3A,CE,7D), \ - V(18,4A,DF,63), V(82,31,1A,E5), V(60,33,51,97), V(45,7F,53,62), \ - V(E0,77,64,B1), V(84,AE,6B,BB), V(1C,A0,81,FE), V(94,2B,08,F9), \ - V(58,68,48,70), V(19,FD,45,8F), V(87,6C,DE,94), V(B7,F8,7B,52), \ - V(23,D3,73,AB), V(E2,02,4B,72), V(57,8F,1F,E3), V(2A,AB,55,66), \ - V(07,28,EB,B2), V(03,C2,B5,2F), V(9A,7B,C5,86), V(A5,08,37,D3), \ - V(F2,87,28,30), V(B2,A5,BF,23), V(BA,6A,03,02), V(5C,82,16,ED), \ - V(2B,1C,CF,8A), V(92,B4,79,A7), V(F0,F2,07,F3), V(A1,E2,69,4E), \ - V(CD,F4,DA,65), V(D5,BE,05,06), V(1F,62,34,D1), V(8A,FE,A6,C4), \ - V(9D,53,2E,34), V(A0,55,F3,A2), V(32,E1,8A,05), V(75,EB,F6,A4), \ - V(39,EC,83,0B), V(AA,EF,60,40), V(06,9F,71,5E), V(51,10,6E,BD), \ - V(F9,8A,21,3E), V(3D,06,DD,96), V(AE,05,3E,DD), V(46,BD,E6,4D), \ - V(B5,8D,54,91), V(05,5D,C4,71), V(6F,D4,06,04), V(FF,15,50,60), \ - V(24,FB,98,19), V(97,E9,BD,D6), V(CC,43,40,89), V(77,9E,D9,67), \ - V(BD,42,E8,B0), V(88,8B,89,07), V(38,5B,19,E7), V(DB,EE,C8,79), \ - V(47,0A,7C,A1), V(E9,0F,42,7C), V(C9,1E,84,F8), V(00,00,00,00), \ - V(83,86,80,09), V(48,ED,2B,32), V(AC,70,11,1E), V(4E,72,5A,6C), \ - V(FB,FF,0E,FD), V(56,38,85,0F), V(1E,D5,AE,3D), V(27,39,2D,36), \ - V(64,D9,0F,0A), V(21,A6,5C,68), V(D1,54,5B,9B), V(3A,2E,36,24), \ - V(B1,67,0A,0C), V(0F,E7,57,93), V(D2,96,EE,B4), V(9E,91,9B,1B), \ - V(4F,C5,C0,80), V(A2,20,DC,61), V(69,4B,77,5A), V(16,1A,12,1C), \ - V(0A,BA,93,E2), V(E5,2A,A0,C0), V(43,E0,22,3C), V(1D,17,1B,12), \ - V(0B,0D,09,0E), V(AD,C7,8B,F2), V(B9,A8,B6,2D), V(C8,A9,1E,14), \ - V(85,19,F1,57), V(4C,07,75,AF), V(BB,DD,99,EE), V(FD,60,7F,A3), \ - V(9F,26,01,F7), V(BC,F5,72,5C), V(C5,3B,66,44), V(34,7E,FB,5B), \ - V(76,29,43,8B), V(DC,C6,23,CB), V(68,FC,ED,B6), V(63,F1,E4,B8), \ - V(CA,DC,31,D7), V(10,85,63,42), V(40,22,97,13), V(20,11,C6,84), \ - V(7D,24,4A,85), V(F8,3D,BB,D2), V(11,32,F9,AE), V(6D,A1,29,C7), \ - V(4B,2F,9E,1D), V(F3,30,B2,DC), V(EC,52,86,0D), V(D0,E3,C1,77), \ - V(6C,16,B3,2B), V(99,B9,70,A9), V(FA,48,94,11), V(22,64,E9,47), \ - V(C4,8C,FC,A8), V(1A,3F,F0,A0), V(D8,2C,7D,56), V(EF,90,33,22), \ - V(C7,4E,49,87), V(C1,D1,38,D9), V(FE,A2,CA,8C), V(36,0B,D4,98), \ - V(CF,81,F5,A6), V(28,DE,7A,A5), V(26,8E,B7,DA), V(A4,BF,AD,3F), \ - V(E4,9D,3A,2C), V(0D,92,78,50), V(9B,CC,5F,6A), V(62,46,7E,54), \ - V(C2,13,8D,F6), V(E8,B8,D8,90), V(5E,F7,39,2E), V(F5,AF,C3,82), \ - V(BE,80,5D,9F), V(7C,93,D0,69), V(A9,2D,D5,6F), V(B3,12,25,CF), \ - V(3B,99,AC,C8), V(A7,7D,18,10), V(6E,63,9C,E8), V(7B,BB,3B,DB), \ - V(09,78,26,CD), V(F4,18,59,6E), V(01,B7,9A,EC), V(A8,9A,4F,83), \ - V(65,6E,95,E6), V(7E,E6,FF,AA), V(08,CF,BC,21), V(E6,E8,15,EF), \ - V(D9,9B,E7,BA), V(CE,36,6F,4A), V(D4,09,9F,EA), V(D6,7C,B0,29), \ - V(AF,B2,A4,31), V(31,23,3F,2A), V(30,94,A5,C6), V(C0,66,A2,35), \ - V(37,BC,4E,74), V(A6,CA,82,FC), V(B0,D0,90,E0), V(15,D8,A7,33), \ - V(4A,98,04,F1), V(F7,DA,EC,41), V(0E,50,CD,7F), V(2F,F6,91,17), \ - V(8D,D6,4D,76), V(4D,B0,EF,43), V(54,4D,AA,CC), V(DF,04,96,E4), \ - V(E3,B5,D1,9E), V(1B,88,6A,4C), V(B8,1F,2C,C1), V(7F,51,65,46), \ - V(04,EA,5E,9D), V(5D,35,8C,01), V(73,74,87,FA), V(2E,41,0B,FB), \ - V(5A,1D,67,B3), V(52,D2,DB,92), V(33,56,10,E9), V(13,47,D6,6D), \ - V(8C,61,D7,9A), V(7A,0C,A1,37), V(8E,14,F8,59), V(89,3C,13,EB), \ - V(EE,27,A9,CE), V(35,C9,61,B7), V(ED,E5,1C,E1), V(3C,B1,47,7A), \ - V(59,DF,D2,9C), V(3F,73,F2,55), V(79,CE,14,18), V(BF,37,C7,73), \ - V(EA,CD,F7,53), V(5B,AA,FD,5F), V(14,6F,3D,DF), V(86,DB,44,78), \ - V(81,F3,AF,CA), V(3E,C4,68,B9), V(2C,34,24,38), V(5F,40,A3,C2), \ - V(72,C3,1D,16), V(0C,25,E2,BC), V(8B,49,3C,28), V(41,95,0D,FF), \ - V(71,01,A8,39), V(DE,B3,0C,08), V(9C,E4,B4,D8), V(90,C1,56,64), \ - V(61,84,CB,7B), V(70,B6,32,D5), V(74,5C,6C,48), V(42,57,B8,D0) - -#define V(a,b,c,d) 0x##a##b##c##d -static const unsigned long RT0[256] = { RT }; -#undef V - -#define V(a,b,c,d) 0x##b##c##d##a -static const unsigned long RT1[256] = { RT }; -#undef V - -#define V(a,b,c,d) 0x##c##d##a##b -static const unsigned long RT2[256] = { RT }; -#undef V - -#define V(a,b,c,d) 0x##d##a##b##c -static const unsigned long RT3[256] = { RT }; -#undef V - -#undef RT - -/* - * Round constants - */ -static const unsigned long RCON[10] = -{ - 0x00000001, 0x00000002, 0x00000004, 0x00000008, - 0x00000010, 0x00000020, 0x00000040, 0x00000080, - 0x0000001B, 0x00000036 -}; - -#else - -/* - * Forward S-box & tables - */ -static unsigned char FSb[256]; -static unsigned long FT0[256]; -static unsigned long FT1[256]; -static unsigned long FT2[256]; -static unsigned long FT3[256]; - -/* - * Reverse S-box & tables - */ -static unsigned char RSb[256]; -static unsigned long RT0[256]; -static unsigned long RT1[256]; -static unsigned long RT2[256]; -static unsigned long RT3[256]; - -/* - * Round constants - */ -static unsigned long RCON[10]; - -/* - * Tables generation code - */ -#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 ) -#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) -#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 ) - -static int aes_init_done = 0; - -static void aes_gen_tables( void ) -{ - int i, x, y, z; - int pow[256]; - int log[256]; - - /* - * compute pow and log tables over GF(2^8) - */ - for( i = 0, x = 1; i < 256; i++ ) - { - pow[i] = x; - log[x] = i; - x = ( x ^ XTIME( x ) ) & 0xFF; - } - - /* - * calculate the round constants - */ - for( i = 0, x = 1; i < 10; i++ ) - { - RCON[i] = (unsigned long) x; - x = XTIME( x ) & 0xFF; - } - - /* - * generate the forward and reverse S-boxes - */ - FSb[0x00] = 0x63; - RSb[0x63] = 0x00; - - for( i = 1; i < 256; i++ ) - { - x = pow[255 - log[i]]; - - y = x; y = ( (y << 1) | (y >> 7) ) & 0xFF; - x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; - x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; - x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; - x ^= y ^ 0x63; - - FSb[i] = (unsigned char) x; - RSb[x] = (unsigned char) i; - } - - /* - * generate the forward and reverse tables - */ - for( i = 0; i < 256; i++ ) - { - x = FSb[i]; - y = XTIME( x ) & 0xFF; - z = ( y ^ x ) & 0xFF; - - FT0[i] = ( (unsigned long) y ) ^ - ( (unsigned long) x << 8 ) ^ - ( (unsigned long) x << 16 ) ^ - ( (unsigned long) z << 24 ); - - FT1[i] = ROTL8( FT0[i] ); - FT2[i] = ROTL8( FT1[i] ); - FT3[i] = ROTL8( FT2[i] ); - - x = RSb[i]; - - RT0[i] = ( (unsigned long) MUL( 0x0E, x ) ) ^ - ( (unsigned long) MUL( 0x09, x ) << 8 ) ^ - ( (unsigned long) MUL( 0x0D, x ) << 16 ) ^ - ( (unsigned long) MUL( 0x0B, x ) << 24 ); - - RT1[i] = ROTL8( RT0[i] ); - RT2[i] = ROTL8( RT1[i] ); - RT3[i] = ROTL8( RT2[i] ); - } -} - -#endif - -/* - * AES key schedule (encryption) - */ -int aes_setkey_enc( aes_context *ctx, const unsigned char *key, int keysize ) -{ - int i; - unsigned long *RK; - -#if !defined(POLARSSL_AES_ROM_TABLES) - if( aes_init_done == 0 ) - { - aes_gen_tables(); - aes_init_done = 1; - } -#endif - - switch( keysize ) - { - case 128: ctx->nr = 10; break; - case 192: ctx->nr = 12; break; - case 256: ctx->nr = 14; break; - default : return( POLARSSL_ERR_AES_INVALID_KEY_LENGTH ); - } - -#if defined(PADLOCK_ALIGN16) - ctx->rk = RK = PADLOCK_ALIGN16( ctx->buf ); -#else - ctx->rk = RK = ctx->buf; -#endif - - for( i = 0; i < (keysize >> 5); i++ ) - { - GET_ULONG_LE( RK[i], key, i << 2 ); - } - - switch( ctx->nr ) - { - case 10: - - for( i = 0; i < 10; i++, RK += 4 ) - { - RK[4] = RK[0] ^ RCON[i] ^ - ( (unsigned long) FSb[ ( RK[3] >> 8 ) & 0xFF ] ) ^ - ( (unsigned long) FSb[ ( RK[3] >> 16 ) & 0xFF ] << 8 ) ^ - ( (unsigned long) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^ - ( (unsigned long) FSb[ ( RK[3] ) & 0xFF ] << 24 ); - - RK[5] = RK[1] ^ RK[4]; - RK[6] = RK[2] ^ RK[5]; - RK[7] = RK[3] ^ RK[6]; - } - break; - - case 12: - - for( i = 0; i < 8; i++, RK += 6 ) - { - RK[6] = RK[0] ^ RCON[i] ^ - ( (unsigned long) FSb[ ( RK[5] >> 8 ) & 0xFF ] ) ^ - ( (unsigned long) FSb[ ( RK[5] >> 16 ) & 0xFF ] << 8 ) ^ - ( (unsigned long) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^ - ( (unsigned long) FSb[ ( RK[5] ) & 0xFF ] << 24 ); - - RK[7] = RK[1] ^ RK[6]; - RK[8] = RK[2] ^ RK[7]; - RK[9] = RK[3] ^ RK[8]; - RK[10] = RK[4] ^ RK[9]; - RK[11] = RK[5] ^ RK[10]; - } - break; - - case 14: - - for( i = 0; i < 7; i++, RK += 8 ) - { - RK[8] = RK[0] ^ RCON[i] ^ - ( (unsigned long) FSb[ ( RK[7] >> 8 ) & 0xFF ] ) ^ - ( (unsigned long) FSb[ ( RK[7] >> 16 ) & 0xFF ] << 8 ) ^ - ( (unsigned long) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^ - ( (unsigned long) FSb[ ( RK[7] ) & 0xFF ] << 24 ); - - RK[9] = RK[1] ^ RK[8]; - RK[10] = RK[2] ^ RK[9]; - RK[11] = RK[3] ^ RK[10]; - - RK[12] = RK[4] ^ - ( (unsigned long) FSb[ ( RK[11] ) & 0xFF ] ) ^ - ( (unsigned long) FSb[ ( RK[11] >> 8 ) & 0xFF ] << 8 ) ^ - ( (unsigned long) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^ - ( (unsigned long) FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 ); - - RK[13] = RK[5] ^ RK[12]; - RK[14] = RK[6] ^ RK[13]; - RK[15] = RK[7] ^ RK[14]; - } - break; - - default: - - break; - } - - return( 0 ); -} - -/* - * AES key schedule (decryption) - */ -int aes_setkey_dec( aes_context *ctx, const unsigned char *key, int keysize ) -{ - int i, j; - aes_context cty; - unsigned long *RK; - unsigned long *SK; - int ret; - - switch( keysize ) - { - case 128: ctx->nr = 10; break; - case 192: ctx->nr = 12; break; - case 256: ctx->nr = 14; break; - default : return( POLARSSL_ERR_AES_INVALID_KEY_LENGTH ); - } - -#if defined(PADLOCK_ALIGN16) - ctx->rk = RK = PADLOCK_ALIGN16( ctx->buf ); -#else - ctx->rk = RK = ctx->buf; -#endif - - ret = aes_setkey_enc( &cty, key, keysize ); - if( ret != 0 ) - return( ret ); - - SK = cty.rk + cty.nr * 4; - - *RK++ = *SK++; - *RK++ = *SK++; - *RK++ = *SK++; - *RK++ = *SK++; - - for( i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8 ) - { - for( j = 0; j < 4; j++, SK++ ) - { - *RK++ = RT0[ FSb[ ( *SK ) & 0xFF ] ] ^ - RT1[ FSb[ ( *SK >> 8 ) & 0xFF ] ] ^ - RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^ - RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ]; - } - } - - *RK++ = *SK++; - *RK++ = *SK++; - *RK++ = *SK++; - *RK++ = *SK++; - - memset( &cty, 0, sizeof( aes_context ) ); - - return( 0 ); -} - -#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ -{ \ - X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \ - FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y3 >> 24 ) & 0xFF ]; \ - \ - X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \ - FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y0 >> 24 ) & 0xFF ]; \ - \ - X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \ - FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y1 >> 24 ) & 0xFF ]; \ - \ - X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \ - FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y2 >> 24 ) & 0xFF ]; \ -} - -#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ -{ \ - X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \ - RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y1 >> 24 ) & 0xFF ]; \ - \ - X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \ - RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y2 >> 24 ) & 0xFF ]; \ - \ - X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \ - RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y3 >> 24 ) & 0xFF ]; \ - \ - X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \ - RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y0 >> 24 ) & 0xFF ]; \ -} - -/* - * AES-ECB block encryption/decryption - */ -int aes_crypt_ecb( aes_context *ctx, - int mode, - const unsigned char input[16], - unsigned char output[16] ) -{ - int i; - unsigned long *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; - -#if defined(POLARSSL_PADLOCK_C) && defined(POLARSSL_HAVE_X86) - if( padlock_supports( PADLOCK_ACE ) ) - { - if( padlock_xcryptecb( ctx, mode, input, output ) == 0 ) - return( 0 ); - - // If padlock data misaligned, we just fall back to - // unaccelerated mode - // - } -#endif - - RK = ctx->rk; - - GET_ULONG_LE( X0, input, 0 ); X0 ^= *RK++; - GET_ULONG_LE( X1, input, 4 ); X1 ^= *RK++; - GET_ULONG_LE( X2, input, 8 ); X2 ^= *RK++; - GET_ULONG_LE( X3, input, 12 ); X3 ^= *RK++; - - if( mode == AES_DECRYPT ) - { - for( i = (ctx->nr >> 1) - 1; i > 0; i-- ) - { - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); - } - - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); - - X0 = *RK++ ^ \ - ( (unsigned long) RSb[ ( Y0 ) & 0xFF ] ) ^ - ( (unsigned long) RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ - ( (unsigned long) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ - ( (unsigned long) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); - - X1 = *RK++ ^ \ - ( (unsigned long) RSb[ ( Y1 ) & 0xFF ] ) ^ - ( (unsigned long) RSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ - ( (unsigned long) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ - ( (unsigned long) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); - - X2 = *RK++ ^ \ - ( (unsigned long) RSb[ ( Y2 ) & 0xFF ] ) ^ - ( (unsigned long) RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ - ( (unsigned long) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ - ( (unsigned long) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); - - X3 = *RK++ ^ \ - ( (unsigned long) RSb[ ( Y3 ) & 0xFF ] ) ^ - ( (unsigned long) RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ - ( (unsigned long) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ - ( (unsigned long) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); - } - else /* AES_ENCRYPT */ - { - for( i = (ctx->nr >> 1) - 1; i > 0; i-- ) - { - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); - } - - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); - - X0 = *RK++ ^ \ - ( (unsigned long) FSb[ ( Y0 ) & 0xFF ] ) ^ - ( (unsigned long) FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ - ( (unsigned long) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ - ( (unsigned long) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); - - X1 = *RK++ ^ \ - ( (unsigned long) FSb[ ( Y1 ) & 0xFF ] ) ^ - ( (unsigned long) FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ - ( (unsigned long) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ - ( (unsigned long) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); - - X2 = *RK++ ^ \ - ( (unsigned long) FSb[ ( Y2 ) & 0xFF ] ) ^ - ( (unsigned long) FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ - ( (unsigned long) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ - ( (unsigned long) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); - - X3 = *RK++ ^ \ - ( (unsigned long) FSb[ ( Y3 ) & 0xFF ] ) ^ - ( (unsigned long) FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ - ( (unsigned long) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ - ( (unsigned long) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); - } - - PUT_ULONG_LE( X0, output, 0 ); - PUT_ULONG_LE( X1, output, 4 ); - PUT_ULONG_LE( X2, output, 8 ); - PUT_ULONG_LE( X3, output, 12 ); - - return( 0 ); -} - -/* - * AES-CBC buffer encryption/decryption - */ -int aes_crypt_cbc( aes_context *ctx, - int mode, - int length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) -{ - int i; - unsigned char temp[16]; - - if( length % 16 ) - return( POLARSSL_ERR_AES_INVALID_INPUT_LENGTH ); - -#if defined(POLARSSL_PADLOCK_C) && defined(POLARSSL_HAVE_X86) - if( padlock_supports( PADLOCK_ACE ) ) - { - if( padlock_xcryptcbc( ctx, mode, length, iv, input, output ) == 0 ) - return( 0 ); - - // If padlock data misaligned, we just fall back to - // unaccelerated mode - // - } -#endif - - if( mode == AES_DECRYPT ) - { - while( length > 0 ) - { - memcpy( temp, input, 16 ); - aes_crypt_ecb( ctx, mode, input, output ); - - for( i = 0; i < 16; i++ ) - output[i] = (unsigned char)( output[i] ^ iv[i] ); - - memcpy( iv, temp, 16 ); - - input += 16; - output += 16; - length -= 16; - } - } - else - { - while( length > 0 ) - { - for( i = 0; i < 16; i++ ) - output[i] = (unsigned char)( input[i] ^ iv[i] ); - - aes_crypt_ecb( ctx, mode, output, output ); - memcpy( iv, output, 16 ); - - input += 16; - output += 16; - length -= 16; - } - } - - return( 0 ); -} - -/* - * AES-CFB128 buffer encryption/decryption - */ -int aes_crypt_cfb128( aes_context *ctx, - int mode, - int length, - int *iv_off, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) -{ - int c, n = *iv_off; - - if( mode == AES_DECRYPT ) - { - while( length-- ) - { - if( n == 0 ) - aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); - - c = *input++; - *output++ = (unsigned char)( c ^ iv[n] ); - iv[n] = (unsigned char) c; - - n = (n + 1) & 0x0F; - } - } - else - { - while( length-- ) - { - if( n == 0 ) - aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); - - iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); - - n = (n + 1) & 0x0F; - } - } - - *iv_off = n; - - return( 0 ); -} - -#if defined(POLARSSL_SELF_TEST) - -#include - -/* - * AES test vectors from: - * - * http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip - */ -static const unsigned char aes_test_ecb_dec[3][16] = -{ - { 0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58, - 0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0 }, - { 0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2, - 0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4 }, - { 0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D, - 0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE } -}; - -static const unsigned char aes_test_ecb_enc[3][16] = -{ - { 0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73, - 0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F }, - { 0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11, - 0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14 }, - { 0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D, - 0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4 } -}; - -static const unsigned char aes_test_cbc_dec[3][16] = -{ - { 0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73, - 0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86 }, - { 0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75, - 0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B }, - { 0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75, - 0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13 } -}; - -static const unsigned char aes_test_cbc_enc[3][16] = -{ - { 0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84, - 0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D }, - { 0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB, - 0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04 }, - { 0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5, - 0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0 } -}; - -/* - * AES-CFB128 test vectors from: - * - * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - */ -static const unsigned char aes_test_cfb128_key[3][32] = -{ - { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, - 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }, - { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, - 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, - 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }, - { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, - 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, - 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, - 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } -}; - -static const unsigned char aes_test_cfb128_iv[16] = -{ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F -}; - -static const unsigned char aes_test_cfb128_pt[64] = -{ - 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, - 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, - 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, - 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, - 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, - 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, - 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, - 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 -}; - -static const unsigned char aes_test_cfb128_ct[3][64] = -{ - { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, - 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A, - 0xC8, 0xA6, 0x45, 0x37, 0xA0, 0xB3, 0xA9, 0x3F, - 0xCD, 0xE3, 0xCD, 0xAD, 0x9F, 0x1C, 0xE5, 0x8B, - 0x26, 0x75, 0x1F, 0x67, 0xA3, 0xCB, 0xB1, 0x40, - 0xB1, 0x80, 0x8C, 0xF1, 0x87, 0xA4, 0xF4, 0xDF, - 0xC0, 0x4B, 0x05, 0x35, 0x7C, 0x5D, 0x1C, 0x0E, - 0xEA, 0xC4, 0xC6, 0x6F, 0x9F, 0xF7, 0xF2, 0xE6 }, - { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB, - 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74, - 0x67, 0xCE, 0x7F, 0x7F, 0x81, 0x17, 0x36, 0x21, - 0x96, 0x1A, 0x2B, 0x70, 0x17, 0x1D, 0x3D, 0x7A, - 0x2E, 0x1E, 0x8A, 0x1D, 0xD5, 0x9B, 0x88, 0xB1, - 0xC8, 0xE6, 0x0F, 0xED, 0x1E, 0xFA, 0xC4, 0xC9, - 0xC0, 0x5F, 0x9F, 0x9C, 0xA9, 0x83, 0x4F, 0xA0, - 0x42, 0xAE, 0x8F, 0xBA, 0x58, 0x4B, 0x09, 0xFF }, - { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B, - 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60, - 0x39, 0xFF, 0xED, 0x14, 0x3B, 0x28, 0xB1, 0xC8, - 0x32, 0x11, 0x3C, 0x63, 0x31, 0xE5, 0x40, 0x7B, - 0xDF, 0x10, 0x13, 0x24, 0x15, 0xE5, 0x4B, 0x92, - 0xA1, 0x3E, 0xD0, 0xA8, 0x26, 0x7A, 0xE2, 0xF9, - 0x75, 0xA3, 0x85, 0x74, 0x1A, 0xB9, 0xCE, 0xF8, - 0x20, 0x31, 0x62, 0x3D, 0x55, 0xB1, 0xE4, 0x71 } -}; - -/* - * Checkup routine - */ -int aes_self_test( int verbose ) -{ - int i, j, u, v, offset; - unsigned char key[32]; - unsigned char buf[64]; - unsigned char prv[16]; - unsigned char iv[16]; - aes_context ctx; - - memset( key, 0, 32 ); - - /* - * ECB mode - */ - for( i = 0; i < 6; i++ ) - { - u = i >> 1; - v = i & 1; - - if( verbose != 0 ) - printf( " AES-ECB-%3d (%s): ", 128 + u * 64, - ( v == AES_DECRYPT ) ? "dec" : "enc" ); - - memset( buf, 0, 16 ); - - if( v == AES_DECRYPT ) - { - aes_setkey_dec( &ctx, key, 128 + u * 64 ); - - for( j = 0; j < 10000; j++ ) - aes_crypt_ecb( &ctx, v, buf, buf ); - - if( memcmp( buf, aes_test_ecb_dec[u], 16 ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - } - else - { - aes_setkey_enc( &ctx, key, 128 + u * 64 ); - - for( j = 0; j < 10000; j++ ) - aes_crypt_ecb( &ctx, v, buf, buf ); - - if( memcmp( buf, aes_test_ecb_enc[u], 16 ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - } - - if( verbose != 0 ) - printf( "passed\n" ); - } - - if( verbose != 0 ) - printf( "\n" ); - - /* - * CBC mode - */ - for( i = 0; i < 6; i++ ) - { - u = i >> 1; - v = i & 1; - - if( verbose != 0 ) - printf( " AES-CBC-%3d (%s): ", 128 + u * 64, - ( v == AES_DECRYPT ) ? "dec" : "enc" ); - - memset( iv , 0, 16 ); - memset( prv, 0, 16 ); - memset( buf, 0, 16 ); - - if( v == AES_DECRYPT ) - { - aes_setkey_dec( &ctx, key, 128 + u * 64 ); - - for( j = 0; j < 10000; j++ ) - aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); - - if( memcmp( buf, aes_test_cbc_dec[u], 16 ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - } - else - { - aes_setkey_enc( &ctx, key, 128 + u * 64 ); - - for( j = 0; j < 10000; j++ ) - { - unsigned char tmp[16]; - - aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); - - memcpy( tmp, prv, 16 ); - memcpy( prv, buf, 16 ); - memcpy( buf, tmp, 16 ); - } - - if( memcmp( prv, aes_test_cbc_enc[u], 16 ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - } - - if( verbose != 0 ) - printf( "passed\n" ); - } - - if( verbose != 0 ) - printf( "\n" ); - - /* - * CFB128 mode - */ - for( i = 0; i < 6; i++ ) - { - u = i >> 1; - v = i & 1; - - if( verbose != 0 ) - printf( " AES-CFB128-%3d (%s): ", 128 + u * 64, - ( v == AES_DECRYPT ) ? "dec" : "enc" ); - - memcpy( iv, aes_test_cfb128_iv, 16 ); - memcpy( key, aes_test_cfb128_key[u], 16 + u * 8 ); - - offset = 0; - aes_setkey_enc( &ctx, key, 128 + u * 64 ); - - if( v == AES_DECRYPT ) - { - memcpy( buf, aes_test_cfb128_ct[u], 64 ); - aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); - - if( memcmp( buf, aes_test_cfb128_pt, 64 ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - } - else - { - memcpy( buf, aes_test_cfb128_pt, 64 ); - aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); - - if( memcmp( buf, aes_test_cfb128_ct[u], 64 ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - } - - if( verbose != 0 ) - printf( "passed\n" ); - } - - - if( verbose != 0 ) - printf( "\n" ); - - return( 0 ); -} - -#endif - -#endif diff --git a/ctrtool/polarssl/aes.h b/ctrtool/polarssl/aes.h deleted file mode 100644 index 5576680..0000000 --- a/ctrtool/polarssl/aes.h +++ /dev/null @@ -1,139 +0,0 @@ -/** - * \file aes.h - * - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef POLARSSL_AES_H -#define POLARSSL_AES_H - -#define AES_ENCRYPT 1 -#define AES_DECRYPT 0 - -#define POLARSSL_ERR_AES_INVALID_KEY_LENGTH -0x0800 -#define POLARSSL_ERR_AES_INVALID_INPUT_LENGTH -0x0810 - -/** - * \brief AES context structure - */ -typedef struct -{ - int nr; /*!< number of rounds */ - unsigned long *rk; /*!< AES round keys */ - unsigned long buf[68]; /*!< unaligned data */ -} -aes_context; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief AES key schedule (encryption) - * - * \param ctx AES context to be initialized - * \param key encryption key - * \param keysize must be 128, 192 or 256 - * - * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH - */ -int aes_setkey_enc( aes_context *ctx, const unsigned char *key, int keysize ); - -/** - * \brief AES key schedule (decryption) - * - * \param ctx AES context to be initialized - * \param key decryption key - * \param keysize must be 128, 192 or 256 - * - * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH - */ -int aes_setkey_dec( aes_context *ctx, const unsigned char *key, int keysize ); - -/** - * \brief AES-ECB block encryption/decryption - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param input 16-byte input block - * \param output 16-byte output block - * - * \return 0 if successful - */ -int aes_crypt_ecb( aes_context *ctx, - int mode, - const unsigned char input[16], - unsigned char output[16] ); - -/** - * \brief AES-CBC buffer encryption/decryption - * Length should be a multiple of the block - * size (16 bytes) - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param length length of the input data - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data - * - * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_INPUT_LENGTH - */ -int aes_crypt_cbc( aes_context *ctx, - int mode, - int length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ); - -/** - * \brief AES-CFB128 buffer encryption/decryption. - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param length length of the input data - * \param iv_off offset in IV (updated after use) - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data - * - * \return 0 if successful - */ -int aes_crypt_cfb128( aes_context *ctx, - int mode, - int length, - int *iv_off, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ); - -/** - * \brief Checkup routine - * - * \return 0 if successful, or 1 if the test failed - */ -int aes_self_test( int verbose ); - -#ifdef __cplusplus -} -#endif - -#endif /* aes.h */ diff --git a/ctrtool/polarssl/bignum.c b/ctrtool/polarssl/bignum.c deleted file mode 100644 index 78e9384..0000000 --- a/ctrtool/polarssl/bignum.c +++ /dev/null @@ -1,2038 +0,0 @@ -/* - * Multi-precision integer library - * - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * This MPI implementation is based on: - * - * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf - * http://www.stillhq.com/extracted/gnupg-api/mpi/ - * http://math.libtomcrypt.com/files/tommath.pdf - */ - -#include "polarssl/config.h" - -#if defined(POLARSSL_BIGNUM_C) - -#include "polarssl/bignum.h" -#include "polarssl/bn_mul.h" - -#include -#include -#include - -#define ciL ((int) sizeof(t_int)) /* chars in limb */ -#define biL (ciL << 3) /* bits in limb */ -#define biH (ciL << 2) /* half limb size */ - -/* - * Convert between bits/chars and number of limbs - */ -#define BITS_TO_LIMBS(i) (((i) + biL - 1) / biL) -#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL) - -/* - * Initialize one or more mpi - */ -void mpi_init( mpi *X, ... ) -{ - va_list args; - - va_start( args, X ); - - while( X != NULL ) - { - X->s = 1; - X->n = 0; - X->p = NULL; - - X = va_arg( args, mpi* ); - } - - va_end( args ); -} - -/* - * Unallocate one or more mpi - */ -void mpi_free( mpi *X, ... ) -{ - va_list args; - - va_start( args, X ); - - while( X != NULL ) - { - if( X->p != NULL ) - { - memset( X->p, 0, X->n * ciL ); - free( X->p ); - } - - X->s = 1; - X->n = 0; - X->p = NULL; - - X = va_arg( args, mpi* ); - } - - va_end( args ); -} - -/* - * Enlarge to the specified number of limbs - */ -int mpi_grow( mpi *X, int nblimbs ) -{ - t_int *p; - - if( X->n < nblimbs ) - { - if( ( p = (t_int *) malloc( nblimbs * ciL ) ) == NULL ) - return( 1 ); - - memset( p, 0, nblimbs * ciL ); - - if( X->p != NULL ) - { - memcpy( p, X->p, X->n * ciL ); - memset( X->p, 0, X->n * ciL ); - free( X->p ); - } - - X->n = nblimbs; - X->p = p; - } - - return( 0 ); -} - -/* - * Copy the contents of Y into X - */ -int mpi_copy( mpi *X, const mpi *Y ) -{ - int ret, i; - - if( X == Y ) - return( 0 ); - - for( i = Y->n - 1; i > 0; i-- ) - if( Y->p[i] != 0 ) - break; - i++; - - X->s = Y->s; - - MPI_CHK( mpi_grow( X, i ) ); - - memset( X->p, 0, X->n * ciL ); - memcpy( X->p, Y->p, i * ciL ); - -cleanup: - - return( ret ); -} - -/* - * Swap the contents of X and Y - */ -void mpi_swap( mpi *X, mpi *Y ) -{ - mpi T; - - memcpy( &T, X, sizeof( mpi ) ); - memcpy( X, Y, sizeof( mpi ) ); - memcpy( Y, &T, sizeof( mpi ) ); -} - -/* - * Set value from integer - */ -int mpi_lset( mpi *X, int z ) -{ - int ret; - - MPI_CHK( mpi_grow( X, 1 ) ); - memset( X->p, 0, X->n * ciL ); - - X->p[0] = ( z < 0 ) ? -z : z; - X->s = ( z < 0 ) ? -1 : 1; - -cleanup: - - return( ret ); -} - -/* - * Return the number of least significant bits - */ -int mpi_lsb( const mpi *X ) -{ - int i, j, count = 0; - - for( i = 0; i < X->n; i++ ) - for( j = 0; j < (int) biL; j++, count++ ) - if( ( ( X->p[i] >> j ) & 1 ) != 0 ) - return( count ); - - return( 0 ); -} - -/* - * Return the number of most significant bits - */ -int mpi_msb( const mpi *X ) -{ - int i, j; - - for( i = X->n - 1; i > 0; i-- ) - if( X->p[i] != 0 ) - break; - - for( j = biL - 1; j >= 0; j-- ) - if( ( ( X->p[i] >> j ) & 1 ) != 0 ) - break; - - return( ( i * biL ) + j + 1 ); -} - -/* - * Return the total size in bytes - */ -int mpi_size( const mpi *X ) -{ - return( ( mpi_msb( X ) + 7 ) >> 3 ); -} - -/* - * Convert an ASCII character to digit value - */ -static int mpi_get_digit( t_int *d, int radix, char c ) -{ - *d = 255; - - if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; - if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; - if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; - - if( *d >= (t_int) radix ) - return( POLARSSL_ERR_MPI_INVALID_CHARACTER ); - - return( 0 ); -} - -/* - * Import from an ASCII string - */ -int mpi_read_string( mpi *X, int radix, const char *s ) -{ - int ret, i, j, n, slen; - t_int d; - mpi T; - - if( radix < 2 || radix > 16 ) - return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); - - mpi_init( &T, NULL ); - - slen = strlen( s ); - - if( radix == 16 ) - { - n = BITS_TO_LIMBS( slen << 2 ); - - MPI_CHK( mpi_grow( X, n ) ); - MPI_CHK( mpi_lset( X, 0 ) ); - - for( i = slen - 1, j = 0; i >= 0; i--, j++ ) - { - if( i == 0 && s[i] == '-' ) - { - X->s = -1; - break; - } - - MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); - X->p[j / (2 * ciL)] |= d << ( (j % (2 * ciL)) << 2 ); - } - } - else - { - MPI_CHK( mpi_lset( X, 0 ) ); - - for( i = 0; i < slen; i++ ) - { - if( i == 0 && s[i] == '-' ) - { - X->s = -1; - continue; - } - - MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); - MPI_CHK( mpi_mul_int( &T, X, radix ) ); - - if( X->s == 1 ) - { - MPI_CHK( mpi_add_int( X, &T, d ) ); - } - else - { - MPI_CHK( mpi_sub_int( X, &T, d ) ); - } - } - } - -cleanup: - - mpi_free( &T, NULL ); - - return( ret ); -} - -/* - * Helper to write the digits high-order first - */ -static int mpi_write_hlp( mpi *X, int radix, char **p ) -{ - int ret; - t_int r; - - if( radix < 2 || radix > 16 ) - return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); - - MPI_CHK( mpi_mod_int( &r, X, radix ) ); - MPI_CHK( mpi_div_int( X, NULL, X, radix ) ); - - if( mpi_cmp_int( X, 0 ) != 0 ) - MPI_CHK( mpi_write_hlp( X, radix, p ) ); - - if( r < 10 ) - *(*p)++ = (char)( r + 0x30 ); - else - *(*p)++ = (char)( r + 0x37 ); - -cleanup: - - return( ret ); -} - -/* - * Export into an ASCII string - */ -int mpi_write_string( const mpi *X, int radix, char *s, int *slen ) -{ - int ret = 0, n; - char *p; - mpi T; - - if( radix < 2 || radix > 16 ) - return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); - - n = mpi_msb( X ); - if( radix >= 4 ) n >>= 1; - if( radix >= 16 ) n >>= 1; - n += 3; - - if( *slen < n ) - { - *slen = n; - return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); - } - - p = s; - mpi_init( &T, NULL ); - - if( X->s == -1 ) - *p++ = '-'; - - if( radix == 16 ) - { - int c, i, j, k; - - for( i = X->n - 1, k = 0; i >= 0; i-- ) - { - for( j = ciL - 1; j >= 0; j-- ) - { - c = ( X->p[i] >> (j << 3) ) & 0xFF; - - if( c == 0 && k == 0 && (i + j) != 0 ) - continue; - - p += sprintf( p, "%02X", c ); - k = 1; - } - } - } - else - { - MPI_CHK( mpi_copy( &T, X ) ); - - if( T.s == -1 ) - T.s = 1; - - MPI_CHK( mpi_write_hlp( &T, radix, &p ) ); - } - - *p++ = '\0'; - *slen = p - s; - -cleanup: - - mpi_free( &T, NULL ); - - return( ret ); -} - -/* - * Read X from an opened file - */ -int mpi_read_file( mpi *X, int radix, FILE *fin ) -{ - t_int d; - int slen; - char *p; - char s[1024]; - - memset( s, 0, sizeof( s ) ); - if( fgets( s, sizeof( s ) - 1, fin ) == NULL ) - return( POLARSSL_ERR_MPI_FILE_IO_ERROR ); - - slen = strlen( s ); - if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; } - if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; } - - p = s + slen; - while( --p >= s ) - if( mpi_get_digit( &d, radix, *p ) != 0 ) - break; - - return( mpi_read_string( X, radix, p + 1 ) ); -} - -/* - * Write X into an opened file (or stdout if fout == NULL) - */ -int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout ) -{ - int n, ret; - size_t slen; - size_t plen; - char s[2048]; - - n = sizeof( s ); - memset( s, 0, n ); - n -= 2; - - MPI_CHK( mpi_write_string( X, radix, s, (int *) &n ) ); - - if( p == NULL ) p = ""; - - plen = strlen( p ); - slen = strlen( s ); - s[slen++] = '\r'; - s[slen++] = '\n'; - - if( fout != NULL ) - { - if( fwrite( p, 1, plen, fout ) != plen || - fwrite( s, 1, slen, fout ) != slen ) - return( POLARSSL_ERR_MPI_FILE_IO_ERROR ); - } - else - printf( "%s%s", p, s ); - -cleanup: - - return( ret ); -} - -/* - * Import X from unsigned binary data, big endian - */ -int mpi_read_binary( mpi *X, const unsigned char *buf, int buflen ) -{ - int ret, i, j, n; - - for( n = 0; n < buflen; n++ ) - if( buf[n] != 0 ) - break; - - MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) ); - MPI_CHK( mpi_lset( X, 0 ) ); - - for( i = buflen - 1, j = 0; i >= n; i--, j++ ) - X->p[j / ciL] |= ((t_int) buf[i]) << ((j % ciL) << 3); - -cleanup: - - return( ret ); -} - -/* - * Export X into unsigned binary data, big endian - */ -int mpi_write_binary( const mpi *X, unsigned char *buf, int buflen ) -{ - int i, j, n; - - n = mpi_size( X ); - - if( buflen < n ) - return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); - - memset( buf, 0, buflen ); - - for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- ) - buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) ); - - return( 0 ); -} - -/* - * Left-shift: X <<= count - */ -int mpi_shift_l( mpi *X, int count ) -{ - int ret, i, v0, t1; - t_int r0 = 0, r1; - - v0 = count / (biL ); - t1 = count & (biL - 1); - - i = mpi_msb( X ) + count; - - if( X->n * (int) biL < i ) - MPI_CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) ); - - ret = 0; - - /* - * shift by count / limb_size - */ - if( v0 > 0 ) - { - for( i = X->n - 1; i >= v0; i-- ) - X->p[i] = X->p[i - v0]; - - for( ; i >= 0; i-- ) - X->p[i] = 0; - } - - /* - * shift by count % limb_size - */ - if( t1 > 0 ) - { - for( i = v0; i < X->n; i++ ) - { - r1 = X->p[i] >> (biL - t1); - X->p[i] <<= t1; - X->p[i] |= r0; - r0 = r1; - } - } - -cleanup: - - return( ret ); -} - -/* - * Right-shift: X >>= count - */ -int mpi_shift_r( mpi *X, int count ) -{ - int i, v0, v1; - t_int r0 = 0, r1; - - v0 = count / biL; - v1 = count & (biL - 1); - - /* - * shift by count / limb_size - */ - if( v0 > 0 ) - { - for( i = 0; i < X->n - v0; i++ ) - X->p[i] = X->p[i + v0]; - - for( ; i < X->n; i++ ) - X->p[i] = 0; - } - - /* - * shift by count % limb_size - */ - if( v1 > 0 ) - { - for( i = X->n - 1; i >= 0; i-- ) - { - r1 = X->p[i] << (biL - v1); - X->p[i] >>= v1; - X->p[i] |= r0; - r0 = r1; - } - } - - return( 0 ); -} - -/* - * Compare unsigned values - */ -int mpi_cmp_abs( const mpi *X, const mpi *Y ) -{ - int i, j; - - for( i = X->n - 1; i >= 0; i-- ) - if( X->p[i] != 0 ) - break; - - for( j = Y->n - 1; j >= 0; j-- ) - if( Y->p[j] != 0 ) - break; - - if( i < 0 && j < 0 ) - return( 0 ); - - if( i > j ) return( 1 ); - if( j > i ) return( -1 ); - - for( ; i >= 0; i-- ) - { - if( X->p[i] > Y->p[i] ) return( 1 ); - if( X->p[i] < Y->p[i] ) return( -1 ); - } - - return( 0 ); -} - -/* - * Compare signed values - */ -int mpi_cmp_mpi( const mpi *X, const mpi *Y ) -{ - int i, j; - - for( i = X->n - 1; i >= 0; i-- ) - if( X->p[i] != 0 ) - break; - - for( j = Y->n - 1; j >= 0; j-- ) - if( Y->p[j] != 0 ) - break; - - if( i < 0 && j < 0 ) - return( 0 ); - - if( i > j ) return( X->s ); - if( j > i ) return( -X->s ); - - if( X->s > 0 && Y->s < 0 ) return( 1 ); - if( Y->s > 0 && X->s < 0 ) return( -1 ); - - for( ; i >= 0; i-- ) - { - if( X->p[i] > Y->p[i] ) return( X->s ); - if( X->p[i] < Y->p[i] ) return( -X->s ); - } - - return( 0 ); -} - -/* - * Compare signed values - */ -int mpi_cmp_int( const mpi *X, int z ) -{ - mpi Y; - t_int p[1]; - - *p = ( z < 0 ) ? -z : z; - Y.s = ( z < 0 ) ? -1 : 1; - Y.n = 1; - Y.p = p; - - return( mpi_cmp_mpi( X, &Y ) ); -} - -/* - * Unsigned addition: X = |A| + |B| (HAC 14.7) - */ -int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ) -{ - int ret, i, j; - t_int *o, *p, c; - - if( X == B ) - { - const mpi *T = A; A = X; B = T; - } - - if( X != A ) - MPI_CHK( mpi_copy( X, A ) ); - - /* - * X should always be positive as a result of unsigned additions. - */ - X->s = 1; - - for( j = B->n - 1; j >= 0; j-- ) - if( B->p[j] != 0 ) - break; - - MPI_CHK( mpi_grow( X, j + 1 ) ); - - o = B->p; p = X->p; c = 0; - - for( i = 0; i <= j; i++, o++, p++ ) - { - *p += c; c = ( *p < c ); - *p += *o; c += ( *p < *o ); - } - - while( c != 0 ) - { - if( i >= X->n ) - { - MPI_CHK( mpi_grow( X, i + 1 ) ); - p = X->p + i; - } - - *p += c; c = ( *p < c ); i++; - } - -cleanup: - - return( ret ); -} - -/* - * Helper for mpi substraction - */ -static void mpi_sub_hlp( int n, t_int *s, t_int *d ) -{ - int i; - t_int c, z; - - for( i = c = 0; i < n; i++, s++, d++ ) - { - z = ( *d < c ); *d -= c; - c = ( *d < *s ) + z; *d -= *s; - } - - while( c != 0 ) - { - z = ( *d < c ); *d -= c; - c = z; i++; d++; - } -} - -/* - * Unsigned substraction: X = |A| - |B| (HAC 14.9) - */ -int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ) -{ - mpi TB; - int ret, n; - - if( mpi_cmp_abs( A, B ) < 0 ) - return( POLARSSL_ERR_MPI_NEGATIVE_VALUE ); - - mpi_init( &TB, NULL ); - - if( X == B ) - { - MPI_CHK( mpi_copy( &TB, B ) ); - B = &TB; - } - - if( X != A ) - MPI_CHK( mpi_copy( X, A ) ); - - /* - * X should always be positive as a result of unsigned substractions. - */ - X->s = 1; - - ret = 0; - - for( n = B->n - 1; n >= 0; n-- ) - if( B->p[n] != 0 ) - break; - - mpi_sub_hlp( n + 1, B->p, X->p ); - -cleanup: - - mpi_free( &TB, NULL ); - - return( ret ); -} - -/* - * Signed addition: X = A + B - */ -int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ) -{ - int ret, s = A->s; - - if( A->s * B->s < 0 ) - { - if( mpi_cmp_abs( A, B ) >= 0 ) - { - MPI_CHK( mpi_sub_abs( X, A, B ) ); - X->s = s; - } - else - { - MPI_CHK( mpi_sub_abs( X, B, A ) ); - X->s = -s; - } - } - else - { - MPI_CHK( mpi_add_abs( X, A, B ) ); - X->s = s; - } - -cleanup: - - return( ret ); -} - -/* - * Signed substraction: X = A - B - */ -int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ) -{ - int ret, s = A->s; - - if( A->s * B->s > 0 ) - { - if( mpi_cmp_abs( A, B ) >= 0 ) - { - MPI_CHK( mpi_sub_abs( X, A, B ) ); - X->s = s; - } - else - { - MPI_CHK( mpi_sub_abs( X, B, A ) ); - X->s = -s; - } - } - else - { - MPI_CHK( mpi_add_abs( X, A, B ) ); - X->s = s; - } - -cleanup: - - return( ret ); -} - -/* - * Signed addition: X = A + b - */ -int mpi_add_int( mpi *X, const mpi *A, int b ) -{ - mpi _B; - t_int p[1]; - - p[0] = ( b < 0 ) ? -b : b; - _B.s = ( b < 0 ) ? -1 : 1; - _B.n = 1; - _B.p = p; - - return( mpi_add_mpi( X, A, &_B ) ); -} - -/* - * Signed substraction: X = A - b - */ -int mpi_sub_int( mpi *X, const mpi *A, int b ) -{ - mpi _B; - t_int p[1]; - - p[0] = ( b < 0 ) ? -b : b; - _B.s = ( b < 0 ) ? -1 : 1; - _B.n = 1; - _B.p = p; - - return( mpi_sub_mpi( X, A, &_B ) ); -} - -/* - * Helper for mpi multiplication - */ -static void mpi_mul_hlp( int i, t_int *s, t_int *d, t_int b ) -{ - t_int c = 0, t = 0; - -#if defined(MULADDC_HUIT) - for( ; i >= 8; i -= 8 ) - { - MULADDC_INIT - MULADDC_HUIT - MULADDC_STOP - } - - for( ; i > 0; i-- ) - { - MULADDC_INIT - MULADDC_CORE - MULADDC_STOP - } -#else - for( ; i >= 16; i -= 16 ) - { - MULADDC_INIT - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - MULADDC_STOP - } - - for( ; i >= 8; i -= 8 ) - { - MULADDC_INIT - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - MULADDC_STOP - } - - for( ; i > 0; i-- ) - { - MULADDC_INIT - MULADDC_CORE - MULADDC_STOP - } -#endif - - t++; - - do { - *d += c; c = ( *d < c ); d++; - } - while( c != 0 ); -} - -/* - * Baseline multiplication: X = A * B (HAC 14.12) - */ -int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ) -{ - int ret, i, j; - mpi TA, TB; - - mpi_init( &TA, &TB, NULL ); - - if( X == A ) { MPI_CHK( mpi_copy( &TA, A ) ); A = &TA; } - if( X == B ) { MPI_CHK( mpi_copy( &TB, B ) ); B = &TB; } - - for( i = A->n - 1; i >= 0; i-- ) - if( A->p[i] != 0 ) - break; - - for( j = B->n - 1; j >= 0; j-- ) - if( B->p[j] != 0 ) - break; - - MPI_CHK( mpi_grow( X, i + j + 2 ) ); - MPI_CHK( mpi_lset( X, 0 ) ); - - for( i++; j >= 0; j-- ) - mpi_mul_hlp( i, A->p, X->p + j, B->p[j] ); - - X->s = A->s * B->s; - -cleanup: - - mpi_free( &TB, &TA, NULL ); - - return( ret ); -} - -/* - * Baseline multiplication: X = A * b - */ -int mpi_mul_int( mpi *X, const mpi *A, t_int b ) -{ - mpi _B; - t_int p[1]; - - _B.s = 1; - _B.n = 1; - _B.p = p; - p[0] = b; - - return( mpi_mul_mpi( X, A, &_B ) ); -} - -/* - * Division by mpi: A = Q * B + R (HAC 14.20) - */ -int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ) -{ - int ret, i, n, t, k; - mpi X, Y, Z, T1, T2; - - if( mpi_cmp_int( B, 0 ) == 0 ) - return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO ); - - mpi_init( &X, &Y, &Z, &T1, &T2, NULL ); - - if( mpi_cmp_abs( A, B ) < 0 ) - { - if( Q != NULL ) MPI_CHK( mpi_lset( Q, 0 ) ); - if( R != NULL ) MPI_CHK( mpi_copy( R, A ) ); - return( 0 ); - } - - MPI_CHK( mpi_copy( &X, A ) ); - MPI_CHK( mpi_copy( &Y, B ) ); - X.s = Y.s = 1; - - MPI_CHK( mpi_grow( &Z, A->n + 2 ) ); - MPI_CHK( mpi_lset( &Z, 0 ) ); - MPI_CHK( mpi_grow( &T1, 2 ) ); - MPI_CHK( mpi_grow( &T2, 3 ) ); - - k = mpi_msb( &Y ) % biL; - if( k < (int) biL - 1 ) - { - k = biL - 1 - k; - MPI_CHK( mpi_shift_l( &X, k ) ); - MPI_CHK( mpi_shift_l( &Y, k ) ); - } - else k = 0; - - n = X.n - 1; - t = Y.n - 1; - mpi_shift_l( &Y, biL * (n - t) ); - - while( mpi_cmp_mpi( &X, &Y ) >= 0 ) - { - Z.p[n - t]++; - mpi_sub_mpi( &X, &X, &Y ); - } - mpi_shift_r( &Y, biL * (n - t) ); - - for( i = n; i > t ; i-- ) - { - if( X.p[i] >= Y.p[t] ) - Z.p[i - t - 1] = ~0; - else - { -#if defined(POLARSSL_HAVE_LONGLONG) - t_dbl r; - - r = (t_dbl) X.p[i] << biL; - r |= (t_dbl) X.p[i - 1]; - r /= Y.p[t]; - if( r > ((t_dbl) 1 << biL) - 1) - r = ((t_dbl) 1 << biL) - 1; - - Z.p[i - t - 1] = (t_int) r; -#else - /* - * __udiv_qrnnd_c, from gmp/longlong.h - */ - t_int q0, q1, r0, r1; - t_int d0, d1, d, m; - - d = Y.p[t]; - d0 = ( d << biH ) >> biH; - d1 = ( d >> biH ); - - q1 = X.p[i] / d1; - r1 = X.p[i] - d1 * q1; - r1 <<= biH; - r1 |= ( X.p[i - 1] >> biH ); - - m = q1 * d0; - if( r1 < m ) - { - q1--, r1 += d; - while( r1 >= d && r1 < m ) - q1--, r1 += d; - } - r1 -= m; - - q0 = r1 / d1; - r0 = r1 - d1 * q0; - r0 <<= biH; - r0 |= ( X.p[i - 1] << biH ) >> biH; - - m = q0 * d0; - if( r0 < m ) - { - q0--, r0 += d; - while( r0 >= d && r0 < m ) - q0--, r0 += d; - } - r0 -= m; - - Z.p[i - t - 1] = ( q1 << biH ) | q0; -#endif - } - - Z.p[i - t - 1]++; - do - { - Z.p[i - t - 1]--; - - MPI_CHK( mpi_lset( &T1, 0 ) ); - T1.p[0] = (t < 1) ? 0 : Y.p[t - 1]; - T1.p[1] = Y.p[t]; - MPI_CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); - - MPI_CHK( mpi_lset( &T2, 0 ) ); - T2.p[0] = (i < 2) ? 0 : X.p[i - 2]; - T2.p[1] = (i < 1) ? 0 : X.p[i - 1]; - T2.p[2] = X.p[i]; - } - while( mpi_cmp_mpi( &T1, &T2 ) > 0 ); - - MPI_CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); - MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); - MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); - - if( mpi_cmp_int( &X, 0 ) < 0 ) - { - MPI_CHK( mpi_copy( &T1, &Y ) ); - MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); - MPI_CHK( mpi_add_mpi( &X, &X, &T1 ) ); - Z.p[i - t - 1]--; - } - } - - if( Q != NULL ) - { - mpi_copy( Q, &Z ); - Q->s = A->s * B->s; - } - - if( R != NULL ) - { - mpi_shift_r( &X, k ); - mpi_copy( R, &X ); - - R->s = A->s; - if( mpi_cmp_int( R, 0 ) == 0 ) - R->s = 1; - } - -cleanup: - - mpi_free( &X, &Y, &Z, &T1, &T2, NULL ); - - return( ret ); -} - -/* - * Division by int: A = Q * b + R - * - * Returns 0 if successful - * 1 if memory allocation failed - * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0 - */ -int mpi_div_int( mpi *Q, mpi *R, const mpi *A, int b ) -{ - mpi _B; - t_int p[1]; - - p[0] = ( b < 0 ) ? -b : b; - _B.s = ( b < 0 ) ? -1 : 1; - _B.n = 1; - _B.p = p; - - return( mpi_div_mpi( Q, R, A, &_B ) ); -} - -/* - * Modulo: R = A mod B - */ -int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B ) -{ - int ret; - - if( mpi_cmp_int( B, 0 ) < 0 ) - return POLARSSL_ERR_MPI_NEGATIVE_VALUE; - - MPI_CHK( mpi_div_mpi( NULL, R, A, B ) ); - - while( mpi_cmp_int( R, 0 ) < 0 ) - MPI_CHK( mpi_add_mpi( R, R, B ) ); - - while( mpi_cmp_mpi( R, B ) >= 0 ) - MPI_CHK( mpi_sub_mpi( R, R, B ) ); - -cleanup: - - return( ret ); -} - -/* - * Modulo: r = A mod b - */ -int mpi_mod_int( t_int *r, const mpi *A, int b ) -{ - int i; - t_int x, y, z; - - if( b == 0 ) - return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO ); - - if( b < 0 ) - return POLARSSL_ERR_MPI_NEGATIVE_VALUE; - - /* - * handle trivial cases - */ - if( b == 1 ) - { - *r = 0; - return( 0 ); - } - - if( b == 2 ) - { - *r = A->p[0] & 1; - return( 0 ); - } - - /* - * general case - */ - for( i = A->n - 1, y = 0; i >= 0; i-- ) - { - x = A->p[i]; - y = ( y << biH ) | ( x >> biH ); - z = y / b; - y -= z * b; - - x <<= biH; - y = ( y << biH ) | ( x >> biH ); - z = y / b; - y -= z * b; - } - - /* - * If A is negative, then the current y represents a negative value. - * Flipping it to the positive side. - */ - if( A->s < 0 && y != 0 ) - y = b - y; - - *r = y; - - return( 0 ); -} - -/* - * Fast Montgomery initialization (thanks to Tom St Denis) - */ -static void mpi_montg_init( t_int *mm, const mpi *N ) -{ - t_int x, m0 = N->p[0]; - - x = m0; - x += ( ( m0 + 2 ) & 4 ) << 1; - x *= ( 2 - ( m0 * x ) ); - - if( biL >= 16 ) x *= ( 2 - ( m0 * x ) ); - if( biL >= 32 ) x *= ( 2 - ( m0 * x ) ); - if( biL >= 64 ) x *= ( 2 - ( m0 * x ) ); - - *mm = ~x + 1; -} - -/* - * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) - */ -static void mpi_montmul( mpi *A, const mpi *B, const mpi *N, t_int mm, const mpi *T ) -{ - int i, n, m; - t_int u0, u1, *d; - - memset( T->p, 0, T->n * ciL ); - - d = T->p; - n = N->n; - m = ( B->n < n ) ? B->n : n; - - for( i = 0; i < n; i++ ) - { - /* - * T = (T + u0*B + u1*N) / 2^biL - */ - u0 = A->p[i]; - u1 = ( d[0] + u0 * B->p[0] ) * mm; - - mpi_mul_hlp( m, B->p, d, u0 ); - mpi_mul_hlp( n, N->p, d, u1 ); - - *d++ = u0; d[n + 1] = 0; - } - - memcpy( A->p, d, (n + 1) * ciL ); - - if( mpi_cmp_abs( A, N ) >= 0 ) - mpi_sub_hlp( n, N->p, A->p ); - else - /* prevent timing attacks */ - mpi_sub_hlp( n, A->p, T->p ); -} - -/* - * Montgomery reduction: A = A * R^-1 mod N - */ -static void mpi_montred( mpi *A, const mpi *N, t_int mm, const mpi *T ) -{ - t_int z = 1; - mpi U; - - U.n = U.s = z; - U.p = &z; - - mpi_montmul( A, &U, N, mm, T ); -} - -/* - * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) - */ -int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ) -{ - int ret, i, j, wsize, wbits; - int bufsize, nblimbs, nbits; - t_int ei, mm, state; - mpi RR, T, W[64]; - - if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) - return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); - - /* - * Init temps and window size - */ - mpi_montg_init( &mm, N ); - mpi_init( &RR, &T, NULL ); - memset( W, 0, sizeof( W ) ); - - i = mpi_msb( E ); - - wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : - ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; - - j = N->n + 1; - MPI_CHK( mpi_grow( X, j ) ); - MPI_CHK( mpi_grow( &W[1], j ) ); - MPI_CHK( mpi_grow( &T, j * 2 ) ); - - /* - * If 1st call, pre-compute R^2 mod N - */ - if( _RR == NULL || _RR->p == NULL ) - { - MPI_CHK( mpi_lset( &RR, 1 ) ); - MPI_CHK( mpi_shift_l( &RR, N->n * 2 * biL ) ); - MPI_CHK( mpi_mod_mpi( &RR, &RR, N ) ); - - if( _RR != NULL ) - memcpy( _RR, &RR, sizeof( mpi ) ); - } - else - memcpy( &RR, _RR, sizeof( mpi ) ); - - /* - * W[1] = A * R^2 * R^-1 mod N = A * R mod N - */ - if( mpi_cmp_mpi( A, N ) >= 0 ) - mpi_mod_mpi( &W[1], A, N ); - else mpi_copy( &W[1], A ); - - mpi_montmul( &W[1], &RR, N, mm, &T ); - - /* - * X = R^2 * R^-1 mod N = R mod N - */ - MPI_CHK( mpi_copy( X, &RR ) ); - mpi_montred( X, N, mm, &T ); - - if( wsize > 1 ) - { - /* - * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) - */ - j = 1 << (wsize - 1); - - MPI_CHK( mpi_grow( &W[j], N->n + 1 ) ); - MPI_CHK( mpi_copy( &W[j], &W[1] ) ); - - for( i = 0; i < wsize - 1; i++ ) - mpi_montmul( &W[j], &W[j], N, mm, &T ); - - /* - * W[i] = W[i - 1] * W[1] - */ - for( i = j + 1; i < (1 << wsize); i++ ) - { - MPI_CHK( mpi_grow( &W[i], N->n + 1 ) ); - MPI_CHK( mpi_copy( &W[i], &W[i - 1] ) ); - - mpi_montmul( &W[i], &W[1], N, mm, &T ); - } - } - - nblimbs = E->n; - bufsize = 0; - nbits = 0; - wbits = 0; - state = 0; - - while( 1 ) - { - if( bufsize == 0 ) - { - if( nblimbs-- == 0 ) - break; - - bufsize = sizeof( t_int ) << 3; - } - - bufsize--; - - ei = (E->p[nblimbs] >> bufsize) & 1; - - /* - * skip leading 0s - */ - if( ei == 0 && state == 0 ) - continue; - - if( ei == 0 && state == 1 ) - { - /* - * out of window, square X - */ - mpi_montmul( X, X, N, mm, &T ); - continue; - } - - /* - * add ei to current window - */ - state = 2; - - nbits++; - wbits |= (ei << (wsize - nbits)); - - if( nbits == wsize ) - { - /* - * X = X^wsize R^-1 mod N - */ - for( i = 0; i < wsize; i++ ) - mpi_montmul( X, X, N, mm, &T ); - - /* - * X = X * W[wbits] R^-1 mod N - */ - mpi_montmul( X, &W[wbits], N, mm, &T ); - - state--; - nbits = 0; - wbits = 0; - } - } - - /* - * process the remaining bits - */ - for( i = 0; i < nbits; i++ ) - { - mpi_montmul( X, X, N, mm, &T ); - - wbits <<= 1; - - if( (wbits & (1 << wsize)) != 0 ) - mpi_montmul( X, &W[1], N, mm, &T ); - } - - /* - * X = A^E * R * R^-1 mod N = A^E mod N - */ - mpi_montred( X, N, mm, &T ); - -cleanup: - - for( i = (1 << (wsize - 1)); i < (1 << wsize); i++ ) - mpi_free( &W[i], NULL ); - - if( _RR != NULL ) - mpi_free( &W[1], &T, NULL ); - else mpi_free( &W[1], &T, &RR, NULL ); - - return( ret ); -} - -/* - * Greatest common divisor: G = gcd(A, B) (HAC 14.54) - */ -int mpi_gcd( mpi *G, const mpi *A, const mpi *B ) -{ - int ret, lz, lzt; - mpi TG, TA, TB; - - mpi_init( &TG, &TA, &TB, NULL ); - - MPI_CHK( mpi_copy( &TA, A ) ); - MPI_CHK( mpi_copy( &TB, B ) ); - - lz = mpi_lsb( &TA ); - lzt = mpi_lsb( &TB ); - - if ( lzt < lz ) - lz = lzt; - - MPI_CHK( mpi_shift_r( &TA, lz ) ); - MPI_CHK( mpi_shift_r( &TB, lz ) ); - - TA.s = TB.s = 1; - - while( mpi_cmp_int( &TA, 0 ) != 0 ) - { - MPI_CHK( mpi_shift_r( &TA, mpi_lsb( &TA ) ) ); - MPI_CHK( mpi_shift_r( &TB, mpi_lsb( &TB ) ) ); - - if( mpi_cmp_mpi( &TA, &TB ) >= 0 ) - { - MPI_CHK( mpi_sub_abs( &TA, &TA, &TB ) ); - MPI_CHK( mpi_shift_r( &TA, 1 ) ); - } - else - { - MPI_CHK( mpi_sub_abs( &TB, &TB, &TA ) ); - MPI_CHK( mpi_shift_r( &TB, 1 ) ); - } - } - - MPI_CHK( mpi_shift_l( &TB, lz ) ); - MPI_CHK( mpi_copy( G, &TB ) ); - -cleanup: - - mpi_free( &TB, &TA, &TG, NULL ); - - return( ret ); -} - -#if defined(POLARSSL_GENPRIME) - -/* - * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) - */ -int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ) -{ - int ret; - mpi G, TA, TU, U1, U2, TB, TV, V1, V2; - - if( mpi_cmp_int( N, 0 ) <= 0 ) - return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); - - mpi_init( &TA, &TU, &U1, &U2, &G, - &TB, &TV, &V1, &V2, NULL ); - - MPI_CHK( mpi_gcd( &G, A, N ) ); - - if( mpi_cmp_int( &G, 1 ) != 0 ) - { - ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; - goto cleanup; - } - - MPI_CHK( mpi_mod_mpi( &TA, A, N ) ); - MPI_CHK( mpi_copy( &TU, &TA ) ); - MPI_CHK( mpi_copy( &TB, N ) ); - MPI_CHK( mpi_copy( &TV, N ) ); - - MPI_CHK( mpi_lset( &U1, 1 ) ); - MPI_CHK( mpi_lset( &U2, 0 ) ); - MPI_CHK( mpi_lset( &V1, 0 ) ); - MPI_CHK( mpi_lset( &V2, 1 ) ); - - do - { - while( ( TU.p[0] & 1 ) == 0 ) - { - MPI_CHK( mpi_shift_r( &TU, 1 ) ); - - if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) - { - MPI_CHK( mpi_add_mpi( &U1, &U1, &TB ) ); - MPI_CHK( mpi_sub_mpi( &U2, &U2, &TA ) ); - } - - MPI_CHK( mpi_shift_r( &U1, 1 ) ); - MPI_CHK( mpi_shift_r( &U2, 1 ) ); - } - - while( ( TV.p[0] & 1 ) == 0 ) - { - MPI_CHK( mpi_shift_r( &TV, 1 ) ); - - if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) - { - MPI_CHK( mpi_add_mpi( &V1, &V1, &TB ) ); - MPI_CHK( mpi_sub_mpi( &V2, &V2, &TA ) ); - } - - MPI_CHK( mpi_shift_r( &V1, 1 ) ); - MPI_CHK( mpi_shift_r( &V2, 1 ) ); - } - - if( mpi_cmp_mpi( &TU, &TV ) >= 0 ) - { - MPI_CHK( mpi_sub_mpi( &TU, &TU, &TV ) ); - MPI_CHK( mpi_sub_mpi( &U1, &U1, &V1 ) ); - MPI_CHK( mpi_sub_mpi( &U2, &U2, &V2 ) ); - } - else - { - MPI_CHK( mpi_sub_mpi( &TV, &TV, &TU ) ); - MPI_CHK( mpi_sub_mpi( &V1, &V1, &U1 ) ); - MPI_CHK( mpi_sub_mpi( &V2, &V2, &U2 ) ); - } - } - while( mpi_cmp_int( &TU, 0 ) != 0 ); - - while( mpi_cmp_int( &V1, 0 ) < 0 ) - MPI_CHK( mpi_add_mpi( &V1, &V1, N ) ); - - while( mpi_cmp_mpi( &V1, N ) >= 0 ) - MPI_CHK( mpi_sub_mpi( &V1, &V1, N ) ); - - MPI_CHK( mpi_copy( X, &V1 ) ); - -cleanup: - - mpi_free( &V2, &V1, &TV, &TB, &G, - &U2, &U1, &TU, &TA, NULL ); - - return( ret ); -} - -static const int small_prime[] = -{ - 3, 5, 7, 11, 13, 17, 19, 23, - 29, 31, 37, 41, 43, 47, 53, 59, - 61, 67, 71, 73, 79, 83, 89, 97, - 101, 103, 107, 109, 113, 127, 131, 137, - 139, 149, 151, 157, 163, 167, 173, 179, - 181, 191, 193, 197, 199, 211, 223, 227, - 229, 233, 239, 241, 251, 257, 263, 269, - 271, 277, 281, 283, 293, 307, 311, 313, - 317, 331, 337, 347, 349, 353, 359, 367, - 373, 379, 383, 389, 397, 401, 409, 419, - 421, 431, 433, 439, 443, 449, 457, 461, - 463, 467, 479, 487, 491, 499, 503, 509, - 521, 523, 541, 547, 557, 563, 569, 571, - 577, 587, 593, 599, 601, 607, 613, 617, - 619, 631, 641, 643, 647, 653, 659, 661, - 673, 677, 683, 691, 701, 709, 719, 727, - 733, 739, 743, 751, 757, 761, 769, 773, - 787, 797, 809, 811, 821, 823, 827, 829, - 839, 853, 857, 859, 863, 877, 881, 883, - 887, 907, 911, 919, 929, 937, 941, 947, - 953, 967, 971, 977, 983, 991, 997, -103 -}; - -/* - * Miller-Rabin primality test (HAC 4.24) - */ -int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng ) -{ - int ret, i, j, n, s, xs; - mpi W, R, T, A, RR; - unsigned char *p; - - if( mpi_cmp_int( X, 0 ) == 0 || - mpi_cmp_int( X, 1 ) == 0 ) - return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); - - if( mpi_cmp_int( X, 2 ) == 0 ) - return( 0 ); - - mpi_init( &W, &R, &T, &A, &RR, NULL ); - - xs = X->s; X->s = 1; - - /* - * test trivial factors first - */ - if( ( X->p[0] & 1 ) == 0 ) - return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); - - for( i = 0; small_prime[i] > 0; i++ ) - { - t_int r; - - if( mpi_cmp_int( X, small_prime[i] ) <= 0 ) - return( 0 ); - - MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) ); - - if( r == 0 ) - return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); - } - - /* - * W = |X| - 1 - * R = W >> lsb( W ) - */ - MPI_CHK( mpi_sub_int( &W, X, 1 ) ); - s = mpi_lsb( &W ); - MPI_CHK( mpi_copy( &R, &W ) ); - MPI_CHK( mpi_shift_r( &R, s ) ); - - i = mpi_msb( X ); - /* - * HAC, table 4.4 - */ - n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 : - ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 : - ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 ); - - for( i = 0; i < n; i++ ) - { - /* - * pick a random A, 1 < A < |X| - 1 - */ - MPI_CHK( mpi_grow( &A, X->n ) ); - - p = (unsigned char *) A.p; - for( j = 0; j < A.n * ciL; j++ ) - *p++ = (unsigned char) f_rng( p_rng ); - - j = mpi_msb( &A ) - mpi_msb( &W ); - MPI_CHK( mpi_shift_r( &A, j + 1 ) ); - A.p[0] |= 3; - - /* - * A = A^R mod |X| - */ - MPI_CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) ); - - if( mpi_cmp_mpi( &A, &W ) == 0 || - mpi_cmp_int( &A, 1 ) == 0 ) - continue; - - j = 1; - while( j < s && mpi_cmp_mpi( &A, &W ) != 0 ) - { - /* - * A = A * A mod |X| - */ - MPI_CHK( mpi_mul_mpi( &T, &A, &A ) ); - MPI_CHK( mpi_mod_mpi( &A, &T, X ) ); - - if( mpi_cmp_int( &A, 1 ) == 0 ) - break; - - j++; - } - - /* - * not prime if A != |X| - 1 or A == 1 - */ - if( mpi_cmp_mpi( &A, &W ) != 0 || - mpi_cmp_int( &A, 1 ) == 0 ) - { - ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; - break; - } - } - -cleanup: - - X->s = xs; - - mpi_free( &RR, &A, &T, &R, &W, NULL ); - - return( ret ); -} - -/* - * Prime number generation - */ -int mpi_gen_prime( mpi *X, int nbits, int dh_flag, - int (*f_rng)(void *), void *p_rng ) -{ - int ret, k, n; - unsigned char *p; - mpi Y; - - if( nbits < 3 ) - return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); - - mpi_init( &Y, NULL ); - - n = BITS_TO_LIMBS( nbits ); - - MPI_CHK( mpi_grow( X, n ) ); - MPI_CHK( mpi_lset( X, 0 ) ); - - p = (unsigned char *) X->p; - for( k = 0; k < X->n * ciL; k++ ) - *p++ = (unsigned char) f_rng( p_rng ); - - k = mpi_msb( X ); - if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) ); - if( k > nbits ) MPI_CHK( mpi_shift_r( X, k - nbits ) ); - - X->p[0] |= 3; - - if( dh_flag == 0 ) - { - while( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) != 0 ) - { - if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) - goto cleanup; - - MPI_CHK( mpi_add_int( X, X, 2 ) ); - } - } - else - { - MPI_CHK( mpi_sub_int( &Y, X, 1 ) ); - MPI_CHK( mpi_shift_r( &Y, 1 ) ); - - while( 1 ) - { - if( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) == 0 ) - { - if( ( ret = mpi_is_prime( &Y, f_rng, p_rng ) ) == 0 ) - break; - - if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) - goto cleanup; - } - - if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) - goto cleanup; - - MPI_CHK( mpi_add_int( &Y, X, 1 ) ); - MPI_CHK( mpi_add_int( X, X, 2 ) ); - MPI_CHK( mpi_shift_r( &Y, 1 ) ); - } - } - -cleanup: - - mpi_free( &Y, NULL ); - - return( ret ); -} - -#endif - -#if defined(POLARSSL_SELF_TEST) - -#define GCD_PAIR_COUNT 3 - -static const int gcd_pairs[GCD_PAIR_COUNT][3] = -{ - { 693, 609, 21 }, - { 1764, 868, 28 }, - { 768454923, 542167814, 1 } -}; - -/* - * Checkup routine - */ -int mpi_self_test( int verbose ) -{ - int ret, i; - mpi A, E, N, X, Y, U, V; - - mpi_init( &A, &E, &N, &X, &Y, &U, &V, NULL ); - - MPI_CHK( mpi_read_string( &A, 16, - "EFE021C2645FD1DC586E69184AF4A31E" \ - "D5F53E93B5F123FA41680867BA110131" \ - "944FE7952E2517337780CB0DB80E61AA" \ - "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) ); - - MPI_CHK( mpi_read_string( &E, 16, - "B2E7EFD37075B9F03FF989C7C5051C20" \ - "34D2A323810251127E7BF8625A4F49A5" \ - "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ - "5B5C25763222FEFCCFC38B832366C29E" ) ); - - MPI_CHK( mpi_read_string( &N, 16, - "0066A198186C18C10B2F5ED9B522752A" \ - "9830B69916E535C8F047518A889A43A5" \ - "94B6BED27A168D31D4A52F88925AA8F5" ) ); - - MPI_CHK( mpi_mul_mpi( &X, &A, &N ) ); - - MPI_CHK( mpi_read_string( &U, 16, - "602AB7ECA597A3D6B56FF9829A5E8B85" \ - "9E857EA95A03512E2BAE7391688D264A" \ - "A5663B0341DB9CCFD2C4C5F421FEC814" \ - "8001B72E848A38CAE1C65F78E56ABDEF" \ - "E12D3C039B8A02D6BE593F0BBBDA56F1" \ - "ECF677152EF804370C1A305CAF3B5BF1" \ - "30879B56C61DE584A0F53A2447A51E" ) ); - - if( verbose != 0 ) - printf( " MPI test #1 (mul_mpi): " ); - - if( mpi_cmp_mpi( &X, &U ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n" ); - - MPI_CHK( mpi_div_mpi( &X, &Y, &A, &N ) ); - - MPI_CHK( mpi_read_string( &U, 16, - "256567336059E52CAE22925474705F39A94" ) ); - - MPI_CHK( mpi_read_string( &V, 16, - "6613F26162223DF488E9CD48CC132C7A" \ - "0AC93C701B001B092E4E5B9F73BCD27B" \ - "9EE50D0657C77F374E903CDFA4C642" ) ); - - if( verbose != 0 ) - printf( " MPI test #2 (div_mpi): " ); - - if( mpi_cmp_mpi( &X, &U ) != 0 || - mpi_cmp_mpi( &Y, &V ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n" ); - - MPI_CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) ); - - MPI_CHK( mpi_read_string( &U, 16, - "36E139AEA55215609D2816998ED020BB" \ - "BD96C37890F65171D948E9BC7CBAA4D9" \ - "325D24D6A3C12710F10A09FA08AB87" ) ); - - if( verbose != 0 ) - printf( " MPI test #3 (exp_mod): " ); - - if( mpi_cmp_mpi( &X, &U ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n" ); - - MPI_CHK( mpi_inv_mod( &X, &A, &N ) ); - - MPI_CHK( mpi_read_string( &U, 16, - "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ - "C3DBA76456363A10869622EAC2DD84EC" \ - "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) ); - - if( verbose != 0 ) - printf( " MPI test #4 (inv_mod): " ); - - if( mpi_cmp_mpi( &X, &U ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n" ); - - if( verbose != 0 ) - printf( " MPI test #5 (simple gcd): " ); - - for ( i = 0; i < GCD_PAIR_COUNT; i++) - { - MPI_CHK( mpi_lset( &X, gcd_pairs[i][0] ) ); - MPI_CHK( mpi_lset( &Y, gcd_pairs[i][1] ) ); - - MPI_CHK( mpi_gcd( &A, &X, &Y ) ); - - if( mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 ) - { - if( verbose != 0 ) - printf( "failed at %d\n", i ); - - return( 1 ); - } - } - - if( verbose != 0 ) - printf( "passed\n" ); - -cleanup: - - if( ret != 0 && verbose != 0 ) - printf( "Unexpected error, return code = %08X\n", ret ); - - mpi_free( &V, &U, &Y, &X, &N, &E, &A, NULL ); - - if( verbose != 0 ) - printf( "\n" ); - - return( ret ); -} - -#endif - -#endif diff --git a/ctrtool/polarssl/bignum.h b/ctrtool/polarssl/bignum.h deleted file mode 100644 index 80399a2..0000000 --- a/ctrtool/polarssl/bignum.h +++ /dev/null @@ -1,533 +0,0 @@ -/** - * \file bignum.h - * - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef POLARSSL_BIGNUM_H -#define POLARSSL_BIGNUM_H - -#include - -#define POLARSSL_ERR_MPI_FILE_IO_ERROR 0x0002 -#define POLARSSL_ERR_MPI_BAD_INPUT_DATA 0x0004 -#define POLARSSL_ERR_MPI_INVALID_CHARACTER 0x0006 -#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL 0x0008 -#define POLARSSL_ERR_MPI_NEGATIVE_VALUE 0x000A -#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO 0x000C -#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE 0x000E - -#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup - -/* - * Define the base integer type, architecture-wise - */ -#if defined(POLARSSL_HAVE_INT8) -typedef unsigned char t_int; -typedef unsigned short t_dbl; -#else -#if defined(POLARSSL_HAVE_INT16) -typedef unsigned short t_int; -typedef unsigned long t_dbl; -#else - typedef unsigned long t_int; - #if defined(_MSC_VER) && defined(_M_IX86) - typedef unsigned __int64 t_dbl; - #else - #if defined(__amd64__) || defined(__x86_64__) || \ - defined(__ppc64__) || defined(__powerpc64__) || \ - defined(__ia64__) || defined(__alpha__) - typedef unsigned int t_dbl __attribute__((mode(TI))); - #else - #if defined(POLARSSL_HAVE_LONGLONG) - typedef unsigned long long t_dbl; - #endif - #endif - #endif -#endif -#endif - -/** - * \brief MPI structure - */ -typedef struct -{ - int s; /*!< integer sign */ - int n; /*!< total # of limbs */ - t_int *p; /*!< pointer to limbs */ -} -mpi; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Initialize one or more mpi - */ -void mpi_init( mpi *X, ... ); - -/** - * \brief Unallocate one or more mpi - */ -void mpi_free( mpi *X, ... ); - -/** - * \brief Enlarge to the specified number of limbs - * - * \param X MPI to grow - * \param nblimbs The target number of limbs - * - * \return 0 if successful, - * 1 if memory allocation failed - */ -int mpi_grow( mpi *X, int nblimbs ); - -/** - * \brief Copy the contents of Y into X - * - * \param X Destination MPI - * \param Y Source MPI - * - * \return 0 if successful, - * 1 if memory allocation failed - */ -int mpi_copy( mpi *X, const mpi *Y ); - -/** - * \brief Swap the contents of X and Y - * - * \param X First MPI value - * \param Y Second MPI value - */ -void mpi_swap( mpi *X, mpi *Y ); - -/** - * \brief Set value from integer - * - * \param X MPI to set - * \param z Value to use - * - * \return 0 if successful, - * 1 if memory allocation failed - */ -int mpi_lset( mpi *X, int z ); - -/** - * \brief Return the number of least significant bits - * - * \param X MPI to use - */ -int mpi_lsb( const mpi *X ); - -/** - * \brief Return the number of most significant bits - * - * \param X MPI to use - */ -int mpi_msb( const mpi *X ); - -/** - * \brief Return the total size in bytes - * - * \param X MPI to use - */ -int mpi_size( const mpi *X ); - -/** - * \brief Import from an ASCII string - * - * \param X Destination MPI - * \param radix Input numeric base - * \param s Null-terminated string buffer - * - * \return 0 if successful, or an POLARSSL_ERR_MPI_XXX error code - */ -int mpi_read_string( mpi *X, int radix, const char *s ); - -/** - * \brief Export into an ASCII string - * - * \param X Source MPI - * \param radix Output numeric base - * \param s String buffer - * \param slen String buffer size - * - * \return 0 if successful, or an POLARSSL_ERR_MPI_XXX error code. - * *slen is always updated to reflect the amount - * of data that has (or would have) been written. - * - * \note Call this function with *slen = 0 to obtain the - * minimum required buffer size in *slen. - */ -int mpi_write_string( const mpi *X, int radix, char *s, int *slen ); - -/** - * \brief Read X from an opened file - * - * \param X Destination MPI - * \param radix Input numeric base - * \param fin Input file handle - * - * \return 0 if successful, or an POLARSSL_ERR_MPI_XXX error code - */ -int mpi_read_file( mpi *X, int radix, FILE *fin ); - -/** - * \brief Write X into an opened file, or stdout if fout is NULL - * - * \param p Prefix, can be NULL - * \param X Source MPI - * \param radix Output numeric base - * \param fout Output file handle (can be NULL) - * - * \return 0 if successful, or an POLARSSL_ERR_MPI_XXX error code - * - * \note Set fout == NULL to print X on the console. - */ -int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout ); - -/** - * \brief Import X from unsigned binary data, big endian - * - * \param X Destination MPI - * \param buf Input buffer - * \param buflen Input buffer size - * - * \return 0 if successful, - * 1 if memory allocation failed - */ -int mpi_read_binary( mpi *X, const unsigned char *buf, int buflen ); - -/** - * \brief Export X into unsigned binary data, big endian - * - * \param X Source MPI - * \param buf Output buffer - * \param buflen Output buffer size - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough - */ -int mpi_write_binary( const mpi *X, unsigned char *buf, int buflen ); - -/** - * \brief Left-shift: X <<= count - * - * \param X MPI to shift - * \param count Amount to shift - * - * \return 0 if successful, - * 1 if memory allocation failed - */ -int mpi_shift_l( mpi *X, int count ); - -/** - * \brief Right-shift: X >>= count - * - * \param X MPI to shift - * \param count Amount to shift - * - * \return 0 if successful, - * 1 if memory allocation failed - */ -int mpi_shift_r( mpi *X, int count ); - -/** - * \brief Compare unsigned values - * - * \param X Left-hand MPI - * \param Y Right-hand MPI - * - * \return 1 if |X| is greater than |Y|, - * -1 if |X| is lesser than |Y| or - * 0 if |X| is equal to |Y| - */ -int mpi_cmp_abs( const mpi *X, const mpi *Y ); - -/** - * \brief Compare signed values - * - * \param X Left-hand MPI - * \param Y Right-hand MPI - * - * \return 1 if X is greater than Y, - * -1 if X is lesser than Y or - * 0 if X is equal to Y - */ -int mpi_cmp_mpi( const mpi *X, const mpi *Y ); - -/** - * \brief Compare signed values - * - * \param X Left-hand MPI - * \param z The integer value to compare to - * - * \return 1 if X is greater than z, - * -1 if X is lesser than z or - * 0 if X is equal to z - */ -int mpi_cmp_int( const mpi *X, int z ); - -/** - * \brief Unsigned addition: X = |A| + |B| - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * 1 if memory allocation failed - */ -int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ); - -/** - * \brief Unsigned substraction: X = |A| - |B| - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A - */ -int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ); - -/** - * \brief Signed addition: X = A + B - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * 1 if memory allocation failed - */ -int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ); - -/** - * \brief Signed substraction: X = A - B - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * 1 if memory allocation failed - */ -int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ); - -/** - * \brief Signed addition: X = A + b - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param b The integer value to add - * - * \return 0 if successful, - * 1 if memory allocation failed - */ -int mpi_add_int( mpi *X, const mpi *A, int b ); - -/** - * \brief Signed substraction: X = A - b - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param b The integer value to subtract - * - * \return 0 if successful, - * 1 if memory allocation failed - */ -int mpi_sub_int( mpi *X, const mpi *A, int b ); - -/** - * \brief Baseline multiplication: X = A * B - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * 1 if memory allocation failed - */ -int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ); - -/** - * \brief Baseline multiplication: X = A * b - * Note: b is an unsigned integer type, thus - * Negative values of b are ignored. - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param b The integer value to multiply with - * - * \return 0 if successful, - * 1 if memory allocation failed - */ -int mpi_mul_int( mpi *X, const mpi *A, t_int b ); - -/** - * \brief Division by mpi: A = Q * B + R - * - * \param Q Destination MPI for the quotient - * \param R Destination MPI for the rest value - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * 1 if memory allocation failed, - * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0 - * - * \note Either Q or R can be NULL. - */ -int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ); - -/** - * \brief Division by int: A = Q * b + R - * - * \param Q Destination MPI for the quotient - * \param R Destination MPI for the rest value - * \param A Left-hand MPI - * \param b Integer to divide by - * - * \return 0 if successful, - * 1 if memory allocation failed, - * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0 - * - * \note Either Q or R can be NULL. - */ -int mpi_div_int( mpi *Q, mpi *R, const mpi *A, int b ); - -/** - * \brief Modulo: R = A mod B - * - * \param R Destination MPI for the rest value - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * 1 if memory allocation failed, - * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0, - * POLARSSL_ERR_MPI_NEGATIVE_VALUE if B < 0 - */ -int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B ); - -/** - * \brief Modulo: r = A mod b - * - * \param r Destination t_int - * \param A Left-hand MPI - * \param b Integer to divide by - * - * \return 0 if successful, - * 1 if memory allocation failed, - * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0, - * POLARSSL_ERR_MPI_NEGATIVE_VALUE if b < 0 - */ -int mpi_mod_int( t_int *r, const mpi *A, int b ); - -/** - * \brief Sliding-window exponentiation: X = A^E mod N - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param E Exponent MPI - * \param N Modular MPI - * \param _RR Speed-up MPI used for recalculations - * - * \return 0 if successful, - * 1 if memory allocation failed, - * POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or even - * - * \note _RR is used to avoid re-computing R*R mod N across - * multiple calls, which speeds up things a bit. It can - * be set to NULL if the extra performance is unneeded. - */ -int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ); - -/** - * \brief Greatest common divisor: G = gcd(A, B) - * - * \param G Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * 1 if memory allocation failed - */ -int mpi_gcd( mpi *G, const mpi *A, const mpi *B ); - -/** - * \brief Modular inverse: X = A^-1 mod N - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param N Right-hand MPI - * - * \return 0 if successful, - * 1 if memory allocation failed, - * POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or nil - POLARSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N - */ -int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ); - -/** - * \brief Miller-Rabin primality test - * - * \param X MPI to check - * \param f_rng RNG function - * \param p_rng RNG parameter - * - * \return 0 if successful (probably prime), - * 1 if memory allocation failed, - * POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime - */ -int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng ); - -/** - * \brief Prime number generation - * - * \param X Destination MPI - * \param nbits Required size of X in bits - * \param dh_flag If 1, then (X-1)/2 will be prime too - * \param f_rng RNG function - * \param p_rng RNG parameter - * - * \return 0 if successful (probably prime), - * 1 if memory allocation failed, - * POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3 - */ -int mpi_gen_prime( mpi *X, int nbits, int dh_flag, - int (*f_rng)(void *), void *p_rng ); - -/** - * \brief Checkup routine - * - * \return 0 if successful, or 1 if the test failed - */ -int mpi_self_test( int verbose ); - -#ifdef __cplusplus -} -#endif - -#endif /* bignum.h */ diff --git a/ctrtool/polarssl/bn_mul.h b/ctrtool/polarssl/bn_mul.h deleted file mode 100644 index a73d5fb..0000000 --- a/ctrtool/polarssl/bn_mul.h +++ /dev/null @@ -1,736 +0,0 @@ -/** - * \file bn_mul.h - * - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * Multiply source vector [s] with b, add result - * to destination vector [d] and set carry c. - * - * Currently supports: - * - * . IA-32 (386+) . AMD64 / EM64T - * . IA-32 (SSE2) . Motorola 68000 - * . PowerPC, 32-bit . MicroBlaze - * . PowerPC, 64-bit . TriCore - * . SPARC v8 . ARM v3+ - * . Alpha . MIPS32 - * . C, longlong . C, generic - */ -#ifndef POLARSSL_BN_MUL_H -#define POLARSSL_BN_MUL_H - -#include "polarssl/config.h" - -#if defined(POLARSSL_HAVE_ASM) - -#if defined(__GNUC__) -#if defined(__i386__) - -#define MULADDC_INIT \ - asm( " \ - movl %%ebx, %0; \ - movl %5, %%esi; \ - movl %6, %%edi; \ - movl %7, %%ecx; \ - movl %8, %%ebx; \ - " - -#define MULADDC_CORE \ - " \ - lodsl; \ - mull %%ebx; \ - addl %%ecx, %%eax; \ - adcl $0, %%edx; \ - addl (%%edi), %%eax; \ - adcl $0, %%edx; \ - movl %%edx, %%ecx; \ - stosl; \ - " - -#if defined(POLARSSL_HAVE_SSE2) - -#define MULADDC_HUIT \ - " \ - movd %%ecx, %%mm1; \ - movd %%ebx, %%mm0; \ - movd (%%edi), %%mm3; \ - paddq %%mm3, %%mm1; \ - movd (%%esi), %%mm2; \ - pmuludq %%mm0, %%mm2; \ - movd 4(%%esi), %%mm4; \ - pmuludq %%mm0, %%mm4; \ - movd 8(%%esi), %%mm6; \ - pmuludq %%mm0, %%mm6; \ - movd 12(%%esi), %%mm7; \ - pmuludq %%mm0, %%mm7; \ - paddq %%mm2, %%mm1; \ - movd 4(%%edi), %%mm3; \ - paddq %%mm4, %%mm3; \ - movd 8(%%edi), %%mm5; \ - paddq %%mm6, %%mm5; \ - movd 12(%%edi), %%mm4; \ - paddq %%mm4, %%mm7; \ - movd %%mm1, (%%edi); \ - movd 16(%%esi), %%mm2; \ - pmuludq %%mm0, %%mm2; \ - psrlq $32, %%mm1; \ - movd 20(%%esi), %%mm4; \ - pmuludq %%mm0, %%mm4; \ - paddq %%mm3, %%mm1; \ - movd 24(%%esi), %%mm6; \ - pmuludq %%mm0, %%mm6; \ - movd %%mm1, 4(%%edi); \ - psrlq $32, %%mm1; \ - movd 28(%%esi), %%mm3; \ - pmuludq %%mm0, %%mm3; \ - paddq %%mm5, %%mm1; \ - movd 16(%%edi), %%mm5; \ - paddq %%mm5, %%mm2; \ - movd %%mm1, 8(%%edi); \ - psrlq $32, %%mm1; \ - paddq %%mm7, %%mm1; \ - movd 20(%%edi), %%mm5; \ - paddq %%mm5, %%mm4; \ - movd %%mm1, 12(%%edi); \ - psrlq $32, %%mm1; \ - paddq %%mm2, %%mm1; \ - movd 24(%%edi), %%mm5; \ - paddq %%mm5, %%mm6; \ - movd %%mm1, 16(%%edi); \ - psrlq $32, %%mm1; \ - paddq %%mm4, %%mm1; \ - movd 28(%%edi), %%mm5; \ - paddq %%mm5, %%mm3; \ - movd %%mm1, 20(%%edi); \ - psrlq $32, %%mm1; \ - paddq %%mm6, %%mm1; \ - movd %%mm1, 24(%%edi); \ - psrlq $32, %%mm1; \ - paddq %%mm3, %%mm1; \ - movd %%mm1, 28(%%edi); \ - addl $32, %%edi; \ - addl $32, %%esi; \ - psrlq $32, %%mm1; \ - movd %%mm1, %%ecx; \ - " - -#define MULADDC_STOP \ - " \ - emms; \ - movl %4, %%ebx; \ - movl %%ecx, %1; \ - movl %%edi, %2; \ - movl %%esi, %3; \ - " \ - : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ - : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ - : "eax", "ecx", "edx", "esi", "edi" \ - ); - -#else - -#define MULADDC_STOP \ - " \ - movl %4, %%ebx; \ - movl %%ecx, %1; \ - movl %%edi, %2; \ - movl %%esi, %3; \ - " \ - : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ - : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ - : "eax", "ecx", "edx", "esi", "edi" \ - ); -#endif /* SSE2 */ -#endif /* i386 */ - -#if defined(__amd64__) || defined (__x86_64__) - -#define MULADDC_INIT \ - asm( "movq %0, %%rsi " :: "m" (s)); \ - asm( "movq %0, %%rdi " :: "m" (d)); \ - asm( "movq %0, %%rcx " :: "m" (c)); \ - asm( "movq %0, %%rbx " :: "m" (b)); \ - asm( "xorq %r8, %r8 " ); - -#define MULADDC_CORE \ - asm( "movq (%rsi),%rax " ); \ - asm( "mulq %rbx " ); \ - asm( "addq $8, %rsi " ); \ - asm( "addq %rcx, %rax " ); \ - asm( "movq %r8, %rcx " ); \ - asm( "adcq $0, %rdx " ); \ - asm( "nop " ); \ - asm( "addq %rax, (%rdi) " ); \ - asm( "adcq %rdx, %rcx " ); \ - asm( "addq $8, %rdi " ); - -#define MULADDC_STOP \ - asm( "movq %%rcx, %0 " : "=m" (c)); \ - asm( "movq %%rdi, %0 " : "=m" (d)); \ - asm( "movq %%rsi, %0 " : "=m" (s) :: \ - "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" ); - -#endif /* AMD64 */ - -#if defined(__mc68020__) || defined(__mcpu32__) - -#define MULADDC_INIT \ - asm( "movl %0, %%a2 " :: "m" (s)); \ - asm( "movl %0, %%a3 " :: "m" (d)); \ - asm( "movl %0, %%d3 " :: "m" (c)); \ - asm( "movl %0, %%d2 " :: "m" (b)); \ - asm( "moveq #0, %d0 " ); - -#define MULADDC_CORE \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d4:%d1 " ); \ - asm( "addl %d3, %d1 " ); \ - asm( "addxl %d0, %d4 " ); \ - asm( "moveq #0, %d3 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "addxl %d4, %d3 " ); - -#define MULADDC_STOP \ - asm( "movl %%d3, %0 " : "=m" (c)); \ - asm( "movl %%a3, %0 " : "=m" (d)); \ - asm( "movl %%a2, %0 " : "=m" (s) :: \ - "d0", "d1", "d2", "d3", "d4", "a2", "a3" ); - -#define MULADDC_HUIT \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d4:%d1 " ); \ - asm( "addxl %d3, %d1 " ); \ - asm( "addxl %d0, %d4 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d3:%d1 " ); \ - asm( "addxl %d4, %d1 " ); \ - asm( "addxl %d0, %d3 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d4:%d1 " ); \ - asm( "addxl %d3, %d1 " ); \ - asm( "addxl %d0, %d4 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d3:%d1 " ); \ - asm( "addxl %d4, %d1 " ); \ - asm( "addxl %d0, %d3 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d4:%d1 " ); \ - asm( "addxl %d3, %d1 " ); \ - asm( "addxl %d0, %d4 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d3:%d1 " ); \ - asm( "addxl %d4, %d1 " ); \ - asm( "addxl %d0, %d3 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d4:%d1 " ); \ - asm( "addxl %d3, %d1 " ); \ - asm( "addxl %d0, %d4 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d3:%d1 " ); \ - asm( "addxl %d4, %d1 " ); \ - asm( "addxl %d0, %d3 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "addxl %d0, %d3 " ); - -#endif /* MC68000 */ - -#if defined(__powerpc__) || defined(__ppc__) -#if defined(__powerpc64__) || defined(__ppc64__) - -#if defined(__MACH__) && defined(__APPLE__) - -#define MULADDC_INIT \ - asm( "ld r3, %0 " :: "m" (s)); \ - asm( "ld r4, %0 " :: "m" (d)); \ - asm( "ld r5, %0 " :: "m" (c)); \ - asm( "ld r6, %0 " :: "m" (b)); \ - asm( "addi r3, r3, -8 " ); \ - asm( "addi r4, r4, -8 " ); \ - asm( "addic r5, r5, 0 " ); - -#define MULADDC_CORE \ - asm( "ldu r7, 8(r3) " ); \ - asm( "mulld r8, r7, r6 " ); \ - asm( "mulhdu r9, r7, r6 " ); \ - asm( "adde r8, r8, r5 " ); \ - asm( "ld r7, 8(r4) " ); \ - asm( "addze r5, r9 " ); \ - asm( "addc r8, r8, r7 " ); \ - asm( "stdu r8, 8(r4) " ); - -#define MULADDC_STOP \ - asm( "addze r5, r5 " ); \ - asm( "addi r4, r4, 8 " ); \ - asm( "addi r3, r3, 8 " ); \ - asm( "std r5, %0 " : "=m" (c)); \ - asm( "std r4, %0 " : "=m" (d)); \ - asm( "std r3, %0 " : "=m" (s) :: \ - "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); - -#else - -#define MULADDC_INIT \ - asm( "ld %%r3, %0 " :: "m" (s)); \ - asm( "ld %%r4, %0 " :: "m" (d)); \ - asm( "ld %%r5, %0 " :: "m" (c)); \ - asm( "ld %%r6, %0 " :: "m" (b)); \ - asm( "addi %r3, %r3, -8 " ); \ - asm( "addi %r4, %r4, -8 " ); \ - asm( "addic %r5, %r5, 0 " ); - -#define MULADDC_CORE \ - asm( "ldu %r7, 8(%r3) " ); \ - asm( "mulld %r8, %r7, %r6 " ); \ - asm( "mulhdu %r9, %r7, %r6 " ); \ - asm( "adde %r8, %r8, %r5 " ); \ - asm( "ld %r7, 8(%r4) " ); \ - asm( "addze %r5, %r9 " ); \ - asm( "addc %r8, %r8, %r7 " ); \ - asm( "stdu %r8, 8(%r4) " ); - -#define MULADDC_STOP \ - asm( "addze %r5, %r5 " ); \ - asm( "addi %r4, %r4, 8 " ); \ - asm( "addi %r3, %r3, 8 " ); \ - asm( "std %%r5, %0 " : "=m" (c)); \ - asm( "std %%r4, %0 " : "=m" (d)); \ - asm( "std %%r3, %0 " : "=m" (s) :: \ - "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); - -#endif - -#else /* PPC32 */ - -#if defined(__MACH__) && defined(__APPLE__) - -#define MULADDC_INIT \ - asm( "lwz r3, %0 " :: "m" (s)); \ - asm( "lwz r4, %0 " :: "m" (d)); \ - asm( "lwz r5, %0 " :: "m" (c)); \ - asm( "lwz r6, %0 " :: "m" (b)); \ - asm( "addi r3, r3, -4 " ); \ - asm( "addi r4, r4, -4 " ); \ - asm( "addic r5, r5, 0 " ); - -#define MULADDC_CORE \ - asm( "lwzu r7, 4(r3) " ); \ - asm( "mullw r8, r7, r6 " ); \ - asm( "mulhwu r9, r7, r6 " ); \ - asm( "adde r8, r8, r5 " ); \ - asm( "lwz r7, 4(r4) " ); \ - asm( "addze r5, r9 " ); \ - asm( "addc r8, r8, r7 " ); \ - asm( "stwu r8, 4(r4) " ); - -#define MULADDC_STOP \ - asm( "addze r5, r5 " ); \ - asm( "addi r4, r4, 4 " ); \ - asm( "addi r3, r3, 4 " ); \ - asm( "stw r5, %0 " : "=m" (c)); \ - asm( "stw r4, %0 " : "=m" (d)); \ - asm( "stw r3, %0 " : "=m" (s) :: \ - "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); - -#else - -#define MULADDC_INIT \ - asm( "lwz %%r3, %0 " :: "m" (s)); \ - asm( "lwz %%r4, %0 " :: "m" (d)); \ - asm( "lwz %%r5, %0 " :: "m" (c)); \ - asm( "lwz %%r6, %0 " :: "m" (b)); \ - asm( "addi %r3, %r3, -4 " ); \ - asm( "addi %r4, %r4, -4 " ); \ - asm( "addic %r5, %r5, 0 " ); - -#define MULADDC_CORE \ - asm( "lwzu %r7, 4(%r3) " ); \ - asm( "mullw %r8, %r7, %r6 " ); \ - asm( "mulhwu %r9, %r7, %r6 " ); \ - asm( "adde %r8, %r8, %r5 " ); \ - asm( "lwz %r7, 4(%r4) " ); \ - asm( "addze %r5, %r9 " ); \ - asm( "addc %r8, %r8, %r7 " ); \ - asm( "stwu %r8, 4(%r4) " ); - -#define MULADDC_STOP \ - asm( "addze %r5, %r5 " ); \ - asm( "addi %r4, %r4, 4 " ); \ - asm( "addi %r3, %r3, 4 " ); \ - asm( "stw %%r5, %0 " : "=m" (c)); \ - asm( "stw %%r4, %0 " : "=m" (d)); \ - asm( "stw %%r3, %0 " : "=m" (s) :: \ - "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); - -#endif - -#endif /* PPC32 */ -#endif /* PPC64 */ - -#if defined(__sparc__) - -#define MULADDC_INIT \ - asm( "ld %0, %%o0 " :: "m" (s)); \ - asm( "ld %0, %%o1 " :: "m" (d)); \ - asm( "ld %0, %%o2 " :: "m" (c)); \ - asm( "ld %0, %%o3 " :: "m" (b)); - -#define MULADDC_CORE \ - asm( "ld [%o0], %o4 " ); \ - asm( "inc 4, %o0 " ); \ - asm( "ld [%o1], %o5 " ); \ - asm( "umul %o3, %o4, %o4 " ); \ - asm( "addcc %o4, %o2, %o4 " ); \ - asm( "rd %y, %g1 " ); \ - asm( "addx %g1, 0, %g1 " ); \ - asm( "addcc %o4, %o5, %o4 " ); \ - asm( "st %o4, [%o1] " ); \ - asm( "addx %g1, 0, %o2 " ); \ - asm( "inc 4, %o1 " ); - -#define MULADDC_STOP \ - asm( "st %%o2, %0 " : "=m" (c)); \ - asm( "st %%o1, %0 " : "=m" (d)); \ - asm( "st %%o0, %0 " : "=m" (s) :: \ - "g1", "o0", "o1", "o2", "o3", "o4", "o5" ); - -#endif /* SPARCv8 */ - -#if defined(__microblaze__) || defined(microblaze) - -#define MULADDC_INIT \ - asm( "lwi r3, %0 " :: "m" (s)); \ - asm( "lwi r4, %0 " :: "m" (d)); \ - asm( "lwi r5, %0 " :: "m" (c)); \ - asm( "lwi r6, %0 " :: "m" (b)); \ - asm( "andi r7, r6, 0xffff" ); \ - asm( "bsrli r6, r6, 16 " ); - -#define MULADDC_CORE \ - asm( "lhui r8, r3, 0 " ); \ - asm( "addi r3, r3, 2 " ); \ - asm( "lhui r9, r3, 0 " ); \ - asm( "addi r3, r3, 2 " ); \ - asm( "mul r10, r9, r6 " ); \ - asm( "mul r11, r8, r7 " ); \ - asm( "mul r12, r9, r7 " ); \ - asm( "mul r13, r8, r6 " ); \ - asm( "bsrli r8, r10, 16 " ); \ - asm( "bsrli r9, r11, 16 " ); \ - asm( "add r13, r13, r8 " ); \ - asm( "add r13, r13, r9 " ); \ - asm( "bslli r10, r10, 16 " ); \ - asm( "bslli r11, r11, 16 " ); \ - asm( "add r12, r12, r10 " ); \ - asm( "addc r13, r13, r0 " ); \ - asm( "add r12, r12, r11 " ); \ - asm( "addc r13, r13, r0 " ); \ - asm( "lwi r10, r4, 0 " ); \ - asm( "add r12, r12, r10 " ); \ - asm( "addc r13, r13, r0 " ); \ - asm( "add r12, r12, r5 " ); \ - asm( "addc r5, r13, r0 " ); \ - asm( "swi r12, r4, 0 " ); \ - asm( "addi r4, r4, 4 " ); - -#define MULADDC_STOP \ - asm( "swi r5, %0 " : "=m" (c)); \ - asm( "swi r4, %0 " : "=m" (d)); \ - asm( "swi r3, %0 " : "=m" (s) :: \ - "r3", "r4" , "r5" , "r6" , "r7" , "r8" , \ - "r9", "r10", "r11", "r12", "r13" ); - -#endif /* MicroBlaze */ - -#if defined(__tricore__) - -#define MULADDC_INIT \ - asm( "ld.a %%a2, %0 " :: "m" (s)); \ - asm( "ld.a %%a3, %0 " :: "m" (d)); \ - asm( "ld.w %%d4, %0 " :: "m" (c)); \ - asm( "ld.w %%d1, %0 " :: "m" (b)); \ - asm( "xor %d5, %d5 " ); - -#define MULADDC_CORE \ - asm( "ld.w %d0, [%a2+] " ); \ - asm( "madd.u %e2, %e4, %d0, %d1 " ); \ - asm( "ld.w %d0, [%a3] " ); \ - asm( "addx %d2, %d2, %d0 " ); \ - asm( "addc %d3, %d3, 0 " ); \ - asm( "mov %d4, %d3 " ); \ - asm( "st.w [%a3+], %d2 " ); - -#define MULADDC_STOP \ - asm( "st.w %0, %%d4 " : "=m" (c)); \ - asm( "st.a %0, %%a3 " : "=m" (d)); \ - asm( "st.a %0, %%a2 " : "=m" (s) :: \ - "d0", "d1", "e2", "d4", "a2", "a3" ); - -#endif /* TriCore */ - -#if defined(__arm__) - -#define MULADDC_INIT \ - asm( "ldr r0, %0 " :: "m" (s)); \ - asm( "ldr r1, %0 " :: "m" (d)); \ - asm( "ldr r2, %0 " :: "m" (c)); \ - asm( "ldr r3, %0 " :: "m" (b)); - -#define MULADDC_CORE \ - asm( "ldr r4, [r0], #4 " ); \ - asm( "mov r5, #0 " ); \ - asm( "ldr r6, [r1] " ); \ - asm( "umlal r2, r5, r3, r4 " ); \ - asm( "adds r7, r6, r2 " ); \ - asm( "adc r2, r5, #0 " ); \ - asm( "str r7, [r1], #4 " ); - -#define MULADDC_STOP \ - asm( "str r2, %0 " : "=m" (c)); \ - asm( "str r1, %0 " : "=m" (d)); \ - asm( "str r0, %0 " : "=m" (s) :: \ - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" ); - -#endif /* ARMv3 */ - -#if defined(__alpha__) - -#define MULADDC_INIT \ - asm( "ldq $1, %0 " :: "m" (s)); \ - asm( "ldq $2, %0 " :: "m" (d)); \ - asm( "ldq $3, %0 " :: "m" (c)); \ - asm( "ldq $4, %0 " :: "m" (b)); - -#define MULADDC_CORE \ - asm( "ldq $6, 0($1) " ); \ - asm( "addq $1, 8, $1 " ); \ - asm( "mulq $6, $4, $7 " ); \ - asm( "umulh $6, $4, $6 " ); \ - asm( "addq $7, $3, $7 " ); \ - asm( "cmpult $7, $3, $3 " ); \ - asm( "ldq $5, 0($2) " ); \ - asm( "addq $7, $5, $7 " ); \ - asm( "cmpult $7, $5, $5 " ); \ - asm( "stq $7, 0($2) " ); \ - asm( "addq $2, 8, $2 " ); \ - asm( "addq $6, $3, $3 " ); \ - asm( "addq $5, $3, $3 " ); - -#define MULADDC_STOP \ - asm( "stq $3, %0 " : "=m" (c)); \ - asm( "stq $2, %0 " : "=m" (d)); \ - asm( "stq $1, %0 " : "=m" (s) :: \ - "$1", "$2", "$3", "$4", "$5", "$6", "$7" ); - -#endif /* Alpha */ - -#if defined(__mips__) - -#define MULADDC_INIT \ - asm( "lw $10, %0 " :: "m" (s)); \ - asm( "lw $11, %0 " :: "m" (d)); \ - asm( "lw $12, %0 " :: "m" (c)); \ - asm( "lw $13, %0 " :: "m" (b)); - -#define MULADDC_CORE \ - asm( "lw $14, 0($10) " ); \ - asm( "multu $13, $14 " ); \ - asm( "addi $10, $10, 4 " ); \ - asm( "mflo $14 " ); \ - asm( "mfhi $9 " ); \ - asm( "addu $14, $12, $14 " ); \ - asm( "lw $15, 0($11) " ); \ - asm( "sltu $12, $14, $12 " ); \ - asm( "addu $15, $14, $15 " ); \ - asm( "sltu $14, $15, $14 " ); \ - asm( "addu $12, $12, $9 " ); \ - asm( "sw $15, 0($11) " ); \ - asm( "addu $12, $12, $14 " ); \ - asm( "addi $11, $11, 4 " ); - -#define MULADDC_STOP \ - asm( "sw $12, %0 " : "=m" (c)); \ - asm( "sw $11, %0 " : "=m" (d)); \ - asm( "sw $10, %0 " : "=m" (s) :: \ - "$9", "$10", "$11", "$12", "$13", "$14", "$15" ); - -#endif /* MIPS */ -#endif /* GNUC */ - -#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) - -#define MULADDC_INIT \ - __asm mov esi, s \ - __asm mov edi, d \ - __asm mov ecx, c \ - __asm mov ebx, b - -#define MULADDC_CORE \ - __asm lodsd \ - __asm mul ebx \ - __asm add eax, ecx \ - __asm adc edx, 0 \ - __asm add eax, [edi] \ - __asm adc edx, 0 \ - __asm mov ecx, edx \ - __asm stosd - -#if defined(POLARSSL_HAVE_SSE2) - -#define EMIT __asm _emit - -#define MULADDC_HUIT \ - EMIT 0x0F EMIT 0x6E EMIT 0xC9 \ - EMIT 0x0F EMIT 0x6E EMIT 0xC3 \ - EMIT 0x0F EMIT 0x6E EMIT 0x1F \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ - EMIT 0x0F EMIT 0x6E EMIT 0x16 \ - EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ - EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \ - EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ - EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \ - EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ - EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \ - EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ - EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xDC \ - EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xEE \ - EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \ - EMIT 0x0F EMIT 0xD4 EMIT 0xFC \ - EMIT 0x0F EMIT 0x7E EMIT 0x0F \ - EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \ - EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \ - EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ - EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \ - EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ - EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \ - EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCD \ - EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \ - EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCF \ - EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \ - EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ - EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \ - EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCC \ - EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \ - EMIT 0x0F EMIT 0xD4 EMIT 0xDD \ - EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCE \ - EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ - EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \ - EMIT 0x83 EMIT 0xC7 EMIT 0x20 \ - EMIT 0x83 EMIT 0xC6 EMIT 0x20 \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0x7E EMIT 0xC9 - -#define MULADDC_STOP \ - EMIT 0x0F EMIT 0x77 \ - __asm mov c, ecx \ - __asm mov d, edi \ - __asm mov s, esi \ - -#else - -#define MULADDC_STOP \ - __asm mov c, ecx \ - __asm mov d, edi \ - __asm mov s, esi \ - -#endif /* SSE2 */ -#endif /* MSVC */ - -#endif /* POLARSSL_HAVE_ASM */ - -#if !defined(MULADDC_CORE) -#if defined(POLARSSL_HAVE_LONGLONG) - -#define MULADDC_INIT \ -{ \ - t_dbl r; \ - t_int r0, r1; - -#define MULADDC_CORE \ - r = *(s++) * (t_dbl) b; \ - r0 = r; \ - r1 = r >> biL; \ - r0 += c; r1 += (r0 < c); \ - r0 += *d; r1 += (r0 < *d); \ - c = r1; *(d++) = r0; - -#define MULADDC_STOP \ -} - -#else -#define MULADDC_INIT \ -{ \ - t_int s0, s1, b0, b1; \ - t_int r0, r1, rx, ry; \ - b0 = ( b << biH ) >> biH; \ - b1 = ( b >> biH ); - -#define MULADDC_CORE \ - s0 = ( *s << biH ) >> biH; \ - s1 = ( *s >> biH ); s++; \ - rx = s0 * b1; r0 = s0 * b0; \ - ry = s1 * b0; r1 = s1 * b1; \ - r1 += ( rx >> biH ); \ - r1 += ( ry >> biH ); \ - rx <<= biH; ry <<= biH; \ - r0 += rx; r1 += (r0 < rx); \ - r0 += ry; r1 += (r0 < ry); \ - r0 += c; r1 += (r0 < c); \ - r0 += *d; r1 += (r0 < *d); \ - c = r1; *(d++) = r0; - -#define MULADDC_STOP \ -} - -#endif /* C (generic) */ -#endif /* C (longlong) */ - -#endif /* bn_mul.h */ diff --git a/ctrtool/polarssl/config.h b/ctrtool/polarssl/config.h deleted file mode 100644 index 267e2dd..0000000 --- a/ctrtool/polarssl/config.h +++ /dev/null @@ -1,336 +0,0 @@ -/** - * \file config.h - * - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * This set of compile-time options may be used to enable - * or disable features selectively, and reduce the global - * memory footprint. - */ -#ifndef POLARSSL_CONFIG_H -#define POLARSSL_CONFIG_H - -#ifndef _CRT_SECURE_NO_DEPRECATE -#define _CRT_SECURE_NO_DEPRECATE 1 -#endif - -/* - * Uncomment if native integers are 8-bit wide. - * -#define POLARSSL_HAVE_INT8 - */ - -/* - * Uncomment if native integers are 16-bit wide. - * -#define POLARSSL_HAVE_INT16 - */ - -/* - * Uncomment if the compiler supports long long. - * -#define POLARSSL_HAVE_LONGLONG - */ - -/* - * Uncomment to enable the use of assembly code. - * - * Requires support for asm() in compiler. - * - * Used in: - * library/timing.c - * library/padlock.c - * include/polarssl/bn_mul.h - * - */ -//#define POLARSSL_HAVE_ASM - -/* - * Uncomment if the CPU supports SSE2 (IA-32 specific). - * -#define POLARSSL_HAVE_SSE2 - */ - -/* - * Enable all SSL/TLS debugging messages. - */ -#define POLARSSL_DEBUG_MSG - -/* - * Enable the checkup functions (*_self_test). - */ -//#define POLARSSL_SELF_TEST - -/* - * Enable run-time version information functions - */ -#define POLARSSL_VERSION_C - -/* - * Enable the prime-number generation code. - */ -#define POLARSSL_GENPRIME - -/* - * Uncomment this macro to store the AES tables in ROM. - * -#define POLARSSL_AES_ROM_TABLES - */ - -/* - * Module: library/aes.c - * Caller: library/ssl_tls.c - * - * This module enables the following ciphersuites: - * SSL_RSA_AES_128_SHA - * SSL_RSA_AES_256_SHA - * SSL_EDH_RSA_AES_256_SHA - */ -#define POLARSSL_AES_C - -/* - * Module: library/arc4.c - * Caller: library/ssl_tls.c - * - * This module enables the following ciphersuites: - * SSL_RSA_RC4_128_MD5 - * SSL_RSA_RC4_128_SHA - */ -#define POLARSSL_ARC4_C - -/* - * Module: library/base64.c - * Caller: library/x509parse.c - * - * This module is required for X.509 support. - */ -#define POLARSSL_BASE64_C - -/* - * Module: library/bignum.c - * Caller: library/dhm.c - * library/rsa.c - * library/ssl_tls.c - * library/x509parse.c - * - * This module is required for RSA and DHM support. - */ -#define POLARSSL_BIGNUM_C - -/* - * Module: library/camellia.c - * Caller: library/ssl_tls.c - * - * This module enabled the following cipher suites: - * SSL_RSA_CAMELLIA_128_SHA - * SSL_RSA_CAMELLIA_256_SHA - * SSL_EDH_RSA_CAMELLIA_256_SHA - */ -#define POLARSSL_CAMELLIA_C - -/* - * Module: library/certs.c - * Caller: - * - * This module is used for testing (ssl_client/server). - */ -#define POLARSSL_CERTS_C - -/* - * Module: library/debug.c - * Caller: library/ssl_cli.c - * library/ssl_srv.c - * library/ssl_tls.c - * - * This module provides debugging functions. - */ -#define POLARSSL_DEBUG_C - -/* - * Module: library/des.c - * Caller: library/ssl_tls.c - * - * This module enables the following ciphersuites: - * SSL_RSA_DES_168_SHA - * SSL_EDH_RSA_DES_168_SHA - */ -#define POLARSSL_DES_C - -/* - * Module: library/dhm.c - * Caller: library/ssl_cli.c - * library/ssl_srv.c - * - * This module enables the following ciphersuites: - * SSL_EDH_RSA_DES_168_SHA - * SSL_EDH_RSA_AES_256_SHA - * SSL_EDH_RSA_CAMELLIA_256_SHA - */ -#define POLARSSL_DHM_C - -/* - * Module: library/havege.c - * Caller: - * - * This module enables the HAVEGE random number generator. - */ -#define POLARSSL_HAVEGE_C - -/* - * Module: library/md2.c - * Caller: library/x509parse.c - * - * Uncomment to enable support for (rare) MD2-signed X.509 certs. - * -#define POLARSSL_MD2_C - */ - -/* - * Module: library/md4.c - * Caller: library/x509parse.c - * - * Uncomment to enable support for (rare) MD4-signed X.509 certs. - * -#define POLARSSL_MD4_C - */ - -/* - * Module: library/md5.c - * Caller: library/ssl_tls.c - * library/x509parse.c - * - * This module is required for SSL/TLS and X.509. - */ -#define POLARSSL_MD5_C - -/* - * Module: library/net.c - * Caller: - * - * This module provides TCP/IP networking routines. - */ -#define POLARSSL_NET_C - -/* - * Module: library/padlock.c - * Caller: library/aes.c - * - * This modules adds support for the VIA PadLock on x86. - */ -#define POLARSSL_PADLOCK_C - -/* - * Module: library/rsa.c - * Caller: library/ssl_cli.c - * library/ssl_srv.c - * library/ssl_tls.c - * library/x509.c - * - * This module is required for SSL/TLS and MD5-signed certificates. - */ -#define POLARSSL_RSA_C - -/* - * Module: library/sha1.c - * Caller: library/ssl_cli.c - * library/ssl_srv.c - * library/ssl_tls.c - * library/x509parse.c - * - * This module is required for SSL/TLS and SHA1-signed certificates. - */ -#define POLARSSL_SHA1_C - -/* - * Module: library/sha2.c - * Caller: - * - * This module adds support for SHA-224 and SHA-256. - */ -#define POLARSSL_SHA2_C - -/* - * Module: library/sha4.c - * Caller: - * - * This module adds support for SHA-384 and SHA-512. - */ -#define POLARSSL_SHA4_C - -/* - * Module: library/ssl_cli.c - * Caller: - * - * This module is required for SSL/TLS client support. - */ -#define POLARSSL_SSL_CLI_C - -/* - * Module: library/ssl_srv.c - * Caller: - * - * This module is required for SSL/TLS server support. - */ -#define POLARSSL_SSL_SRV_C - -/* - * Module: library/ssl_tls.c - * Caller: library/ssl_cli.c - * library/ssl_srv.c - * - * This module is required for SSL/TLS. - */ -#define POLARSSL_SSL_TLS_C - -/* - * Module: library/timing.c - * Caller: library/havege.c - * - * This module is used by the HAVEGE random number generator. - */ -#define POLARSSL_TIMING_C - -/* - * Module: library/x509parse.c - * Caller: library/ssl_cli.c - * library/ssl_srv.c - * library/ssl_tls.c - * - * This module is required for X.509 certificate parsing. - */ -#define POLARSSL_X509_PARSE_C - -/* - * Module: library/x509_write.c - * Caller: - * - * This module is required for X.509 certificate writing. - */ -#define POLARSSL_X509_WRITE_C - -/* - * Module: library/xtea.c - * Caller: - */ -#define POLARSSL_XTEA_C - -#endif /* config.h */ diff --git a/ctrtool/polarssl/padlock.h b/ctrtool/polarssl/padlock.h deleted file mode 100644 index 12fa7d3..0000000 --- a/ctrtool/polarssl/padlock.h +++ /dev/null @@ -1,98 +0,0 @@ -/** - * \file padlock.h - * - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef POLARSSL_PADLOCK_H -#define POLARSSL_PADLOCK_H - -#include "polarssl/aes.h" - -#if defined(POLARSSL_HAVE_ASM) && defined(__GNUC__) && defined(__i386__) - -#ifndef POLARSSL_HAVE_X86 -#define POLARSSL_HAVE_X86 -#endif - -#define PADLOCK_RNG 0x000C -#define PADLOCK_ACE 0x00C0 -#define PADLOCK_PHE 0x0C00 -#define PADLOCK_PMM 0x3000 - -#define PADLOCK_ALIGN16(x) (unsigned long *) (16 + ((long) x & ~15)) - -#define POLARSSL_ERR_PADLOCK_DATA_MISALIGNED -0x08E0 - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief PadLock detection routine - * - * \param The feature to detect - * - * \return 1 if CPU has support for the feature, 0 otherwise - */ -int padlock_supports( int feature ); - -/** - * \brief PadLock AES-ECB block en(de)cryption - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param input 16-byte input block - * \param output 16-byte output block - * - * \return 0 if success, 1 if operation failed - */ -int padlock_xcryptecb( aes_context *ctx, - int mode, - const unsigned char input[16], - unsigned char output[16] ); - -/** - * \brief PadLock AES-CBC buffer en(de)cryption - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param length length of the input data - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data - * - * \return 0 if success, 1 if operation failed - */ -int padlock_xcryptcbc( aes_context *ctx, - int mode, - int length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ); - -#ifdef __cplusplus -} -#endif - -#endif /* HAVE_X86 */ - -#endif /* padlock.h */ diff --git a/ctrtool/polarssl/rsa.c b/ctrtool/polarssl/rsa.c deleted file mode 100644 index 77404fc..0000000 --- a/ctrtool/polarssl/rsa.c +++ /dev/null @@ -1,823 +0,0 @@ -/* - * The RSA public-key cryptosystem - * - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * RSA was designed by Ron Rivest, Adi Shamir and Len Adleman. - * - * http://theory.lcs.mit.edu/~rivest/rsapaper.pdf - * http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf - */ - -#include "polarssl/config.h" - -#if defined(POLARSSL_RSA_C) - -#include "polarssl/rsa.h" - -#include -#include -#include - -/* - * Initialize an RSA context - */ -void rsa_init( rsa_context *ctx, - int padding, - int hash_id ) -{ - memset( ctx, 0, sizeof( rsa_context ) ); - - ctx->padding = padding; - ctx->hash_id = hash_id; -} - -#if defined(POLARSSL_GENPRIME) - -/* - * Generate an RSA keypair - */ -int rsa_gen_key( rsa_context *ctx, - int (*f_rng)(void *), - void *p_rng, - int nbits, int exponent ) -{ - int ret; - mpi P1, Q1, H, G; - - if( f_rng == NULL || nbits < 128 || exponent < 3 ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - mpi_init( &P1, &Q1, &H, &G, NULL ); - - /* - * find primes P and Q with Q < P so that: - * GCD( E, (P-1)*(Q-1) ) == 1 - */ - MPI_CHK( mpi_lset( &ctx->E, exponent ) ); - - do - { - MPI_CHK( mpi_gen_prime( &ctx->P, ( nbits + 1 ) >> 1, 0, - f_rng, p_rng ) ); - - MPI_CHK( mpi_gen_prime( &ctx->Q, ( nbits + 1 ) >> 1, 0, - f_rng, p_rng ) ); - - if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 ) - mpi_swap( &ctx->P, &ctx->Q ); - - if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 ) - continue; - - MPI_CHK( mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) ); - if( mpi_msb( &ctx->N ) != nbits ) - continue; - - MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) ); - MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) ); - MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) ); - MPI_CHK( mpi_gcd( &G, &ctx->E, &H ) ); - } - while( mpi_cmp_int( &G, 1 ) != 0 ); - - /* - * D = E^-1 mod ((P-1)*(Q-1)) - * DP = D mod (P - 1) - * DQ = D mod (Q - 1) - * QP = Q^-1 mod P - */ - MPI_CHK( mpi_inv_mod( &ctx->D , &ctx->E, &H ) ); - MPI_CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) ); - MPI_CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) ); - MPI_CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) ); - - ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3; - -cleanup: - - mpi_free( &G, &H, &Q1, &P1, NULL ); - - if( ret != 0 ) - { - rsa_free( ctx ); - return( POLARSSL_ERR_RSA_KEY_GEN_FAILED | ret ); - } - - return( 0 ); -} - -#endif - -/* - * Check a public RSA key - */ -int rsa_check_pubkey( const rsa_context *ctx ) -{ - if( !ctx->N.p || !ctx->E.p ) - return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); - - if( ( ctx->N.p[0] & 1 ) == 0 || - ( ctx->E.p[0] & 1 ) == 0 ) - return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); - - if( mpi_msb( &ctx->N ) < 128 || - mpi_msb( &ctx->N ) > 4096 ) - return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); - - if( mpi_msb( &ctx->E ) < 2 || - mpi_msb( &ctx->E ) > 64 ) - return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); - - return( 0 ); -} - -/* - * Check a private RSA key - */ -int rsa_check_privkey( const rsa_context *ctx ) -{ - int ret; - mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2; - - if( ( ret = rsa_check_pubkey( ctx ) ) != 0 ) - return( ret ); - - if( !ctx->P.p || !ctx->Q.p || !ctx->D.p ) - return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); - - mpi_init( &PQ, &DE, &P1, &Q1, &H, &I, &G, &G2, &L1, &L2, NULL ); - - MPI_CHK( mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) ); - MPI_CHK( mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) ); - MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) ); - MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) ); - MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) ); - MPI_CHK( mpi_gcd( &G, &ctx->E, &H ) ); - - MPI_CHK( mpi_gcd( &G2, &P1, &Q1 ) ); - MPI_CHK( mpi_div_mpi( &L1, &L2, &H, &G2 ) ); - MPI_CHK( mpi_mod_mpi( &I, &DE, &L1 ) ); - - /* - * Check for a valid PKCS1v2 private key - */ - if( mpi_cmp_mpi( &PQ, &ctx->N ) == 0 && - mpi_cmp_int( &L2, 0 ) == 0 && - mpi_cmp_int( &I, 1 ) == 0 && - mpi_cmp_int( &G, 1 ) == 0 ) - { - mpi_free( &G, &I, &H, &Q1, &P1, &DE, &PQ, &G2, &L1, &L2, NULL ); - return( 0 ); - } - - -cleanup: - - mpi_free( &G, &I, &H, &Q1, &P1, &DE, &PQ, &G2, &L1, &L2, NULL ); - return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED | ret ); -} - -/* - * Do an RSA public key operation - */ -int rsa_public( rsa_context *ctx, - const unsigned char *input, - unsigned char *output ) -{ - int ret, olen; - mpi T; - - mpi_init( &T, NULL ); - - MPI_CHK( mpi_read_binary( &T, input, ctx->len ) ); - - if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) - { - mpi_free( &T, NULL ); - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - } - - olen = ctx->len; - MPI_CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); - MPI_CHK( mpi_write_binary( &T, output, olen ) ); - -cleanup: - - mpi_free( &T, NULL ); - - if( ret != 0 ) - return( POLARSSL_ERR_RSA_PUBLIC_FAILED | ret ); - - return( 0 ); -} - -/* - * Do an RSA private key operation - */ -int rsa_private( rsa_context *ctx, - const unsigned char *input, - unsigned char *output ) -{ - int ret, olen; - mpi T, T1, T2; - - mpi_init( &T, &T1, &T2, NULL ); - - MPI_CHK( mpi_read_binary( &T, input, ctx->len ) ); - - if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) - { - mpi_free( &T, NULL ); - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - } - -#if 0 - MPI_CHK( mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) ); -#else - /* - * faster decryption using the CRT - * - * T1 = input ^ dP mod P - * T2 = input ^ dQ mod Q - */ - MPI_CHK( mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) ); - MPI_CHK( mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) ); - - /* - * T = (T1 - T2) * (Q^-1 mod P) mod P - */ - MPI_CHK( mpi_sub_mpi( &T, &T1, &T2 ) ); - MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->QP ) ); - MPI_CHK( mpi_mod_mpi( &T, &T1, &ctx->P ) ); - - /* - * output = T2 + T * Q - */ - MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) ); - MPI_CHK( mpi_add_mpi( &T, &T2, &T1 ) ); -#endif - - olen = ctx->len; - MPI_CHK( mpi_write_binary( &T, output, olen ) ); - -cleanup: - - mpi_free( &T, &T1, &T2, NULL ); - - if( ret != 0 ) - return( POLARSSL_ERR_RSA_PRIVATE_FAILED | ret ); - - return( 0 ); -} - -/* - * Add the message padding, then do an RSA operation - */ -int rsa_pkcs1_encrypt( rsa_context *ctx, - int (*f_rng)(void *), - void *p_rng, - int mode, int ilen, - const unsigned char *input, - unsigned char *output ) -{ - int nb_pad, olen; - unsigned char *p = output; - - olen = ctx->len; - - switch( ctx->padding ) - { - case RSA_PKCS_V15: - - if( ilen < 0 || olen < ilen + 11 || f_rng == NULL ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - nb_pad = olen - 3 - ilen; - - *p++ = 0; - *p++ = RSA_CRYPT; - - while( nb_pad-- > 0 ) - { - int rng_dl = 100; - - do { - *p = (unsigned char) f_rng( p_rng ); - } while( *p == 0 && --rng_dl ); - - // Check if RNG failed to generate data - // - if( rng_dl == 0 ) - return POLARSSL_ERR_RSA_RNG_FAILED; - - p++; - } - *p++ = 0; - memcpy( p, input, ilen ); - break; - - default: - - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - } - - return( ( mode == RSA_PUBLIC ) - ? rsa_public( ctx, output, output ) - : rsa_private( ctx, output, output ) ); -} - -/* - * Do an RSA operation, then remove the message padding - */ -int rsa_pkcs1_decrypt( rsa_context *ctx, - int mode, int *olen, - const unsigned char *input, - unsigned char *output, - int output_max_len) -{ - int ret, ilen; - unsigned char *p; - unsigned char buf[1024]; - - ilen = ctx->len; - - if( ilen < 16 || ilen > (int) sizeof( buf ) ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - ret = ( mode == RSA_PUBLIC ) - ? rsa_public( ctx, input, buf ) - : rsa_private( ctx, input, buf ); - - if( ret != 0 ) - return( ret ); - - p = buf; - - switch( ctx->padding ) - { - case RSA_PKCS_V15: - - if( *p++ != 0 || *p++ != RSA_CRYPT ) - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - - while( *p != 0 ) - { - if( p >= buf + ilen - 1 ) - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - p++; - } - p++; - break; - - default: - - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - } - - if (ilen - (int)(p - buf) > output_max_len) - return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE ); - - *olen = ilen - (int)(p - buf); - memcpy( output, p, *olen ); - - return( 0 ); -} - -/* - * Do an RSA operation to sign the message digest - */ -int rsa_pkcs1_sign( rsa_context *ctx, - int mode, - int hash_id, - int hashlen, - const unsigned char *hash, - unsigned char *sig ) -{ - int nb_pad, olen; - unsigned char *p = sig; - - olen = ctx->len; - - switch( ctx->padding ) - { - case RSA_PKCS_V15: - - switch( hash_id ) - { - case SIG_RSA_RAW: - nb_pad = olen - 3 - hashlen; - break; - - case SIG_RSA_MD2: - case SIG_RSA_MD4: - case SIG_RSA_MD5: - nb_pad = olen - 3 - 34; - break; - - case SIG_RSA_SHA1: - nb_pad = olen - 3 - 35; - break; - - case SIG_RSA_SHA224: - nb_pad = olen - 3 - 47; - break; - - case SIG_RSA_SHA256: - nb_pad = olen - 3 - 51; - break; - - case SIG_RSA_SHA384: - nb_pad = olen - 3 - 67; - break; - - case SIG_RSA_SHA512: - nb_pad = olen - 3 - 83; - break; - - - default: - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - } - - if( nb_pad < 8 ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - *p++ = 0; - *p++ = RSA_SIGN; - memset( p, 0xFF, nb_pad ); - p += nb_pad; - *p++ = 0; - break; - - default: - - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - } - - switch( hash_id ) - { - case SIG_RSA_RAW: - memcpy( p, hash, hashlen ); - break; - - case SIG_RSA_MD2: - memcpy( p, ASN1_HASH_MDX, 18 ); - memcpy( p + 18, hash, 16 ); - p[13] = 2; break; - - case SIG_RSA_MD4: - memcpy( p, ASN1_HASH_MDX, 18 ); - memcpy( p + 18, hash, 16 ); - p[13] = 4; break; - - case SIG_RSA_MD5: - memcpy( p, ASN1_HASH_MDX, 18 ); - memcpy( p + 18, hash, 16 ); - p[13] = 5; break; - - case SIG_RSA_SHA1: - memcpy( p, ASN1_HASH_SHA1, 15 ); - memcpy( p + 15, hash, 20 ); - break; - - case SIG_RSA_SHA224: - memcpy( p, ASN1_HASH_SHA2X, 19 ); - memcpy( p + 19, hash, 28 ); - p[1] += 28; p[14] = 4; p[18] += 28; break; - - case SIG_RSA_SHA256: - memcpy( p, ASN1_HASH_SHA2X, 19 ); - memcpy( p + 19, hash, 32 ); - p[1] += 32; p[14] = 1; p[18] += 32; break; - - case SIG_RSA_SHA384: - memcpy( p, ASN1_HASH_SHA2X, 19 ); - memcpy( p + 19, hash, 48 ); - p[1] += 48; p[14] = 2; p[18] += 48; break; - - case SIG_RSA_SHA512: - memcpy( p, ASN1_HASH_SHA2X, 19 ); - memcpy( p + 19, hash, 64 ); - p[1] += 64; p[14] = 3; p[18] += 64; break; - - default: - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - } - - return( ( mode == RSA_PUBLIC ) - ? rsa_public( ctx, sig, sig ) - : rsa_private( ctx, sig, sig ) ); -} - -/* - * Do an RSA operation and check the message digest - */ -int rsa_pkcs1_verify( rsa_context *ctx, - int mode, - int hash_id, - int hashlen, - const unsigned char *hash, - unsigned char *sig ) -{ - int ret, len, siglen; - unsigned char *p, c; - unsigned char buf[1024]; - - siglen = ctx->len; - - if( siglen < 16 || siglen > (int) sizeof( buf ) ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - ret = ( mode == RSA_PUBLIC ) - ? rsa_public( ctx, sig, buf ) - : rsa_private( ctx, sig, buf ); - - if( ret != 0 ) - return( ret ); - - p = buf; - - switch( ctx->padding ) - { - case RSA_PKCS_V15: - - if( *p++ != 0 || *p++ != RSA_SIGN ) - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - - while( *p != 0 ) - { - if( p >= buf + siglen - 1 || *p != 0xFF ) - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - p++; - } - p++; - break; - - default: - - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - } - - len = siglen - (int)( p - buf ); - - if( len == 34 ) - { - c = p[13]; - p[13] = 0; - - if( memcmp( p, ASN1_HASH_MDX, 18 ) != 0 ) - return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - - if( ( c == 2 && hash_id == SIG_RSA_MD2 ) || - ( c == 4 && hash_id == SIG_RSA_MD4 ) || - ( c == 5 && hash_id == SIG_RSA_MD5 ) ) - { - if( memcmp( p + 18, hash, 16 ) == 0 ) - return( 0 ); - else - return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - } - } - - if( len == 35 && hash_id == SIG_RSA_SHA1 ) - { - if( memcmp( p, ASN1_HASH_SHA1, 15 ) == 0 && - memcmp( p + 15, hash, 20 ) == 0 ) - return( 0 ); - else - return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - } - if( ( len == 19 + 28 && p[14] == 4 && hash_id == SIG_RSA_SHA224 ) || - ( len == 19 + 32 && p[14] == 1 && hash_id == SIG_RSA_SHA256 ) || - ( len == 19 + 48 && p[14] == 2 && hash_id == SIG_RSA_SHA384 ) || - ( len == 19 + 64 && p[14] == 3 && hash_id == SIG_RSA_SHA512 ) ) - { - c = p[1] - 17; - p[1] = 17; - p[14] = 0; - - if( p[18] == c && - memcmp( p, ASN1_HASH_SHA2X, 18 ) == 0 && - memcmp( p + 19, hash, c ) == 0 ) - return( 0 ); - else - return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - } - - if( len == hashlen && hash_id == SIG_RSA_RAW ) - { - if( memcmp( p, hash, hashlen ) == 0 ) - return( 0 ); - else - return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - } - - return( POLARSSL_ERR_RSA_INVALID_PADDING ); -} - -/* - * Free the components of an RSA key - */ -void rsa_free( rsa_context *ctx ) -{ - mpi_free( &ctx->RQ, &ctx->RP, &ctx->RN, - &ctx->QP, &ctx->DQ, &ctx->DP, - &ctx->Q, &ctx->P, &ctx->D, - &ctx->E, &ctx->N, NULL ); -} - -#if defined(POLARSSL_SELF_TEST) - -#include "polarssl/sha1.h" - -/* - * Example RSA-1024 keypair, for test purposes - */ -#define KEY_LEN 128 - -#define RSA_N "9292758453063D803DD603D5E777D788" \ - "8ED1D5BF35786190FA2F23EBC0848AEA" \ - "DDA92CA6C3D80B32C4D109BE0F36D6AE" \ - "7130B9CED7ACDF54CFC7555AC14EEBAB" \ - "93A89813FBF3C4F8066D2D800F7C38A8" \ - "1AE31942917403FF4946B0A83D3D3E05" \ - "EE57C6F5F5606FB5D4BC6CD34EE0801A" \ - "5E94BB77B07507233A0BC7BAC8F90F79" - -#define RSA_E "10001" - -#define RSA_D "24BF6185468786FDD303083D25E64EFC" \ - "66CA472BC44D253102F8B4A9D3BFA750" \ - "91386C0077937FE33FA3252D28855837" \ - "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ - "DF79C5CE07EE72C7F123142198164234" \ - "CABB724CF78B8173B9F880FC86322407" \ - "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ - "071513A1E85B5DFA031F21ECAE91A34D" - -#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ - "2C01CAD19EA484A87EA4377637E75500" \ - "FCB2005C5C7DD6EC4AC023CDA285D796" \ - "C3D9E75E1EFC42488BB4F1D13AC30A57" - -#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \ - "E211C2B9E5DB1ED0BF61D0D9899620F4" \ - "910E4168387E3C30AA1E00C339A79508" \ - "8452DD96A9A5EA5D9DCA68DA636032AF" - -#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \ - "3C94D22288ACD763FD8E5600ED4A702D" \ - "F84198A5F06C2E72236AE490C93F07F8" \ - "3CC559CD27BC2D1CA488811730BB5725" - -#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \ - "D8AAEA56749EA28623272E4F7D0592AF" \ - "7C1F1313CAC9471B5C523BFE592F517B" \ - "407A1BD76C164B93DA2D32A383E58357" - -#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \ - "F38D18D2B2F0E2DD275AA977E2BF4411" \ - "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ - "A74206CEC169D74BF5A8C50D6F48EA08" - -#define PT_LEN 24 -#define RSA_PT "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \ - "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD" - -static int myrand( void *rng_state ) -{ - if( rng_state != NULL ) - rng_state = NULL; - - return( rand() ); -} - -/* - * Checkup routine - */ -int rsa_self_test( int verbose ) -{ - int len; - rsa_context rsa; - unsigned char sha1sum[20]; - unsigned char rsa_plaintext[PT_LEN]; - unsigned char rsa_decrypted[PT_LEN]; - unsigned char rsa_ciphertext[KEY_LEN]; - - rsa_init( &rsa, RSA_PKCS_V15, 0 ); - - rsa.len = KEY_LEN; - mpi_read_string( &rsa.N , 16, RSA_N ); - mpi_read_string( &rsa.E , 16, RSA_E ); - mpi_read_string( &rsa.D , 16, RSA_D ); - mpi_read_string( &rsa.P , 16, RSA_P ); - mpi_read_string( &rsa.Q , 16, RSA_Q ); - mpi_read_string( &rsa.DP, 16, RSA_DP ); - mpi_read_string( &rsa.DQ, 16, RSA_DQ ); - mpi_read_string( &rsa.QP, 16, RSA_QP ); - - if( verbose != 0 ) - printf( " RSA key validation: " ); - - if( rsa_check_pubkey( &rsa ) != 0 || - rsa_check_privkey( &rsa ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n PKCS#1 encryption : " ); - - memcpy( rsa_plaintext, RSA_PT, PT_LEN ); - - if( rsa_pkcs1_encrypt( &rsa, &myrand, NULL, RSA_PUBLIC, PT_LEN, - rsa_plaintext, rsa_ciphertext ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n PKCS#1 decryption : " ); - - if( rsa_pkcs1_decrypt( &rsa, RSA_PRIVATE, &len, - rsa_ciphertext, rsa_decrypted, - sizeof(rsa_decrypted) ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n PKCS#1 data sign : " ); - - sha1( rsa_plaintext, PT_LEN, sha1sum ); - - if( rsa_pkcs1_sign( &rsa, RSA_PRIVATE, SIG_RSA_SHA1, 20, - sha1sum, rsa_ciphertext ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n PKCS#1 sig. verify: " ); - - if( rsa_pkcs1_verify( &rsa, RSA_PUBLIC, SIG_RSA_SHA1, 20, - sha1sum, rsa_ciphertext ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n\n" ); - - rsa_free( &rsa ); - - return( 0 ); -} - -#endif - -#endif diff --git a/ctrtool/polarssl/rsa.h b/ctrtool/polarssl/rsa.h deleted file mode 100644 index 5fae794..0000000 --- a/ctrtool/polarssl/rsa.h +++ /dev/null @@ -1,353 +0,0 @@ -/** - * \file rsa.h - * - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef POLARSSL_RSA_H -#define POLARSSL_RSA_H - -#include "polarssl/bignum.h" - -/* - * RSA Error codes - */ -#define POLARSSL_ERR_RSA_BAD_INPUT_DATA -0x0400 -#define POLARSSL_ERR_RSA_INVALID_PADDING -0x0410 -#define POLARSSL_ERR_RSA_KEY_GEN_FAILED -0x0420 -#define POLARSSL_ERR_RSA_KEY_CHECK_FAILED -0x0430 -#define POLARSSL_ERR_RSA_PUBLIC_FAILED -0x0440 -#define POLARSSL_ERR_RSA_PRIVATE_FAILED -0x0450 -#define POLARSSL_ERR_RSA_VERIFY_FAILED -0x0460 -#define POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE -0x0470 -#define POLARSSL_ERR_RSA_RNG_FAILED -0x0480 - -/* - * PKCS#1 constants - */ -#define SIG_RSA_RAW 0 -#define SIG_RSA_MD2 2 -#define SIG_RSA_MD4 3 -#define SIG_RSA_MD5 4 -#define SIG_RSA_SHA1 5 -#define SIG_RSA_SHA224 14 -#define SIG_RSA_SHA256 11 -#define SIG_RSA_SHA384 12 -#define SIG_RSA_SHA512 13 - -#define RSA_PUBLIC 0 -#define RSA_PRIVATE 1 - -#define RSA_PKCS_V15 0 -#define RSA_PKCS_V21 1 - -#define RSA_SIGN 1 -#define RSA_CRYPT 2 - -#define ASN1_STR_CONSTRUCTED_SEQUENCE "\x30" -#define ASN1_STR_NULL "\x05" -#define ASN1_STR_OID "\x06" -#define ASN1_STR_OCTET_STRING "\x04" - -#define OID_DIGEST_ALG_MDX "\x2A\x86\x48\x86\xF7\x0D\x02\x00" -#define OID_HASH_ALG_SHA1 "\x2b\x0e\x03\x02\x1a" -#define OID_HASH_ALG_SHA2X "\x60\x86\x48\x01\x65\x03\x04\x02\x00" - -#define OID_ISO_MEMBER_BODIES "\x2a" -#define OID_ISO_IDENTIFIED_ORG "\x2b" - -/* - * ISO Member bodies OID parts - */ -#define OID_COUNTRY_US "\x86\x48" -#define OID_RSA_DATA_SECURITY "\x86\xf7\x0d" - -/* - * ISO Identified organization OID parts - */ -#define OID_OIW_SECSIG_SHA1 "\x0e\x03\x02\x1a" - -/* - * DigestInfo ::= SEQUENCE { - * digestAlgorithm DigestAlgorithmIdentifier, - * digest Digest } - * - * DigestAlgorithmIdentifier ::= AlgorithmIdentifier - * - * Digest ::= OCTET STRING - */ -#define ASN1_HASH_MDX \ -( \ - ASN1_STR_CONSTRUCTED_SEQUENCE "\x20" \ - ASN1_STR_CONSTRUCTED_SEQUENCE "\x0C" \ - ASN1_STR_OID "\x08" \ - OID_DIGEST_ALG_MDX \ - ASN1_STR_NULL "\x00" \ - ASN1_STR_OCTET_STRING "\x10" \ -) - -#define ASN1_HASH_SHA1 \ - ASN1_STR_CONSTRUCTED_SEQUENCE "\x21" \ - ASN1_STR_CONSTRUCTED_SEQUENCE "\x09" \ - ASN1_STR_OID "\x05" \ - OID_HASH_ALG_SHA1 \ - ASN1_STR_NULL "\x00" \ - ASN1_STR_OCTET_STRING "\x14" - -#define ASN1_HASH_SHA2X \ - ASN1_STR_CONSTRUCTED_SEQUENCE "\x11" \ - ASN1_STR_CONSTRUCTED_SEQUENCE "\x0d" \ - ASN1_STR_OID "\x09" \ - OID_HASH_ALG_SHA2X \ - ASN1_STR_NULL "\x00" \ - ASN1_STR_OCTET_STRING "\x00" - -/** - * \brief RSA context structure - */ -typedef struct -{ - int ver; /*!< always 0 */ - int len; /*!< size(N) in chars */ - - mpi N; /*!< public modulus */ - mpi E; /*!< public exponent */ - - mpi D; /*!< private exponent */ - mpi P; /*!< 1st prime factor */ - mpi Q; /*!< 2nd prime factor */ - mpi DP; /*!< D % (P - 1) */ - mpi DQ; /*!< D % (Q - 1) */ - mpi QP; /*!< 1 / (Q % P) */ - - mpi RN; /*!< cached R^2 mod N */ - mpi RP; /*!< cached R^2 mod P */ - mpi RQ; /*!< cached R^2 mod Q */ - - int padding; /*!< 1.5 or OAEP/PSS */ - int hash_id; /*!< hash identifier */ -} -rsa_context; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Initialize an RSA context - * - * \param ctx RSA context to be initialized - * \param padding RSA_PKCS_V15 or RSA_PKCS_V21 - * \param hash_id RSA_PKCS_V21 hash identifier - * - * \note The hash_id parameter is actually ignored - * when using RSA_PKCS_V15 padding. - * - * \note Currently, RSA_PKCS_V21 padding - * is not supported. - */ -void rsa_init( rsa_context *ctx, - int padding, - int hash_id); - -/** - * \brief Generate an RSA keypair - * - * \param ctx RSA context that will hold the key - * \param f_rng RNG function - * \param p_rng RNG parameter - * \param nbits size of the public key in bits - * \param exponent public exponent (e.g., 65537) - * - * \note rsa_init() must be called beforehand to setup - * the RSA context. - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - */ -int rsa_gen_key( rsa_context *ctx, - int (*f_rng)(void *), - void *p_rng, - int nbits, int exponent ); - -/** - * \brief Check a public RSA key - * - * \param ctx RSA context to be checked - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - */ -int rsa_check_pubkey( const rsa_context *ctx ); - -/** - * \brief Check a private RSA key - * - * \param ctx RSA context to be checked - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - */ -int rsa_check_privkey( const rsa_context *ctx ); - -/** - * \brief Do an RSA public key operation - * - * \param ctx RSA context - * \param input input buffer - * \param output output buffer - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - * - * \note This function does NOT take care of message - * padding. Also, be sure to set input[0] = 0 or assure that - * input is smaller than N. - * - * \note The input and output buffers must be large - * enough (eg. 128 bytes if RSA-1024 is used). - */ -int rsa_public( rsa_context *ctx, - const unsigned char *input, - unsigned char *output ); - -/** - * \brief Do an RSA private key operation - * - * \param ctx RSA context - * \param input input buffer - * \param output output buffer - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - * - * \note The input and output buffers must be large - * enough (eg. 128 bytes if RSA-1024 is used). - */ -int rsa_private( rsa_context *ctx, - const unsigned char *input, - unsigned char *output ); - -/** - * \brief Add the message padding, then do an RSA operation - * - * \param ctx RSA context - * \param f_rng RNG function - * \param p_rng RNG parameter - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param ilen contains the plaintext length - * \param input buffer holding the data to be encrypted - * \param output buffer that will hold the ciphertext - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - * - * \note The output buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used). - */ -int rsa_pkcs1_encrypt( rsa_context *ctx, - int (*f_rng)(void *), - void *p_rng, - int mode, int ilen, - const unsigned char *input, - unsigned char *output ); - -/** - * \brief Do an RSA operation, then remove the message padding - * - * \param ctx RSA context - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param input buffer holding the encrypted data - * \param output buffer that will hold the plaintext - * \param olen will contain the plaintext length - * \param output_max_len maximum length of the output buffer - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - * - * \note The output buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise - * an error is thrown. - */ -int rsa_pkcs1_decrypt( rsa_context *ctx, - int mode, int *olen, - const unsigned char *input, - unsigned char *output, - int output_max_len ); - -/** - * \brief Do a private RSA to sign a message digest - * - * \param ctx RSA context - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} - * \param hashlen message digest length (for SIG_RSA_RAW only) - * \param hash buffer holding the message digest - * \param sig buffer that will hold the ciphertext - * - * \return 0 if the signing operation was successful, - * or an POLARSSL_ERR_RSA_XXX error code - * - * \note The "sig" buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used). - */ -int rsa_pkcs1_sign( rsa_context *ctx, - int mode, - int hash_id, - int hashlen, - const unsigned char *hash, - unsigned char *sig ); - -/** - * \brief Do a public RSA and check the message digest - * - * \param ctx points to an RSA public key - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} - * \param hashlen message digest length (for SIG_RSA_RAW only) - * \param hash buffer holding the message digest - * \param sig buffer holding the ciphertext - * - * \return 0 if the verify operation was successful, - * or an POLARSSL_ERR_RSA_XXX error code - * - * \note The "sig" buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used). - */ -int rsa_pkcs1_verify( rsa_context *ctx, - int mode, - int hash_id, - int hashlen, - const unsigned char *hash, - unsigned char *sig ); - -/** - * \brief Free the components of an RSA key - * - * \param ctx RSA Context to free - */ -void rsa_free( rsa_context *ctx ); - -/** - * \brief Checkup routine - * - * \return 0 if successful, or 1 if the test failed - */ -int rsa_self_test( int verbose ); - -#ifdef __cplusplus -} -#endif - -#endif /* rsa.h */ diff --git a/ctrtool/polarssl/sha2.c b/ctrtool/polarssl/sha2.c deleted file mode 100644 index dd5ae98..0000000 --- a/ctrtool/polarssl/sha2.c +++ /dev/null @@ -1,702 +0,0 @@ -/* - * FIPS-180-2 compliant SHA-256 implementation - * - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * The SHA-256 Secure Hash Standard was published by NIST in 2002. - * - * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf - */ - -#include "polarssl/config.h" - -#if defined(POLARSSL_SHA2_C) - -#include "polarssl/sha2.h" - -#include -#include - -/* - * 32-bit integer manipulation macros (big endian) - */ -#ifndef GET_ULONG_BE -#define GET_ULONG_BE(n,b,i) \ -{ \ - (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ - | ( (unsigned long) (b)[(i) + 1] << 16 ) \ - | ( (unsigned long) (b)[(i) + 2] << 8 ) \ - | ( (unsigned long) (b)[(i) + 3] ); \ -} -#endif - -#ifndef PUT_ULONG_BE -#define PUT_ULONG_BE(n,b,i) \ -{ \ - (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ - (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ - (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ - (b)[(i) + 3] = (unsigned char) ( (n) ); \ -} -#endif - -/* - * SHA-256 context setup - */ -void sha2_starts( sha2_context *ctx, int is224 ) -{ - ctx->total[0] = 0; - ctx->total[1] = 0; - - if( is224 == 0 ) - { - /* SHA-256 */ - ctx->state[0] = 0x6A09E667; - ctx->state[1] = 0xBB67AE85; - ctx->state[2] = 0x3C6EF372; - ctx->state[3] = 0xA54FF53A; - ctx->state[4] = 0x510E527F; - ctx->state[5] = 0x9B05688C; - ctx->state[6] = 0x1F83D9AB; - ctx->state[7] = 0x5BE0CD19; - } - else - { - /* SHA-224 */ - ctx->state[0] = 0xC1059ED8; - ctx->state[1] = 0x367CD507; - ctx->state[2] = 0x3070DD17; - ctx->state[3] = 0xF70E5939; - ctx->state[4] = 0xFFC00B31; - ctx->state[5] = 0x68581511; - ctx->state[6] = 0x64F98FA7; - ctx->state[7] = 0xBEFA4FA4; - } - - ctx->is224 = is224; -} - -static void sha2_process( sha2_context *ctx, const unsigned char data[64] ) -{ - unsigned long temp1, temp2, W[64]; - unsigned long A, B, C, D, E, F, G, H; - - GET_ULONG_BE( W[ 0], data, 0 ); - GET_ULONG_BE( W[ 1], data, 4 ); - GET_ULONG_BE( W[ 2], data, 8 ); - GET_ULONG_BE( W[ 3], data, 12 ); - GET_ULONG_BE( W[ 4], data, 16 ); - GET_ULONG_BE( W[ 5], data, 20 ); - GET_ULONG_BE( W[ 6], data, 24 ); - GET_ULONG_BE( W[ 7], data, 28 ); - GET_ULONG_BE( W[ 8], data, 32 ); - GET_ULONG_BE( W[ 9], data, 36 ); - GET_ULONG_BE( W[10], data, 40 ); - GET_ULONG_BE( W[11], data, 44 ); - GET_ULONG_BE( W[12], data, 48 ); - GET_ULONG_BE( W[13], data, 52 ); - GET_ULONG_BE( W[14], data, 56 ); - GET_ULONG_BE( W[15], data, 60 ); - -#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) -#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) - -#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) -#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) - -#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) -#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) - -#define F0(x,y,z) ((x & y) | (z & (x | y))) -#define F1(x,y,z) (z ^ (x & (y ^ z))) - -#define R(t) \ -( \ - W[t] = S1(W[t - 2]) + W[t - 7] + \ - S0(W[t - 15]) + W[t - 16] \ -) - -#define P(a,b,c,d,e,f,g,h,x,K) \ -{ \ - temp1 = h + S3(e) + F1(e,f,g) + K + x; \ - temp2 = S2(a) + F0(a,b,c); \ - d += temp1; h = temp1 + temp2; \ -} - - A = ctx->state[0]; - B = ctx->state[1]; - C = ctx->state[2]; - D = ctx->state[3]; - E = ctx->state[4]; - F = ctx->state[5]; - G = ctx->state[6]; - H = ctx->state[7]; - - P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 ); - P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 ); - P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF ); - P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 ); - P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B ); - P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 ); - P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 ); - P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 ); - P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 ); - P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 ); - P( G, H, A, B, C, D, E, F, W[10], 0x243185BE ); - P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 ); - P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 ); - P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE ); - P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 ); - P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 ); - P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 ); - P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 ); - P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 ); - P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC ); - P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F ); - P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA ); - P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC ); - P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA ); - P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 ); - P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D ); - P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 ); - P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 ); - P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 ); - P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 ); - P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 ); - P( B, C, D, E, F, G, H, A, R(31), 0x14292967 ); - P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 ); - P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 ); - P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC ); - P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 ); - P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 ); - P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB ); - P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E ); - P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 ); - P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 ); - P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B ); - P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 ); - P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 ); - P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 ); - P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 ); - P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 ); - P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 ); - P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 ); - P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 ); - P( G, H, A, B, C, D, E, F, R(50), 0x2748774C ); - P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 ); - P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 ); - P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A ); - P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F ); - P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 ); - P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE ); - P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F ); - P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 ); - P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 ); - P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA ); - P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB ); - P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 ); - P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 ); - - ctx->state[0] += A; - ctx->state[1] += B; - ctx->state[2] += C; - ctx->state[3] += D; - ctx->state[4] += E; - ctx->state[5] += F; - ctx->state[6] += G; - ctx->state[7] += H; -} - -/* - * SHA-256 process buffer - */ -void sha2_update( sha2_context *ctx, const unsigned char *input, int ilen ) -{ - int fill; - unsigned long left; - - if( ilen <= 0 ) - return; - - left = ctx->total[0] & 0x3F; - fill = 64 - left; - - ctx->total[0] += ilen; - ctx->total[0] &= 0xFFFFFFFF; - - if( ctx->total[0] < (unsigned long) ilen ) - ctx->total[1]++; - - if( left && ilen >= fill ) - { - memcpy( (void *) (ctx->buffer + left), - (void *) input, fill ); - sha2_process( ctx, ctx->buffer ); - input += fill; - ilen -= fill; - left = 0; - } - - while( ilen >= 64 ) - { - sha2_process( ctx, input ); - input += 64; - ilen -= 64; - } - - if( ilen > 0 ) - { - memcpy( (void *) (ctx->buffer + left), - (void *) input, ilen ); - } -} - -static const unsigned char sha2_padding[64] = -{ - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* - * SHA-256 final digest - */ -void sha2_finish( sha2_context *ctx, unsigned char output[32] ) -{ - unsigned long last, padn; - unsigned long high, low; - unsigned char msglen[8]; - - high = ( ctx->total[0] >> 29 ) - | ( ctx->total[1] << 3 ); - low = ( ctx->total[0] << 3 ); - - PUT_ULONG_BE( high, msglen, 0 ); - PUT_ULONG_BE( low, msglen, 4 ); - - last = ctx->total[0] & 0x3F; - padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); - - sha2_update( ctx, (unsigned char *) sha2_padding, padn ); - sha2_update( ctx, msglen, 8 ); - - PUT_ULONG_BE( ctx->state[0], output, 0 ); - PUT_ULONG_BE( ctx->state[1], output, 4 ); - PUT_ULONG_BE( ctx->state[2], output, 8 ); - PUT_ULONG_BE( ctx->state[3], output, 12 ); - PUT_ULONG_BE( ctx->state[4], output, 16 ); - PUT_ULONG_BE( ctx->state[5], output, 20 ); - PUT_ULONG_BE( ctx->state[6], output, 24 ); - - if( ctx->is224 == 0 ) - PUT_ULONG_BE( ctx->state[7], output, 28 ); -} - -/* - * output = SHA-256( input buffer ) - */ -void sha2( const unsigned char *input, int ilen, - unsigned char output[32], int is224 ) -{ - sha2_context ctx; - - sha2_starts( &ctx, is224 ); - sha2_update( &ctx, input, ilen ); - sha2_finish( &ctx, output ); - - memset( &ctx, 0, sizeof( sha2_context ) ); -} - -/* - * output = SHA-256( file contents ) - */ -int sha2_file( const char *path, unsigned char output[32], int is224 ) -{ - FILE *f; - size_t n; - sha2_context ctx; - unsigned char buf[1024]; - - if( ( f = fopen( path, "rb" ) ) == NULL ) - return( 1 ); - - sha2_starts( &ctx, is224 ); - - while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) - sha2_update( &ctx, buf, (int) n ); - - sha2_finish( &ctx, output ); - - memset( &ctx, 0, sizeof( sha2_context ) ); - - if( ferror( f ) != 0 ) - { - fclose( f ); - return( 2 ); - } - - fclose( f ); - return( 0 ); -} - -/* - * SHA-256 HMAC context setup - */ -void sha2_hmac_starts( sha2_context *ctx, const unsigned char *key, int keylen, - int is224 ) -{ - int i; - unsigned char sum[32]; - - if( keylen > 64 ) - { - sha2( key, keylen, sum, is224 ); - keylen = ( is224 ) ? 28 : 32; - key = sum; - } - - memset( ctx->ipad, 0x36, 64 ); - memset( ctx->opad, 0x5C, 64 ); - - for( i = 0; i < keylen; i++ ) - { - ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); - ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); - } - - sha2_starts( ctx, is224 ); - sha2_update( ctx, ctx->ipad, 64 ); - - memset( sum, 0, sizeof( sum ) ); -} - -/* - * SHA-256 HMAC process buffer - */ -void sha2_hmac_update( sha2_context *ctx, const unsigned char *input, int ilen ) -{ - sha2_update( ctx, input, ilen ); -} - -/* - * SHA-256 HMAC final digest - */ -void sha2_hmac_finish( sha2_context *ctx, unsigned char output[32] ) -{ - int is224, hlen; - unsigned char tmpbuf[32]; - - is224 = ctx->is224; - hlen = ( is224 == 0 ) ? 32 : 28; - - sha2_finish( ctx, tmpbuf ); - sha2_starts( ctx, is224 ); - sha2_update( ctx, ctx->opad, 64 ); - sha2_update( ctx, tmpbuf, hlen ); - sha2_finish( ctx, output ); - - memset( tmpbuf, 0, sizeof( tmpbuf ) ); -} - -/* - * SHA-256 HMAC context reset - */ -void sha2_hmac_reset( sha2_context *ctx ) -{ - sha2_starts( ctx, ctx->is224 ); - sha2_update( ctx, ctx->ipad, 64 ); -} - -/* - * output = HMAC-SHA-256( hmac key, input buffer ) - */ -void sha2_hmac( const unsigned char *key, int keylen, - const unsigned char *input, int ilen, - unsigned char output[32], int is224 ) -{ - sha2_context ctx; - - sha2_hmac_starts( &ctx, key, keylen, is224 ); - sha2_hmac_update( &ctx, input, ilen ); - sha2_hmac_finish( &ctx, output ); - - memset( &ctx, 0, sizeof( sha2_context ) ); -} - -#if defined(POLARSSL_SELF_TEST) -/* - * FIPS-180-2 test vectors - */ -static unsigned char sha2_test_buf[3][57] = -{ - { "abc" }, - { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, - { "" } -}; - -static const int sha2_test_buflen[3] = -{ - 3, 56, 1000 -}; - -static const unsigned char sha2_test_sum[6][32] = -{ - /* - * SHA-224 test vectors - */ - { 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22, - 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3, - 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7, - 0xE3, 0x6C, 0x9D, 0xA7 }, - { 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC, - 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50, - 0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19, - 0x52, 0x52, 0x25, 0x25 }, - { 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8, - 0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B, - 0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE, - 0x4E, 0xE7, 0xAD, 0x67 }, - - /* - * SHA-256 test vectors - */ - { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, - 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23, - 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, - 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD }, - { 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8, - 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39, - 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67, - 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 }, - { 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92, - 0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67, - 0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E, - 0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 } -}; - -/* - * RFC 4231 test vectors - */ -static unsigned char sha2_hmac_test_key[7][26] = -{ - { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" - "\x0B\x0B\x0B\x0B" }, - { "Jefe" }, - { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" - "\xAA\xAA\xAA\xAA" }, - { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10" - "\x11\x12\x13\x14\x15\x16\x17\x18\x19" }, - { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" - "\x0C\x0C\x0C\x0C" }, - { "" }, /* 0xAA 131 times */ - { "" } -}; - -static const int sha2_hmac_test_keylen[7] = -{ - 20, 4, 20, 25, 20, 131, 131 -}; - -static unsigned char sha2_hmac_test_buf[7][153] = -{ - { "Hi There" }, - { "what do ya want for nothing?" }, - { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" - "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" - "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" - "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" - "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" }, - { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" - "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" - "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" - "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" - "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" }, - { "Test With Truncation" }, - { "Test Using Larger Than Block-Size Key - Hash Key First" }, - { "This is a test using a larger than block-size key " - "and a larger than block-size data. The key needs to " - "be hashed before being used by the HMAC algorithm." } -}; - -static const int sha2_hmac_test_buflen[7] = -{ - 8, 28, 50, 50, 20, 54, 152 -}; - -static const unsigned char sha2_hmac_test_sum[14][32] = -{ - /* - * HMAC-SHA-224 test vectors - */ - { 0x89, 0x6F, 0xB1, 0x12, 0x8A, 0xBB, 0xDF, 0x19, - 0x68, 0x32, 0x10, 0x7C, 0xD4, 0x9D, 0xF3, 0x3F, - 0x47, 0xB4, 0xB1, 0x16, 0x99, 0x12, 0xBA, 0x4F, - 0x53, 0x68, 0x4B, 0x22 }, - { 0xA3, 0x0E, 0x01, 0x09, 0x8B, 0xC6, 0xDB, 0xBF, - 0x45, 0x69, 0x0F, 0x3A, 0x7E, 0x9E, 0x6D, 0x0F, - 0x8B, 0xBE, 0xA2, 0xA3, 0x9E, 0x61, 0x48, 0x00, - 0x8F, 0xD0, 0x5E, 0x44 }, - { 0x7F, 0xB3, 0xCB, 0x35, 0x88, 0xC6, 0xC1, 0xF6, - 0xFF, 0xA9, 0x69, 0x4D, 0x7D, 0x6A, 0xD2, 0x64, - 0x93, 0x65, 0xB0, 0xC1, 0xF6, 0x5D, 0x69, 0xD1, - 0xEC, 0x83, 0x33, 0xEA }, - { 0x6C, 0x11, 0x50, 0x68, 0x74, 0x01, 0x3C, 0xAC, - 0x6A, 0x2A, 0xBC, 0x1B, 0xB3, 0x82, 0x62, 0x7C, - 0xEC, 0x6A, 0x90, 0xD8, 0x6E, 0xFC, 0x01, 0x2D, - 0xE7, 0xAF, 0xEC, 0x5A }, - { 0x0E, 0x2A, 0xEA, 0x68, 0xA9, 0x0C, 0x8D, 0x37, - 0xC9, 0x88, 0xBC, 0xDB, 0x9F, 0xCA, 0x6F, 0xA8 }, - { 0x95, 0xE9, 0xA0, 0xDB, 0x96, 0x20, 0x95, 0xAD, - 0xAE, 0xBE, 0x9B, 0x2D, 0x6F, 0x0D, 0xBC, 0xE2, - 0xD4, 0x99, 0xF1, 0x12, 0xF2, 0xD2, 0xB7, 0x27, - 0x3F, 0xA6, 0x87, 0x0E }, - { 0x3A, 0x85, 0x41, 0x66, 0xAC, 0x5D, 0x9F, 0x02, - 0x3F, 0x54, 0xD5, 0x17, 0xD0, 0xB3, 0x9D, 0xBD, - 0x94, 0x67, 0x70, 0xDB, 0x9C, 0x2B, 0x95, 0xC9, - 0xF6, 0xF5, 0x65, 0xD1 }, - - /* - * HMAC-SHA-256 test vectors - */ - { 0xB0, 0x34, 0x4C, 0x61, 0xD8, 0xDB, 0x38, 0x53, - 0x5C, 0xA8, 0xAF, 0xCE, 0xAF, 0x0B, 0xF1, 0x2B, - 0x88, 0x1D, 0xC2, 0x00, 0xC9, 0x83, 0x3D, 0xA7, - 0x26, 0xE9, 0x37, 0x6C, 0x2E, 0x32, 0xCF, 0xF7 }, - { 0x5B, 0xDC, 0xC1, 0x46, 0xBF, 0x60, 0x75, 0x4E, - 0x6A, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xC7, - 0x5A, 0x00, 0x3F, 0x08, 0x9D, 0x27, 0x39, 0x83, - 0x9D, 0xEC, 0x58, 0xB9, 0x64, 0xEC, 0x38, 0x43 }, - { 0x77, 0x3E, 0xA9, 0x1E, 0x36, 0x80, 0x0E, 0x46, - 0x85, 0x4D, 0xB8, 0xEB, 0xD0, 0x91, 0x81, 0xA7, - 0x29, 0x59, 0x09, 0x8B, 0x3E, 0xF8, 0xC1, 0x22, - 0xD9, 0x63, 0x55, 0x14, 0xCE, 0xD5, 0x65, 0xFE }, - { 0x82, 0x55, 0x8A, 0x38, 0x9A, 0x44, 0x3C, 0x0E, - 0xA4, 0xCC, 0x81, 0x98, 0x99, 0xF2, 0x08, 0x3A, - 0x85, 0xF0, 0xFA, 0xA3, 0xE5, 0x78, 0xF8, 0x07, - 0x7A, 0x2E, 0x3F, 0xF4, 0x67, 0x29, 0x66, 0x5B }, - { 0xA3, 0xB6, 0x16, 0x74, 0x73, 0x10, 0x0E, 0xE0, - 0x6E, 0x0C, 0x79, 0x6C, 0x29, 0x55, 0x55, 0x2B }, - { 0x60, 0xE4, 0x31, 0x59, 0x1E, 0xE0, 0xB6, 0x7F, - 0x0D, 0x8A, 0x26, 0xAA, 0xCB, 0xF5, 0xB7, 0x7F, - 0x8E, 0x0B, 0xC6, 0x21, 0x37, 0x28, 0xC5, 0x14, - 0x05, 0x46, 0x04, 0x0F, 0x0E, 0xE3, 0x7F, 0x54 }, - { 0x9B, 0x09, 0xFF, 0xA7, 0x1B, 0x94, 0x2F, 0xCB, - 0x27, 0x63, 0x5F, 0xBC, 0xD5, 0xB0, 0xE9, 0x44, - 0xBF, 0xDC, 0x63, 0x64, 0x4F, 0x07, 0x13, 0x93, - 0x8A, 0x7F, 0x51, 0x53, 0x5C, 0x3A, 0x35, 0xE2 } -}; - -/* - * Checkup routine - */ -int sha2_self_test( int verbose ) -{ - int i, j, k, buflen; - unsigned char buf[1024]; - unsigned char sha2sum[32]; - sha2_context ctx; - - for( i = 0; i < 6; i++ ) - { - j = i % 3; - k = i < 3; - - if( verbose != 0 ) - printf( " SHA-%d test #%d: ", 256 - k * 32, j + 1 ); - - sha2_starts( &ctx, k ); - - if( j == 2 ) - { - memset( buf, 'a', buflen = 1000 ); - - for( j = 0; j < 1000; j++ ) - sha2_update( &ctx, buf, buflen ); - } - else - sha2_update( &ctx, sha2_test_buf[j], - sha2_test_buflen[j] ); - - sha2_finish( &ctx, sha2sum ); - - if( memcmp( sha2sum, sha2_test_sum[i], 32 - k * 4 ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n" ); - } - - if( verbose != 0 ) - printf( "\n" ); - - for( i = 0; i < 14; i++ ) - { - j = i % 7; - k = i < 7; - - if( verbose != 0 ) - printf( " HMAC-SHA-%d test #%d: ", 256 - k * 32, j + 1 ); - - if( j == 5 || j == 6 ) - { - memset( buf, '\xAA', buflen = 131 ); - sha2_hmac_starts( &ctx, buf, buflen, k ); - } - else - sha2_hmac_starts( &ctx, sha2_hmac_test_key[j], - sha2_hmac_test_keylen[j], k ); - - sha2_hmac_update( &ctx, sha2_hmac_test_buf[j], - sha2_hmac_test_buflen[j] ); - - sha2_hmac_finish( &ctx, sha2sum ); - - buflen = ( j == 4 ) ? 16 : 32 - k * 4; - - if( memcmp( sha2sum, sha2_hmac_test_sum[i], buflen ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n" ); - } - - if( verbose != 0 ) - printf( "\n" ); - - return( 0 ); -} - -#endif - -#endif diff --git a/ctrtool/polarssl/sha2.h b/ctrtool/polarssl/sha2.h deleted file mode 100644 index be4ae56..0000000 --- a/ctrtool/polarssl/sha2.h +++ /dev/null @@ -1,155 +0,0 @@ -/** - * \file sha2.h - * - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef POLARSSL_SHA2_H -#define POLARSSL_SHA2_H - -/** - * \brief SHA-256 context structure - */ -typedef struct -{ - unsigned long total[2]; /*!< number of bytes processed */ - unsigned long state[8]; /*!< intermediate digest state */ - unsigned char buffer[64]; /*!< data block being processed */ - - unsigned char ipad[64]; /*!< HMAC: inner padding */ - unsigned char opad[64]; /*!< HMAC: outer padding */ - int is224; /*!< 0 => SHA-256, else SHA-224 */ -} -sha2_context; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief SHA-256 context setup - * - * \param ctx context to be initialized - * \param is224 0 = use SHA256, 1 = use SHA224 - */ -void sha2_starts( sha2_context *ctx, int is224 ); - -/** - * \brief SHA-256 process buffer - * - * \param ctx SHA-256 context - * \param input buffer holding the data - * \param ilen length of the input data - */ -void sha2_update( sha2_context *ctx, const unsigned char *input, int ilen ); - -/** - * \brief SHA-256 final digest - * - * \param ctx SHA-256 context - * \param output SHA-224/256 checksum result - */ -void sha2_finish( sha2_context *ctx, unsigned char output[32] ); - -/** - * \brief Output = SHA-256( input buffer ) - * - * \param input buffer holding the data - * \param ilen length of the input data - * \param output SHA-224/256 checksum result - * \param is224 0 = use SHA256, 1 = use SHA224 - */ -void sha2( const unsigned char *input, int ilen, - unsigned char output[32], int is224 ); - -/** - * \brief Output = SHA-256( file contents ) - * - * \param path input file name - * \param output SHA-224/256 checksum result - * \param is224 0 = use SHA256, 1 = use SHA224 - * - * \return 0 if successful, 1 if fopen failed, - * or 2 if fread failed - */ -int sha2_file( const char *path, unsigned char output[32], int is224 ); - -/** - * \brief SHA-256 HMAC context setup - * - * \param ctx HMAC context to be initialized - * \param key HMAC secret key - * \param keylen length of the HMAC key - * \param is224 0 = use SHA256, 1 = use SHA224 - */ -void sha2_hmac_starts( sha2_context *ctx, const unsigned char *key, int keylen, - int is224 ); - -/** - * \brief SHA-256 HMAC process buffer - * - * \param ctx HMAC context - * \param input buffer holding the data - * \param ilen length of the input data - */ -void sha2_hmac_update( sha2_context *ctx, const unsigned char *input, int ilen ); - -/** - * \brief SHA-256 HMAC final digest - * - * \param ctx HMAC context - * \param output SHA-224/256 HMAC checksum result - */ -void sha2_hmac_finish( sha2_context *ctx, unsigned char output[32] ); - -/** - * \brief SHA-256 HMAC context reset - * - * \param ctx HMAC context to be reset - */ -void sha2_hmac_reset( sha2_context *ctx ); - -/** - * \brief Output = HMAC-SHA-256( hmac key, input buffer ) - * - * \param key HMAC secret key - * \param keylen length of the HMAC key - * \param input buffer holding the data - * \param ilen length of the input data - * \param output HMAC-SHA-224/256 result - * \param is224 0 = use SHA256, 1 = use SHA224 - */ -void sha2_hmac( const unsigned char *key, int keylen, - const unsigned char *input, int ilen, - unsigned char output[32], int is224 ); - -/** - * \brief Checkup routine - * - * \return 0 if successful, or 1 if the test failed - */ -int sha2_self_test( int verbose ); - -#ifdef __cplusplus -} -#endif - -#endif /* sha2.h */ diff --git a/ctrtool/romfs.c b/ctrtool/romfs.c deleted file mode 100644 index 6f00467..0000000 --- a/ctrtool/romfs.c +++ /dev/null @@ -1,406 +0,0 @@ -#include -#include -#include "types.h" -#include "romfs.h" -#include "utils.h" - -void romfs_init(romfs_context* ctx) -{ - memset(ctx, 0, sizeof(romfs_context)); - ivfc_init(&ctx->ivfc); -} - -void romfs_set_file(romfs_context* ctx, FILE* file) -{ - ctx->file = file; -} - -void romfs_set_offset(romfs_context* ctx, u64 offset) -{ - ctx->offset = offset; -} - -void romfs_set_size(romfs_context* ctx, u64 size) -{ - ctx->size = size; -} - -void romfs_set_usersettings(romfs_context* ctx, settings* usersettings) -{ - ctx->usersettings = usersettings; -} - -void romfs_set_encrypted(romfs_context* ctx, u32 encrypted) -{ - ctx->encrypted = encrypted; -} - -void romfs_set_key(romfs_context* ctx, u8 key[16]) -{ - memcpy(ctx->key, key, 16); - ctr_init_key(&ctx->aes, key); -} - -void romfs_set_counter(romfs_context* ctx, u8 counter[16]) -{ - memcpy(ctx->counter, counter, 16); -} - -void romfs_fseek(romfs_context* ctx, u64 offset) -{ - u64 data_pos = offset - ctx->offset; - fseeko64(ctx->file, offset, SEEK_SET); - - if (ctx->encrypted) { - ctr_init_counter(&ctx->aes, ctx->counter); - ctr_add_counter(&ctx->aes, (u32)(data_pos / 0x10)); - } -} - -size_t romfs_fread(romfs_context* ctx, void* buffer, size_t size, size_t count) -{ - size_t read; - if ((read = fread(buffer, size, count, ctx->file)) != count) { - //printf("romfs_fread() fail\n"); - return read; - } - if (ctx->encrypted) { - ctr_crypt_counter(&ctx->aes, buffer, buffer, size*read); - } - return read; -} - -void romfs_process(romfs_context* ctx, u32 actions) -{ - u32 dirblockoffset = 0; - u32 dirblocksize = 0; - u32 fileblockoffset = 0; - u32 fileblocksize = 0; - - ivfc_set_offset(&ctx->ivfc, ctx->offset); - ivfc_set_size(&ctx->ivfc, ctx->size); - ivfc_set_file(&ctx->ivfc, ctx->file); - ivfc_set_usersettings(&ctx->ivfc, ctx->usersettings); - ivfc_set_counter(&ctx->ivfc, ctx->counter); - ivfc_set_key(&ctx->ivfc, ctx->key); - ivfc_set_encrypted(&ctx->ivfc, ctx->encrypted); - ivfc_process(&ctx->ivfc, actions); - - romfs_fseek(ctx, ctx->offset); - romfs_fread(ctx, &ctx->header, 1, sizeof(romfs_header)); - - if (getle32(ctx->header.magic) != MAGIC_IVFC) - { - fprintf(stdout, "Error, RomFS corrupted\n"); - return; - } - - ctx->infoblockoffset = (u32) (ctx->offset + 0x1000); - - romfs_fseek(ctx, ctx->infoblockoffset); - romfs_fread(ctx, &ctx->infoheader, 1, sizeof(romfs_infoheader)); - - if (getle32(ctx->infoheader.headersize) != sizeof(romfs_infoheader)) - { - fprintf(stderr, "Error, info header mismatch\n"); - return; - } - - dirblockoffset = ctx->infoblockoffset + getle32(ctx->infoheader.section[1].offset); - dirblocksize = getle32(ctx->infoheader.section[1].size); - fileblockoffset = ctx->infoblockoffset + getle32(ctx->infoheader.section[3].offset); - fileblocksize = getle32(ctx->infoheader.section[3].size); - - u32 hdrsize = getle32(ctx->infoheader.dataoffset); - u8 *block = malloc(hdrsize); - romfs_fseek(ctx, ctx->infoblockoffset); - romfs_fread(ctx, block, hdrsize, 1); - - ctx->dirblock = malloc(dirblocksize); - ctx->dirblocksize = dirblocksize; - if(ctx->dirblock) - memcpy(ctx->dirblock, block + getle32(ctx->infoheader.section[1].offset), dirblocksize); - - ctx->fileblock = malloc(fileblocksize); - ctx->fileblocksize = fileblocksize; - if (ctx->fileblock) - memcpy(ctx->fileblock, block + getle32(ctx->infoheader.section[3].offset), fileblocksize); - - free(block); - - ctx->datablockoffset = ctx->infoblockoffset + getle32(ctx->infoheader.dataoffset); - - if (actions & InfoFlag) - romfs_print(ctx); - - if (settings_get_romfs_dir_path(ctx->usersettings)->valid) - ctx->extractdir = os_CopyConvertCharStr(settings_get_romfs_dir_path(ctx->usersettings)->pathname); - else - ctx->extractdir = NULL; - - romfs_visit_dir(ctx, 0, 0, actions, ctx->extractdir); - free(ctx->extractdir); -} - -int romfs_dirblock_read(romfs_context* ctx, u32 diroffset, u32 dirsize, void* buffer) -{ - if (!ctx->dirblock) - return 0; - - if (diroffset+dirsize > ctx->dirblocksize) - return 0; - - memcpy(buffer, ctx->dirblock + diroffset, dirsize); - return 1; -} - -int romfs_dirblock_readentry(romfs_context* ctx, u32 diroffset, romfs_direntry* entry) -{ - u32 size_without_name = sizeof(romfs_direntry) - ROMFS_MAXNAMESIZE; - u32 namesize; - - - if (!ctx->dirblock) - return 0; - - if (!romfs_dirblock_read(ctx, diroffset, size_without_name, entry)) - return 0; - - namesize = getle32(entry->namesize); - if (namesize > (ROMFS_MAXNAMESIZE-2)) - namesize = (ROMFS_MAXNAMESIZE-2); - memset(entry->name + namesize, 0, 2); - if (!romfs_dirblock_read(ctx, diroffset + size_without_name, namesize, entry->name)) - return 0; - - return 1; -} - - -int romfs_fileblock_read(romfs_context* ctx, u32 fileoffset, u32 filesize, void* buffer) -{ - if (!ctx->fileblock) - return 0; - - if (fileoffset+filesize > ctx->fileblocksize) - return 0; - - memcpy(buffer, ctx->fileblock + fileoffset, filesize); - return 1; -} - -int romfs_fileblock_readentry(romfs_context* ctx, u32 fileoffset, romfs_fileentry* entry) -{ - u32 size_without_name = sizeof(romfs_fileentry) - ROMFS_MAXNAMESIZE; - u32 namesize; - - - if (!ctx->fileblock) - return 0; - - if (!romfs_fileblock_read(ctx, fileoffset, size_without_name, entry)) - return 0; - - namesize = getle32(entry->namesize); - if (namesize > (ROMFS_MAXNAMESIZE-2)) - namesize = (ROMFS_MAXNAMESIZE-2); - memset(entry->name + namesize, 0, 2); - if (!romfs_fileblock_read(ctx, fileoffset + size_without_name, namesize, entry->name)) - return 0; - - return 1; -} - - - -void romfs_visit_dir(romfs_context* ctx, u32 diroffset, u32 depth, u32 actions, const oschar_t* rootpath) -{ - u32 siblingoffset; - u32 childoffset; - u32 fileoffset; - oschar_t* currentpath; - romfs_direntry* entry = &ctx->direntry; - - - if (!romfs_dirblock_readentry(ctx, diroffset, entry)) - return; - - -// fprintf(stdout, "%08X %08X %08X %08X %08X ", -// getle32(entry->parentoffset), getle32(entry->siblingoffset), getle32(entry->childoffset), -// getle32(entry->fileoffset), getle32(entry->weirdoffset)); -// fwprintf(stdout, L"%ls\n", entry->name); - - - if (rootpath && os_strlen(rootpath)) - { - if (utf16_strlen((const utf16char_t*)entry->name) > 0) - currentpath = os_AppendUTF16StrToPath(rootpath, (const utf16char_t*)entry->name); - else // root dir, use the provided extract path instead of the empty root name. - currentpath = os_CopyStr(rootpath); - - if (currentpath) - { - os_makedir(currentpath); - } - else - { - fputs("Error creating directory in root ", stderr); - os_fputs(rootpath, stderr); - fputs("\n", stderr); - return; - } - } - else - { - currentpath = os_CopyConvertUTF16Str((const utf16char_t*)entry->name); - if (settings_get_list_romfs_files(ctx->usersettings)) - { - u32 i; - - for(i=0; isiblingoffset); - childoffset = getle32(entry->childoffset); - fileoffset = getle32(entry->fileoffset); - - if (fileoffset != (~0)) - romfs_visit_file(ctx, fileoffset, depth+1, actions, currentpath); - - if (childoffset != (~0)) - romfs_visit_dir(ctx, childoffset, depth+1, actions, currentpath); - - if (siblingoffset != (~0)) - romfs_visit_dir(ctx, siblingoffset, depth, actions, rootpath); - - free(currentpath); -} - - -void romfs_visit_file(romfs_context* ctx, u32 fileoffset, u32 depth, u32 actions, const oschar_t* rootpath) -{ - u32 siblingoffset = 0; - oschar_t* currentpath = NULL; - romfs_fileentry* entry = &ctx->fileentry; - - - if (!romfs_fileblock_readentry(ctx, fileoffset, entry)) - return; - - -// fprintf(stdout, "%08X %08X %016llX %016llX %08X ", -// getle32(entry->parentdiroffset), getle32(entry->siblingoffset), ctx->datablockoffset+getle64(entry->dataoffset), -// getle64(entry->datasize), getle32(entry->unknown)); -// fwprintf(stdout, L"%ls\n", entry->name); - - if (rootpath && os_strlen(rootpath)) - { - currentpath = os_AppendUTF16StrToPath(rootpath, (const utf16char_t*)entry->name); - if (currentpath) - { - fputs("Saving ", stdout); - os_fputs(currentpath, stdout); - fputs("...\n", stdout); - romfs_extract_datafile(ctx, getle64(entry->dataoffset), getle64(entry->datasize), currentpath); - } - else - { - fputs("Error creating file in root ", stderr); - os_fputs(rootpath, stderr); - fputs("\n", stderr); - return; - } - } - else - { - currentpath = os_CopyConvertUTF16Str((const utf16char_t*)entry->name); - if (settings_get_list_romfs_files(ctx->usersettings)) - { - u32 i; - - for(i=0; isiblingoffset); - - if (siblingoffset != (~0)) - romfs_visit_file(ctx, siblingoffset, depth, actions, rootpath); - - free(currentpath); -} - -void romfs_extract_datafile(romfs_context* ctx, u64 offset, u64 size, const oschar_t* path) -{ - FILE* outfile = 0; - u32 max; - u8 buffer[4096]; - - - if (path == NULL || os_strlen(path) == 0) - goto clean; - - offset += ctx->datablockoffset; - - romfs_fseek(ctx, offset); - outfile = os_fopen(path, OS_MODE_WRITE); - if (outfile == NULL) - { - fprintf(stderr, "Error opening file for writing\n"); - goto clean; - } - - while(size) - { - max = sizeof(buffer); - if (max > size) - max = (u32) size; - - if (max != romfs_fread(ctx, buffer, 1, max)) - { - fprintf(stderr, "Error reading file\n"); - goto clean; - } - - if (max != fwrite(buffer, 1, max, outfile)) - { - fprintf(stderr, "Error writing file\n"); - goto clean; - } - - size -= max; - } -clean: - if (outfile) - fclose(outfile); -} - - -void romfs_print(romfs_context* ctx) -{ - u32 i; - - fprintf(stdout, "\nRomFS:\n"); - - fprintf(stdout, "Header size: 0x%08X\n", getle32(ctx->infoheader.headersize)); - for(i=0; i<4; i++) - { - fprintf(stdout, "Section %d offset: 0x%08"PRIX64"\n", i, ctx->offset + 0x1000 + getle32(ctx->infoheader.section[i].offset)); - fprintf(stdout, "Section %d size: 0x%08X\n", i, getle32(ctx->infoheader.section[i].size)); - } - - fprintf(stdout, "Data offset: 0x%08"PRIX64"\n", ctx->offset + 0x1000 + getle32(ctx->infoheader.dataoffset)); -} diff --git a/ctrtool/romfs.h b/ctrtool/romfs.h deleted file mode 100644 index 7706be5..0000000 --- a/ctrtool/romfs.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef __ROMFS_H__ -#define __ROMFS_H__ - -#include "types.h" -#include "info.h" -#include "ctr.h" -#include "oschar.h" -#include "settings.h" -#include "ivfc.h" - -#define ROMFS_MAXNAMESIZE 254 // limit set by ctrtool - -typedef struct -{ - u8 magic[4]; -} romfs_header; - -typedef struct -{ - u8 offset[4]; - u8 size[4]; -} romfs_sectionheader; - -typedef struct -{ - u8 headersize[4]; - romfs_sectionheader section[4]; - u8 dataoffset[4]; -} romfs_infoheader; - - -typedef struct -{ - u8 parentoffset[4]; - u8 siblingoffset[4]; - u8 childoffset[4]; - u8 fileoffset[4]; - u8 weirdoffset[4]; // this one is weird. it always points to a dir entry, but seems unrelated to the romfs structure. - u8 namesize[4]; - u8 name[ROMFS_MAXNAMESIZE]; -} romfs_direntry; - -typedef struct -{ - u8 parentdiroffset[4]; - u8 siblingoffset[4]; - u8 dataoffset[8]; - u8 datasize[8]; - u8 weirdoffset[4]; // this one is also weird. it always points to a file entry, but seems unrelated to the romfs structure. - u8 namesize[4]; - u8 name[ROMFS_MAXNAMESIZE]; -} romfs_fileentry; - - -typedef struct -{ - FILE* file; - oschar_t* extractdir; - settings* usersettings; - u8 counter[16]; - u8 key[16]; - u64 offset; - u64 size; - romfs_header header; - romfs_infoheader infoheader; - u8* dirblock; - u32 dirblocksize; - u8* fileblock; - u32 fileblocksize; - u32 datablockoffset; - u32 infoblockoffset; - romfs_direntry direntry; - romfs_fileentry fileentry; - ivfc_context ivfc; - ctr_aes_context aes; - int encrypted; -} romfs_context; - -void romfs_init(romfs_context* ctx); -void romfs_set_file(romfs_context* ctx, FILE* file); -void romfs_set_offset(romfs_context* ctx, u64 offset); -void romfs_set_size(romfs_context* ctx, u64 size); -void romfs_set_usersettings(romfs_context* ctx, settings* usersettings); -void romfs_set_encrypted(romfs_context* ctx, u32 encrypted); -void romfs_set_key(romfs_context* ctx, u8 key[16]); -void romfs_set_counter(romfs_context* ctx, u8 counter[16]); -void romfs_fseek(romfs_context* ctx, u64 offset); -size_t romfs_fread(romfs_context* ctx, void* buffer, size_t size, size_t count); -int romfs_dirblock_read(romfs_context* ctx, u32 diroffset, u32 dirsize, void* buffer); -int romfs_dirblock_readentry(romfs_context* ctx, u32 diroffset, romfs_direntry* entry); -int romfs_fileblock_read(romfs_context* ctx, u32 fileoffset, u32 filesize, void* buffer); -int romfs_fileblock_readentry(romfs_context* ctx, u32 fileoffset, romfs_fileentry* entry); -void romfs_visit_dir(romfs_context* ctx, u32 diroffset, u32 depth, u32 actions, const oschar_t* rootpath); -void romfs_visit_file(romfs_context* ctx, u32 fileoffset, u32 depth, u32 actions, const oschar_t* rootpath); -void romfs_extract_datafile(romfs_context* ctx, u64 offset, u64 size, const oschar_t* path); -void romfs_process(romfs_context* ctx, u32 actions); -void romfs_print(romfs_context* ctx); - -#endif // __ROMFS_H__ diff --git a/ctrtool/settings.c b/ctrtool/settings.c deleted file mode 100644 index 9fbf056..0000000 --- a/ctrtool/settings.c +++ /dev/null @@ -1,314 +0,0 @@ -#include -#include -#include "settings.h" - -void settings_init(settings* usersettings) -{ - memset(usersettings, 0, sizeof(settings)); -} - -filepath* settings_get_wav_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->wavpath; - else - return 0; -} - -filepath* settings_get_lzss_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->lzsspath; - else - return 0; -} - -filepath* settings_get_exefs_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->exefspath; - else - return 0; -} - -filepath* settings_get_romfs_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->romfspath; - else - return 0; -} - -filepath* settings_get_exheader_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->exheaderpath; - else - return 0; -} - -filepath* settings_get_logo_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->logopath; - else - return 0; -} - -filepath* settings_get_exefs_dir_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->exefsdirpath; - else - return 0; -} - -filepath* settings_get_romfs_dir_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->romfsdirpath; - else - return 0; -} - -filepath* settings_get_firm_dir_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->firmdirpath; - else - return 0; -} - - -filepath* settings_get_certs_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->certspath; - else - return 0; -} - -filepath* settings_get_tik_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->tikpath; - else - return 0; -} - -filepath* settings_get_tmd_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->tmdpath; - else - return 0; -} - -filepath* settings_get_content_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->contentpath; - else - return 0; -} - -filepath* settings_get_meta_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->metapath; - else - return 0; -} - -filepath* settings_get_plainrgn_path(settings* usersettings) -{ - if (usersettings) - return &usersettings->plainrgnpath; - else - return 0; -} - -unsigned int settings_get_mediaunit_size(settings* usersettings) -{ - if (usersettings) - return usersettings->mediaunitsize; - else - return 0; -} - -#define GETKEY(s, k) do {\ - if ((s) && (s)->keys.k.valid)\ - return (s)->keys.k.data;\ - else\ - return NULL;\ -} while (0) - -unsigned char* settings_get_ncch_fixedsystemkey(settings* usersettings) -{ - GETKEY(usersettings, ncchfixedsystemkey); -} - -unsigned char* settings_get_ncchkeyX_old(settings* usersettings) -{ - GETKEY(usersettings, ncchkeyX_old); -} - -unsigned char* settings_get_ncchkeyX_seven(settings* usersettings) -{ - GETKEY(usersettings, ncchkeyX_seven); -} - -unsigned char* settings_get_ncchkeyX_ninethree(settings* usersettings) -{ - GETKEY(usersettings, ncchkeyX_ninethree); -} - -unsigned char* settings_get_ncchkeyX_ninesix(settings* usersettings) -{ - GETKEY(usersettings, ncchkeyX_ninesix); -} - -unsigned char* settings_get_common_key(settings* usersettings, u8 index) -{ - if (index > (COMMONKEY_NUM - 1)) return NULL; - GETKEY(usersettings, commonkey[index]); -} - -unsigned char* settings_get_seed(settings* usersettings, u64 title_id) -{ - for (u32 i = 0; i < usersettings->keys.seed_num; i++) - { - if (title_id == getle64(usersettings->keys.seed_db[i].title_id)) - { - return usersettings->keys.seed_db[i].seed; - } - } - GETKEY(usersettings, seed_fallback); -} - -unsigned char* settings_get_title_key(settings* usersettings) -{ - GETKEY(usersettings, titlekey); -} - -#undef GETKEY - -int settings_get_ignore_programid(settings* usersettings) -{ - if (usersettings) - return usersettings->ignoreprogramid; - else - return 0; -} - -int settings_get_list_romfs_files(settings* usersettings) -{ - if (usersettings) - return usersettings->listromfs; - else - return 0; -} - -int settings_get_cwav_loopcount(settings* usersettings) -{ - if (usersettings) - return usersettings->cwavloopcount; - else - return 0; -} - -void settings_set_wav_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->wavpath, path); -} - -void settings_set_lzss_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->lzsspath, path); -} - -void settings_set_exefs_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->exefspath, path); -} - -void settings_set_romfs_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->romfspath, path); -} - -void settings_set_firm_dir_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->firmdirpath, path); -} - - -void settings_set_exheader_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->exheaderpath, path); -} - -void settings_set_logo_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->logopath, path); -} - -void settings_set_certs_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->certspath, path); -} - -void settings_set_tik_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->tikpath, path); -} - -void settings_set_tmd_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->tmdpath, path); -} - -void settings_set_content_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->contentpath, path); -} - -void settings_set_meta_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->metapath, path); -} - -void settings_set_exefs_dir_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->exefsdirpath, path); -} - -void settings_set_romfs_dir_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->romfsdirpath, path); -} - -void settings_set_plainrgn_path(settings* usersettings, const char* path) -{ - filepath_set(&usersettings->plainrgnpath, path); -} - -void settings_set_mediaunit_size(settings* usersettings, unsigned int size) -{ - usersettings->mediaunitsize = size; -} - -void settings_set_ignore_programid(settings* usersettings, int enable) -{ - usersettings->ignoreprogramid = enable; -} - -void settings_set_list_romfs_files(settings* usersettings, int enable) -{ - usersettings->listromfs = enable; -} - -void settings_set_cwav_loopcount(settings* usersettings, u32 loopcount) -{ - usersettings->cwavloopcount = loopcount; -} diff --git a/ctrtool/settings.h b/ctrtool/settings.h deleted file mode 100644 index e634eaa..0000000 --- a/ctrtool/settings.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef _SETTINGS_H_ -#define _SETTINGS_H_ - -#include "types.h" -#include "keyset.h" -#include "filepath.h" - -typedef struct -{ - keyset keys; - filepath exefspath; - filepath exefsdirpath; - filepath firmdirpath; - filepath romfspath; - filepath romfsdirpath; - filepath exheaderpath; - filepath logopath; - filepath plainrgnpath; - filepath certspath; - filepath contentpath; - filepath tikpath; - filepath tmdpath; - filepath metapath; - filepath lzsspath; - filepath wavpath; - unsigned int mediaunitsize; - int ignoreprogramid; - int listromfs; - u32 cwavloopcount; -} settings; - -void settings_init(settings* usersettings); -filepath* settings_get_lzss_path(settings* usersettings); -filepath* settings_get_exefs_path(settings* usersettings); -filepath* settings_get_romfs_path(settings* usersettings); -filepath* settings_get_exheader_path(settings* usersettings); -filepath* settings_get_logo_path(settings* usersettings); -filepath* settings_get_certs_path(settings* usersettings); -filepath* settings_get_tik_path(settings* usersettings); -filepath* settings_get_tmd_path(settings* usersettings); -filepath* settings_get_content_path(settings* usersettings); -filepath* settings_get_meta_path(settings* usersettings); -filepath* settings_get_exefs_dir_path(settings* usersettings); -filepath* settings_get_romfs_dir_path(settings* usersettings); -filepath* settings_get_firm_dir_path(settings* usersettings); -filepath* settings_get_wav_path(settings* usersettings); -filepath* settings_get_plainrgn_path(settings* usersettings); -unsigned int settings_get_mediaunit_size(settings* usersettings); -unsigned char* settings_get_ncch_fixedsystemkey(settings* usersettings); -unsigned char* settings_get_ncchkeyX_old(settings* usersettings); -unsigned char* settings_get_ncchkeyX_seven(settings* usersettings); -unsigned char* settings_get_ncchkeyX_ninethree(settings* usersettings); -unsigned char* settings_get_ncchkeyX_ninesix(settings* usersettings); -unsigned char* settings_get_common_key(settings* usersettings, u8 index); -unsigned char* settings_get_seed(settings* usersettings, u64 title_id); -unsigned char* settings_get_title_key(settings* usersettings); -int settings_get_ignore_programid(settings* usersettings); -int settings_get_list_romfs_files(settings* usersettings); -int settings_get_cwav_loopcount(settings* usersettings); - -void settings_set_lzss_path(settings* usersettings, const char* path); -void settings_set_exefs_path(settings* usersettings, const char* path); -void settings_set_romfs_path(settings* usersettings, const char* path); -void settings_set_exheader_path(settings* usersettings, const char* path); -void settings_set_logo_path(settings* usersettings, const char* path); -void settings_set_certs_path(settings* usersettings, const char* path); -void settings_set_tik_path(settings* usersettings, const char* path); -void settings_set_tmd_path(settings* usersettings, const char* path); -void settings_set_content_path(settings* usersettings, const char* path); -void settings_set_meta_path(settings* usersettings, const char* path); -void settings_set_exefs_dir_path(settings* usersettings, const char* path); -void settings_set_romfs_dir_path(settings* usersettings, const char* path); -void settings_set_firm_dir_path(settings* usersettings, const char* path); -void settings_set_wav_path(settings* usersettings, const char* path); -void settings_set_plainrgn_path(settings* usersettings, const char* path); -void settings_set_mediaunit_size(settings* usersettings, unsigned int size); -void settings_set_ignore_programid(settings* usersettings, int enable); -void settings_set_list_romfs_files(settings* usersettings, int enable); -void settings_set_cwav_loopcount(settings* usersettings, u32 loopcount); - -#endif // _SETTINGS_H_ diff --git a/ctrtool/stream.c b/ctrtool/stream.c deleted file mode 100644 index dfb1ac6..0000000 --- a/ctrtool/stream.c +++ /dev/null @@ -1,138 +0,0 @@ -#include -#include -#include - - -#include "types.h" -#include "stream.h" - - -void stream_in_init(stream_in_context* ctx) -{ - memset(ctx, 0, sizeof(stream_in_context)); -} - -void stream_out_init(stream_out_context* ctx) -{ - memset(ctx, 0, sizeof(stream_out_context)); -} - -void stream_in_allocate(stream_in_context* ctx, u32 buffersize, FILE* file) -{ - ctx->inbuffer = malloc(buffersize); - ctx->inbuffersize = buffersize; - ctx->infile = file; - ctx->infileposition = 0; -} - -void stream_out_allocate(stream_out_context* ctx, u32 buffersize, FILE* file) -{ - ctx->outbuffer = malloc(buffersize); - ctx->outbuffersize = buffersize; - ctx->outfile = file; -} - -void stream_in_destroy(stream_in_context* ctx) -{ - free(ctx->inbuffer); - ctx->inbuffer = 0; -} - -void stream_out_destroy(stream_out_context* ctx) -{ - free(ctx->outbuffer); - ctx->outbuffer = 0; -} - -int stream_in_byte(stream_in_context* ctx, u8* byte) -{ - if (ctx->inbufferpos >= ctx->inbufferavailable) - { - size_t readbytes = fread(ctx->inbuffer, 1, ctx->inbuffersize, ctx->infile); - if (readbytes <= 0) - return 0; - - ctx->inbufferavailable = readbytes; - ctx->inbufferpos = 0; - ctx->infileposition += readbytes; - } - - *byte = ctx->inbuffer[ctx->inbufferpos++]; - return 1; -} - -void stream_in_seek(stream_in_context* ctx, u32 position) -{ - fseek(ctx->infile, position, SEEK_SET); - ctx->infileposition = position; - ctx->inbufferpos = 0; - ctx->inbufferavailable = 0; -} - -void stream_in_reseek(stream_in_context* ctx) -{ - fseek(ctx->infile, ctx->infileposition, SEEK_SET); -} - - -void stream_out_seek(stream_out_context* ctx, u32 position) -{ - stream_out_flush(ctx); - - fseek(ctx->outfile, position, SEEK_SET); -} - -void stream_out_skip(stream_out_context* ctx, u32 size) -{ - stream_out_flush(ctx); - - fseek(ctx->outfile, size, SEEK_CUR); -} - -int stream_out_byte(stream_out_context* ctx, u8 byte) -{ - if (ctx->outbufferpos >= ctx->outbuffersize) - { - if (stream_out_flush(ctx) == 0) - return 0; - } - - ctx->outbuffer[ctx->outbufferpos++] = byte; - return 1; -} - -int stream_out_buffer(stream_out_context* ctx, const void* buffer, u32 size) -{ - u32 i; - - for(i=0; ioutbufferpos > 0) - { - size_t writtenbytes = fwrite(ctx->outbuffer, 1, ctx->outbufferpos, ctx->outfile); - if (writtenbytes == 0) // will be zero if nothing is written - return 0; - - - ctx->outbufferpos = 0; - } - return 1; -} - -void stream_out_position(stream_out_context* ctx, u32* position) -{ - stream_out_flush(ctx); - - *position = ftell(ctx->outfile); -} - - diff --git a/ctrtool/stream.h b/ctrtool/stream.h deleted file mode 100644 index df5bcbc..0000000 --- a/ctrtool/stream.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __STREAM_H__ -#define __STREAM_H__ - -#include -#include "types.h" - -typedef struct -{ - FILE* infile; - u32 infileposition; - u8* inbuffer; - u32 inbuffersize; - u32 inbufferavailable; - u32 inbufferpos; -} stream_in_context; - -typedef struct -{ - FILE* outfile; - u8* outbuffer; - u32 outbuffersize; - u32 outbufferpos; -} stream_out_context; - -// create/destroy -void stream_in_init(stream_in_context* ctx); -void stream_in_allocate(stream_in_context* ctx, u32 buffersize, FILE* file); -void stream_in_destroy(stream_in_context* ctx); -void stream_out_init(stream_out_context* ctx); -void stream_out_allocate(stream_out_context* ctx, u32 buffersize, FILE* file); -void stream_out_destroy(stream_out_context* ctx); - -// read/write operations -int stream_in_byte(stream_in_context* ctx, u8* byte); -void stream_in_seek(stream_in_context* ctx, u32 position); -void stream_in_reseek(stream_in_context* ctx); - -int stream_out_byte(stream_out_context* ctx, u8 byte); -int stream_out_buffer(stream_out_context* ctx, const void* buffer, u32 size); -int stream_out_flush(stream_out_context* ctx); -void stream_out_seek(stream_out_context* ctx, u32 position); -void stream_out_skip(stream_out_context* ctx, u32 size); -void stream_out_position(stream_out_context* ctx, u32* position); - -#endif // __STREAM_H__ diff --git a/ctrtool/syscalls.c b/ctrtool/syscalls.c deleted file mode 100644 index f450535..0000000 --- a/ctrtool/syscalls.c +++ /dev/null @@ -1,171 +0,0 @@ -#include -#include -#include -#include "syscalls.h" - -// List of 3DS system calls. NULL indicates unknown. -static const char *const syscall_list[NUM_SYSCALLS] = -{ - NULL, // 00 - "ControlMemory", // 01 - "QueryMemory", // 02 - "ExitProcess", // 03 - "GetProcessAffinityMask", // 04 - "SetProcessAffinityMask", // 05 - "GetProcessIdealProcessor", // 06 - "SetProcessIdealProcessor", // 07 - "CreateThread", // 08 - "ExitThread", // 09 - "SleepThread", // 0A - "GetThreadPriority", // 0B - "SetThreadPriority", // 0C - "GetThreadAffinityMask", // 0D - "SetThreadAffinityMask", // 0E - "GetThreadIdealProcessor", // 0F - "SetThreadIdealProcessor", // 10 - "GetCurrentProcessorNumber", // 11 - "Run", // 12 - "CreateMutex", // 13 - "ReleaseMutex", // 14 - "CreateSemaphore", // 15 - "ReleaseSemaphore", // 16 - "CreateEvent", // 17 - "SignalEvent", // 18 - "ClearEvent", // 19 - "CreateTimer", // 1A - "SetTimer", // 1B - "CancelTimer", // 1C - "ClearTimer", // 1D - "CreateMemoryBlock", // 1E - "MapMemoryBlock", // 1F - "UnmapMemoryBlock", // 20 - "CreateAddressArbiter", // 21 - "ArbitrateAddress", // 22 - "CloseHandle", // 23 - "WaitSynchronization1", // 24 - "WaitSynchronizationN", // 25 - "SignalAndWait", // 26 - "DuplicateHandle", // 27 - "GetSystemTick", // 28 - "GetHandleInfo", // 29 - "GetSystemInfo", // 2A - "GetProcessInfo", // 2B - "GetThreadInfo", // 2C - "ConnectToPort", // 2D - "SendSyncRequest1", // 2E - "SendSyncRequest2", // 2F - "SendSyncRequest3", // 30 - "SendSyncRequest4", // 31 - "SendSyncRequest", // 32 - "OpenProcess", // 33 - "OpenThread", // 34 - "GetProcessId", // 35 - "GetProcessIdOfThread", // 36 - "GetThreadId", // 37 - "GetResourceLimit", // 38 - "GetResourceLimitLimitValues", // 39 - "GetResourceLimitCurrentValues", // 3A - "GetThreadContext", // 3B - "Break", // 3C - "OutputDebugString", // 3D - "ControlPerformanceCounter", // 3E - NULL, // 3F - NULL, // 40 - NULL, // 41 - NULL, // 42 - NULL, // 43 - NULL, // 44 - NULL, // 45 - NULL, // 46 - "CreatePort", // 47 - "CreateSessionToPort", // 48 - "CreateSession", // 49 - "AcceptSession", // 4A - "ReplyAndReceive1", // 4B - "ReplyAndReceive2", // 4C - "ReplyAndReceive3", // 4D - "ReplyAndReceive4", // 4E - "ReplyAndReceive", // 4F - "BindInterrupt", // 50 - "UnbindInterrupt", // 51 - "InvalidateProcessDataCache", // 52 - "StoreProcessDataCache", // 53 - "FlushProcessDataCache", // 54 - "StartInterProcessDma", // 55 - "StopDma", // 56 - "GetDmaState", // 57 - "RestartDma", // 58 - "SetGpuProt", // 59 - "SetWifiEnabled", // 5A - NULL, // 5B - NULL, // 5C - NULL, // 5D - NULL, // 5E - NULL, // 5F - "DebugActiveProcess", // 60 - "BreakDebugProcess", // 61 - "TerminateDebugProcess", // 62 - "GetProcessDebugEvent", // 63 - "ContinueDebugEvent", // 64 - "GetProcessList", // 65 - "GetThreadList", // 66 - "GetDebugThreadContext", // 67 - "SetDebugThreadContext", // 68 - "QueryDebugProcessMemory", // 69 - "ReadProcessMemory", // 6A - "WriteProcessMemory", // 6B - "SetHardwareBreakPoint", // 6C - "GetDebugThreadParam", // 6D - NULL, // 6E - NULL, // 6F - "ControlProcessMemory", // 70 - "MapProcessMemory", // 71 - "UnmapProcessMemory", // 72 - "CreateCodeSet", // 73 - NULL, // 74 - "CreateProcess", // 75 - "TerminateProcess", // 76 - "SetProcessResourceLimits", // 77 - "CreateResourceLimit", // 78 - "SetResourceLimitValues", // 79 - "AddCodeSegment", // 7A - "Backdoor", // 7B - "KernelSetState", // 7C - "QueryProcessMemory", // 7D - NULL, // 7E - NULL, // 7F -}; - - -void syscall_get_name(char *output, size_t size, unsigned int call_num) -{ -#ifdef _MSC_VER - typedef char StaticAssert[sizeof(syscall_list) / sizeof(syscall_list[0]) == NUM_SYSCALLS ? 1 : -1]; -#else - _Static_assert(sizeof(syscall_list) / sizeof(syscall_list[0]) == NUM_SYSCALLS, - "syscall table length mismatch"); -#endif - - - if (size == 0) - { - return; - } - - const char *name = NULL; - if (call_num < (unsigned int) NUM_SYSCALLS) - { - name = syscall_list[call_num]; - } - - char name_buf[] = "UnknownXX"; - sprintf(&name_buf[sizeof(name_buf) - 3], "%02X", call_num & 0xFFu); - - name = name ? name : name_buf; - - size_t length = strlen(name); - length = (length > (size - 1)) ? (size - 1) : length; - - memcpy(output, name, length); - output[length] = '\0'; -} diff --git a/ctrtool/syscalls.h b/ctrtool/syscalls.h deleted file mode 100644 index 5afca89..0000000 --- a/ctrtool/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _SYSCALLS_H_ -#define _SYSCALLS_H_ - -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -enum { NUM_SYSCALLS = 0x80 }; - -void syscall_get_name(char *output, size_t size, unsigned int call_num); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/ctrtool/tik.c b/ctrtool/tik.c deleted file mode 100644 index 285f403..0000000 --- a/ctrtool/tik.c +++ /dev/null @@ -1,127 +0,0 @@ -#include -#include -#include - -#include "aes_keygen.h" -#include "tik.h" -#include "ctr.h" -#include "utils.h" - -void tik_init(tik_context* ctx) -{ - memset(ctx, 0, sizeof(tik_context)); -} - -void tik_set_file(tik_context* ctx, FILE* file) -{ - ctx->file = file; -} - -void tik_set_offset(tik_context* ctx, u64 offset) -{ - ctx->offset = offset; -} - -void tik_set_size(tik_context* ctx, u32 size) -{ - ctx->size = size; -} - -void tik_set_usersettings(tik_context* ctx, settings* usersettings) -{ - ctx->usersettings = usersettings; -} - -const unsigned char* tik_get_titlekey(tik_context* ctx) -{ - return ctx->titlekey.valid ? ctx->titlekey.data : NULL; -} - -void tik_get_titleid(tik_context* ctx, u8 titleid[8]) -{ - memcpy(titleid, ctx->tik.title_id, 8); -} - -void tik_get_iv(tik_context* ctx, u8 iv[16]) -{ - memset(iv, 0, 16); - memcpy(iv, ctx->tik.title_id, 8); -} - -int tik_decrypt_titlekey(tik_context* ctx, u8 decryptedkey[0x10]) -{ - u8 iv[16]; - u8* commonkey = settings_get_common_key(ctx->usersettings, ctx->tik.commonkey_idx); - - memset(decryptedkey, 0, 0x10); - if (!commonkey) - { - fprintf(stdout, "Error, could not read common key.\n"); - return 1; - } - - memset(iv, 0, 0x10); - memcpy(iv, ctx->tik.title_id, 8); - - ctr_init_cbc_decrypt(&ctx->aes, commonkey, iv); - ctr_decrypt_cbc(&ctx->aes, ctx->tik.encrypted_title_key, decryptedkey, 0x10); - return 0; -} - -void tik_process(tik_context* ctx, u32 actions) -{ - if (ctx->size < sizeof(eticket)) - { - fprintf(stderr, "Error, ticket size too small\n"); - goto clean; - } - - fseeko64(ctx->file, ctx->offset, SEEK_SET); - fread((u8*)&ctx->tik, 1, sizeof(eticket), ctx->file); - - ctx->titlekey.valid = tik_decrypt_titlekey(ctx, ctx->titlekey.data) == 0 ? 1 : 0; - - if (actions & InfoFlag) - { - tik_print(ctx); - } - -clean: - return; -} - -void tik_print(tik_context* ctx) -{ - int i; - eticket* tik = &ctx->tik; - - fprintf(stdout, "\nTicket content:\n"); - fprintf(stdout, - "Signature Type: %08x\n" - "Issuer: %s\n", - getle32(tik->sig_type), tik->issuer - ); - - fprintf(stdout, "Signature:\n"); - hexdump(tik->signature, 0x100); - fprintf(stdout, "\n"); - - memdump(stdout, "Encrypted Titlekey: ", tik->encrypted_title_key, 0x10); - - if (ctx->titlekey.valid) - memdump(stdout, "Decrypted Titlekey: ", ctx->titlekey.data, 0x10); - - memdump(stdout, "Ticket ID: ", tik->ticket_id, 0x08); - fprintf(stdout, "Ticket Version: %d\n", getle16(tik->ticket_version)); - memdump(stdout, "Title ID: ", tik->title_id, 0x08); - fprintf(stdout, "Common Key Index: %d\n", tik->commonkey_idx); - - fprintf(stdout, "Content permission map:\n"); - for(i = 0; i < 0x40; i++) { - printf(" %02x", tik->content_permissions[i]); - - if ((i+1) % 8 == 0) - printf("\n"); - } - printf("\n"); -} diff --git a/ctrtool/tik.h b/ctrtool/tik.h deleted file mode 100644 index 4d85aaa..0000000 --- a/ctrtool/tik.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef __TIK_H__ -#define __TIK_H__ - -#include "types.h" -#include "keyset.h" -#include "ctr.h" -#include "settings.h" - -typedef struct -{ - u8 enable_timelimit[4]; - u8 timelimit_seconds[4]; -} timelimit_entry; - -typedef struct -{ - u8 sig_type[4]; - u8 signature[0x100]; - u8 padding1[0x3c]; - u8 issuer[0x40]; - u8 ecdsa[0x3c]; - u8 padding2[0x03]; - u8 encrypted_title_key[0x10]; - u8 unknown; - u8 ticket_id[8]; - u8 console_id[4]; - u8 title_id[8]; - u8 sys_access[2]; - u8 ticket_version[2]; - u8 time_mask[4]; - u8 permit_mask[4]; - u8 title_export; - u8 commonkey_idx; - u8 unknown_buf[0x30]; - u8 content_permissions[0x40]; - u8 padding0[2]; - - timelimit_entry timelimits[8]; -} eticket; - -typedef struct -{ - FILE* file; - u64 offset; - u32 size; - key128 titlekey; - eticket tik; - ctr_aes_context aes; - settings* usersettings; -} tik_context; - -void tik_init(tik_context* ctx); -void tik_set_file(tik_context* ctx, FILE* file); -void tik_set_offset(tik_context* ctx, u64 offset); -void tik_set_size(tik_context* ctx, u32 size); -void tik_set_usersettings(tik_context* ctx, settings* usersettings); -const unsigned char* tik_get_titlekey(tik_context* ctx); -void tik_get_titleid(tik_context* ctx, u8 titleid[8]); -void tik_get_iv(tik_context* ctx, u8 iv[0x10]); -int tik_decrypt_titlekey(tik_context* ctx, u8 decryptedkey[0x10]); -void tik_print(tik_context* ctx); -void tik_process(tik_context* ctx, u32 actions); - -#endif diff --git a/ctrtool/tinyxml/tinystr.cpp b/ctrtool/tinyxml/tinystr.cpp deleted file mode 100644 index 6ca4dc8..0000000 --- a/ctrtool/tinyxml/tinystr.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - - -#ifndef TIXML_USE_STL - -#include "tinyxml/tinystr.h" - -// Error value for find primitive -const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); - - -// Null rep. -TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; - - -void TiXmlString::reserve (size_type cap) -{ - if (cap > capacity()) - { - TiXmlString tmp; - tmp.init(length(), cap); - memcpy(tmp.start(), data(), length()); - swap(tmp); - } -} - - -TiXmlString& TiXmlString::assign(const char* str, size_type len) -{ - size_type cap = capacity(); - if (len > cap || cap > 3*(len + 8)) - { - TiXmlString tmp; - tmp.init(len); - memcpy(tmp.start(), str, len); - swap(tmp); - } - else - { - memmove(start(), str, len); - set_size(len); - } - return *this; -} - - -TiXmlString& TiXmlString::append(const char* str, size_type len) -{ - size_type newsize = length() + len; - if (newsize > capacity()) - { - reserve (newsize + capacity()); - } - memmove(finish(), str, len); - set_size(newsize); - return *this; -} - - -TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) -{ - TiXmlString tmp; - tmp.reserve(a.length() + b.length()); - tmp += a; - tmp += b; - return tmp; -} - -TiXmlString operator + (const TiXmlString & a, const char* b) -{ - TiXmlString tmp; - TiXmlString::size_type b_len = static_cast( strlen(b) ); - tmp.reserve(a.length() + b_len); - tmp += a; - tmp.append(b, b_len); - return tmp; -} - -TiXmlString operator + (const char* a, const TiXmlString & b) -{ - TiXmlString tmp; - TiXmlString::size_type a_len = static_cast( strlen(a) ); - tmp.reserve(a_len + b.length()); - tmp.append(a, a_len); - tmp += b; - return tmp; -} - - -#endif // TIXML_USE_STL diff --git a/ctrtool/tinyxml/tinystr.h b/ctrtool/tinyxml/tinystr.h deleted file mode 100644 index 89cca33..0000000 --- a/ctrtool/tinyxml/tinystr.h +++ /dev/null @@ -1,305 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - - -#ifndef TIXML_USE_STL - -#ifndef TIXML_STRING_INCLUDED -#define TIXML_STRING_INCLUDED - -#include -#include - -/* The support for explicit isn't that universal, and it isn't really - required - it is used to check that the TiXmlString class isn't incorrectly - used. Be nice to old compilers and macro it here: -*/ -#if defined(_MSC_VER) && (_MSC_VER >= 1200 ) - // Microsoft visual studio, version 6 and higher. - #define TIXML_EXPLICIT explicit -#elif defined(__GNUC__) && (__GNUC__ >= 3 ) - // GCC version 3 and higher.s - #define TIXML_EXPLICIT explicit -#else - #define TIXML_EXPLICIT -#endif - - -/* - TiXmlString is an emulation of a subset of the std::string template. - Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. - Only the member functions relevant to the TinyXML project have been implemented. - The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase - a string and there's no more room, we allocate a buffer twice as big as we need. -*/ -class TiXmlString -{ - public : - // The size type used - typedef size_t size_type; - - // Error value for find primitive - static const size_type npos; // = -1; - - - // TiXmlString empty constructor - TiXmlString () : rep_(&nullrep_) - { - } - - // TiXmlString copy constructor - TiXmlString ( const TiXmlString & copy) : rep_(0) - { - init(copy.length()); - memcpy(start(), copy.data(), length()); - } - - // TiXmlString constructor, based on a string - TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) - { - init( static_cast( strlen(copy) )); - memcpy(start(), copy, length()); - } - - // TiXmlString constructor, based on a string - TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) - { - init(len); - memcpy(start(), str, len); - } - - // TiXmlString destructor - ~TiXmlString () - { - quit(); - } - - TiXmlString& operator = (const char * copy) - { - return assign( copy, (size_type)strlen(copy)); - } - - TiXmlString& operator = (const TiXmlString & copy) - { - return assign(copy.start(), copy.length()); - } - - - // += operator. Maps to append - TiXmlString& operator += (const char * suffix) - { - return append(suffix, static_cast( strlen(suffix) )); - } - - // += operator. Maps to append - TiXmlString& operator += (char single) - { - return append(&single, 1); - } - - // += operator. Maps to append - TiXmlString& operator += (const TiXmlString & suffix) - { - return append(suffix.data(), suffix.length()); - } - - - // Convert a TiXmlString into a null-terminated char * - const char * c_str () const { return rep_->str; } - - // Convert a TiXmlString into a char * (need not be null terminated). - const char * data () const { return rep_->str; } - - // Return the length of a TiXmlString - size_type length () const { return rep_->size; } - - // Alias for length() - size_type size () const { return rep_->size; } - - // Checks if a TiXmlString is empty - bool empty () const { return rep_->size == 0; } - - // Return capacity of string - size_type capacity () const { return rep_->capacity; } - - - // single char extraction - const char& at (size_type index) const - { - assert( index < length() ); - return rep_->str[ index ]; - } - - // [] operator - char& operator [] (size_type index) const - { - assert( index < length() ); - return rep_->str[ index ]; - } - - // find a char in a string. Return TiXmlString::npos if not found - size_type find (char lookup) const - { - return find(lookup, 0); - } - - // find a char in a string from an offset. Return TiXmlString::npos if not found - size_type find (char tofind, size_type offset) const - { - if (offset >= length()) return npos; - - for (const char* p = c_str() + offset; *p != '\0'; ++p) - { - if (*p == tofind) return static_cast< size_type >( p - c_str() ); - } - return npos; - } - - void clear () - { - //Lee: - //The original was just too strange, though correct: - // TiXmlString().swap(*this); - //Instead use the quit & re-init: - quit(); - init(0,0); - } - - /* Function to reserve a big amount of data when we know we'll need it. Be aware that this - function DOES NOT clear the content of the TiXmlString if any exists. - */ - void reserve (size_type cap); - - TiXmlString& assign (const char* str, size_type len); - - TiXmlString& append (const char* str, size_type len); - - void swap (TiXmlString& other) - { - Rep* r = rep_; - rep_ = other.rep_; - other.rep_ = r; - } - - private: - - void init(size_type sz) { init(sz, sz); } - void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } - char* start() const { return rep_->str; } - char* finish() const { return rep_->str + rep_->size; } - - struct Rep - { - size_type size, capacity; - char str[1]; - }; - - void init(size_type sz, size_type cap) - { - if (cap) - { - // Lee: the original form: - // rep_ = static_cast(operator new(sizeof(Rep) + cap)); - // doesn't work in some cases of new being overloaded. Switching - // to the normal allocation, although use an 'int' for systems - // that are overly picky about structure alignment. - const size_type bytesNeeded = sizeof(Rep) + cap; - const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); - rep_ = reinterpret_cast( new int[ intsNeeded ] ); - - rep_->str[ rep_->size = sz ] = '\0'; - rep_->capacity = cap; - } - else - { - rep_ = &nullrep_; - } - } - - void quit() - { - if (rep_ != &nullrep_) - { - // The rep_ is really an array of ints. (see the allocator, above). - // Cast it back before delete, so the compiler won't incorrectly call destructors. - delete [] ( reinterpret_cast( rep_ ) ); - } - } - - Rep * rep_; - static Rep nullrep_; - -} ; - - -inline bool operator == (const TiXmlString & a, const TiXmlString & b) -{ - return ( a.length() == b.length() ) // optimization on some platforms - && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare -} -inline bool operator < (const TiXmlString & a, const TiXmlString & b) -{ - return strcmp(a.c_str(), b.c_str()) < 0; -} - -inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } -inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } -inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } -inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } - -inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } -inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } -inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } -inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } - -TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); -TiXmlString operator + (const TiXmlString & a, const char* b); -TiXmlString operator + (const char* a, const TiXmlString & b); - - -/* - TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. - Only the operators that we need for TinyXML have been developped. -*/ -class TiXmlOutStream : public TiXmlString -{ -public : - - // TiXmlOutStream << operator. - TiXmlOutStream & operator << (const TiXmlString & in) - { - *this += in; - return *this; - } - - // TiXmlOutStream << operator. - TiXmlOutStream & operator << (const char * in) - { - *this += in; - return *this; - } - -} ; - -#endif // TIXML_STRING_INCLUDED -#endif // TIXML_USE_STL diff --git a/ctrtool/tinyxml/tinyxml.cpp b/ctrtool/tinyxml/tinyxml.cpp deleted file mode 100644 index cec7b8c..0000000 --- a/ctrtool/tinyxml/tinyxml.cpp +++ /dev/null @@ -1,1886 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml -Original code by Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#include - -#ifdef TIXML_USE_STL -#include -#include -#endif - -#include "tinyxml/tinyxml.h" - -FILE* TiXmlFOpen( const char* filename, const char* mode ); - -bool TiXmlBase::condenseWhiteSpace = true; - -// Microsoft compiler security -FILE* TiXmlFOpen( const char* filename, const char* mode ) -{ - #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) - FILE* fp = 0; - errno_t err = fopen_s( &fp, filename, mode ); - if ( !err && fp ) - return fp; - return 0; - #else - return fopen( filename, mode ); - #endif -} - -void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString ) -{ - int i=0; - - while( i<(int)str.length() ) - { - unsigned char c = (unsigned char) str[i]; - - if ( c == '&' - && i < ( (int)str.length() - 2 ) - && str[i+1] == '#' - && str[i+2] == 'x' ) - { - // Hexadecimal character reference. - // Pass through unchanged. - // © -- copyright symbol, for example. - // - // The -1 is a bug fix from Rob Laveaux. It keeps - // an overflow from happening if there is no ';'. - // There are actually 2 ways to exit this loop - - // while fails (error case) and break (semicolon found). - // However, there is no mechanism (currently) for - // this function to return an error. - while ( i<(int)str.length()-1 ) - { - outString->append( str.c_str() + i, 1 ); - ++i; - if ( str[i] == ';' ) - break; - } - } - else if ( c == '&' ) - { - outString->append( entity[0].str, entity[0].strLength ); - ++i; - } - else if ( c == '<' ) - { - outString->append( entity[1].str, entity[1].strLength ); - ++i; - } - else if ( c == '>' ) - { - outString->append( entity[2].str, entity[2].strLength ); - ++i; - } - else if ( c == '\"' ) - { - outString->append( entity[3].str, entity[3].strLength ); - ++i; - } - else if ( c == '\'' ) - { - outString->append( entity[4].str, entity[4].strLength ); - ++i; - } - else if ( c < 32 ) - { - // Easy pass at non-alpha/numeric/symbol - // Below 32 is symbolic. - char buf[ 32 ]; - - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); - #else - sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); - #endif - - //*ME: warning C4267: convert 'size_t' to 'int' - //*ME: Int-Cast to make compiler happy ... - outString->append( buf, (int)strlen( buf ) ); - ++i; - } - else - { - //char realc = (char) c; - //outString->append( &realc, 1 ); - *outString += (char) c; // somewhat more efficient function call. - ++i; - } - } -} - - -TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() -{ - parent = 0; - type = _type; - firstChild = 0; - lastChild = 0; - prev = 0; - next = 0; -} - - -TiXmlNode::~TiXmlNode() -{ - TiXmlNode* node = firstChild; - TiXmlNode* temp = 0; - - while ( node ) - { - temp = node; - node = node->next; - delete temp; - } -} - - -void TiXmlNode::CopyTo( TiXmlNode* target ) const -{ - target->SetValue (value.c_str() ); - target->userData = userData; - target->location = location; -} - - -void TiXmlNode::Clear() -{ - TiXmlNode* node = firstChild; - TiXmlNode* temp = 0; - - while ( node ) - { - temp = node; - node = node->next; - delete temp; - } - - firstChild = 0; - lastChild = 0; -} - - -TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) -{ - assert( node->parent == 0 || node->parent == this ); - assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); - - if ( node->Type() == TiXmlNode::TINYXML_DOCUMENT ) - { - delete node; - if ( GetDocument() ) - GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - node->parent = this; - - node->prev = lastChild; - node->next = 0; - - if ( lastChild ) - lastChild->next = node; - else - firstChild = node; // it was an empty list. - - lastChild = node; - return node; -} - - -TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) -{ - if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) - { - if ( GetDocument() ) - GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; - - return LinkEndChild( node ); -} - - -TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) -{ - if ( !beforeThis || beforeThis->parent != this ) { - return 0; - } - if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) - { - if ( GetDocument() ) - GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; - node->parent = this; - - node->next = beforeThis; - node->prev = beforeThis->prev; - if ( beforeThis->prev ) - { - beforeThis->prev->next = node; - } - else - { - assert( firstChild == beforeThis ); - firstChild = node; - } - beforeThis->prev = node; - return node; -} - - -TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) -{ - if ( !afterThis || afterThis->parent != this ) { - return 0; - } - if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) - { - if ( GetDocument() ) - GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - TiXmlNode* node = addThis.Clone(); - if ( !node ) - return 0; - node->parent = this; - - node->prev = afterThis; - node->next = afterThis->next; - if ( afterThis->next ) - { - afterThis->next->prev = node; - } - else - { - assert( lastChild == afterThis ); - lastChild = node; - } - afterThis->next = node; - return node; -} - - -TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) -{ - if ( !replaceThis ) - return 0; - - if ( replaceThis->parent != this ) - return 0; - - if ( withThis.ToDocument() ) { - // A document can never be a child. Thanks to Noam. - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - TiXmlNode* node = withThis.Clone(); - if ( !node ) - return 0; - - node->next = replaceThis->next; - node->prev = replaceThis->prev; - - if ( replaceThis->next ) - replaceThis->next->prev = node; - else - lastChild = node; - - if ( replaceThis->prev ) - replaceThis->prev->next = node; - else - firstChild = node; - - delete replaceThis; - node->parent = this; - return node; -} - - -bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) -{ - if ( !removeThis ) { - return false; - } - - if ( removeThis->parent != this ) - { - assert( 0 ); - return false; - } - - if ( removeThis->next ) - removeThis->next->prev = removeThis->prev; - else - lastChild = removeThis->prev; - - if ( removeThis->prev ) - removeThis->prev->next = removeThis->next; - else - firstChild = removeThis->next; - - delete removeThis; - return true; -} - -const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = firstChild; node; node = node->next ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = lastChild; node; node = node->prev ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const -{ - if ( !previous ) - { - return FirstChild(); - } - else - { - assert( previous->parent == this ); - return previous->NextSibling(); - } -} - - -const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const -{ - if ( !previous ) - { - return FirstChild( val ); - } - else - { - assert( previous->parent == this ); - return previous->NextSibling( val ); - } -} - - -const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = next; node; node = node->next ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const -{ - const TiXmlNode* node; - for ( node = prev; node; node = node->prev ) - { - if ( strcmp( node->Value(), _value ) == 0 ) - return node; - } - return 0; -} - - -void TiXmlElement::RemoveAttribute( const char * name ) -{ - #ifdef TIXML_USE_STL - TIXML_STRING str( name ); - TiXmlAttribute* node = attributeSet.Find( str ); - #else - TiXmlAttribute* node = attributeSet.Find( name ); - #endif - if ( node ) - { - attributeSet.Remove( node ); - delete node; - } -} - -const TiXmlElement* TiXmlNode::FirstChildElement() const -{ - const TiXmlNode* node; - - for ( node = FirstChild(); - node; - node = node->NextSibling() ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const -{ - const TiXmlNode* node; - - for ( node = FirstChild( _value ); - node; - node = node->NextSibling( _value ) ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlElement* TiXmlNode::NextSiblingElement() const -{ - const TiXmlNode* node; - - for ( node = NextSibling(); - node; - node = node->NextSibling() ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const -{ - const TiXmlNode* node; - - for ( node = NextSibling( _value ); - node; - node = node->NextSibling( _value ) ) - { - if ( node->ToElement() ) - return node->ToElement(); - } - return 0; -} - - -const TiXmlDocument* TiXmlNode::GetDocument() const -{ - const TiXmlNode* node; - - for( node = this; node; node = node->parent ) - { - if ( node->ToDocument() ) - return node->ToDocument(); - } - return 0; -} - - -TiXmlElement::TiXmlElement (const char * _value) - : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) -{ - firstChild = lastChild = 0; - value = _value; -} - - -#ifdef TIXML_USE_STL -TiXmlElement::TiXmlElement( const std::string& _value ) - : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) -{ - firstChild = lastChild = 0; - value = _value; -} -#endif - - -TiXmlElement::TiXmlElement( const TiXmlElement& copy) - : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) -{ - firstChild = lastChild = 0; - copy.CopyTo( this ); -} - - -TiXmlElement& TiXmlElement::operator=( const TiXmlElement& base ) -{ - ClearThis(); - base.CopyTo( this ); - return *this; -} - - -TiXmlElement::~TiXmlElement() -{ - ClearThis(); -} - - -void TiXmlElement::ClearThis() -{ - Clear(); - while( attributeSet.First() ) - { - TiXmlAttribute* node = attributeSet.First(); - attributeSet.Remove( node ); - delete node; - } -} - - -const char* TiXmlElement::Attribute( const char* name ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( node ) - return node->Value(); - return 0; -} - - -#ifdef TIXML_USE_STL -const std::string* TiXmlElement::Attribute( const std::string& name ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( attrib ) - return &attrib->ValueStr(); - return 0; -} -#endif - - -const char* TiXmlElement::Attribute( const char* name, int* i ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - const char* result = 0; - - if ( attrib ) { - result = attrib->Value(); - if ( i ) { - attrib->QueryIntValue( i ); - } - } - return result; -} - - -#ifdef TIXML_USE_STL -const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - const std::string* result = 0; - - if ( attrib ) { - result = &attrib->ValueStr(); - if ( i ) { - attrib->QueryIntValue( i ); - } - } - return result; -} -#endif - - -const char* TiXmlElement::Attribute( const char* name, double* d ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - const char* result = 0; - - if ( attrib ) { - result = attrib->Value(); - if ( d ) { - attrib->QueryDoubleValue( d ); - } - } - return result; -} - - -#ifdef TIXML_USE_STL -const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - const std::string* result = 0; - - if ( attrib ) { - result = &attrib->ValueStr(); - if ( d ) { - attrib->QueryDoubleValue( d ); - } - } - return result; -} -#endif - - -int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( !attrib ) - return TIXML_NO_ATTRIBUTE; - return attrib->QueryIntValue( ival ); -} - - -int TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* value ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - - int ival = 0; - int result = node->QueryIntValue( &ival ); - *value = (unsigned)ival; - return result; -} - - -int TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const -{ - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - - int result = TIXML_WRONG_TYPE; - if ( StringEqual( node->Value(), "true", true, TIXML_ENCODING_UNKNOWN ) - || StringEqual( node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN ) - || StringEqual( node->Value(), "1", true, TIXML_ENCODING_UNKNOWN ) ) - { - *bval = true; - result = TIXML_SUCCESS; - } - else if ( StringEqual( node->Value(), "false", true, TIXML_ENCODING_UNKNOWN ) - || StringEqual( node->Value(), "no", true, TIXML_ENCODING_UNKNOWN ) - || StringEqual( node->Value(), "0", true, TIXML_ENCODING_UNKNOWN ) ) - { - *bval = false; - result = TIXML_SUCCESS; - } - return result; -} - - - -#ifdef TIXML_USE_STL -int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( !attrib ) - return TIXML_NO_ATTRIBUTE; - return attrib->QueryIntValue( ival ); -} -#endif - - -int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( !attrib ) - return TIXML_NO_ATTRIBUTE; - return attrib->QueryDoubleValue( dval ); -} - - -#ifdef TIXML_USE_STL -int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const -{ - const TiXmlAttribute* attrib = attributeSet.Find( name ); - if ( !attrib ) - return TIXML_NO_ATTRIBUTE; - return attrib->QueryDoubleValue( dval ); -} -#endif - - -void TiXmlElement::SetAttribute( const char * name, int val ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); - if ( attrib ) { - attrib->SetIntValue( val ); - } -} - - -#ifdef TIXML_USE_STL -void TiXmlElement::SetAttribute( const std::string& name, int val ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); - if ( attrib ) { - attrib->SetIntValue( val ); - } -} -#endif - - -void TiXmlElement::SetDoubleAttribute( const char * name, double val ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); - if ( attrib ) { - attrib->SetDoubleValue( val ); - } -} - - -#ifdef TIXML_USE_STL -void TiXmlElement::SetDoubleAttribute( const std::string& name, double val ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); - if ( attrib ) { - attrib->SetDoubleValue( val ); - } -} -#endif - - -void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname ); - if ( attrib ) { - attrib->SetValue( cvalue ); - } -} - - -#ifdef TIXML_USE_STL -void TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value ) -{ - TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name ); - if ( attrib ) { - attrib->SetValue( _value ); - } -} -#endif - - -void TiXmlElement::Print( FILE* cfile, int depth ) const -{ - int i; - assert( cfile ); - for ( i=0; iNext() ) - { - fprintf( cfile, " " ); - attrib->Print( cfile, depth ); - } - - // There are 3 different formatting approaches: - // 1) An element without children is printed as a node - // 2) An element with only a text child is printed as text - // 3) An element with children is printed on multiple lines. - TiXmlNode* node; - if ( !firstChild ) - { - fprintf( cfile, " />" ); - } - else if ( firstChild == lastChild && firstChild->ToText() ) - { - fprintf( cfile, ">" ); - firstChild->Print( cfile, depth + 1 ); - fprintf( cfile, "", value.c_str() ); - } - else - { - fprintf( cfile, ">" ); - - for ( node = firstChild; node; node=node->NextSibling() ) - { - if ( !node->ToText() ) - { - fprintf( cfile, "\n" ); - } - node->Print( cfile, depth+1 ); - } - fprintf( cfile, "\n" ); - for( i=0; i", value.c_str() ); - } -} - - -void TiXmlElement::CopyTo( TiXmlElement* target ) const -{ - // superclass: - TiXmlNode::CopyTo( target ); - - // Element class: - // Clone the attributes, then clone the children. - const TiXmlAttribute* attribute = 0; - for( attribute = attributeSet.First(); - attribute; - attribute = attribute->Next() ) - { - target->SetAttribute( attribute->Name(), attribute->Value() ); - } - - TiXmlNode* node = 0; - for ( node = firstChild; node; node = node->NextSibling() ) - { - target->LinkEndChild( node->Clone() ); - } -} - -bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const -{ - if ( visitor->VisitEnter( *this, attributeSet.First() ) ) - { - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - if ( !node->Accept( visitor ) ) - break; - } - } - return visitor->VisitExit( *this ); -} - - -TiXmlNode* TiXmlElement::Clone() const -{ - TiXmlElement* clone = new TiXmlElement( Value() ); - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -const char* TiXmlElement::GetText() const -{ - const TiXmlNode* child = this->FirstChild(); - if ( child ) { - const TiXmlText* childText = child->ToText(); - if ( childText ) { - return childText->Value(); - } - } - return 0; -} - - -TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) -{ - tabsize = 4; - useMicrosoftBOM = false; - ClearError(); -} - -TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) -{ - tabsize = 4; - useMicrosoftBOM = false; - value = documentName; - ClearError(); -} - - -#ifdef TIXML_USE_STL -TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) -{ - tabsize = 4; - useMicrosoftBOM = false; - value = documentName; - ClearError(); -} -#endif - - -TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) -{ - copy.CopyTo( this ); -} - - -TiXmlDocument& TiXmlDocument::operator=( const TiXmlDocument& copy ) -{ - Clear(); - copy.CopyTo( this ); - return *this; -} - - -bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) -{ - return LoadFile( Value(), encoding ); -} - - -bool TiXmlDocument::SaveFile() const -{ - return SaveFile( Value() ); -} - -bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) -{ - TIXML_STRING filename( _filename ); - value = filename; - - // reading in binary mode so that tinyxml can normalize the EOL - FILE* file = TiXmlFOpen( value.c_str (), "rb" ); - - if ( file ) - { - bool result = LoadFile( file, encoding ); - fclose( file ); - return result; - } - else - { - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } -} - -bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) -{ - if ( !file ) - { - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - // Delete the existing data: - Clear(); - location.Clear(); - - // Get the file size, so we can pre-allocate the string. HUGE speed impact. - long length = 0; - fseek( file, 0, SEEK_END ); - length = ftell( file ); - fseek( file, 0, SEEK_SET ); - - // Strange case, but good to handle up front. - if ( length <= 0 ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - // Subtle bug here. TinyXml did use fgets. But from the XML spec: - // 2.11 End-of-Line Handling - // - // - // ...the XML processor MUST behave as if it normalized all line breaks in external - // parsed entities (including the document entity) on input, before parsing, by translating - // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to - // a single #xA character. - // - // - // It is not clear fgets does that, and certainly isn't clear it works cross platform. - // Generally, you expect fgets to translate from the convention of the OS to the c/unix - // convention, and not work generally. - - /* - while( fgets( buf, sizeof(buf), file ) ) - { - data += buf; - } - */ - - char* buf = new char[ length+1 ]; - buf[0] = 0; - - if ( fread( buf, length, 1, file ) != 1 ) { - delete [] buf; - SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); - return false; - } - - // Process the buffer in place to normalize new lines. (See comment above.) - // Copies from the 'p' to 'q' pointer, where p can advance faster if - // a newline-carriage return is hit. - // - // Wikipedia: - // Systems based on ASCII or a compatible character set use either LF (Line feed, '\n', 0x0A, 10 in decimal) or - // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)... - // * LF: Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others - // * CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, Microsoft Windows, Symbian OS - // * CR: Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9 - - const char* p = buf; // the read head - char* q = buf; // the write head - const char CR = 0x0d; - const char LF = 0x0a; - - buf[length] = 0; - while( *p ) { - assert( p < (buf+length) ); - assert( q <= (buf+length) ); - assert( q <= p ); - - if ( *p == CR ) { - *q++ = LF; - p++; - if ( *p == LF ) { // check for CR+LF (and skip LF) - p++; - } - } - else { - *q++ = *p++; - } - } - assert( q <= (buf+length) ); - *q = 0; - - Parse( buf, 0, encoding ); - - delete [] buf; - return !Error(); -} - - -bool TiXmlDocument::SaveFile( const char * filename ) const -{ - // The old c stuff lives on... - FILE* fp = TiXmlFOpen( filename, "w" ); - if ( fp ) - { - bool result = SaveFile( fp ); - fclose( fp ); - return result; - } - return false; -} - - -bool TiXmlDocument::SaveFile( FILE* fp ) const -{ - if ( useMicrosoftBOM ) - { - const unsigned char TIXML_UTF_LEAD_0 = 0xefU; - const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; - const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; - - fputc( TIXML_UTF_LEAD_0, fp ); - fputc( TIXML_UTF_LEAD_1, fp ); - fputc( TIXML_UTF_LEAD_2, fp ); - } - Print( fp, 0 ); - return (ferror(fp) == 0); -} - - -void TiXmlDocument::CopyTo( TiXmlDocument* target ) const -{ - TiXmlNode::CopyTo( target ); - - target->error = error; - target->errorId = errorId; - target->errorDesc = errorDesc; - target->tabsize = tabsize; - target->errorLocation = errorLocation; - target->useMicrosoftBOM = useMicrosoftBOM; - - TiXmlNode* node = 0; - for ( node = firstChild; node; node = node->NextSibling() ) - { - target->LinkEndChild( node->Clone() ); - } -} - - -TiXmlNode* TiXmlDocument::Clone() const -{ - TiXmlDocument* clone = new TiXmlDocument(); - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -void TiXmlDocument::Print( FILE* cfile, int depth ) const -{ - assert( cfile ); - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - node->Print( cfile, depth ); - fprintf( cfile, "\n" ); - } -} - - -bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const -{ - if ( visitor->VisitEnter( *this ) ) - { - for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) - { - if ( !node->Accept( visitor ) ) - break; - } - } - return visitor->VisitExit( *this ); -} - - -const TiXmlAttribute* TiXmlAttribute::Next() const -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( next->value.empty() && next->name.empty() ) - return 0; - return next; -} - -/* -TiXmlAttribute* TiXmlAttribute::Next() -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( next->value.empty() && next->name.empty() ) - return 0; - return next; -} -*/ - -const TiXmlAttribute* TiXmlAttribute::Previous() const -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( prev->value.empty() && prev->name.empty() ) - return 0; - return prev; -} - -/* -TiXmlAttribute* TiXmlAttribute::Previous() -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( prev->value.empty() && prev->name.empty() ) - return 0; - return prev; -} -*/ - -void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const -{ - TIXML_STRING n, v; - - EncodeString( name, &n ); - EncodeString( value, &v ); - - if (value.find ('\"') == TIXML_STRING::npos) { - if ( cfile ) { - fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); - } - if ( str ) { - (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; - } - } - else { - if ( cfile ) { - fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); - } - if ( str ) { - (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; - } - } -} - - -int TiXmlAttribute::QueryIntValue( int* ival ) const -{ - if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) - return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; -} - -int TiXmlAttribute::QueryDoubleValue( double* dval ) const -{ - if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) - return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; -} - -void TiXmlAttribute::SetIntValue( int _value ) -{ - char buf [64]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); - #else - sprintf (buf, "%d", _value); - #endif - SetValue (buf); -} - -void TiXmlAttribute::SetDoubleValue( double _value ) -{ - char buf [256]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value); - #else - sprintf (buf, "%g", _value); - #endif - SetValue (buf); -} - -int TiXmlAttribute::IntValue() const -{ - return atoi (value.c_str ()); -} - -double TiXmlAttribute::DoubleValue() const -{ - return atof (value.c_str ()); -} - - -TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) -{ - copy.CopyTo( this ); -} - - -TiXmlComment& TiXmlComment::operator=( const TiXmlComment& base ) -{ - Clear(); - base.CopyTo( this ); - return *this; -} - - -void TiXmlComment::Print( FILE* cfile, int depth ) const -{ - assert( cfile ); - for ( int i=0; i", value.c_str() ); -} - - -void TiXmlComment::CopyTo( TiXmlComment* target ) const -{ - TiXmlNode::CopyTo( target ); -} - - -bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlComment::Clone() const -{ - TiXmlComment* clone = new TiXmlComment(); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -void TiXmlText::Print( FILE* cfile, int depth ) const -{ - assert( cfile ); - if ( cdata ) - { - int i; - fprintf( cfile, "\n" ); - for ( i=0; i\n", value.c_str() ); // unformatted output - } - else - { - TIXML_STRING buffer; - EncodeString( value, &buffer ); - fprintf( cfile, "%s", buffer.c_str() ); - } -} - - -void TiXmlText::CopyTo( TiXmlText* target ) const -{ - TiXmlNode::CopyTo( target ); - target->cdata = cdata; -} - - -bool TiXmlText::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlText::Clone() const -{ - TiXmlText* clone = 0; - clone = new TiXmlText( "" ); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -TiXmlDeclaration::TiXmlDeclaration( const char * _version, - const char * _encoding, - const char * _standalone ) - : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) -{ - version = _version; - encoding = _encoding; - standalone = _standalone; -} - - -#ifdef TIXML_USE_STL -TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, - const std::string& _encoding, - const std::string& _standalone ) - : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) -{ - version = _version; - encoding = _encoding; - standalone = _standalone; -} -#endif - - -TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) - : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) -{ - copy.CopyTo( this ); -} - - -TiXmlDeclaration& TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) -{ - Clear(); - copy.CopyTo( this ); - return *this; -} - - -void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const -{ - if ( cfile ) fprintf( cfile, "" ); - if ( str ) (*str) += "?>"; -} - - -void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const -{ - TiXmlNode::CopyTo( target ); - - target->version = version; - target->encoding = encoding; - target->standalone = standalone; -} - - -bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlDeclaration::Clone() const -{ - TiXmlDeclaration* clone = new TiXmlDeclaration(); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -void TiXmlUnknown::Print( FILE* cfile, int depth ) const -{ - for ( int i=0; i", value.c_str() ); -} - - -void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const -{ - TiXmlNode::CopyTo( target ); -} - - -bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const -{ - return visitor->Visit( *this ); -} - - -TiXmlNode* TiXmlUnknown::Clone() const -{ - TiXmlUnknown* clone = new TiXmlUnknown(); - - if ( !clone ) - return 0; - - CopyTo( clone ); - return clone; -} - - -TiXmlAttributeSet::TiXmlAttributeSet() -{ - sentinel.next = &sentinel; - sentinel.prev = &sentinel; -} - - -TiXmlAttributeSet::~TiXmlAttributeSet() -{ - assert( sentinel.next == &sentinel ); - assert( sentinel.prev == &sentinel ); -} - - -void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) -{ - #ifdef TIXML_USE_STL - assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. - #else - assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. - #endif - - addMe->next = &sentinel; - addMe->prev = sentinel.prev; - - sentinel.prev->next = addMe; - sentinel.prev = addMe; -} - -void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) -{ - TiXmlAttribute* node; - - for( node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( node == removeMe ) - { - node->prev->next = node->next; - node->next->prev = node->prev; - node->next = 0; - node->prev = 0; - return; - } - } - assert( 0 ); // we tried to remove a non-linked attribute. -} - - -#ifdef TIXML_USE_STL -TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const -{ - for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( node->name == name ) - return node; - } - return 0; -} - -TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name ) -{ - TiXmlAttribute* attrib = Find( _name ); - if ( !attrib ) { - attrib = new TiXmlAttribute(); - Add( attrib ); - attrib->SetName( _name ); - } - return attrib; -} -#endif - - -TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const -{ - for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( strcmp( node->name.c_str(), name ) == 0 ) - return node; - } - return 0; -} - - -TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name ) -{ - TiXmlAttribute* attrib = Find( _name ); - if ( !attrib ) { - attrib = new TiXmlAttribute(); - Add( attrib ); - attrib->SetName( _name ); - } - return attrib; -} - - -#ifdef TIXML_USE_STL -std::istream& operator>> (std::istream & in, TiXmlNode & base) -{ - TIXML_STRING tag; - tag.reserve( 8 * 1000 ); - base.StreamIn( &in, &tag ); - - base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); - return in; -} -#endif - - -#ifdef TIXML_USE_STL -std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) -{ - TiXmlPrinter printer; - printer.SetStreamPrinting(); - base.Accept( &printer ); - out << printer.Str(); - - return out; -} - - -std::string& operator<< (std::string& out, const TiXmlNode& base ) -{ - TiXmlPrinter printer; - printer.SetStreamPrinting(); - base.Accept( &printer ); - out.append( printer.Str() ); - - return out; -} -#endif - - -TiXmlHandle TiXmlHandle::FirstChild() const -{ - if ( node ) - { - TiXmlNode* child = node->FirstChild(); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const -{ - if ( node ) - { - TiXmlNode* child = node->FirstChild( value ); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::FirstChildElement() const -{ - if ( node ) - { - TiXmlElement* child = node->FirstChildElement(); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const -{ - if ( node ) - { - TiXmlElement* child = node->FirstChildElement( value ); - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::Child( int count ) const -{ - if ( node ) - { - int i; - TiXmlNode* child = node->FirstChild(); - for ( i=0; - child && iNextSibling(), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const -{ - if ( node ) - { - int i; - TiXmlNode* child = node->FirstChild( value ); - for ( i=0; - child && iNextSibling( value ), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::ChildElement( int count ) const -{ - if ( node ) - { - int i; - TiXmlElement* child = node->FirstChildElement(); - for ( i=0; - child && iNextSiblingElement(), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const -{ - if ( node ) - { - int i; - TiXmlElement* child = node->FirstChildElement( value ); - for ( i=0; - child && iNextSiblingElement( value ), ++i ) - { - // nothing - } - if ( child ) - return TiXmlHandle( child ); - } - return TiXmlHandle( 0 ); -} - - -bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) -{ - return true; -} - -bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) -{ - return true; -} - -bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) -{ - DoIndent(); - buffer += "<"; - buffer += element.Value(); - - for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) - { - buffer += " "; - attrib->Print( 0, 0, &buffer ); - } - - if ( !element.FirstChild() ) - { - buffer += " />"; - DoLineBreak(); - } - else - { - buffer += ">"; - if ( element.FirstChild()->ToText() - && element.LastChild() == element.FirstChild() - && element.FirstChild()->ToText()->CDATA() == false ) - { - simpleTextPrint = true; - // no DoLineBreak()! - } - else - { - DoLineBreak(); - } - } - ++depth; - return true; -} - - -bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) -{ - --depth; - if ( !element.FirstChild() ) - { - // nothing. - } - else - { - if ( simpleTextPrint ) - { - simpleTextPrint = false; - } - else - { - DoIndent(); - } - buffer += ""; - DoLineBreak(); - } - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlText& text ) -{ - if ( text.CDATA() ) - { - DoIndent(); - buffer += ""; - DoLineBreak(); - } - else if ( simpleTextPrint ) - { - TIXML_STRING str; - TiXmlBase::EncodeString( text.ValueTStr(), &str ); - buffer += str; - } - else - { - DoIndent(); - TIXML_STRING str; - TiXmlBase::EncodeString( text.ValueTStr(), &str ); - buffer += str; - DoLineBreak(); - } - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) -{ - DoIndent(); - declaration.Print( 0, 0, &buffer ); - DoLineBreak(); - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlComment& comment ) -{ - DoIndent(); - buffer += ""; - DoLineBreak(); - return true; -} - - -bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) -{ - DoIndent(); - buffer += "<"; - buffer += unknown.Value(); - buffer += ">"; - DoLineBreak(); - return true; -} - diff --git a/ctrtool/tinyxml/tinyxml.h b/ctrtool/tinyxml/tinyxml.h deleted file mode 100644 index eea0f06..0000000 --- a/ctrtool/tinyxml/tinyxml.h +++ /dev/null @@ -1,1805 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml -Original code by Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - - -#ifndef TINYXML_INCLUDED -#define TINYXML_INCLUDED - -#ifdef _MSC_VER -#pragma warning( push ) -#pragma warning( disable : 4530 ) -#pragma warning( disable : 4786 ) -#endif - -#include -#include -#include -#include -#include - -// Help out windows: -#if defined( _DEBUG ) && !defined( DEBUG ) -#define DEBUG -#endif - -#ifdef TIXML_USE_STL - #include - #include - #include - #define TIXML_STRING std::string -#else - #include "tinyxml/tinystr.h" - #define TIXML_STRING TiXmlString -#endif - -// Deprecated library function hell. Compilers want to use the -// new safe versions. This probably doesn't fully address the problem, -// but it gets closer. There are too many compilers for me to fully -// test. If you get compilation troubles, undefine TIXML_SAFE -#define TIXML_SAFE - -#ifdef TIXML_SAFE - #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) - // Microsoft visual studio, version 2005 and higher. - #define TIXML_SNPRINTF _snprintf_s - #define TIXML_SSCANF sscanf_s - #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) - // Microsoft visual studio, version 6 and higher. - //#pragma message( "Using _sn* functions." ) - #define TIXML_SNPRINTF _snprintf - #define TIXML_SSCANF sscanf - #elif defined(__GNUC__) && (__GNUC__ >= 3 ) - // GCC version 3 and higher.s - //#warning( "Using sn* functions." ) - #define TIXML_SNPRINTF snprintf - #define TIXML_SSCANF sscanf - #else - #define TIXML_SNPRINTF snprintf - #define TIXML_SSCANF sscanf - #endif -#endif - -class TiXmlDocument; -class TiXmlElement; -class TiXmlComment; -class TiXmlUnknown; -class TiXmlAttribute; -class TiXmlText; -class TiXmlDeclaration; -class TiXmlParsingData; - -const int TIXML_MAJOR_VERSION = 2; -const int TIXML_MINOR_VERSION = 6; -const int TIXML_PATCH_VERSION = 2; - -/* Internal structure for tracking location of items - in the XML file. -*/ -struct TiXmlCursor -{ - TiXmlCursor() { Clear(); } - void Clear() { row = col = -1; } - - int row; // 0 based. - int col; // 0 based. -}; - - -/** - Implements the interface to the "Visitor pattern" (see the Accept() method.) - If you call the Accept() method, it requires being passed a TiXmlVisitor - class to handle callbacks. For nodes that contain other nodes (Document, Element) - you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves - are simply called with Visit(). - - If you return 'true' from a Visit method, recursive parsing will continue. If you return - false, no children of this node or its sibilings will be Visited. - - All flavors of Visit methods have a default implementation that returns 'true' (continue - visiting). You need to only override methods that are interesting to you. - - Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. - - You should never change the document from a callback. - - @sa TiXmlNode::Accept() -*/ -class TiXmlVisitor -{ -public: - virtual ~TiXmlVisitor() {} - - /// Visit a document. - virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; } - /// Visit a document. - virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; } - - /// Visit an element. - virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; } - /// Visit an element. - virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; } - - /// Visit a declaration - virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; } - /// Visit a text node - virtual bool Visit( const TiXmlText& /*text*/ ) { return true; } - /// Visit a comment node - virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; } - /// Visit an unknown node - virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; } -}; - -// Only used by Attribute::Query functions -enum -{ - TIXML_SUCCESS, - TIXML_NO_ATTRIBUTE, - TIXML_WRONG_TYPE -}; - - -// Used by the parsing routines. -enum TiXmlEncoding -{ - TIXML_ENCODING_UNKNOWN, - TIXML_ENCODING_UTF8, - TIXML_ENCODING_LEGACY -}; - -const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; - -/** TiXmlBase is a base class for every class in TinyXml. - It does little except to establish that TinyXml classes - can be printed and provide some utility functions. - - In XML, the document and elements can contain - other elements and other types of nodes. - - @verbatim - A Document can contain: Element (container or leaf) - Comment (leaf) - Unknown (leaf) - Declaration( leaf ) - - An Element can contain: Element (container or leaf) - Text (leaf) - Attributes (not on tree) - Comment (leaf) - Unknown (leaf) - - A Decleration contains: Attributes (not on tree) - @endverbatim -*/ -class TiXmlBase -{ - friend class TiXmlNode; - friend class TiXmlElement; - friend class TiXmlDocument; - -public: - TiXmlBase() : userData(0) {} - virtual ~TiXmlBase() {} - - /** All TinyXml classes can print themselves to a filestream - or the string class (TiXmlString in non-STL mode, std::string - in STL mode.) Either or both cfile and str can be null. - - This is a formatted print, and will insert - tabs and newlines. - - (For an unformatted stream, use the << operator.) - */ - virtual void Print( FILE* cfile, int depth ) const = 0; - - /** The world does not agree on whether white space should be kept or - not. In order to make everyone happy, these global, static functions - are provided to set whether or not TinyXml will condense all white space - into a single space or not. The default is to condense. Note changing this - value is not thread safe. - */ - static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } - - /// Return the current white space setting. - static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } - - /** Return the position, in the original source file, of this node or attribute. - The row and column are 1-based. (That is the first row and first column is - 1,1). If the returns values are 0 or less, then the parser does not have - a row and column value. - - Generally, the row and column value will be set when the TiXmlDocument::Load(), - TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set - when the DOM was created from operator>>. - - The values reflect the initial load. Once the DOM is modified programmatically - (by adding or changing nodes and attributes) the new values will NOT update to - reflect changes in the document. - - There is a minor performance cost to computing the row and column. Computation - can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. - - @sa TiXmlDocument::SetTabSize() - */ - int Row() const { return location.row + 1; } - int Column() const { return location.col + 1; } ///< See Row() - - void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. - void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data. - const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data. - - // Table that returs, for a given lead byte, the total number of bytes - // in the UTF-8 sequence. - static const int utf8ByteTable[256]; - - virtual const char* Parse( const char* p, - TiXmlParsingData* data, - TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; - - /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, - or they will be transformed into entities! - */ - static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out ); - - enum - { - TIXML_NO_ERROR = 0, - TIXML_ERROR, - TIXML_ERROR_OPENING_FILE, - TIXML_ERROR_PARSING_ELEMENT, - TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, - TIXML_ERROR_READING_ELEMENT_VALUE, - TIXML_ERROR_READING_ATTRIBUTES, - TIXML_ERROR_PARSING_EMPTY, - TIXML_ERROR_READING_END_TAG, - TIXML_ERROR_PARSING_UNKNOWN, - TIXML_ERROR_PARSING_COMMENT, - TIXML_ERROR_PARSING_DECLARATION, - TIXML_ERROR_DOCUMENT_EMPTY, - TIXML_ERROR_EMBEDDED_NULL, - TIXML_ERROR_PARSING_CDATA, - TIXML_ERROR_DOCUMENT_TOP_ONLY, - - TIXML_ERROR_STRING_COUNT - }; - -protected: - - static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); - - inline static bool IsWhiteSpace( char c ) - { - return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); - } - inline static bool IsWhiteSpace( int c ) - { - if ( c < 256 ) - return IsWhiteSpace( (char) c ); - return false; // Again, only truly correct for English/Latin...but usually works. - } - - #ifdef TIXML_USE_STL - static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); - static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); - #endif - - /* Reads an XML name into the string provided. Returns - a pointer just past the last character of the name, - or 0 if the function has an error. - */ - static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); - - /* Reads text. Returns a pointer past the given end tag. - Wickedly complex options, but it keeps the (sensitive) code in one place. - */ - static const char* ReadText( const char* in, // where to start - TIXML_STRING* text, // the string read - bool ignoreWhiteSpace, // whether to keep the white space - const char* endTag, // what ends this text - bool ignoreCase, // whether to ignore case in the end tag - TiXmlEncoding encoding ); // the current encoding - - // If an entity has been found, transform it into a character. - static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); - - // Get a character, while interpreting entities. - // The length can be from 0 to 4 bytes. - inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) - { - assert( p ); - if ( encoding == TIXML_ENCODING_UTF8 ) - { - *length = utf8ByteTable[ *((const unsigned char*)p) ]; - assert( *length >= 0 && *length < 5 ); - } - else - { - *length = 1; - } - - if ( *length == 1 ) - { - if ( *p == '&' ) - return GetEntity( p, _value, length, encoding ); - *_value = *p; - return p+1; - } - else if ( *length ) - { - //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), - // and the null terminator isn't needed - for( int i=0; p[i] && i<*length; ++i ) { - _value[i] = p[i]; - } - return p + (*length); - } - else - { - // Not valid text. - return 0; - } - } - - // Return true if the next characters in the stream are any of the endTag sequences. - // Ignore case only works for english, and should only be relied on when comparing - // to English words: StringEqual( p, "version", true ) is fine. - static bool StringEqual( const char* p, - const char* endTag, - bool ignoreCase, - TiXmlEncoding encoding ); - - static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; - - TiXmlCursor location; - - /// Field containing a generic user pointer - void* userData; - - // None of these methods are reliable for any language except English. - // Good for approximation, not great for accuracy. - static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); - static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); - inline static int ToLower( int v, TiXmlEncoding encoding ) - { - if ( encoding == TIXML_ENCODING_UTF8 ) - { - if ( v < 128 ) return tolower( v ); - return v; - } - else - { - return tolower( v ); - } - } - static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); - -private: - TiXmlBase( const TiXmlBase& ); // not implemented. - void operator=( const TiXmlBase& base ); // not allowed. - - struct Entity - { - const char* str; - unsigned int strLength; - char chr; - }; - enum - { - NUM_ENTITY = 5, - MAX_ENTITY_LENGTH = 6 - - }; - static Entity entity[ NUM_ENTITY ]; - static bool condenseWhiteSpace; -}; - - -/** The parent class for everything in the Document Object Model. - (Except for attributes). - Nodes have siblings, a parent, and children. A node can be - in a document, or stand on its own. The type of a TiXmlNode - can be queried, and it can be cast to its more defined type. -*/ -class TiXmlNode : public TiXmlBase -{ - friend class TiXmlDocument; - friend class TiXmlElement; - -public: - #ifdef TIXML_USE_STL - - /** An input stream operator, for every class. Tolerant of newlines and - formatting, but doesn't expect them. - */ - friend std::istream& operator >> (std::istream& in, TiXmlNode& base); - - /** An output stream operator, for every class. Note that this outputs - without any newlines or formatting, as opposed to Print(), which - includes tabs and new lines. - - The operator<< and operator>> are not completely symmetric. Writing - a node to a stream is very well defined. You'll get a nice stream - of output, without any extra whitespace or newlines. - - But reading is not as well defined. (As it always is.) If you create - a TiXmlElement (for example) and read that from an input stream, - the text needs to define an element or junk will result. This is - true of all input streams, but it's worth keeping in mind. - - A TiXmlDocument will read nodes until it reads a root element, and - all the children of that root element. - */ - friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); - - /// Appends the XML node or attribute to a std::string. - friend std::string& operator<< (std::string& out, const TiXmlNode& base ); - - #endif - - /** The types of XML nodes supported by TinyXml. (All the - unsupported types are picked up by UNKNOWN.) - */ - enum NodeType - { - TINYXML_DOCUMENT, - TINYXML_ELEMENT, - TINYXML_COMMENT, - TINYXML_UNKNOWN, - TINYXML_TEXT, - TINYXML_DECLARATION, - TINYXML_TYPECOUNT - }; - - virtual ~TiXmlNode(); - - /** The meaning of 'value' changes for the specific type of - TiXmlNode. - @verbatim - Document: filename of the xml file - Element: name of the element - Comment: the comment text - Unknown: the tag contents - Text: the text string - @endverbatim - - The subclasses will wrap this function. - */ - const char *Value() const { return value.c_str (); } - - #ifdef TIXML_USE_STL - /** Return Value() as a std::string. If you only use STL, - this is more efficient than calling Value(). - Only available in STL mode. - */ - const std::string& ValueStr() const { return value; } - #endif - - const TIXML_STRING& ValueTStr() const { return value; } - - /** Changes the value of the node. Defined as: - @verbatim - Document: filename of the xml file - Element: name of the element - Comment: the comment text - Unknown: the tag contents - Text: the text string - @endverbatim - */ - void SetValue(const char * _value) { value = _value;} - - #ifdef TIXML_USE_STL - /// STL std::string form. - void SetValue( const std::string& _value ) { value = _value; } - #endif - - /// Delete all the children of this node. Does not affect 'this'. - void Clear(); - - /// One step up the DOM. - TiXmlNode* Parent() { return parent; } - const TiXmlNode* Parent() const { return parent; } - - const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. - TiXmlNode* FirstChild() { return firstChild; } - const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. - /// The first child of this node with the matching 'value'. Will be null if none found. - TiXmlNode* FirstChild( const char * _value ) { - // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) - // call the method, cast the return back to non-const. - return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); - } - const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. - TiXmlNode* LastChild() { return lastChild; } - - const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. - TiXmlNode* LastChild( const char * _value ) { - return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); - } - - #ifdef TIXML_USE_STL - const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. - const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. - #endif - - /** An alternate way to walk the children of a node. - One way to iterate over nodes is: - @verbatim - for( child = parent->FirstChild(); child; child = child->NextSibling() ) - @endverbatim - - IterateChildren does the same thing with the syntax: - @verbatim - child = 0; - while( child = parent->IterateChildren( child ) ) - @endverbatim - - IterateChildren takes the previous child as input and finds - the next one. If the previous child is null, it returns the - first. IterateChildren will return null when done. - */ - const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; - TiXmlNode* IterateChildren( const TiXmlNode* previous ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); - } - - /// This flavor of IterateChildren searches for children with a particular 'value' - const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; - TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. - TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. - #endif - - /** Add a new node related to this. Adds a child past the LastChild. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); - - - /** Add a new node related to this. Adds a child past the LastChild. - - NOTE: the node to be added is passed by pointer, and will be - henceforth owned (and deleted) by tinyXml. This method is efficient - and avoids an extra copy, but should be used with care as it - uses a different memory model than the other insert functions. - - @sa InsertEndChild - */ - TiXmlNode* LinkEndChild( TiXmlNode* addThis ); - - /** Add a new node related to this. Adds a child before the specified child. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); - - /** Add a new node related to this. Adds a child after the specified child. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); - - /** Replace a child of this node. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); - - /// Delete a child of this node. - bool RemoveChild( TiXmlNode* removeThis ); - - /// Navigate to a sibling node. - const TiXmlNode* PreviousSibling() const { return prev; } - TiXmlNode* PreviousSibling() { return prev; } - - /// Navigate to a sibling node. - const TiXmlNode* PreviousSibling( const char * ) const; - TiXmlNode* PreviousSibling( const char *_prev ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. - const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. - TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. - #endif - - /// Navigate to a sibling node. - const TiXmlNode* NextSibling() const { return next; } - TiXmlNode* NextSibling() { return next; } - - /// Navigate to a sibling node with the given 'value'. - const TiXmlNode* NextSibling( const char * ) const; - TiXmlNode* NextSibling( const char* _next ) { - return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); - } - - /** Convenience function to get through elements. - Calls NextSibling and ToElement. Will skip all non-Element - nodes. Returns 0 if there is not another element. - */ - const TiXmlElement* NextSiblingElement() const; - TiXmlElement* NextSiblingElement() { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); - } - - /** Convenience function to get through elements. - Calls NextSibling and ToElement. Will skip all non-Element - nodes. Returns 0 if there is not another element. - */ - const TiXmlElement* NextSiblingElement( const char * ) const; - TiXmlElement* NextSiblingElement( const char *_next ) { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. - TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. - #endif - - /// Convenience function to get through elements. - const TiXmlElement* FirstChildElement() const; - TiXmlElement* FirstChildElement() { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); - } - - /// Convenience function to get through elements. - const TiXmlElement* FirstChildElement( const char * _value ) const; - TiXmlElement* FirstChildElement( const char * _value ) { - return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); - } - - #ifdef TIXML_USE_STL - const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. - TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. - #endif - - /** Query the type (as an enumerated value, above) of this node. - The possible types are: TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT, - TINYXML_UNKNOWN, TINYXML_TEXT, and TINYXML_DECLARATION. - */ - int Type() const { return type; } - - /** Return a pointer to the Document this node lives in. - Returns null if not in a document. - */ - const TiXmlDocument* GetDocument() const; - TiXmlDocument* GetDocument() { - return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); - } - - /// Returns true if this node has no children. - bool NoChildren() const { return !firstChild; } - - virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - - virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. - - /** Create an exact duplicate of this node and return it. The memory must be deleted - by the caller. - */ - virtual TiXmlNode* Clone() const = 0; - - /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the - XML tree will be conditionally visited and the host will be called back - via the TiXmlVisitor interface. - - This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse - the XML for the callbacks, so the performance of TinyXML is unchanged by using this - interface versus any other.) - - The interface has been based on ideas from: - - - http://www.saxproject.org/ - - http://c2.com/cgi/wiki?HierarchicalVisitorPattern - - Which are both good references for "visiting". - - An example of using Accept(): - @verbatim - TiXmlPrinter printer; - tinyxmlDoc.Accept( &printer ); - const char* xmlcstr = printer.CStr(); - @endverbatim - */ - virtual bool Accept( TiXmlVisitor* visitor ) const = 0; - -protected: - TiXmlNode( NodeType _type ); - - // Copy to the allocated object. Shared functionality between Clone, Copy constructor, - // and the assignment operator. - void CopyTo( TiXmlNode* target ) const; - - #ifdef TIXML_USE_STL - // The real work of the input operator. - virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; - #endif - - // Figure out what is at *p, and parse it. Returns null if it is not an xml node. - TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); - - TiXmlNode* parent; - NodeType type; - - TiXmlNode* firstChild; - TiXmlNode* lastChild; - - TIXML_STRING value; - - TiXmlNode* prev; - TiXmlNode* next; - -private: - TiXmlNode( const TiXmlNode& ); // not implemented. - void operator=( const TiXmlNode& base ); // not allowed. -}; - - -/** An attribute is a name-value pair. Elements have an arbitrary - number of attributes, each with a unique name. - - @note The attributes are not TiXmlNodes, since they are not - part of the tinyXML document object model. There are other - suggested ways to look at this problem. -*/ -class TiXmlAttribute : public TiXmlBase -{ - friend class TiXmlAttributeSet; - -public: - /// Construct an empty attribute. - TiXmlAttribute() : TiXmlBase() - { - document = 0; - prev = next = 0; - } - - #ifdef TIXML_USE_STL - /// std::string constructor. - TiXmlAttribute( const std::string& _name, const std::string& _value ) - { - name = _name; - value = _value; - document = 0; - prev = next = 0; - } - #endif - - /// Construct an attribute with a name and value. - TiXmlAttribute( const char * _name, const char * _value ) - { - name = _name; - value = _value; - document = 0; - prev = next = 0; - } - - const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. - const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. - #ifdef TIXML_USE_STL - const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. - #endif - int IntValue() const; ///< Return the value of this attribute, converted to an integer. - double DoubleValue() const; ///< Return the value of this attribute, converted to a double. - - // Get the tinyxml string representation - const TIXML_STRING& NameTStr() const { return name; } - - /** QueryIntValue examines the value string. It is an alternative to the - IntValue() method with richer error checking. - If the value is an integer, it is stored in 'value' and - the call returns TIXML_SUCCESS. If it is not - an integer, it returns TIXML_WRONG_TYPE. - - A specialized but useful call. Note that for success it returns 0, - which is the opposite of almost all other TinyXml calls. - */ - int QueryIntValue( int* _value ) const; - /// QueryDoubleValue examines the value string. See QueryIntValue(). - int QueryDoubleValue( double* _value ) const; - - void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. - void SetValue( const char* _value ) { value = _value; } ///< Set the value. - - void SetIntValue( int _value ); ///< Set the value from an integer. - void SetDoubleValue( double _value ); ///< Set the value from a double. - - #ifdef TIXML_USE_STL - /// STL std::string form. - void SetName( const std::string& _name ) { name = _name; } - /// STL std::string form. - void SetValue( const std::string& _value ) { value = _value; } - #endif - - /// Get the next sibling attribute in the DOM. Returns null at end. - const TiXmlAttribute* Next() const; - TiXmlAttribute* Next() { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); - } - - /// Get the previous sibling attribute in the DOM. Returns null at beginning. - const TiXmlAttribute* Previous() const; - TiXmlAttribute* Previous() { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); - } - - bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } - bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } - bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } - - /* Attribute parsing starts: first letter of the name - returns: the next char after the value end quote - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - // Prints this Attribute to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const { - Print( cfile, depth, 0 ); - } - void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; - - // [internal use] - // Set the document pointer so the attribute can report errors. - void SetDocument( TiXmlDocument* doc ) { document = doc; } - -private: - TiXmlAttribute( const TiXmlAttribute& ); // not implemented. - void operator=( const TiXmlAttribute& base ); // not allowed. - - TiXmlDocument* document; // A pointer back to a document, for error reporting. - TIXML_STRING name; - TIXML_STRING value; - TiXmlAttribute* prev; - TiXmlAttribute* next; -}; - - -/* A class used to manage a group of attributes. - It is only used internally, both by the ELEMENT and the DECLARATION. - - The set can be changed transparent to the Element and Declaration - classes that use it, but NOT transparent to the Attribute - which has to implement a next() and previous() method. Which makes - it a bit problematic and prevents the use of STL. - - This version is implemented with circular lists because: - - I like circular lists - - it demonstrates some independence from the (typical) doubly linked list. -*/ -class TiXmlAttributeSet -{ -public: - TiXmlAttributeSet(); - ~TiXmlAttributeSet(); - - void Add( TiXmlAttribute* attribute ); - void Remove( TiXmlAttribute* attribute ); - - const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } - TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } - const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } - TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } - - TiXmlAttribute* Find( const char* _name ) const; - TiXmlAttribute* FindOrCreate( const char* _name ); - -# ifdef TIXML_USE_STL - TiXmlAttribute* Find( const std::string& _name ) const; - TiXmlAttribute* FindOrCreate( const std::string& _name ); -# endif - - -private: - //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), - //*ME: this class must be also use a hidden/disabled copy-constructor !!! - TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed - void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) - - TiXmlAttribute sentinel; -}; - - -/** The element is a container class. It has a value, the element name, - and can contain other elements, text, comments, and unknowns. - Elements also contain an arbitrary number of attributes. -*/ -class TiXmlElement : public TiXmlNode -{ -public: - /// Construct an element. - TiXmlElement (const char * in_value); - - #ifdef TIXML_USE_STL - /// std::string constructor. - TiXmlElement( const std::string& _value ); - #endif - - TiXmlElement( const TiXmlElement& ); - - TiXmlElement& operator=( const TiXmlElement& base ); - - virtual ~TiXmlElement(); - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - */ - const char* Attribute( const char* name ) const; - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - If the attribute exists and can be converted to an integer, - the integer value will be put in the return 'i', if 'i' - is non-null. - */ - const char* Attribute( const char* name, int* i ) const; - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - If the attribute exists and can be converted to an double, - the double value will be put in the return 'd', if 'd' - is non-null. - */ - const char* Attribute( const char* name, double* d ) const; - - /** QueryIntAttribute examines the attribute - it is an alternative to the - Attribute() method with richer error checking. - If the attribute is an integer, it is stored in 'value' and - the call returns TIXML_SUCCESS. If it is not - an integer, it returns TIXML_WRONG_TYPE. If the attribute - does not exist, then TIXML_NO_ATTRIBUTE is returned. - */ - int QueryIntAttribute( const char* name, int* _value ) const; - /// QueryUnsignedAttribute examines the attribute - see QueryIntAttribute(). - int QueryUnsignedAttribute( const char* name, unsigned* _value ) const; - /** QueryBoolAttribute examines the attribute - see QueryIntAttribute(). - Note that '1', 'true', or 'yes' are considered true, while '0', 'false' - and 'no' are considered false. - */ - int QueryBoolAttribute( const char* name, bool* _value ) const; - /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). - int QueryDoubleAttribute( const char* name, double* _value ) const; - /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). - int QueryFloatAttribute( const char* name, float* _value ) const { - double d; - int result = QueryDoubleAttribute( name, &d ); - if ( result == TIXML_SUCCESS ) { - *_value = (float)d; - } - return result; - } - - #ifdef TIXML_USE_STL - /// QueryStringAttribute examines the attribute - see QueryIntAttribute(). - int QueryStringAttribute( const char* name, std::string* _value ) const { - const char* cstr = Attribute( name ); - if ( cstr ) { - *_value = std::string( cstr ); - return TIXML_SUCCESS; - } - return TIXML_NO_ATTRIBUTE; - } - - /** Template form of the attribute query which will try to read the - attribute into the specified type. Very easy, very powerful, but - be careful to make sure to call this with the correct type. - - NOTE: This method doesn't work correctly for 'string' types that contain spaces. - - @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE - */ - template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const - { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - - std::stringstream sstream( node->ValueStr() ); - sstream >> *outValue; - if ( !sstream.fail() ) - return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; - } - - int QueryValueAttribute( const std::string& name, std::string* outValue ) const - { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) - return TIXML_NO_ATTRIBUTE; - *outValue = node->ValueStr(); - return TIXML_SUCCESS; - } - #endif - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetAttribute( const char* name, const char * _value ); - - #ifdef TIXML_USE_STL - const std::string* Attribute( const std::string& name ) const; - const std::string* Attribute( const std::string& name, int* i ) const; - const std::string* Attribute( const std::string& name, double* d ) const; - int QueryIntAttribute( const std::string& name, int* _value ) const; - int QueryDoubleAttribute( const std::string& name, double* _value ) const; - - /// STL std::string form. - void SetAttribute( const std::string& name, const std::string& _value ); - ///< STL std::string form. - void SetAttribute( const std::string& name, int _value ); - ///< STL std::string form. - void SetDoubleAttribute( const std::string& name, double value ); - #endif - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetAttribute( const char * name, int value ); - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetDoubleAttribute( const char * name, double value ); - - /** Deletes an attribute with the given name. - */ - void RemoveAttribute( const char * name ); - #ifdef TIXML_USE_STL - void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. - #endif - - const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. - TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } - const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. - TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } - - /** Convenience function for easy access to the text inside an element. Although easy - and concise, GetText() is limited compared to getting the TiXmlText child - and accessing it directly. - - If the first child of 'this' is a TiXmlText, the GetText() - returns the character string of the Text node, else null is returned. - - This is a convenient method for getting the text of simple contained text: - @verbatim - This is text - const char* str = fooElement->GetText(); - @endverbatim - - 'str' will be a pointer to "This is text". - - Note that this function can be misleading. If the element foo was created from - this XML: - @verbatim - This is text - @endverbatim - - then the value of str would be null. The first child node isn't a text node, it is - another element. From this XML: - @verbatim - This is text - @endverbatim - GetText() will return "This is ". - - WARNING: GetText() accesses a child node - don't become confused with the - similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are - safe type casts on the referenced node. - */ - const char* GetText() const; - - /// Creates a new Element and returns it - the returned element is a copy. - virtual TiXmlNode* Clone() const; - // Print the Element to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - /* Attribtue parsing starts: next char past '<' - returns: next char past '>' - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* visitor ) const; - -protected: - - void CopyTo( TiXmlElement* target ) const; - void ClearThis(); // like clear, but initializes 'this' object as well - - // Used to be public [internal use] - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - /* [internal use] - Reads the "value" of the element -- another element, or text. - This should terminate with the current end tag. - */ - const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); - -private: - TiXmlAttributeSet attributeSet; -}; - - -/** An XML comment. -*/ -class TiXmlComment : public TiXmlNode -{ -public: - /// Constructs an empty comment. - TiXmlComment() : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {} - /// Construct a comment from text. - TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { - SetValue( _value ); - } - TiXmlComment( const TiXmlComment& ); - TiXmlComment& operator=( const TiXmlComment& base ); - - virtual ~TiXmlComment() {} - - /// Returns a copy of this Comment. - virtual TiXmlNode* Clone() const; - // Write this Comment to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - /* Attribtue parsing starts: at the ! of the !-- - returns: next char past '>' - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* visitor ) const; - -protected: - void CopyTo( TiXmlComment* target ) const; - - // used to be public - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif -// virtual void StreamOut( TIXML_OSTREAM * out ) const; - -private: - -}; - - -/** XML text. A text node can have 2 ways to output the next. "normal" output - and CDATA. It will default to the mode it was parsed from the XML file and - you generally want to leave it alone, but you can change the output mode with - SetCDATA() and query it with CDATA(). -*/ -class TiXmlText : public TiXmlNode -{ - friend class TiXmlElement; -public: - /** Constructor for text element. By default, it is treated as - normal, encoded text. If you want it be output as a CDATA text - element, set the parameter _cdata to 'true' - */ - TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) - { - SetValue( initValue ); - cdata = false; - } - virtual ~TiXmlText() {} - - #ifdef TIXML_USE_STL - /// Constructor. - TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) - { - SetValue( initValue ); - cdata = false; - } - #endif - - TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TINYXML_TEXT ) { copy.CopyTo( this ); } - TiXmlText& operator=( const TiXmlText& base ) { base.CopyTo( this ); return *this; } - - // Write this text object to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - /// Queries whether this represents text using a CDATA section. - bool CDATA() const { return cdata; } - /// Turns on or off a CDATA representation of text. - void SetCDATA( bool _cdata ) { cdata = _cdata; } - - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* content ) const; - -protected : - /// [internal use] Creates a new Element and returns it. - virtual TiXmlNode* Clone() const; - void CopyTo( TiXmlText* target ) const; - - bool Blank() const; // returns true if all white space and new lines - // [internal use] - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - bool cdata; // true if this should be input and output as a CDATA style text element -}; - - -/** In correct XML the declaration is the first entry in the file. - @verbatim - - @endverbatim - - TinyXml will happily read or write files without a declaration, - however. There are 3 possible attributes to the declaration: - version, encoding, and standalone. - - Note: In this version of the code, the attributes are - handled as special cases, not generic attributes, simply - because there can only be at most 3 and they are always the same. -*/ -class TiXmlDeclaration : public TiXmlNode -{ -public: - /// Construct an empty declaration. - TiXmlDeclaration() : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) {} - -#ifdef TIXML_USE_STL - /// Constructor. - TiXmlDeclaration( const std::string& _version, - const std::string& _encoding, - const std::string& _standalone ); -#endif - - /// Construct. - TiXmlDeclaration( const char* _version, - const char* _encoding, - const char* _standalone ); - - TiXmlDeclaration( const TiXmlDeclaration& copy ); - TiXmlDeclaration& operator=( const TiXmlDeclaration& copy ); - - virtual ~TiXmlDeclaration() {} - - /// Version. Will return an empty string if none was found. - const char *Version() const { return version.c_str (); } - /// Encoding. Will return an empty string if none was found. - const char *Encoding() const { return encoding.c_str (); } - /// Is this a standalone document? - const char *Standalone() const { return standalone.c_str (); } - - /// Creates a copy of this Declaration and returns it. - virtual TiXmlNode* Clone() const; - // Print this declaration to a FILE stream. - virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; - virtual void Print( FILE* cfile, int depth ) const { - Print( cfile, depth, 0 ); - } - - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* visitor ) const; - -protected: - void CopyTo( TiXmlDeclaration* target ) const; - // used to be public - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - - TIXML_STRING version; - TIXML_STRING encoding; - TIXML_STRING standalone; -}; - - -/** Any tag that tinyXml doesn't recognize is saved as an - unknown. It is a tag of text, but should not be modified. - It will be written back to the XML, unchanged, when the file - is saved. - - DTD tags get thrown into TiXmlUnknowns. -*/ -class TiXmlUnknown : public TiXmlNode -{ -public: - TiXmlUnknown() : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) {} - virtual ~TiXmlUnknown() {} - - TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) { copy.CopyTo( this ); } - TiXmlUnknown& operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); return *this; } - - /// Creates a copy of this Unknown and returns it. - virtual TiXmlNode* Clone() const; - // Print this Unknown to a FILE stream. - virtual void Print( FILE* cfile, int depth ) const; - - virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - - virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* content ) const; - -protected: - void CopyTo( TiXmlUnknown* target ) const; - - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - -}; - - -/** Always the top level node. A document binds together all the - XML pieces. It can be saved, loaded, and printed to the screen. - The 'value' of a document node is the xml file name. -*/ -class TiXmlDocument : public TiXmlNode -{ -public: - /// Create an empty document, that has no name. - TiXmlDocument(); - /// Create a document with a name. The name of the document is also the filename of the xml. - TiXmlDocument( const char * documentName ); - - #ifdef TIXML_USE_STL - /// Constructor. - TiXmlDocument( const std::string& documentName ); - #endif - - TiXmlDocument( const TiXmlDocument& copy ); - TiXmlDocument& operator=( const TiXmlDocument& copy ); - - virtual ~TiXmlDocument() {} - - /** Load a file using the current document value. - Returns true if successful. Will delete any existing - document data before loading. - */ - bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - /// Save a file using the current document value. Returns true if successful. - bool SaveFile() const; - /// Load a file using the given filename. Returns true if successful. - bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - /// Save a file using the given filename. Returns true if successful. - bool SaveFile( const char * filename ) const; - /** Load a file using the given FILE*. Returns true if successful. Note that this method - doesn't stream - the entire object pointed at by the FILE* - will be interpreted as an XML file. TinyXML doesn't stream in XML from the current - file location. Streaming may be added in the future. - */ - bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - /// Save a file using the given FILE*. Returns true if successful. - bool SaveFile( FILE* ) const; - - #ifdef TIXML_USE_STL - bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. - { - return LoadFile( filename.c_str(), encoding ); - } - bool SaveFile( const std::string& filename ) const ///< STL std::string version. - { - return SaveFile( filename.c_str() ); - } - #endif - - /** Parse the given null terminated block of xml data. Passing in an encoding to this - method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml - to use that encoding, regardless of what TinyXml might otherwise try to detect. - */ - virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); - - /** Get the root element -- the only top level element -- of the document. - In well formed XML, there should only be one. TinyXml is tolerant of - multiple elements at the document level. - */ - const TiXmlElement* RootElement() const { return FirstChildElement(); } - TiXmlElement* RootElement() { return FirstChildElement(); } - - /** If an error occurs, Error will be set to true. Also, - - The ErrorId() will contain the integer identifier of the error (not generally useful) - - The ErrorDesc() method will return the name of the error. (very useful) - - The ErrorRow() and ErrorCol() will return the location of the error (if known) - */ - bool Error() const { return error; } - - /// Contains a textual (english) description of the error if one occurs. - const char * ErrorDesc() const { return errorDesc.c_str (); } - - /** Generally, you probably want the error string ( ErrorDesc() ). But if you - prefer the ErrorId, this function will fetch it. - */ - int ErrorId() const { return errorId; } - - /** Returns the location (if known) of the error. The first column is column 1, - and the first row is row 1. A value of 0 means the row and column wasn't applicable - (memory errors, for example, have no row/column) or the parser lost the error. (An - error in the error reporting, in that case.) - - @sa SetTabSize, Row, Column - */ - int ErrorRow() const { return errorLocation.row+1; } - int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() - - /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) - to report the correct values for row and column. It does not change the output - or input in any way. - - By calling this method, with a tab size - greater than 0, the row and column of each node and attribute is stored - when the file is loaded. Very useful for tracking the DOM back in to - the source file. - - The tab size is required for calculating the location of nodes. If not - set, the default of 4 is used. The tabsize is set per document. Setting - the tabsize to 0 disables row/column tracking. - - Note that row and column tracking is not supported when using operator>>. - - The tab size needs to be enabled before the parse or load. Correct usage: - @verbatim - TiXmlDocument doc; - doc.SetTabSize( 8 ); - doc.Load( "myfile.xml" ); - @endverbatim - - @sa Row, Column - */ - void SetTabSize( int _tabsize ) { tabsize = _tabsize; } - - int TabSize() const { return tabsize; } - - /** If you have handled the error, it can be reset with this call. The error - state is automatically cleared if you Parse a new XML block. - */ - void ClearError() { error = false; - errorId = 0; - errorDesc = ""; - errorLocation.row = errorLocation.col = 0; - //errorLocation.last = 0; - } - - /** Write the document to standard out using formatted printing ("pretty print"). */ - void Print() const { Print( stdout, 0 ); } - - /* Write the document to a string using formatted printing ("pretty print"). This - will allocate a character array (new char[]) and return it as a pointer. The - calling code pust call delete[] on the return char* to avoid a memory leak. - */ - //char* PrintToMemory() const; - - /// Print this Document to a FILE stream. - virtual void Print( FILE* cfile, int depth = 0 ) const; - // [internal use] - void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); - - virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept( TiXmlVisitor* content ) const; - -protected : - // [internal use] - virtual TiXmlNode* Clone() const; - #ifdef TIXML_USE_STL - virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); - #endif - -private: - void CopyTo( TiXmlDocument* target ) const; - - bool error; - int errorId; - TIXML_STRING errorDesc; - int tabsize; - TiXmlCursor errorLocation; - bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. -}; - - -/** - A TiXmlHandle is a class that wraps a node pointer with null checks; this is - an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml - DOM structure. It is a separate utility class. - - Take an example: - @verbatim - - - - - - - @endverbatim - - Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very - easy to write a *lot* of code that looks like: - - @verbatim - TiXmlElement* root = document.FirstChildElement( "Document" ); - if ( root ) - { - TiXmlElement* element = root->FirstChildElement( "Element" ); - if ( element ) - { - TiXmlElement* child = element->FirstChildElement( "Child" ); - if ( child ) - { - TiXmlElement* child2 = child->NextSiblingElement( "Child" ); - if ( child2 ) - { - // Finally do something useful. - @endverbatim - - And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity - of such code. A TiXmlHandle checks for null pointers so it is perfectly safe - and correct to use: - - @verbatim - TiXmlHandle docHandle( &document ); - TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); - if ( child2 ) - { - // do something useful - @endverbatim - - Which is MUCH more concise and useful. - - It is also safe to copy handles - internally they are nothing more than node pointers. - @verbatim - TiXmlHandle handleCopy = handle; - @endverbatim - - What they should not be used for is iteration: - - @verbatim - int i=0; - while ( true ) - { - TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); - if ( !child ) - break; - // do something - ++i; - } - @endverbatim - - It seems reasonable, but it is in fact two embedded while loops. The Child method is - a linear walk to find the element, so this code would iterate much more than it needs - to. Instead, prefer: - - @verbatim - TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); - - for( child; child; child=child->NextSiblingElement() ) - { - // do something - } - @endverbatim -*/ -class TiXmlHandle -{ -public: - /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. - TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } - /// Copy constructor - TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } - TiXmlHandle operator=( const TiXmlHandle& ref ) { if ( &ref != this ) this->node = ref.node; return *this; } - - /// Return a handle to the first child node. - TiXmlHandle FirstChild() const; - /// Return a handle to the first child node with the given name. - TiXmlHandle FirstChild( const char * value ) const; - /// Return a handle to the first child element. - TiXmlHandle FirstChildElement() const; - /// Return a handle to the first child element with the given name. - TiXmlHandle FirstChildElement( const char * value ) const; - - /** Return a handle to the "index" child with the given name. - The first child is 0, the second 1, etc. - */ - TiXmlHandle Child( const char* value, int index ) const; - /** Return a handle to the "index" child. - The first child is 0, the second 1, etc. - */ - TiXmlHandle Child( int index ) const; - /** Return a handle to the "index" child element with the given name. - The first child element is 0, the second 1, etc. Note that only TiXmlElements - are indexed: other types are not counted. - */ - TiXmlHandle ChildElement( const char* value, int index ) const; - /** Return a handle to the "index" child element. - The first child element is 0, the second 1, etc. Note that only TiXmlElements - are indexed: other types are not counted. - */ - TiXmlHandle ChildElement( int index ) const; - - #ifdef TIXML_USE_STL - TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } - TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } - - TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } - TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } - #endif - - /** Return the handle as a TiXmlNode. This may return null. - */ - TiXmlNode* ToNode() const { return node; } - /** Return the handle as a TiXmlElement. This may return null. - */ - TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } - /** Return the handle as a TiXmlText. This may return null. - */ - TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } - /** Return the handle as a TiXmlUnknown. This may return null. - */ - TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } - - /** @deprecated use ToNode. - Return the handle as a TiXmlNode. This may return null. - */ - TiXmlNode* Node() const { return ToNode(); } - /** @deprecated use ToElement. - Return the handle as a TiXmlElement. This may return null. - */ - TiXmlElement* Element() const { return ToElement(); } - /** @deprecated use ToText() - Return the handle as a TiXmlText. This may return null. - */ - TiXmlText* Text() const { return ToText(); } - /** @deprecated use ToUnknown() - Return the handle as a TiXmlUnknown. This may return null. - */ - TiXmlUnknown* Unknown() const { return ToUnknown(); } - -private: - TiXmlNode* node; -}; - - -/** Print to memory functionality. The TiXmlPrinter is useful when you need to: - - -# Print to memory (especially in non-STL mode) - -# Control formatting (line endings, etc.) - - When constructed, the TiXmlPrinter is in its default "pretty printing" mode. - Before calling Accept() you can call methods to control the printing - of the XML document. After TiXmlNode::Accept() is called, the printed document can - be accessed via the CStr(), Str(), and Size() methods. - - TiXmlPrinter uses the Visitor API. - @verbatim - TiXmlPrinter printer; - printer.SetIndent( "\t" ); - - doc.Accept( &printer ); - fprintf( stdout, "%s", printer.CStr() ); - @endverbatim -*/ -class TiXmlPrinter : public TiXmlVisitor -{ -public: - TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), - buffer(), indent( " " ), lineBreak( "\n" ) {} - - virtual bool VisitEnter( const TiXmlDocument& doc ); - virtual bool VisitExit( const TiXmlDocument& doc ); - - virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); - virtual bool VisitExit( const TiXmlElement& element ); - - virtual bool Visit( const TiXmlDeclaration& declaration ); - virtual bool Visit( const TiXmlText& text ); - virtual bool Visit( const TiXmlComment& comment ); - virtual bool Visit( const TiXmlUnknown& unknown ); - - /** Set the indent characters for printing. By default 4 spaces - but tab (\t) is also useful, or null/empty string for no indentation. - */ - void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } - /// Query the indention string. - const char* Indent() { return indent.c_str(); } - /** Set the line breaking string. By default set to newline (\n). - Some operating systems prefer other characters, or can be - set to the null/empty string for no indenation. - */ - void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } - /// Query the current line breaking string. - const char* LineBreak() { return lineBreak.c_str(); } - - /** Switch over to "stream printing" which is the most dense formatting without - linebreaks. Common when the XML is needed for network transmission. - */ - void SetStreamPrinting() { indent = ""; - lineBreak = ""; - } - /// Return the result. - const char* CStr() { return buffer.c_str(); } - /// Return the length of the result string. - size_t Size() { return buffer.size(); } - - #ifdef TIXML_USE_STL - /// Return the result. - const std::string& Str() { return buffer; } - #endif - -private: - void DoIndent() { - for( int i=0; i -#include - -#include "tinyxml/tinyxml.h" - -//#define DEBUG_PARSER -#if defined( DEBUG_PARSER ) -# if defined( DEBUG ) && defined( _MSC_VER ) -# include -# define TIXML_LOG OutputDebugString -# else -# define TIXML_LOG printf -# endif -#endif - -// Note tha "PutString" hardcodes the same list. This -// is less flexible than it appears. Changing the entries -// or order will break putstring. -TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = -{ - { "&", 5, '&' }, - { "<", 4, '<' }, - { ">", 4, '>' }, - { """, 6, '\"' }, - { "'", 6, '\'' } -}; - -// Bunch of unicode info at: -// http://www.unicode.org/faq/utf_bom.html -// Including the basic of this table, which determines the #bytes in the -// sequence from the lead byte. 1 placed for invalid sequences -- -// although the result will be junk, pass it through as much as possible. -// Beware of the non-characters in UTF-8: -// ef bb bf (Microsoft "lead bytes") -// ef bf be -// ef bf bf - -const unsigned char TIXML_UTF_LEAD_0 = 0xefU; -const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; -const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; - -const int TiXmlBase::utf8ByteTable[256] = -{ - // 0 1 2 3 4 5 6 7 8 9 a b c d e f - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 - 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte - 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid -}; - - -void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) -{ - const unsigned long BYTE_MASK = 0xBF; - const unsigned long BYTE_MARK = 0x80; - const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - - if (input < 0x80) - *length = 1; - else if ( input < 0x800 ) - *length = 2; - else if ( input < 0x10000 ) - *length = 3; - else if ( input < 0x200000 ) - *length = 4; - else - { *length = 0; return; } // This code won't covert this correctly anyway. - - output += *length; - - // Scary scary fall throughs. - switch (*length) - { - case 4: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 3: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 2: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 1: - --output; - *output = (char)(input | FIRST_BYTE_MARK[*length]); - } -} - - -/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) -{ - // This will only work for low-ascii, everything else is assumed to be a valid - // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very - // conservative approach. - -// if ( encoding == TIXML_ENCODING_UTF8 ) -// { - if ( anyByte < 127 ) - return isalpha( anyByte ); - else - return 1; // What else to do? The unicode set is huge...get the english ones right. -// } -// else -// { -// return isalpha( anyByte ); -// } -} - - -/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) -{ - // This will only work for low-ascii, everything else is assumed to be a valid - // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very - // conservative approach. - -// if ( encoding == TIXML_ENCODING_UTF8 ) -// { - if ( anyByte < 127 ) - return isalnum( anyByte ); - else - return 1; // What else to do? The unicode set is huge...get the english ones right. -// } -// else -// { -// return isalnum( anyByte ); -// } -} - - -class TiXmlParsingData -{ - friend class TiXmlDocument; - public: - void Stamp( const char* now, TiXmlEncoding encoding ); - - const TiXmlCursor& Cursor() const { return cursor; } - - private: - // Only used by the document! - TiXmlParsingData( const char* start, int _tabsize, int row, int col ) - { - assert( start ); - stamp = start; - tabsize = _tabsize; - cursor.row = row; - cursor.col = col; - } - - TiXmlCursor cursor; - const char* stamp; - int tabsize; -}; - - -void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) -{ - assert( now ); - - // Do nothing if the tabsize is 0. - if ( tabsize < 1 ) - { - return; - } - - // Get the current row, column. - int row = cursor.row; - int col = cursor.col; - const char* p = stamp; - assert( p ); - - while ( p < now ) - { - // Treat p as unsigned, so we have a happy compiler. - const unsigned char* pU = (const unsigned char*)p; - - // Code contributed by Fletcher Dunn: (modified by lee) - switch (*pU) { - case 0: - // We *should* never get here, but in case we do, don't - // advance past the terminating null character, ever - return; - - case '\r': - // bump down to the next line - ++row; - col = 0; - // Eat the character - ++p; - - // Check for \r\n sequence, and treat this as a single character - if (*p == '\n') { - ++p; - } - break; - - case '\n': - // bump down to the next line - ++row; - col = 0; - - // Eat the character - ++p; - - // Check for \n\r sequence, and treat this as a single - // character. (Yes, this bizarre thing does occur still - // on some arcane platforms...) - if (*p == '\r') { - ++p; - } - break; - - case '\t': - // Eat the character - ++p; - - // Skip to next tab stop - col = (col / tabsize + 1) * tabsize; - break; - - case TIXML_UTF_LEAD_0: - if ( encoding == TIXML_ENCODING_UTF8 ) - { - if ( *(p+1) && *(p+2) ) - { - // In these cases, don't advance the column. These are - // 0-width spaces. - if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) - p += 3; - else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) - p += 3; - else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) - p += 3; - else - { p +=3; ++col; } // A normal character. - } - } - else - { - ++p; - ++col; - } - break; - - default: - if ( encoding == TIXML_ENCODING_UTF8 ) - { - // Eat the 1 to 4 byte utf8 character. - int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; - if ( step == 0 ) - step = 1; // Error case from bad encoding, but handle gracefully. - p += step; - - // Just advance one column, of course. - ++col; - } - else - { - ++p; - ++col; - } - break; - } - } - cursor.row = row; - cursor.col = col; - assert( cursor.row >= -1 ); - assert( cursor.col >= -1 ); - stamp = p; - assert( stamp ); -} - - -const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) -{ - if ( !p || !*p ) - { - return 0; - } - if ( encoding == TIXML_ENCODING_UTF8 ) - { - while ( *p ) - { - const unsigned char* pU = (const unsigned char*)p; - - // Skip the stupid Microsoft UTF-8 Byte order marks - if ( *(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==TIXML_UTF_LEAD_1 - && *(pU+2)==TIXML_UTF_LEAD_2 ) - { - p += 3; - continue; - } - else if(*(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==0xbfU - && *(pU+2)==0xbeU ) - { - p += 3; - continue; - } - else if(*(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==0xbfU - && *(pU+2)==0xbfU ) - { - p += 3; - continue; - } - - if ( IsWhiteSpace( *p ) ) // Still using old rules for white space. - ++p; - else - break; - } - } - else - { - while ( *p && IsWhiteSpace( *p ) ) - ++p; - } - - return p; -} - -#ifdef TIXML_USE_STL -/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) -{ - for( ;; ) - { - if ( !in->good() ) return false; - - int c = in->peek(); - // At this scope, we can't get to a document. So fail silently. - if ( !IsWhiteSpace( c ) || c <= 0 ) - return true; - - *tag += (char) in->get(); - } -} - -/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) -{ - //assert( character > 0 && character < 128 ); // else it won't work in utf-8 - while ( in->good() ) - { - int c = in->peek(); - if ( c == character ) - return true; - if ( c <= 0 ) // Silent failure: can't get document at this scope - return false; - - in->get(); - *tag += (char) c; - } - return false; -} -#endif - -// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The -// "assign" optimization removes over 10% of the execution time. -// -const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) -{ - // Oddly, not supported on some comilers, - //name->clear(); - // So use this: - *name = ""; - assert( p ); - - // Names start with letters or underscores. - // Of course, in unicode, tinyxml has no idea what a letter *is*. The - // algorithm is generous. - // - // After that, they can be letters, underscores, numbers, - // hyphens, or colons. (Colons are valid ony for namespaces, - // but tinyxml can't tell namespaces from names.) - if ( p && *p - && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) - { - const char* start = p; - while( p && *p - && ( IsAlphaNum( (unsigned char ) *p, encoding ) - || *p == '_' - || *p == '-' - || *p == '.' - || *p == ':' ) ) - { - //(*name) += *p; // expensive - ++p; - } - if ( p-start > 0 ) { - name->assign( start, p-start ); - } - return p; - } - return 0; -} - -const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) -{ - // Presume an entity, and pull it out. - TIXML_STRING ent; - int i; - *length = 0; - - if ( *(p+1) && *(p+1) == '#' && *(p+2) ) - { - unsigned long ucs = 0; - ptrdiff_t delta = 0; - unsigned mult = 1; - - if ( *(p+2) == 'x' ) - { - // Hexadecimal. - if ( !*(p+3) ) return 0; - - const char* q = p+3; - q = strchr( q, ';' ); - - if ( !q || !*q ) return 0; - - delta = q-p; - --q; - - while ( *q != 'x' ) - { - if ( *q >= '0' && *q <= '9' ) - ucs += mult * (*q - '0'); - else if ( *q >= 'a' && *q <= 'f' ) - ucs += mult * (*q - 'a' + 10); - else if ( *q >= 'A' && *q <= 'F' ) - ucs += mult * (*q - 'A' + 10 ); - else - return 0; - mult *= 16; - --q; - } - } - else - { - // Decimal. - if ( !*(p+2) ) return 0; - - const char* q = p+2; - q = strchr( q, ';' ); - - if ( !q || !*q ) return 0; - - delta = q-p; - --q; - - while ( *q != '#' ) - { - if ( *q >= '0' && *q <= '9' ) - ucs += mult * (*q - '0'); - else - return 0; - mult *= 10; - --q; - } - } - if ( encoding == TIXML_ENCODING_UTF8 ) - { - // convert the UCS to UTF-8 - ConvertUTF32ToUTF8( ucs, value, length ); - } - else - { - *value = (char)ucs; - *length = 1; - } - return p + delta + 1; - } - - // Now try to match it. - for( i=0; iappend( cArr, len ); - } - } - else - { - bool whitespace = false; - - // Remove leading white space: - p = SkipWhiteSpace( p, encoding ); - while ( p && *p - && !StringEqual( p, endTag, caseInsensitive, encoding ) ) - { - if ( *p == '\r' || *p == '\n' ) - { - whitespace = true; - ++p; - } - else if ( IsWhiteSpace( *p ) ) - { - whitespace = true; - ++p; - } - else - { - // If we've found whitespace, add it before the - // new character. Any whitespace just becomes a space. - if ( whitespace ) - { - (*text) += ' '; - whitespace = false; - } - int len; - char cArr[4] = { 0, 0, 0, 0 }; - p = GetChar( p, cArr, &len, encoding ); - if ( len == 1 ) - (*text) += cArr[0]; // more efficient - else - text->append( cArr, len ); - } - } - } - if ( p && *p ) - p += strlen( endTag ); - return ( p && *p ) ? p : 0; -} - -#ifdef TIXML_USE_STL - -void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) -{ - // The basic issue with a document is that we don't know what we're - // streaming. Read something presumed to be a tag (and hope), then - // identify it, and call the appropriate stream method on the tag. - // - // This "pre-streaming" will never read the closing ">" so the - // sub-tag can orient itself. - - if ( !StreamTo( in, '<', tag ) ) - { - SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - - while ( in->good() ) - { - int tagIndex = (int) tag->length(); - while ( in->good() && in->peek() != '>' ) - { - int c = in->get(); - if ( c <= 0 ) - { - SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - break; - } - (*tag) += (char) c; - } - - if ( in->good() ) - { - // We now have something we presume to be a node of - // some sort. Identify it, and call the node to - // continue streaming. - TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); - - if ( node ) - { - node->StreamIn( in, tag ); - bool isElement = node->ToElement() != 0; - delete node; - node = 0; - - // If this is the root element, we're done. Parsing will be - // done by the >> operator. - if ( isElement ) - { - return; - } - } - else - { - SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - } - } - // We should have returned sooner. - SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); -} - -#endif - -const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) -{ - ClearError(); - - // Parse away, at the document level. Since a document - // contains nothing but other tags, most of what happens - // here is skipping white space. - if ( !p || !*p ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - // Note that, for a document, this needs to come - // before the while space skip, so that parsing - // starts from the pointer we are given. - location.Clear(); - if ( prevData ) - { - location.row = prevData->cursor.row; - location.col = prevData->cursor.col; - } - else - { - location.row = 0; - location.col = 0; - } - TiXmlParsingData data( p, TabSize(), location.row, location.col ); - location = data.Cursor(); - - if ( encoding == TIXML_ENCODING_UNKNOWN ) - { - // Check for the Microsoft UTF-8 lead bytes. - const unsigned char* pU = (const unsigned char*)p; - if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 - && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 - && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) - { - encoding = TIXML_ENCODING_UTF8; - useMicrosoftBOM = true; - } - } - - p = SkipWhiteSpace( p, encoding ); - if ( !p ) - { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); - return 0; - } - - while ( p && *p ) - { - TiXmlNode* node = Identify( p, encoding ); - if ( node ) - { - p = node->Parse( p, &data, encoding ); - LinkEndChild( node ); - } - else - { - break; - } - - // Did we get encoding info? - if ( encoding == TIXML_ENCODING_UNKNOWN - && node->ToDeclaration() ) - { - TiXmlDeclaration* dec = node->ToDeclaration(); - const char* enc = dec->Encoding(); - assert( enc ); - - if ( *enc == 0 ) - encoding = TIXML_ENCODING_UTF8; - else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) - encoding = TIXML_ENCODING_UTF8; - else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) - encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice - else - encoding = TIXML_ENCODING_LEGACY; - } - - p = SkipWhiteSpace( p, encoding ); - } - - // Was this empty? - if ( !firstChild ) { - SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); - return 0; - } - - // All is well. - return p; -} - -void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ - // The first error in a chain is more accurate - don't set again! - if ( error ) - return; - - assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); - error = true; - errorId = err; - errorDesc = errorString[ errorId ]; - - errorLocation.Clear(); - if ( pError && data ) - { - data->Stamp( pError, encoding ); - errorLocation = data->Cursor(); - } -} - - -TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) -{ - TiXmlNode* returnNode = 0; - - p = SkipWhiteSpace( p, encoding ); - if( !p || !*p || *p != '<' ) - { - return 0; - } - - p = SkipWhiteSpace( p, encoding ); - - if ( !p || !*p ) - { - return 0; - } - - // What is this thing? - // - Elements start with a letter or underscore, but xml is reserved. - // - Comments: "; - - if ( !StringEqual( p, startTag, false, encoding ) ) - { - if ( document ) - document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); - return 0; - } - p += strlen( startTag ); - - // [ 1475201 ] TinyXML parses entities in comments - // Oops - ReadText doesn't work, because we don't want to parse the entities. - // p = ReadText( p, &value, false, endTag, false, encoding ); - // - // from the XML spec: - /* - [Definition: Comments may appear anywhere in a document outside other markup; in addition, - they may appear within the document type declaration at places allowed by the grammar. - They are not part of the document's character data; an XML processor MAY, but need not, - make it possible for an application to retrieve the text of comments. For compatibility, - the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity - references MUST NOT be recognized within comments. - - An example of a comment: - - - */ - - value = ""; - // Keep all the white space. - while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) - { - value.append( p, 1 ); - ++p; - } - if ( p && *p ) - p += strlen( endTag ); - - return p; -} - - -const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p ) return 0; - - if ( data ) - { - data->Stamp( p, encoding ); - location = data->Cursor(); - } - // Read the name, the '=' and the value. - const char* pErr = p; - p = ReadName( p, &name, encoding ); - if ( !p || !*p ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); - return 0; - } - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p || *p != '=' ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - - ++p; // skip '=' - p = SkipWhiteSpace( p, encoding ); - if ( !p || !*p ) - { - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - - const char* end; - const char SINGLE_QUOTE = '\''; - const char DOUBLE_QUOTE = '\"'; - - if ( *p == SINGLE_QUOTE ) - { - ++p; - end = "\'"; // single quote in string - p = ReadText( p, &value, false, end, false, encoding ); - } - else if ( *p == DOUBLE_QUOTE ) - { - ++p; - end = "\""; // double quote in string - p = ReadText( p, &value, false, end, false, encoding ); - } - else - { - // All attribute values should be in single or double quotes. - // But this is such a common error that the parser will try - // its best, even without them. - value = ""; - while ( p && *p // existence - && !IsWhiteSpace( *p ) // whitespace - && *p != '/' && *p != '>' ) // tag end - { - if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { - // [ 1451649 ] Attribute values with trailing quotes not handled correctly - // We did not have an opening quote but seem to have a - // closing one. Give up and throw an error. - if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); - return 0; - } - value += *p; - ++p; - } - } - return p; -} - -#ifdef TIXML_USE_STL -void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) -{ - while ( in->good() ) - { - int c = in->peek(); - if ( !cdata && (c == '<' ) ) - { - return; - } - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - - (*tag) += (char) c; - in->get(); // "commits" the peek made above - - if ( cdata && c == '>' && tag->size() >= 3 ) { - size_t len = tag->size(); - if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { - // terminator of cdata. - return; - } - } - } -} -#endif - -const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ - value = ""; - TiXmlDocument* document = GetDocument(); - - if ( data ) - { - data->Stamp( p, encoding ); - location = data->Cursor(); - } - - const char* const startTag = ""; - - if ( cdata || StringEqual( p, startTag, false, encoding ) ) - { - cdata = true; - - if ( !StringEqual( p, startTag, false, encoding ) ) - { - if ( document ) - document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); - return 0; - } - p += strlen( startTag ); - - // Keep all the white space, ignore the encoding, etc. - while ( p && *p - && !StringEqual( p, endTag, false, encoding ) - ) - { - value += *p; - ++p; - } - - TIXML_STRING dummy; - p = ReadText( p, &dummy, false, endTag, false, encoding ); - return p; - } - else - { - bool ignoreWhite = true; - - const char* end = "<"; - p = ReadText( p, &value, ignoreWhite, end, false, encoding ); - if ( p && *p ) - return p-1; // don't truncate the '<' - return 0; - } -} - -#ifdef TIXML_USE_STL -void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) -{ - while ( in->good() ) - { - int c = in->get(); - if ( c <= 0 ) - { - TiXmlDocument* document = GetDocument(); - if ( document ) - document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); - return; - } - (*tag) += (char) c; - - if ( c == '>' ) - { - // All is well. - return; - } - } -} -#endif - -const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) -{ - p = SkipWhiteSpace( p, _encoding ); - // Find the beginning, find the end, and look for - // the stuff in-between. - TiXmlDocument* document = GetDocument(); - if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); - return 0; - } - if ( data ) - { - data->Stamp( p, _encoding ); - location = data->Cursor(); - } - p += 5; - - version = ""; - encoding = ""; - standalone = ""; - - while ( p && *p ) - { - if ( *p == '>' ) - { - ++p; - return p; - } - - p = SkipWhiteSpace( p, _encoding ); - if ( StringEqual( p, "version", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - version = attrib.Value(); - } - else if ( StringEqual( p, "encoding", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - encoding = attrib.Value(); - } - else if ( StringEqual( p, "standalone", true, _encoding ) ) - { - TiXmlAttribute attrib; - p = attrib.Parse( p, data, _encoding ); - standalone = attrib.Value(); - } - else - { - // Read over whatever it is. - while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) - ++p; - } - } - return 0; -} - -bool TiXmlText::Blank() const -{ - for ( unsigned i=0; i -#include -#include -#include -#include "tmd.h" -#include "utils.h" -#include - - -void tmd_init(tmd_context* ctx) -{ - memset(ctx, 0, sizeof(tmd_context)); -} - -void tmd_set_file(tmd_context* ctx, FILE* file) -{ - ctx->file = file; -} - -void tmd_set_offset(tmd_context* ctx, u64 offset) -{ - ctx->offset = offset; -} - -void tmd_set_size(tmd_context* ctx, u32 size) -{ - ctx->size = size; -} - -void tmd_set_usersettings(tmd_context* ctx, settings* usersettings) -{ - ctx->usersettings = usersettings; -} - -void tmd_process(tmd_context* ctx, u32 actions) -{ - if (ctx->buffer == 0) - ctx->buffer = malloc(ctx->size); - - if (ctx->buffer) - { - fseeko64(ctx->file, ctx->offset, SEEK_SET); - fread(ctx->buffer, 1, ctx->size, ctx->file); - - if (actions & InfoFlag) - { - tmd_print(ctx); - } - } -} - -ctr_tmd_body *tmd_get_body(tmd_context *ctx) -{ - unsigned int type = getbe32(ctx->buffer); - ctr_tmd_body *body = NULL; - - if (type == TMD_RSA_2048_SHA256 || type == TMD_RSA_2048_SHA1) - { - body = (ctr_tmd_body*)(ctx->buffer + sizeof(ctr_tmd_header_2048)); - } - else if (type == TMD_RSA_4096_SHA256 || type == TMD_RSA_4096_SHA1) - { - body = (ctr_tmd_body*)(ctx->buffer + sizeof(ctr_tmd_header_4096)); - } - - return body; -} - -const char* tmd_get_type_string(unsigned int type) -{ - switch(type) - { - case TMD_RSA_2048_SHA256: return "RSA 2048 - SHA256"; - case TMD_RSA_4096_SHA256: return "RSA 4096 - SHA256"; - case TMD_RSA_2048_SHA1: return "RSA 2048 - SHA1"; - case TMD_RSA_4096_SHA1: return "RSA 4096 - SHA1"; - default: - return "unknown"; - } -} - -void tmd_print(tmd_context* ctx) -{ - unsigned int type = getbe32(ctx->buffer); - ctr_tmd_header_4096* header4096 = 0; - ctr_tmd_header_2048* header2048 = 0; - ctr_tmd_body* body = 0; - unsigned int contentcount = 0; - unsigned int savesize = 0; - unsigned int titlever = 0; - unsigned int i; - - if (type == TMD_RSA_2048_SHA256 || type == TMD_RSA_2048_SHA1) - { - header2048 = (ctr_tmd_header_2048*)ctx->buffer; - } - else if (type == TMD_RSA_4096_SHA256 || type == TMD_RSA_4096_SHA1) - { - header4096 = (ctr_tmd_header_4096*)ctx->buffer; - } - else - { - return; - } - - body = tmd_get_body(ctx); - - contentcount = getbe16(body->contentcount); - savesize = getle32(body->savedatasize); - titlever = getbe16(body->titleversion); - - fprintf(stdout, "\nTMD header:\n"); - fprintf(stdout, "Signature type: %s\n", tmd_get_type_string(type)); - fprintf(stdout, "Issuer: %s\n", body->issuer); - fprintf(stdout, "Version: %d\n", body->version); - fprintf(stdout, "CA CRL version: %d\n", body->ca_crl_version); - fprintf(stdout, "Signer CRL version: %d\n", body->signer_crl_version); - memdump(stdout, "System version: ", body->systemversion, 8); - memdump(stdout, "Title id: ", body->titleid, 8); - fprintf(stdout, "Title type: %08x\n", getbe32(body->titletype)); - fprintf(stdout, "Group id: %04x\n", getbe16(body->groupid)); - if(savesize < sizeKB) - fprintf(stdout, "Save Size: %08x\n", savesize); - else if(savesize < sizeMB) - fprintf(stdout, "Save Size: %dKB (%08x)\n", savesize/sizeKB, savesize); - else - fprintf(stdout, "Save Size: %dMB (%08x)\n", savesize/sizeMB, savesize); - fprintf(stdout, "Access rights: %08x\n", getbe32(body->accessrights)); - fprintf(stdout, "Title version: %d.%d.%d (v%d)\n", (titlever >> 10) & 0x3F, (titlever >> 4) & 0x3F, titlever & 0xF, titlever); - fprintf(stdout, "Content count: %04x\n", getbe16(body->contentcount)); - fprintf(stdout, "Boot content: %04x\n", getbe16(body->bootcontent)); - memdump(stdout, "Hash: ", body->hash, 32); - - fprintf(stdout, "\nTMD content info:\n"); - for(i = 0; i < TMD_MAX_CONTENTS; i++) - { - ctr_tmd_contentinfo* info = (ctr_tmd_contentinfo*)(body->contentinfo + sizeof(ctr_tmd_contentinfo)*i); - - if (getbe16(info->commandcount) == 0) - continue; - - fprintf(stdout, "Content index: %04x\n", getbe16(info->index)); - fprintf(stdout, "Command count: %04x\n", getbe16(info->commandcount)); - memdump(stdout, "Unknown: ", info->unk, 32); - } - fprintf(stdout, "\nTMD contents:\n"); - for(i = 0; i < contentcount; i++) - { - ctr_tmd_contentchunk* chunk = (ctr_tmd_contentchunk*)(body->contentinfo + 36*64 + i*48); - unsigned short type = getbe16(chunk->type); - - fprintf(stdout, "Content id: %08x\n", getbe32(chunk->id)); - fprintf(stdout, "Content index: %04x\n", getbe16(chunk->index)); - fprintf(stdout, "Content type: %04x", getbe16(chunk->type)); - if (type) - { - fprintf(stdout, " "); - if (type & 1) - fprintf(stdout, "[encrypted]"); - if (type & 2) - fprintf(stdout, "[disc]"); - if (type & 4) - fprintf(stdout, "[cfm]"); - if (type & 0x4000) - fprintf(stdout, "[optional]"); - if (type & 0x8000) - fprintf(stdout, "[shared]"); - } - fprintf(stdout, "\n"); - fprintf(stdout, "Content size: %016"PRIx64"\n", getbe64(chunk->size)); - - switch(ctx->content_hash_stat[i]) { - case 1: memdump(stdout, "Content hash [OK]: ", chunk->hash, 32); break; - case 2: memdump(stdout, "Content hash [FAIL]: ", chunk->hash, 32); break; - default: memdump(stdout, "Content hash: ", chunk->hash, 32); break; - } - - fprintf(stdout, "\n"); - } -} diff --git a/ctrtool/tmd.h b/ctrtool/tmd.h deleted file mode 100644 index d9701a7..0000000 --- a/ctrtool/tmd.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef _TMD_H_ -#define _TMD_H_ - -#include "types.h" -#include "settings.h" - -#define TMD_MAX_CONTENTS 64 - -typedef enum -{ - TMD_RSA_2048_SHA256 = 0x00010004, - TMD_RSA_4096_SHA256 = 0x00010003, - TMD_RSA_2048_SHA1 = 0x00010001, - TMD_RSA_4096_SHA1 = 0x00010000 -} ctr_tmdtype; - - -typedef struct -{ - unsigned char padding[60]; - unsigned char issuer[64]; - unsigned char version; - unsigned char ca_crl_version; - unsigned char signer_crl_version; - unsigned char padding2; - unsigned char systemversion[8]; - unsigned char titleid[8]; - unsigned char titletype[4]; - unsigned char groupid[2]; - unsigned char savedatasize[4]; - unsigned char privsavedatasize[4]; - unsigned char padding3[4]; - unsigned char twlflag; - unsigned char padding4[0x31]; - unsigned char accessrights[4]; - unsigned char titleversion[2]; - unsigned char contentcount[2]; - unsigned char bootcontent[2]; - unsigned char padding5[2]; - unsigned char hash[32]; - unsigned char contentinfo[36*64]; -} ctr_tmd_body; - -typedef struct -{ - unsigned char index[2]; - unsigned char commandcount[2]; - unsigned char unk[32]; -} ctr_tmd_contentinfo; - - -typedef struct -{ - unsigned char id[4]; - unsigned char index[2]; - unsigned char type[2]; - unsigned char size[8]; - unsigned char hash[32]; -} ctr_tmd_contentchunk; - - -typedef struct -{ - unsigned char signaturetype[4]; - unsigned char signature[256]; -} ctr_tmd_header_2048; - -typedef struct -{ - unsigned char signaturetype[4]; - unsigned char signature[512]; -} ctr_tmd_header_4096; - -typedef struct -{ - FILE* file; - u64 offset; - u32 size; - u8* buffer; - u8 content_hash_stat[64]; - settings* usersettings; -} tmd_context; - - - -#ifdef __cplusplus -extern "C" { -#endif - -void tmd_init(tmd_context* ctx); -void tmd_set_file(tmd_context* ctx, FILE* file); -void tmd_set_offset(tmd_context* ctx, u64 offset); -void tmd_set_size(tmd_context* ctx, u32 size); -void tmd_set_usersettings(tmd_context* ctx, settings* usersettings); -void tmd_print(tmd_context* ctx); -void tmd_process(tmd_context* ctx, u32 actions); -ctr_tmd_body *tmd_get_body(tmd_context *ctx); - -#ifdef __cplusplus -} -#endif - -#endif // _TMD_H_ diff --git a/ctrtool/types.h b/ctrtool/types.h deleted file mode 100644 index c35e2ba..0000000 --- a/ctrtool/types.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef __TYPES_H__ -#define __TYPES_H__ - -#include -#include - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int64_t s64; - -enum flags -{ - ExtractFlag = (1<<0), - InfoFlag = (1<<1), - PlainFlag = (1<<2), - VerboseFlag = (1<<3), - VerifyFlag = (1<<4), - RawFlag = (1<<5), - ShowKeysFlag = (1<<6), - DecompressCodeFlag = (1<<7), - ShowSyscallsFlag = (1<<8), - DevFlag = (1<<9), -}; - -enum validstate -{ - Unchecked = 0, - Good = 1, - Fail = 2, -}; - -enum sizeunits -{ - sizeKB = 0x400, - sizeMB = 0x100000, -}; - -#endif diff --git a/ctrtool/utils.c b/ctrtool/utils.c deleted file mode 100644 index 92125e5..0000000 --- a/ctrtool/utils.c +++ /dev/null @@ -1,239 +0,0 @@ -#include -#include -#include -#ifdef _WIN32 -#include -#endif -#include "utils.h" - - - -u32 align(u32 offset, u32 alignment) -{ - u32 mask = ~(alignment-1); - - return (offset + (alignment-1)) & mask; -} - -u64 align64(u64 offset, u32 alignment) -{ - u64 mask = ~(u64)(alignment-1); - - return (offset + (alignment-1)) & mask; -} - -u64 getle64(const u8* p) -{ - u64 n = p[0]; - - n |= (u64)p[1]<<8; - n |= (u64)p[2]<<16; - n |= (u64)p[3]<<24; - n |= (u64)p[4]<<32; - n |= (u64)p[5]<<40; - n |= (u64)p[6]<<48; - n |= (u64)p[7]<<56; - return n; -} - -u64 getbe64(const u8* p) -{ - u64 n = 0; - - n |= (u64)p[0]<<56; - n |= (u64)p[1]<<48; - n |= (u64)p[2]<<40; - n |= (u64)p[3]<<32; - n |= (u64)p[4]<<24; - n |= (u64)p[5]<<16; - n |= (u64)p[6]<<8; - n |= (u64)p[7]<<0; - return n; -} - -u32 getle32(const u8* p) -{ - return (p[0]<<0) | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); -} - -u32 getbe32(const u8* p) -{ - return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | (p[3]<<0); -} - -u32 getle16(const u8* p) -{ - return (p[0]<<0) | (p[1]<<8); -} - -u32 getbe16(const u8* p) -{ - return (p[0]<<8) | (p[1]<<0); -} - -void putle16(u8* p, u16 n) -{ - p[0] = (u8) n; - p[1] = (u8) (n>>8); -} - -void putle32(u8* p, u32 n) -{ - p[0] = (u8) n; - p[1] = (u8) (n>>8); - p[2] = (u8) (n>>16); - p[3] = (u8) (n>>24); -} - -void putle64(u8* p, u64 n) -{ - p[0] = (u8) n; - p[1] = (u8) (n >> 8); - p[2] = (u8) (n >> 16); - p[3] = (u8) (n >> 24); - p[4] = (u8) (n >> 32); - p[5] = (u8) (n >> 40); - p[6] = (u8) (n >> 48); - p[7] = (u8) (n >> 56); -} - -void putbe16(u8* p, u16 n) -{ - p[1] = (u8) n; - p[0] = (u8) (n >> 8); -} - -void putbe32(u8* p, u32 n) -{ - p[3] = (u8) n; - p[2] = (u8) (n >> 8); - p[1] = (u8) (n >> 16); - p[0] = (u8) (n >> 24); -} - -void putbe64(u8* p, u64 n) -{ - p[7] = (u8) n; - p[6] = (u8) (n >> 8); - p[5] = (u8) (n >> 16); - p[4] = (u8) (n >> 24); - p[3] = (u8) (n >> 32); - p[2] = (u8) (n >> 40); - p[1] = (u8) (n >> 48); - p[0] = (u8) (n >> 56); -} - -void readkeyfile(u8* key, const char* keyfname) -{ - u64 keysize = _fsize(keyfname); - FILE* f = fopen(keyfname, "rb"); - - if (0 == f) - { - fprintf(stdout, "Error opening key file\n"); - goto clean; - } - - if (keysize != 16) - { - fprintf(stdout, "Error key size mismatch, got %"PRIu64", expected %d\n", keysize, 16); - goto clean; - } - - if (16 != fread(key, 1, 16, f)) - { - fprintf(stdout, "Error reading key file\n"); - goto clean; - } - -clean: - if (f) - fclose(f); -} - -void hexdump(void *ptr, int buflen) -{ - u8 *buf = (u8*)ptr; - int i, j; - - for (i=0; i= 0x20 && buf[i+j] <= 0x7e) ? buf[i+j] : '.'); - } - } - printf("\n"); - } -} - -void memdump(FILE* fout, const char* prefix, const u8* data, u32 size) -{ - u32 i; - u32 prefixlen = strlen(prefix); - u32 offs = 0; - u32 line = 0; - while(size) - { - u32 max = 32; - - if (max > size) - max = size; - - if (line==0) - fprintf(fout, "%s", prefix); - else - fprintf(fout, "%*s", prefixlen, ""); - - - for(i=0; i. - Ditto for AIX 3.2 and . */ -#ifndef _NO_PROTO -# define _NO_PROTO -#endif - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#if !defined __STDC__ || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -# ifndef const -# define const -# endif -#endif - -#include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#define GETOPT_INTERFACE_VERSION 2 -#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 -# include -# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -# define ELIDE_CODE -# endif -#endif - -#ifndef ELIDE_CODE - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -/* Don't include stdlib.h for non-GNU C libraries because some of them - contain conflicting prototypes for getopt. */ -# include -# include -#endif /* GNU C library. */ - -#ifdef VMS -# include -# if HAVE_STRING_H - 0 -# include -# endif -#endif - -#ifndef _ -/* This is for other GNU distributions with internationalized messages. - When compiling libc, the _ macro is predefined. */ -# ifdef HAVE_LIBINTL_H -# include -# define _(msgid) gettext (msgid) -# else -# define _(msgid) (msgid) -# endif -#endif - -/* This version of `getopt' appears to the caller like standard Unix `getopt' - but it behaves differently for the user, since it allows the user - to intersperse the options with the other arguments. - - As `getopt' works, it permutes the elements of ARGV so that, - when it is done, all the options precede everything else. Thus - all application programs are extended to handle flexible argument order. - - Setting the environment variable POSIXLY_CORRECT disables permutation. - Then the behavior is completely standard. - - GNU application programs can use a third alternative mode in which - they can distinguish the relative order of options and other arguments. */ - -#include "getopt.h" - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -/* 1003.2 says this must be 1 before any call. */ -int optind = 1; - -/* Formerly, initialization of getopt depended on optind==0, which - causes problems with re-calling getopt as programs generally don't - know that. */ - -int __getopt_initialized; - -/* The next char to be scanned in the option-element - in which the last option character we returned was found. - This allows us to pick up the scan where we left off. - - If this is zero, or a null string, it means resume the scan - by advancing to the next ARGV-element. */ - -static char *nextchar; - -/* Callers store zero here to inhibit the error message - for unrecognized options. */ - -int opterr = 1; - -/* Set to an option character which was unrecognized. - This must be initialized on some systems to avoid linking in the - system's own getopt implementation. */ - -int optopt = '?'; - -/* Describe how to deal with options that follow non-option ARGV-elements. - - If the caller did not specify anything, - the default is REQUIRE_ORDER if the environment variable - POSIXLY_CORRECT is defined, PERMUTE otherwise. - - REQUIRE_ORDER means don't recognize them as options; - stop option processing when the first non-option is seen. - This is what Unix does. - This mode of operation is selected by either setting the environment - variable POSIXLY_CORRECT, or using `+' as the first character - of the list of option characters. - - PERMUTE is the default. We permute the contents of ARGV as we scan, - so that eventually all the non-options are at the end. This allows options - to be given in any order, even with programs that were not written to - expect this. - - RETURN_IN_ORDER is an option available to programs that were written - to expect options and other ARGV-elements in any order and that care about - the ordering of the two. We describe each non-option ARGV-element - as if it were the argument of an option with character code 1. - Using `-' as the first character of the list of option characters - selects this mode of operation. - - The special argument `--' forces an end of option-scanning regardless - of the value of `ordering'. In the case of RETURN_IN_ORDER, only - `--' can cause `getopt' to return -1 with `optind' != ARGC. */ - -static enum -{ - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER -} ordering; - -/* Value of POSIXLY_CORRECT environment variable. */ -static char *posixly_correct; - -#ifdef __GNU_LIBRARY__ -/* We want to avoid inclusion of string.h with non-GNU libraries - because there are many ways it can cause trouble. - On some systems, it contains special magic macros that don't work - in GCC. */ -# include -# define my_index strchr -#else - -#include - -/* Avoid depending on library functions or files - whose names are inconsistent. */ - -#ifndef getenv -extern char *getenv (); -#endif - -static char * -my_index (str, chr) - const char *str; - int chr; -{ - while (*str) - { - if (*str == chr) - return (char *) str; - str++; - } - return 0; -} - -/* If using GCC, we can safely declare strlen this way. - If not using GCC, it is ok not to declare it. */ -#ifdef __GNUC__ -/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. - That was relevant to code that was here before. */ -# if (!defined __STDC__ || !__STDC__) && !defined strlen -/* gcc with -traditional declares the built-in strlen to return int, - and has done so at least since version 2.4.5. -- rms. */ -extern int strlen (const char *); -# endif /* not __STDC__ */ -#endif /* __GNUC__ */ - -#endif /* not __GNU_LIBRARY__ */ - -/* Handle permutation of arguments. */ - -/* Describe the part of ARGV that contains non-options that have - been skipped. `first_nonopt' is the index in ARGV of the first of them; - `last_nonopt' is the index after the last of them. */ - -static int first_nonopt; -static int last_nonopt; - -#ifdef _LIBC -/* Bash 2.0 gives us an environment variable containing flags - indicating ARGV elements that should not be considered arguments. */ - -/* Defined in getopt_init.c */ -extern char *__getopt_nonoption_flags; - -static int nonoption_flags_max_len; -static int nonoption_flags_len; - -static int original_argc; -static char *const *original_argv; - -/* Make sure the environment variable bash 2.0 puts in the environment - is valid for the getopt call we must make sure that the ARGV passed - to getopt is that one passed to the process. */ -static void -__attribute__ ((unused)) -store_args_and_env (int argc, char *const *argv) -{ - /* XXX This is no good solution. We should rather copy the args so - that we can compare them later. But we must not use malloc(3). */ - original_argc = argc; - original_argv = argv; -} -# ifdef text_set_element -text_set_element (__libc_subinit, store_args_and_env); -# endif /* text_set_element */ - -# define SWAP_FLAGS(ch1, ch2) \ - if (nonoption_flags_len > 0) \ - { \ - char __tmp = __getopt_nonoption_flags[ch1]; \ - __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ - __getopt_nonoption_flags[ch2] = __tmp; \ - } -#else /* !_LIBC */ -# define SWAP_FLAGS(ch1, ch2) -#endif /* _LIBC */ - -/* Exchange two adjacent subsequences of ARGV. - One subsequence is elements [first_nonopt,last_nonopt) - which contains all the non-options that have been skipped so far. - The other is elements [last_nonopt,optind), which contains all - the options processed since those non-options were skipped. - - `first_nonopt' and `last_nonopt' are relocated so that they describe - the new indices of the non-options in ARGV after they are moved. */ - -#if defined __STDC__ && __STDC__ -static void exchange (char **); -#endif - -static void -exchange (argv) - char **argv; -{ - int bottom = first_nonopt; - int middle = last_nonopt; - int top = optind; - char *tem; - - /* Exchange the shorter segment with the far end of the longer segment. - That puts the shorter segment into the right place. - It leaves the longer segment in the right place overall, - but it consists of two parts that need to be swapped next. */ - -#ifdef _LIBC - /* First make sure the handling of the `__getopt_nonoption_flags' - string can work normally. Our top argument must be in the range - of the string. */ - if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) - { - /* We must extend the array. The user plays games with us and - presents new arguments. */ - char *new_str = malloc (top + 1); - if (new_str == NULL) - nonoption_flags_len = nonoption_flags_max_len = 0; - else - { - memset (__mempcpy (new_str, __getopt_nonoption_flags, - nonoption_flags_max_len), - '\0', top + 1 - nonoption_flags_max_len); - nonoption_flags_max_len = top + 1; - __getopt_nonoption_flags = new_str; - } - } -#endif - - while (top > middle && middle > bottom) - { - if (top - middle > middle - bottom) - { - /* Bottom segment is the short one. */ - int len = middle - bottom; - register int i; - - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } - else - { - /* Top segment is the short one. */ - int len = top - middle; - register int i; - - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - SWAP_FLAGS (bottom + i, middle + i); - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; - } - } - - /* Update records for the slots the non-options now occupy. */ - - first_nonopt += (optind - last_nonopt); - last_nonopt = optind; -} - -/* Initialize the internal data when the first call is made. */ - -#if defined __STDC__ && __STDC__ -static const char *_getopt_initialize (int, char *const *, const char *); -#endif -static const char * -_getopt_initialize (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; -{ - /* Start processing options with ARGV-element 1 (since ARGV-element 0 - is the program name); the sequence of previously skipped - non-option ARGV-elements is empty. */ - - first_nonopt = last_nonopt = optind; - - nextchar = NULL; - - posixly_correct = getenv ("POSIXLY_CORRECT"); - - /* Determine how to handle the ordering of options and nonoptions. */ - - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - else if (posixly_correct != NULL) - ordering = REQUIRE_ORDER; - else - ordering = PERMUTE; - -#ifdef _LIBC - if (posixly_correct == NULL - && argc == original_argc && argv == original_argv) - { - if (nonoption_flags_max_len == 0) - { - if (__getopt_nonoption_flags == NULL - || __getopt_nonoption_flags[0] == '\0') - nonoption_flags_max_len = -1; - else - { - const char *orig_str = __getopt_nonoption_flags; - int len = nonoption_flags_max_len = strlen (orig_str); - if (nonoption_flags_max_len < argc) - nonoption_flags_max_len = argc; - __getopt_nonoption_flags = - (char *) malloc (nonoption_flags_max_len); - if (__getopt_nonoption_flags == NULL) - nonoption_flags_max_len = -1; - else - memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), - '\0', nonoption_flags_max_len - len); - } - } - nonoption_flags_len = nonoption_flags_max_len; - } - else - nonoption_flags_len = 0; -#endif - - return optstring; -} - -/* Scan elements of ARGV (whose length is ARGC) for option characters - given in OPTSTRING. - - If an element of ARGV starts with '-', and is not exactly "-" or "--", - then it is an option element. The characters of this element - (aside from the initial '-') are option characters. If `getopt' - is called repeatedly, it returns successively each of the option characters - from each of the option elements. - - If `getopt' finds another option character, it returns that character, - updating `optind' and `nextchar' so that the next call to `getopt' can - resume the scan with the following option character or ARGV-element. - - If there are no more option characters, `getopt' returns -1. - Then `optind' is the index in ARGV of the first ARGV-element - that is not an option. (The ARGV-elements have been permuted - so that those that are not options now come last.) - - OPTSTRING is a string containing the legitimate option characters. - If an option character is seen that is not listed in OPTSTRING, - return '?' after printing an error message. If you set `opterr' to - zero, the error message is suppressed but we still return '?'. - - If a char in OPTSTRING is followed by a colon, that means it wants an arg, - so the following text in the same ARGV-element, or the text of the following - ARGV-element, is returned in `optarg'. Two colons mean an option that - wants an optional arg; if there is text in the current ARGV-element, - it is returned in `optarg', otherwise `optarg' is set to zero. - - If OPTSTRING starts with `-' or `+', it requests different methods of - handling the non-option ARGV-elements. - See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. - - Long-named options begin with `--' instead of `-'. - Their names may be abbreviated as long as the abbreviation is unique - or is an exact match for some defined option. If they have an - argument, it follows the option name in the same ARGV-element, separated - from the option name by a `=', or else the in next ARGV-element. - When `getopt' finds a long-named option, it returns 0 if that option's - `flag' field is nonzero, the value of the option's `val' field - if the `flag' field is zero. - - The elements of ARGV aren't really const, because we permute them. - But we pretend they're const in the prototype to be compatible - with other systems. - - LONGOPTS is a vector of `struct option' terminated by an - element containing a name which is zero. - - LONGIND returns the index in LONGOPT of the long-named option found. - It is only valid when a long-named option has been found by the most - recent call. - - If LONG_ONLY is nonzero, '-' as well as '--' can introduce - long-named options. */ - -int -_getopt_internal (argc, argv, optstring, longopts, longind, long_only) - int argc; - char *const *argv; - const char *optstring; - const struct option *longopts; - int *longind; - int long_only; -{ - optarg = NULL; - - if (optind == 0 || !__getopt_initialized) - { - if (optind == 0) - optind = 1; /* Don't scan ARGV[0], the program name. */ - optstring = _getopt_initialize (argc, argv, optstring); - __getopt_initialized = 1; - } - - /* Test whether ARGV[optind] points to a non-option argument. - Either it does not have option syntax, or there is an environment flag - from the shell indicating it is not an option. The later information - is only used when the used in the GNU libc. */ -#ifdef _LIBC -# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ - || (optind < nonoption_flags_len \ - && __getopt_nonoption_flags[optind] == '1')) -#else -# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') -#endif - - if (nextchar == NULL || *nextchar == '\0') - { - /* Advance to the next ARGV-element. */ - - /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been - moved back by the user (who may also have changed the arguments). */ - if (last_nonopt > optind) - last_nonopt = optind; - if (first_nonopt > optind) - first_nonopt = optind; - - if (ordering == PERMUTE) - { - /* If we have just processed some options following some non-options, - exchange them so that the options come first. */ - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (last_nonopt != optind) - first_nonopt = optind; - - /* Skip any additional non-options - and extend the range of non-options previously skipped. */ - - while (optind < argc && NONOPTION_P) - optind++; - last_nonopt = optind; - } - - /* The special ARGV-element `--' means premature end of options. - Skip it like a null option, - then exchange with previous non-options as if it were an option, - then skip everything else like a non-option. */ - - if (optind != argc && !strcmp (argv[optind], "--")) - { - optind++; - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (first_nonopt == last_nonopt) - first_nonopt = optind; - last_nonopt = argc; - - optind = argc; - } - - /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ - - if (optind == argc) - { - /* Set the next-arg-index to point at the non-options - that we previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) - optind = first_nonopt; - return -1; - } - - /* If we have come to a non-option and did not permute it, - either stop the scan or describe it to the caller and pass it by. */ - - if (NONOPTION_P) - { - if (ordering == REQUIRE_ORDER) - return -1; - optarg = argv[optind++]; - return 1; - } - - /* We have found another option-ARGV-element. - Skip the initial punctuation. */ - - nextchar = (argv[optind] + 1 - + (longopts != NULL && argv[optind][1] == '-')); - } - - /* Decode the current option-ARGV-element. */ - - /* Check whether the ARGV-element is a long option. - - If long_only and the ARGV-element has the form "-f", where f is - a valid short option, don't consider it an abbreviated form of - a long option that starts with f. Otherwise there would be no - way to give the -f short option. - - On the other hand, if there's a long option "fubar" and - the ARGV-element is "-fu", do consider that an abbreviation of - the long option, just like "--fu", and not "-f" with arg "u". - - This distinction seems to be the most useful approach. */ - - if (longopts != NULL - && (argv[optind][1] == '-' - || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = -1; - int option_index; - - for (nameend = nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) - == (unsigned int) strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - - if (ambig && !exact) - { - if (opterr) - fprintf (stderr, _("%s: option `%s' is ambiguous\n"), - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - optopt = 0; - return '?'; - } - - if (pfound != NULL) - { - option_index = indfound; - optind++; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (opterr) - { - if (argv[optind - 1][1] == '-') - /* --option */ - fprintf (stderr, - _("%s: option `--%s' doesn't allow an argument\n"), - argv[0], pfound->name); - else - /* +option or -option */ - fprintf (stderr, - _("%s: option `%c%s' doesn't allow an argument\n"), - argv[0], argv[optind - 1][0], pfound->name); - } - - nextchar += strlen (nextchar); - - optopt = pfound->val; - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (opterr) - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - optopt = pfound->val; - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - - /* Can't find it as a long option. If this is not getopt_long_only, - or the option starts with '--' or is not a valid short - option, then it's an error. - Otherwise interpret it as a short option. */ - if (!long_only || argv[optind][1] == '-' - || my_index (optstring, *nextchar) == NULL) - { - if (opterr) - { - if (argv[optind][1] == '-') - /* --option */ - fprintf (stderr, _("%s: unrecognized option `--%s'\n"), - argv[0], nextchar); - else - /* +option or -option */ - fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), - argv[0], argv[optind][0], nextchar); - } - nextchar = (char *) ""; - optind++; - optopt = 0; - return '?'; - } - } - - /* Look at and handle the next short option-character. */ - - { - char c = *nextchar++; - char *temp = my_index (optstring, c); - - /* Increment `optind' when we start to process its last character. */ - if (*nextchar == '\0') - ++optind; - - if (temp == NULL || c == ':') - { - if (opterr) - { - if (posixly_correct) - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, _("%s: illegal option -- %c\n"), - argv[0], c); - else - fprintf (stderr, _("%s: invalid option -- %c\n"), - argv[0], c); - } - optopt = c; - return '?'; - } - /* Convenience. Treat POSIX -W foo same as long option --foo */ - if (temp[0] == 'W' && temp[1] == ';') - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = 0; - int option_index; - - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (opterr) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, _("%s: option requires an argument -- %c\n"), - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - return c; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - - /* optarg is now the argument, see if it's in the - table of longopts. */ - - for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) == strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - if (ambig && !exact) - { - if (opterr) - fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - return '?'; - } - if (pfound != NULL) - { - option_index = indfound; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (opterr) - fprintf (stderr, _("\ -%s: option `-W %s' doesn't allow an argument\n"), - argv[0], pfound->name); - - nextchar += strlen (nextchar); - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (opterr) - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - nextchar = NULL; - return 'W'; /* Let the application handle it. */ - } - if (temp[1] == ':') - { - if (temp[2] == ':') - { - /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') - { - optarg = nextchar; - optind++; - } - else - optarg = NULL; - nextchar = NULL; - } - else - { - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (opterr) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, - _("%s: option requires an argument -- %c\n"), - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - nextchar = NULL; - } - } - return c; - } -} - -int -getopt (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; -{ - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0); -} - -#endif /* Not ELIDE_CODE. */ - -#ifdef TEST - -/* Compile with -DTEST to make an executable for use in testing - the above definition of `getopt'. */ - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - - c = getopt (argc, argv, "abc:d:0123456789"); - if (c == -1) - break; - - switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ diff --git a/ctrtool/windows/getopt.h b/ctrtool/windows/getopt.h deleted file mode 100644 index b65740d..0000000 --- a/ctrtool/windows/getopt.h +++ /dev/null @@ -1,172 +0,0 @@ -/* Declarations for getopt. - Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef _GETOPT_H - -#ifndef __need_getopt -# define _GETOPT_H 1 -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - - extern char *optarg; - - /* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - - extern int optind; - - /* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - - extern int opterr; - - /* Set to an option character which was unrecognized. */ - - extern int optopt; - -#ifndef __need_getopt - /* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - - struct option { -# if defined __STDC__ && __STDC__ - const char *name; -# else - - char *name; -# endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; - }; - - /* Names for the values of the `has_arg' field of `struct option'. */ - -# define no_argument 0 -# define required_argument 1 -# define optional_argument 2 -#endif /* need getopt */ - - - /* Get definitions and prototypes for functions to process the - arguments in ARGV (ARGC of them, minus the program name) for - options given in OPTS. - - Return the option character from OPTS just read. Return -1 when - there are no more options. For unrecognized options, or options - missing arguments, `optopt' is set to the option letter, and '?' is - returned. - - The OPTS string is a list of characters which are recognized option - letters, optionally followed by colons, specifying that that letter - takes an argument, to be placed in `optarg'. - - If a letter in OPTS is followed by two colons, its argument is - optional. This behavior is specific to the GNU `getopt'. - - The argument `--' causes premature termination of argument - scanning, explicitly telling `getopt' that there are no more - options. - - If OPTS begins with `--', then non-option arguments are treated as - arguments to the option '\0'. This behavior is specific to the GNU - `getopt'. */ - -#if defined __STDC__ && __STDC__ -# ifdef __GNU_LIBRARY__ - /* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ - extern int getopt (int __argc, char *const *__argv, const char *__shortopts); -# else /* not __GNU_LIBRARY__ */ - extern int getopt (); -# endif /* __GNU_LIBRARY__ */ - -# ifndef __need_getopt - - extern int getopt_long (int argc, char ** argv, const char * shortopts, - const struct option * longopts, int * longind); - - extern int getopt_long_only (int __argc, char *const *__argv, - const char *__shortopts, - const struct option *__longopts, int *__longind); - - /* Internal only. Users should not call this directly. */ - extern int _getopt_internal (int __argc, char *const *__argv, - const char *__shortopts, - const struct option *__longopts, int *__longind, - int __long_only); -# endif -#else /* not __STDC__ */ - extern int getopt (); -# ifndef __need_getopt - extern int getopt_long (); - extern int getopt_long_only (); - - extern int _getopt_internal (); -# endif -#endif /* __STDC__ */ - -#ifdef __cplusplus -} -#endif - -/* Make sure we later can get all the definitions and declarations. */ -#undef __need_getopt - -#endif /* getopt.h */ diff --git a/ctrtool/windows/getopt1.c b/ctrtool/windows/getopt1.c deleted file mode 100644 index 00c3071..0000000 --- a/ctrtool/windows/getopt1.c +++ /dev/null @@ -1,188 +0,0 @@ -/* getopt_long and getopt_long_only entry points for GNU getopt. - Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 - Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "getopt.h" - -#if !defined __STDC__ || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - -#include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#define GETOPT_INTERFACE_VERSION 2 -#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 -#include -#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -#define ELIDE_CODE -#endif -#endif - -#ifndef ELIDE_CODE - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -#include -#endif - -#ifndef NULL -#define NULL 0 -#endif - -int -getopt_long (argc, argv, options, long_options, opt_index) - int argc; - char **argv; - const char *options; - const struct option *long_options; - int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 0); -} - -/* Like getopt_long, but '-' as well as '--' can indicate a long option. - If an option that starts with '-' (not '--') doesn't match a long option, - but does match a short option, it is parsed as a short option - instead. */ - -int -getopt_long_only (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 1); -} - - -#endif /* Not ELIDE_CODE. */ - -#ifdef TEST - -#include - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - int option_index = 0; - static struct option long_options[] = - { - {"add", 1, 0, 0}, - {"append", 0, 0, 0}, - {"delete", 1, 0, 0}, - {"verbose", 0, 0, 0}, - {"create", 0, 0, 0}, - {"file", 1, 0, 0}, - {0, 0, 0, 0} - }; - - c = getopt_long (argc, argv, "abc:d:0123456789", - long_options, &option_index); - if (c == -1) - break; - - switch (c) - { - case 0: - printf ("option %s", long_options[option_index].name); - if (optarg) - printf (" with arg %s", optarg); - printf ("\n"); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case 'd': - printf ("option d with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ From cf1ec3dda32194a3b886bc141686bd6d9a5667ca Mon Sep 17 00:00:00 2001 From: jakcron Date: Sat, 12 Mar 2022 14:14:13 +0800 Subject: [PATCH 02/25] Separate build scripts for MakeROM and CTRTool --- .github/workflows/{build_master.yml => Build_MakeROM.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{build_master.yml => Build_MakeROM.yml} (97%) diff --git a/.github/workflows/build_master.yml b/.github/workflows/Build_MakeROM.yml similarity index 97% rename from .github/workflows/build_master.yml rename to .github/workflows/Build_MakeROM.yml index 437e2b6..8e3fd3f 100644 --- a/.github/workflows/build_master.yml +++ b/.github/workflows/Build_MakeROM.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: dist: [ubuntu_x86_64, macos_x86_64, win_x86_64] - prog: [ctrtool, makerom] + prog: [makerom] include: - dist: win_x86_64 os: windows-latest From 74db0204f3ad47ffde37c1cd90293869f6a52511 Mon Sep 17 00:00:00 2001 From: jakcron Date: Sat, 12 Mar 2022 15:58:46 +0800 Subject: [PATCH 03/25] Update gitignore --- .gitignore | 311 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 209 insertions(+), 102 deletions(-) diff --git a/.gitignore b/.gitignore index 7872f09..fbf0828 100644 --- a/.gitignore +++ b/.gitignore @@ -1,68 +1,81 @@ -################# -## Eclipse -################# - -*.pydevproject -.project -.metadata -bin/ -tmp/ -*.tmp -*.bak -*.swp -*~.nib -local.properties -.classpath -.settings/ -.loadpath - -# External tool builders -.externalToolBuilders/ - -# Locally stored "Eclipse launch configurations" -*.launch - -# CDT-specific -.cproject - -# PDT-specific -.buildpath - - -################# -## Visual Studio -################# +bin/* +data/* +*.o +*.a +*.so.* +.DS_Store +.vscode/* ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. - -*.VC.opendb +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.suo *.user +*.userosscache *.sln.docstates -# Build results +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs +# Build results [Dd]ebug/ +[Dd]ebugPublic/ [Rr]elease/ +[Rr]eleases/ x64/ -build/ +x86/ +bld/ [Bb]in/ [Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio *_i.c *_p.c +*_i.h *.ilk *.meta *.obj +*.iobj *.pch *.pdb +*.ipdb *.pgc *.pgd *.rsp @@ -77,21 +90,34 @@ build/ *.vssscc .builds *.pidb -*.log +*.svclog *.scc +# Chutzpah Test files +_Chutzpah* + # Visual C++ cache files ipch/ *.aps *.ncb +*.opendb *.opensdf *.sdf *.cachefile +*.VC.db +*.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ # Guidance Automation Toolkit *.gpState @@ -99,6 +125,10 @@ ipch/ # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode # TeamCity is a build add-in _TeamCity* @@ -106,9 +136,25 @@ _TeamCity* # DotCover is a Code Coverage Tool *.dotCover +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + # NCrunch -*.ncrunch* +_NCrunch_* .*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ # Installshield output folder [Ee]xpress/ @@ -127,105 +173,166 @@ DocProject/Help/html publish/ # Publish Web Output -*.Publish.xml +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted *.pubxml +*.publishproj -# NuGet Packages Directory -## TODO: If you have NuGet Package Restore enabled, uncomment the next line -#packages/ +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ -# Windows Azure Build Output -csx +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ *.build.csdef -# Windows Store app package directory +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ # Others -sql/ -*.Cache ClientBin/ -[Ss]tyle[Cc]op.* ~$* *~ *.dbmdl -*.[Pp]ublish.xml +*.dbproj.schemaview +*.jfm *.pfx *.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ # RIA/Silverlight projects Generated_Code/ -# Backup & report files from converting an old project file to a newer -# Visual Studio version. Backup files are not needed, because we have git ;-) +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak # SQL Server files -App_Data/*.mdf -App_Data/*.ldf +*.mdf +*.ldf +*.ndf -############# -## Windows detritus -############# +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser -# Windows image file caches -Thumbs.db -ehthumbs.db +# Microsoft Fakes +FakesAssemblies/ -# Folder config file -Desktop.ini +# GhostDoc plugin setting file +*.GhostDoc.xml -# Recycle Bin used on file shares -$RECYCLE.BIN/ +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ -# Mac crap -.DS_Store +# Visual Studio 6 build log +*.plg +# Visual Studio 6 workspace options file +*.opt -############# -## Python -############# +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw -*.py[co] +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions -# Packages -*.egg -*.egg-info -dist/ -build/ -eggs/ -parts/ -var/ -sdist/ -develop-eggs/ -.installed.cfg +# Paket dependency manager +.paket/paket.exe +paket-files/ -# Installer logs -pip-log.txt +# FAKE - F# Make +.fake/ -# Unit test / coverage reports -.coverage -.tox +# JetBrains Rider +.idea/ +*.sln.iml -#Translations -*.mo +# CodeRush +.cr/ -#Mr Developer -.mr.developer.cfg +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc -*.o +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config -#CTR -*.cxi -*.cfa -*.cci -*.3ds -*.cia +# Tabs Studio +*.tss -#exec -*.exe -*.db -/.vs/slnx.sqlite +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ \ No newline at end of file From 6ad2f13c50819a34d4fe106fcd371ca3a17b499d Mon Sep 17 00:00:00 2001 From: jakcron Date: Sat, 12 Mar 2022 16:00:10 +0800 Subject: [PATCH 04/25] Change title for MakeROM workflow --- .github/workflows/Build_MakeROM.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Build_MakeROM.yml b/.github/workflows/Build_MakeROM.yml index 8e3fd3f..f6db208 100644 --- a/.github/workflows/Build_MakeROM.yml +++ b/.github/workflows/Build_MakeROM.yml @@ -1,4 +1,4 @@ -name: Compile Master Branch +name: Compile MakeROM (on master branch) on: push: From 800f5776bca9c509d7db691b39b471e57c1b0b9c Mon Sep 17 00:00:00 2001 From: jakcron Date: Sat, 12 Mar 2022 16:00:33 +0800 Subject: [PATCH 05/25] Add source code for ctrtool --- ctrtool/build/visualstudio/CTRTool.sln | 90 + .../visualstudio/CTRTool/CTRTool.vcxproj | 192 + .../CTRTool/CTRTool.vcxproj.filters | 111 + ctrtool/deps/libbroadon-es/LICENSE | 21 + ctrtool/deps/libbroadon-es/README.md | 2 + .../build/visualstudio/libbroadon-es.sln | 62 + .../libbroadon-es/libbroadon-es.vcxproj | 151 + .../libbroadon-es.vcxproj.filters | 48 + ctrtool/deps/libbroadon-es/include/brd/es.h | 7 + .../libbroadon-es/include/brd/es/es_cert.h | 101 + .../libbroadon-es/include/brd/es/es_sign.h | 73 + .../libbroadon-es/include/brd/es/es_ticket.h | 232 + .../libbroadon-es/include/brd/es/es_tmd.h | 129 + .../deps/libbroadon-es/include/brd/es/types.h | 73 + ctrtool/deps/libbroadon-es/makefile | 193 + ctrtool/deps/libbroadon-es/src/Dummy.cpp | 138 + ctrtool/deps/libfmt/LICENSE.rst | 27 + ctrtool/deps/libfmt/README.md | 2 + .../deps/libfmt/build/visualstudio/libfmt.sln | 31 + .../build/visualstudio/libfmt/libfmt.vcxproj | 171 + .../libfmt/libfmt.vcxproj.filters | 66 + ctrtool/deps/libfmt/include/fmt/args.h | 234 + ctrtool/deps/libfmt/include/fmt/chrono.h | 2067 ++++ ctrtool/deps/libfmt/include/fmt/color.h | 638 ++ ctrtool/deps/libfmt/include/fmt/compile.h | 642 ++ ctrtool/deps/libfmt/include/fmt/core.h | 3236 ++++++ ctrtool/deps/libfmt/include/fmt/format-inl.h | 2643 +++++ ctrtool/deps/libfmt/include/fmt/format.h | 3104 ++++++ ctrtool/deps/libfmt/include/fmt/locale.h | 2 + ctrtool/deps/libfmt/include/fmt/os.h | 527 + ctrtool/deps/libfmt/include/fmt/ostream.h | 135 + ctrtool/deps/libfmt/include/fmt/printf.h | 657 ++ ctrtool/deps/libfmt/include/fmt/ranges.h | 793 ++ ctrtool/deps/libfmt/include/fmt/xchar.h | 236 + ctrtool/deps/libfmt/makefile | 197 + ctrtool/deps/libfmt/src/format.cc | 124 + ctrtool/deps/libfmt/src/os.cc | 361 + ctrtool/deps/libmbedtls/BUILDING.md | 31 + ctrtool/deps/libmbedtls/LICENSE | 2 + ctrtool/deps/libmbedtls/README.md | 2 + ctrtool/deps/libmbedtls/apache-2.0.txt | 202 + .../build/visualstudio/libmbedtls.sln | 31 + .../libmbedtls/libmbedtls.vcxproj | 289 + .../libmbedtls/libmbedtls.vcxproj.filters | 492 + ctrtool/deps/libmbedtls/include/mbedtls/aes.h | 674 ++ .../deps/libmbedtls/include/mbedtls/aesni.h | 138 + .../deps/libmbedtls/include/mbedtls/arc4.h | 146 + .../deps/libmbedtls/include/mbedtls/aria.h | 370 + .../deps/libmbedtls/include/mbedtls/asn1.h | 358 + .../libmbedtls/include/mbedtls/asn1write.h | 329 + .../deps/libmbedtls/include/mbedtls/base64.h | 98 + .../deps/libmbedtls/include/mbedtls/bignum.h | 984 ++ .../libmbedtls/include/mbedtls/blowfish.h | 287 + .../deps/libmbedtls/include/mbedtls/bn_mul.h | 916 ++ .../libmbedtls/include/mbedtls/camellia.h | 326 + ctrtool/deps/libmbedtls/include/mbedtls/ccm.h | 310 + .../deps/libmbedtls/include/mbedtls/certs.h | 252 + .../libmbedtls/include/mbedtls/chacha20.h | 226 + .../libmbedtls/include/mbedtls/chachapoly.h | 358 + .../libmbedtls/include/mbedtls/check_config.h | 708 ++ .../deps/libmbedtls/include/mbedtls/cipher.h | 872 ++ .../include/mbedtls/cipher_internal.h | 125 + .../deps/libmbedtls/include/mbedtls/cmac.h | 213 + .../libmbedtls/include/mbedtls/compat-1.3.h | 2531 +++++ .../deps/libmbedtls/include/mbedtls/config.h | 3344 ++++++ .../libmbedtls/include/mbedtls/ctr_drbg.h | 512 + .../deps/libmbedtls/include/mbedtls/debug.h | 265 + ctrtool/deps/libmbedtls/include/mbedtls/des.h | 356 + ctrtool/deps/libmbedtls/include/mbedtls/dhm.h | 1096 ++ .../deps/libmbedtls/include/mbedtls/ecdh.h | 440 + .../deps/libmbedtls/include/mbedtls/ecdsa.h | 604 + .../deps/libmbedtls/include/mbedtls/ecjpake.h | 277 + ctrtool/deps/libmbedtls/include/mbedtls/ecp.h | 1132 ++ .../libmbedtls/include/mbedtls/ecp_internal.h | 299 + .../deps/libmbedtls/include/mbedtls/entropy.h | 289 + .../libmbedtls/include/mbedtls/entropy_poll.h | 110 + .../deps/libmbedtls/include/mbedtls/error.h | 129 + ctrtool/deps/libmbedtls/include/mbedtls/gcm.h | 326 + .../deps/libmbedtls/include/mbedtls/havege.h | 81 + .../deps/libmbedtls/include/mbedtls/hkdf.h | 141 + .../libmbedtls/include/mbedtls/hmac_drbg.h | 415 + ctrtool/deps/libmbedtls/include/mbedtls/md.h | 468 + ctrtool/deps/libmbedtls/include/mbedtls/md2.h | 306 + ctrtool/deps/libmbedtls/include/mbedtls/md4.h | 311 + ctrtool/deps/libmbedtls/include/mbedtls/md5.h | 311 + .../libmbedtls/include/mbedtls/md_internal.h | 115 + .../include/mbedtls/memory_buffer_alloc.h | 151 + ctrtool/deps/libmbedtls/include/mbedtls/net.h | 37 + .../libmbedtls/include/mbedtls/net_sockets.h | 271 + .../deps/libmbedtls/include/mbedtls/nist_kw.h | 184 + ctrtool/deps/libmbedtls/include/mbedtls/oid.h | 605 + .../deps/libmbedtls/include/mbedtls/padlock.h | 126 + ctrtool/deps/libmbedtls/include/mbedtls/pem.h | 136 + ctrtool/deps/libmbedtls/include/mbedtls/pk.h | 755 ++ .../libmbedtls/include/mbedtls/pk_internal.h | 138 + .../deps/libmbedtls/include/mbedtls/pkcs11.h | 175 + .../deps/libmbedtls/include/mbedtls/pkcs12.h | 130 + .../deps/libmbedtls/include/mbedtls/pkcs5.h | 109 + .../libmbedtls/include/mbedtls/platform.h | 367 + .../include/mbedtls/platform_time.h | 82 + .../include/mbedtls/platform_util.h | 196 + .../libmbedtls/include/mbedtls/poly1305.h | 192 + .../libmbedtls/include/mbedtls/ripemd160.h | 237 + ctrtool/deps/libmbedtls/include/mbedtls/rsa.h | 1274 +++ .../libmbedtls/include/mbedtls/rsa_internal.h | 226 + .../deps/libmbedtls/include/mbedtls/sha1.h | 352 + .../deps/libmbedtls/include/mbedtls/sha256.h | 297 + .../deps/libmbedtls/include/mbedtls/sha512.h | 300 + ctrtool/deps/libmbedtls/include/mbedtls/ssl.h | 3262 ++++++ .../libmbedtls/include/mbedtls/ssl_cache.h | 150 + .../include/mbedtls/ssl_ciphersuites.h | 540 + .../libmbedtls/include/mbedtls/ssl_cookie.h | 115 + .../libmbedtls/include/mbedtls/ssl_internal.h | 782 ++ .../libmbedtls/include/mbedtls/ssl_ticket.h | 142 + .../libmbedtls/include/mbedtls/threading.h | 122 + .../deps/libmbedtls/include/mbedtls/timing.h | 153 + .../deps/libmbedtls/include/mbedtls/version.h | 112 + .../deps/libmbedtls/include/mbedtls/x509.h | 337 + .../libmbedtls/include/mbedtls/x509_crl.h | 174 + .../libmbedtls/include/mbedtls/x509_crt.h | 785 ++ .../libmbedtls/include/mbedtls/x509_csr.h | 307 + .../deps/libmbedtls/include/mbedtls/xtea.h | 139 + ctrtool/deps/libmbedtls/makefile | 197 + ctrtool/deps/libmbedtls/src/aes.c | 2233 ++++ ctrtool/deps/libmbedtls/src/aesni.c | 470 + ctrtool/deps/libmbedtls/src/arc4.c | 201 + ctrtool/deps/libmbedtls/src/aria.c | 1079 ++ ctrtool/deps/libmbedtls/src/asn1parse.c | 389 + ctrtool/deps/libmbedtls/src/asn1write.c | 421 + ctrtool/deps/libmbedtls/src/base64.c | 293 + ctrtool/deps/libmbedtls/src/bignum.c | 2866 +++++ ctrtool/deps/libmbedtls/src/blowfish.c | 696 ++ ctrtool/deps/libmbedtls/src/camellia.c | 1114 ++ ctrtool/deps/libmbedtls/src/ccm.c | 545 + ctrtool/deps/libmbedtls/src/certs.c | 1753 +++ ctrtool/deps/libmbedtls/src/chacha20.c | 570 + ctrtool/deps/libmbedtls/src/chachapoly.c | 540 + ctrtool/deps/libmbedtls/src/cipher.c | 1158 ++ ctrtool/deps/libmbedtls/src/cipher_wrap.c | 2272 ++++ ctrtool/deps/libmbedtls/src/cmac.c | 1078 ++ ctrtool/deps/libmbedtls/src/ctr_drbg.c | 722 ++ ctrtool/deps/libmbedtls/src/debug.c | 450 + ctrtool/deps/libmbedtls/src/des.c | 1064 ++ ctrtool/deps/libmbedtls/src/dhm.c | 712 ++ ctrtool/deps/libmbedtls/src/ecdh.c | 676 ++ ctrtool/deps/libmbedtls/src/ecdsa.c | 991 ++ ctrtool/deps/libmbedtls/src/ecjpake.c | 1140 ++ ctrtool/deps/libmbedtls/src/ecp.c | 2999 +++++ ctrtool/deps/libmbedtls/src/ecp_curves.c | 1470 +++ ctrtool/deps/libmbedtls/src/entropy.c | 721 ++ ctrtool/deps/libmbedtls/src/entropy_poll.c | 236 + ctrtool/deps/libmbedtls/src/error.c | 916 ++ ctrtool/deps/libmbedtls/src/gcm.c | 994 ++ ctrtool/deps/libmbedtls/src/havege.c | 253 + ctrtool/deps/libmbedtls/src/hkdf.c | 192 + ctrtool/deps/libmbedtls/src/hmac_drbg.c | 625 ++ ctrtool/deps/libmbedtls/src/md.c | 475 + ctrtool/deps/libmbedtls/src/md2.c | 363 + ctrtool/deps/libmbedtls/src/md4.c | 484 + ctrtool/deps/libmbedtls/src/md5.c | 498 + ctrtool/deps/libmbedtls/src/md_wrap.c | 586 + .../deps/libmbedtls/src/memory_buffer_alloc.c | 750 ++ ctrtool/deps/libmbedtls/src/net_sockets.c | 668 ++ ctrtool/deps/libmbedtls/src/nist_kw.c | 755 ++ ctrtool/deps/libmbedtls/src/oid.c | 758 ++ ctrtool/deps/libmbedtls/src/padlock.c | 170 + ctrtool/deps/libmbedtls/src/pem.c | 490 + ctrtool/deps/libmbedtls/src/pk.c | 546 + ctrtool/deps/libmbedtls/src/pk_wrap.c | 719 ++ ctrtool/deps/libmbedtls/src/pkcs11.c | 240 + ctrtool/deps/libmbedtls/src/pkcs12.c | 365 + ctrtool/deps/libmbedtls/src/pkcs5.c | 411 + ctrtool/deps/libmbedtls/src/pkparse.c | 1538 +++ ctrtool/deps/libmbedtls/src/pkwrite.c | 566 + ctrtool/deps/libmbedtls/src/platform.c | 348 + ctrtool/deps/libmbedtls/src/platform_util.c | 139 + ctrtool/deps/libmbedtls/src/poly1305.c | 559 + ctrtool/deps/libmbedtls/src/ripemd160.c | 559 + ctrtool/deps/libmbedtls/src/rsa.c | 2729 +++++ ctrtool/deps/libmbedtls/src/rsa_internal.c | 492 + ctrtool/deps/libmbedtls/src/sha1.c | 573 + ctrtool/deps/libmbedtls/src/sha256.c | 586 + ctrtool/deps/libmbedtls/src/sha512.c | 636 ++ ctrtool/deps/libmbedtls/src/ssl_cache.c | 327 + .../deps/libmbedtls/src/ssl_ciphersuites.c | 2373 ++++ ctrtool/deps/libmbedtls/src/ssl_cli.c | 3636 ++++++ ctrtool/deps/libmbedtls/src/ssl_cookie.c | 256 + ctrtool/deps/libmbedtls/src/ssl_srv.c | 4379 ++++++++ ctrtool/deps/libmbedtls/src/ssl_ticket.c | 485 + ctrtool/deps/libmbedtls/src/ssl_tls.c | 9791 +++++++++++++++++ ctrtool/deps/libmbedtls/src/threading.c | 187 + ctrtool/deps/libmbedtls/src/timing.c | 536 + ctrtool/deps/libmbedtls/src/version.c | 50 + .../deps/libmbedtls/src/version_features.c | 785 ++ ctrtool/deps/libmbedtls/src/x509.c | 1072 ++ ctrtool/deps/libmbedtls/src/x509_create.c | 379 + ctrtool/deps/libmbedtls/src/x509_crl.c | 773 ++ ctrtool/deps/libmbedtls/src/x509_crt.c | 2730 +++++ ctrtool/deps/libmbedtls/src/x509_csr.c | 419 + ctrtool/deps/libmbedtls/src/x509write_crt.c | 522 + ctrtool/deps/libmbedtls/src/x509write_csr.c | 302 + ctrtool/deps/libmbedtls/src/xtea.c | 277 + ctrtool/deps/libnintendo-n3ds/LICENSE | 21 + ctrtool/deps/libnintendo-n3ds/README.md | 2 + .../build/visualstudio/libnintendo-n3ds.sln | 71 + .../libnintendo-n3ds/libnintendo-n3ds.vcxproj | 185 + .../libnintendo-n3ds.vcxproj.filters | 147 + .../deps/libnintendo-n3ds/include/ntd/n3ds.h | 26 + .../include/ntd/n3ds/CciFsSnapshotGenerator.h | 19 + .../include/ntd/n3ds/CiaFsSnapshotGenerator.h | 19 + .../include/ntd/n3ds/CtrKeyGenerator.h | 19 + .../include/ntd/n3ds/ExeFsSnapshotGenerator.h | 14 + .../include/ntd/n3ds/IvfcStream.h | 141 + .../include/ntd/n3ds/RomFsSnapshotGenerator.h | 30 + .../libnintendo-n3ds/include/ntd/n3ds/bcwav.h | 212 + .../libnintendo-n3ds/include/ntd/n3ds/cci.h | 258 + .../libnintendo-n3ds/include/ntd/n3ds/cia.h | 61 + .../libnintendo-n3ds/include/ntd/n3ds/cro.h | 160 + .../libnintendo-n3ds/include/ntd/n3ds/crr.h | 48 + .../libnintendo-n3ds/include/ntd/n3ds/es.h | 5 + .../include/ntd/n3ds/es/Certificate.h | 117 + .../include/ntd/n3ds/es/ISigner.h | 18 + .../include/ntd/n3ds/es/RsaSigner.h | 30 + .../include/ntd/n3ds/es/Signature.h | 50 + .../include/ntd/n3ds/es/Ticket.h | 72 + .../include/ntd/n3ds/es/TitleMetaData.h | 106 + .../libnintendo-n3ds/include/ntd/n3ds/exefs.h | 33 + .../include/ntd/n3ds/exheader.h | 317 + .../libnintendo-n3ds/include/ntd/n3ds/firm.h | 40 + .../libnintendo-n3ds/include/ntd/n3ds/ivfc.h | 70 + .../libnintendo-n3ds/include/ntd/n3ds/ncch.h | 158 + .../libnintendo-n3ds/include/ntd/n3ds/romfs.h | 62 + .../libnintendo-n3ds/include/ntd/n3ds/smdh.h | 128 + .../include/ntd/n3ds/systemupdater.h | 129 + ctrtool/deps/libnintendo-n3ds/makefile | 193 + .../src/CciFsSnapshotGenerator.cpp | 131 + .../src/CiaFsSnapshotGenerator.cpp | 241 + .../libnintendo-n3ds/src/CtrKeyGenerator.cpp | 99 + .../src/ExeFsSnapshotGenerator.cpp | 122 + .../deps/libnintendo-n3ds/src/IvfcStream.cpp | 467 + .../src/RomFsSnapshotGenerator.cpp | 360 + .../libnintendo-n3ds/src/es/Certificate.cpp | 200 + .../libnintendo-n3ds/src/es/RsaSigner.cpp | 84 + .../libnintendo-n3ds/src/es/Signature.cpp | 138 + .../deps/libnintendo-n3ds/src/es/Ticket.cpp | 182 + .../libnintendo-n3ds/src/es/TitleMetaData.cpp | 135 + ctrtool/deps/libtoolchain/BUILDING.md | 44 + ctrtool/deps/libtoolchain/Doxyfile | 2565 +++++ ctrtool/deps/libtoolchain/DoxygenMainpage.md | 3 + ctrtool/deps/libtoolchain/LICENSE | 20 + ctrtool/deps/libtoolchain/README.md | 46 + .../libtoolchain-test.vcxproj | 325 + .../libtoolchain-test.vcxproj.filters | 567 + .../build/visualstudio/libtoolchain.sln | 64 + .../libtoolchain/libtoolchain.vcxproj | 350 + .../libtoolchain/libtoolchain.vcxproj.filters | 690 ++ ctrtool/deps/libtoolchain/include/tc.h | 37 + .../include/tc/AccessViolationException.h | 57 + .../include/tc/ArgumentException.h | 57 + .../include/tc/ArgumentNullException.h | 57 + .../include/tc/ArgumentOutOfRangeException.h | 57 + .../include/tc/ArithmeticException.h | 57 + .../deps/libtoolchain/include/tc/ByteData.h | 102 + .../deps/libtoolchain/include/tc/Exception.h | 71 + .../include/tc/InvalidOperationException.h | 57 + .../include/tc/NotImplementedException.h | 57 + .../include/tc/NotSupportedException.h | 57 + .../include/tc/ObjectDisposedException.h | 57 + .../deps/libtoolchain/include/tc/Optional.h | 151 + .../include/tc/OutOfMemoryException.h | 57 + .../include/tc/OverflowException.h | 57 + .../include/tc/PlatformErrorHandlingUtil.h | 46 + .../libtoolchain/include/tc/ResourceStatus.h | 29 + .../include/tc/SecurityException.h | 57 + .../include/tc/UnauthorisedAccessException.h | 57 + ctrtool/deps/libtoolchain/include/tc/bn.h | 17 + .../libtoolchain/include/tc/bn/binary_utils.h | 39 + .../libtoolchain/include/tc/bn/bitarray.h | 69 + .../libtoolchain/include/tc/bn/endian_types.h | 233 + ctrtool/deps/libtoolchain/include/tc/bn/pad.h | 29 + .../deps/libtoolchain/include/tc/bn/string.h | 141 + ctrtool/deps/libtoolchain/include/tc/cli.h | 14 + .../libtoolchain/include/tc/cli/FormatUtil.h | 105 + .../include/tc/cli/OptionParser.h | 285 + ctrtool/deps/libtoolchain/include/tc/crypto.h | 85 + .../tc/crypto/Aes128CbcEncryptedStream.h | 168 + .../include/tc/crypto/Aes128CbcEncryptor.h | 94 + .../tc/crypto/Aes128CtrEncryptedStream.h | 166 + .../include/tc/crypto/Aes128CtrEncryptor.h | 115 + .../include/tc/crypto/Aes128EcbEncryptor.h | 84 + .../include/tc/crypto/Aes128XtsEncryptor.h | 104 + .../include/tc/crypto/Aes192CbcEncryptor.h | 94 + .../include/tc/crypto/Aes192CtrEncryptor.h | 115 + .../include/tc/crypto/Aes192EcbEncryptor.h | 84 + .../include/tc/crypto/Aes256CbcEncryptor.h | 94 + .../include/tc/crypto/Aes256CtrEncryptor.h | 115 + .../include/tc/crypto/Aes256EcbEncryptor.h | 84 + .../include/tc/crypto/Aes256XtsEncryptor.h | 104 + .../include/tc/crypto/AesEncryptor.h | 140 + .../include/tc/crypto/CbcEncryptor.h | 177 + .../include/tc/crypto/CryptoException.h | 57 + .../include/tc/crypto/CtrEncryptor.h | 154 + .../include/tc/crypto/EcbEncryptor.h | 146 + .../include/tc/crypto/HmacGenerator.h | 219 + .../include/tc/crypto/HmacMd5Generator.h | 45 + .../include/tc/crypto/HmacSha1Generator.h | 45 + .../include/tc/crypto/HmacSha256Generator.h | 45 + .../include/tc/crypto/HmacSha512Generator.h | 45 + .../include/tc/crypto/Md5Generator.h | 221 + .../include/tc/crypto/Pbkdf1KeyDeriver.h | 116 + .../include/tc/crypto/Pbkdf1Md5KeyDeriver.h | 47 + .../include/tc/crypto/Pbkdf1Sha1KeyDeriver.h | 47 + .../include/tc/crypto/Pbkdf2KeyDeriver.h | 118 + .../include/tc/crypto/Pbkdf2Sha1KeyDeriver.h | 47 + .../tc/crypto/Pbkdf2Sha256KeyDeriver.h | 47 + .../tc/crypto/Pbkdf2Sha512KeyDeriver.h | 47 + .../tc/crypto/PseudoRandomByteGenerator.h | 65 + .../libtoolchain/include/tc/crypto/RsaKey.h | 75 + .../include/tc/crypto/RsaKeyGenerator.h | 71 + .../include/tc/crypto/RsaOaepEncryptor.h | 246 + .../tc/crypto/RsaOaepSha256Encryptor.h | 201 + .../tc/crypto/RsaOaepSha512Encryptor.h | 139 + .../include/tc/crypto/RsaPkcs1Md5Signer.h | 144 + .../include/tc/crypto/RsaPkcs1Sha1Signer.h | 144 + .../include/tc/crypto/RsaPkcs1Sha256Signer.h | 144 + .../include/tc/crypto/RsaPkcs1Sha512Signer.h | 144 + .../include/tc/crypto/RsaPkcs1Signer.h | 172 + .../include/tc/crypto/RsaPssSha256Signer.h | 144 + .../include/tc/crypto/RsaPssSha512Signer.h | 144 + .../include/tc/crypto/RsaPssSigner.h | 208 + .../include/tc/crypto/Sha1Generator.h | 221 + .../include/tc/crypto/Sha256Generator.h | 216 + .../include/tc/crypto/Sha512Generator.h | 217 + .../include/tc/crypto/XtsEncryptor.h | 167 + .../include/tc/crypto/detail/AesImpl.h | 102 + .../include/tc/crypto/detail/BlockUtilImpl.h | 69 + .../include/tc/crypto/detail/CbcModeImpl.h | 130 + .../include/tc/crypto/detail/CtrModeImpl.h | 113 + .../include/tc/crypto/detail/EcbModeImpl.h | 147 + .../include/tc/crypto/detail/HmacImpl.h | 107 + .../include/tc/crypto/detail/Md5Impl.h | 44 + .../include/tc/crypto/detail/Pbkdf1Impl.h | 159 + .../include/tc/crypto/detail/Pbkdf2Impl.h | 179 + .../include/tc/crypto/detail/PrbgImpl.h | 61 + .../include/tc/crypto/detail/RsaImpl.h | 119 + .../tc/crypto/detail/RsaKeyGeneratorImpl.h | 79 + .../include/tc/crypto/detail/RsaOaepPadding.h | 169 + .../tc/crypto/detail/RsaPkcs1Padding.h | 117 + .../include/tc/crypto/detail/RsaPssPadding.h | 260 + .../include/tc/crypto/detail/Sha1Impl.h | 44 + .../include/tc/crypto/detail/Sha2Impl.h | 57 + .../include/tc/crypto/detail/XtsModeImpl.h | 330 + ctrtool/deps/libtoolchain/include/tc/io.h | 48 + .../include/tc/io/BasicPathResolver.h | 109 + .../include/tc/io/ConcatenatedStream.h | 205 + .../tc/io/DirectoryNotEmptyException.h | 57 + .../tc/io/DirectoryNotFoundException.h | 57 + .../libtoolchain/include/tc/io/FileAccess.h | 23 + .../include/tc/io/FileExistsException.h | 57 + .../libtoolchain/include/tc/io/FileMode.h | 26 + .../include/tc/io/FileNotFoundException.h | 57 + .../libtoolchain/include/tc/io/FileStream.h | 240 + .../libtoolchain/include/tc/io/IFileSystem.h | 124 + .../libtoolchain/include/tc/io/IOException.h | 57 + .../deps/libtoolchain/include/tc/io/IOUtil.h | 63 + .../include/tc/io/IPathResolver.h | 40 + .../include/tc/io/IPortablePathResolver.h | 37 + .../include/tc/io/IReadableSink.h | 28 + .../deps/libtoolchain/include/tc/io/ISink.h | 46 + .../deps/libtoolchain/include/tc/io/ISource.h | 39 + .../deps/libtoolchain/include/tc/io/IStream.h | 117 + .../include/tc/io/LocalFileSystem.h | 143 + .../libtoolchain/include/tc/io/MemorySource.h | 68 + .../libtoolchain/include/tc/io/MemoryStream.h | 155 + .../include/tc/io/OverlayedSource.h | 96 + .../include/tc/io/PaddingSource.h | 59 + .../deps/libtoolchain/include/tc/io/Path.h | 253 + .../include/tc/io/PathTooLongException.h | 57 + .../libtoolchain/include/tc/io/PathUtil.h | 39 + .../libtoolchain/include/tc/io/SeekOrigin.h | 23 + .../libtoolchain/include/tc/io/StreamSink.h | 76 + .../libtoolchain/include/tc/io/StreamSource.h | 66 + .../libtoolchain/include/tc/io/StreamUtil.h | 37 + .../include/tc/io/SubFileSystem.h | 136 + .../deps/libtoolchain/include/tc/io/SubSink.h | 77 + .../libtoolchain/include/tc/io/SubSource.h | 64 + .../libtoolchain/include/tc/io/SubStream.h | 155 + .../include/tc/io/VirtualFileSystem.h | 212 + ctrtool/deps/libtoolchain/include/tc/os.h | 13 + .../libtoolchain/include/tc/os/Environment.h | 28 + .../libtoolchain/include/tc/os/UnicodeMain.h | 71 + ctrtool/deps/libtoolchain/include/tc/string.h | 12 + .../include/tc/string/TranscodeUtil.h | 77 + .../include/tc/string/detail/utf16.h | 22 + .../include/tc/string/detail/utf8.h | 39 + ctrtool/deps/libtoolchain/include/tc/types.h | 65 + ctrtool/deps/libtoolchain/makefile | 197 + ctrtool/deps/libtoolchain/src/ByteData.cpp | 110 + ctrtool/deps/libtoolchain/src/Exception.cpp | 46 + .../src/PlatformErrorHandlingUtil.cpp | 41 + .../deps/libtoolchain/src/cli/FormatUtil.cpp | 222 + .../libtoolchain/src/cli/OptionParser.cpp | 185 + .../src/crypto/Aes128CbcEncryptedStream.cpp | 328 + .../src/crypto/Aes128CbcEncryptor.cpp | 15 + .../src/crypto/Aes128CtrEncryptedStream.cpp | 284 + .../src/crypto/Aes128CtrEncryptor.cpp | 24 + .../src/crypto/Aes128EcbEncryptor.cpp | 15 + .../src/crypto/Aes128XtsEncryptor.cpp | 15 + .../src/crypto/Aes192CbcEncryptor.cpp | 15 + .../src/crypto/Aes192CtrEncryptor.cpp | 24 + .../src/crypto/Aes192EcbEncryptor.cpp | 15 + .../src/crypto/Aes256CbcEncryptor.cpp | 15 + .../src/crypto/Aes256CtrEncryptor.cpp | 24 + .../src/crypto/Aes256EcbEncryptor.cpp | 15 + .../src/crypto/Aes256XtsEncryptor.cpp | 15 + .../src/crypto/HmacMd5Generator.cpp | 9 + .../src/crypto/HmacSha1Generator.cpp | 9 + .../src/crypto/HmacSha256Generator.cpp | 9 + .../src/crypto/HmacSha512Generator.cpp | 9 + .../libtoolchain/src/crypto/Md5Generator.cpp | 11 + .../src/crypto/Pbkdf1Md5KeyDeriver.cpp | 8 + .../src/crypto/Pbkdf1Sha1KeyDeriver.cpp | 8 + .../src/crypto/Pbkdf2Sha1KeyDeriver.cpp | 8 + .../src/crypto/Pbkdf2Sha256KeyDeriver.cpp | 8 + .../src/crypto/Pbkdf2Sha512KeyDeriver.cpp | 8 + .../src/crypto/PseudoRandomByteGenerator.cpp | 7 + .../deps/libtoolchain/src/crypto/RsaKey.cpp | 29 + .../src/crypto/RsaKeyGenerator.cpp | 7 + .../src/crypto/RsaOaepSha256Encryptor.cpp | 43 + .../src/crypto/RsaOaepSha512Encryptor.cpp | 29 + .../src/crypto/RsaPkcs1Md5Signer.cpp | 43 + .../src/crypto/RsaPkcs1Sha1Signer.cpp | 43 + .../src/crypto/RsaPkcs1Sha256Signer.cpp | 43 + .../src/crypto/RsaPkcs1Sha512Signer.cpp | 43 + .../src/crypto/RsaPssSha256Signer.cpp | 43 + .../src/crypto/RsaPssSha512Signer.cpp | 43 + .../libtoolchain/src/crypto/Sha1Generator.cpp | 12 + .../src/crypto/Sha256Generator.cpp | 11 + .../src/crypto/Sha512Generator.cpp | 11 + .../src/crypto/detail/AesImpl.cpp | 51 + .../src/crypto/detail/Md5Impl.cpp | 44 + .../src/crypto/detail/PrbgImpl.cpp | 50 + .../src/crypto/detail/RsaImpl.cpp | 140 + .../src/crypto/detail/RsaKeyGeneratorImpl.cpp | 85 + .../src/crypto/detail/Sha1Impl.cpp | 44 + .../src/crypto/detail/Sha2Impl.cpp | 58 + .../libtoolchain/src/io/BasicPathResolver.cpp | 97 + .../src/io/ConcatenatedStream.cpp | 370 + .../deps/libtoolchain/src/io/FileStream.cpp | 752 ++ ctrtool/deps/libtoolchain/src/io/IOUtil.cpp | 40 + .../libtoolchain/src/io/LocalFileSystem.cpp | 419 + .../deps/libtoolchain/src/io/MemorySource.cpp | 49 + .../deps/libtoolchain/src/io/MemoryStream.cpp | 155 + .../libtoolchain/src/io/OverlayedSource.cpp | 143 + .../libtoolchain/src/io/PaddingSource.cpp | 34 + ctrtool/deps/libtoolchain/src/io/Path.cpp | 331 + ctrtool/deps/libtoolchain/src/io/PathUtil.cpp | 12 + .../deps/libtoolchain/src/io/StreamSink.cpp | 54 + .../deps/libtoolchain/src/io/StreamSource.cpp | 55 + .../deps/libtoolchain/src/io/StreamUtil.cpp | 22 + .../libtoolchain/src/io/SubFileSystem.cpp | 216 + ctrtool/deps/libtoolchain/src/io/SubSink.cpp | 73 + .../deps/libtoolchain/src/io/SubSource.cpp | 66 + .../deps/libtoolchain/src/io/SubStream.cpp | 183 + .../libtoolchain/src/io/VirtualFileSystem.cpp | 192 + .../deps/libtoolchain/src/os/Environment.cpp | 40 + .../libtoolchain/src/string/TranscodeUtil.cpp | 165 + ctrtool/deps/libtoolchain/src/types.cpp | 26 + .../libtoolchain/test/ByteData_TestClass.cpp | 671 ++ .../libtoolchain/test/ByteData_TestClass.h | 23 + .../libtoolchain/test/FileSystemTestUtil.cpp | 3 + .../libtoolchain/test/FileSystemTestUtil.h | 79 + ctrtool/deps/libtoolchain/test/ITestClass.h | 8 + .../libtoolchain/test/Optional_TestClass.cpp | 300 + .../libtoolchain/test/Optional_TestClass.h | 20 + ctrtool/deps/libtoolchain/test/PbkdfUtil.cpp | 245 + ctrtool/deps/libtoolchain/test/PbkdfUtil.h | 34 + .../deps/libtoolchain/test/RsaOaepUtil.cpp | 172 + ctrtool/deps/libtoolchain/test/RsaOaepUtil.h | 34 + .../deps/libtoolchain/test/RsaPkcs1Util.cpp | 146 + ctrtool/deps/libtoolchain/test/RsaPkcs1Util.h | 31 + ctrtool/deps/libtoolchain/test/RsaPssUtil.cpp | 143 + ctrtool/deps/libtoolchain/test/RsaPssUtil.h | 32 + .../deps/libtoolchain/test/SinkTestUtil.cpp | 90 + ctrtool/deps/libtoolchain/test/SinkTestUtil.h | 42 + .../deps/libtoolchain/test/SourceTestUtil.cpp | 32 + .../deps/libtoolchain/test/SourceTestUtil.h | 9 + .../deps/libtoolchain/test/StreamTestUtil.cpp | 125 + .../deps/libtoolchain/test/StreamTestUtil.h | 154 + .../test/bn_binaryutils_TestClass.cpp | 173 + .../test/bn_binaryutils_TestClass.h | 25 + .../test/bn_bitarrayByteBEBitBE_TestClass.cpp | 238 + .../test/bn_bitarrayByteBEBitBE_TestClass.h | 19 + .../test/bn_bitarrayByteBEBitLE_TestClass.cpp | 238 + .../test/bn_bitarrayByteBEBitLE_TestClass.h | 19 + .../test/bn_bitarrayByteLEBitBE_TestClass.cpp | 238 + .../test/bn_bitarrayByteLEBitBE_TestClass.h | 19 + .../test/bn_bitarrayByteLEBitLE_TestClass.cpp | 238 + .../test/bn_bitarrayByteLEBitLE_TestClass.h | 19 + .../libtoolchain/test/bn_endian_TestClass.cpp | 778 ++ .../libtoolchain/test/bn_endian_TestClass.h | 32 + .../libtoolchain/test/bn_pad_TestClass.cpp | 55 + .../deps/libtoolchain/test/bn_pad_TestClass.h | 14 + .../libtoolchain/test/bn_string_TestClass.cpp | 219 + .../libtoolchain/test/bn_string_TestClass.h | 16 + .../test/cli_FormatUtil_TestClass.cpp | 366 + .../test/cli_FormatUtil_TestClass.h | 15 + .../test/cli_OptionParser_TestClass.cpp | 770 ++ .../test/cli_OptionParser_TestClass.h | 20 + ...pto_Aes128CbcEncryptedStream_TestClass.cpp | 265 + ...rypto_Aes128CbcEncryptedStream_TestClass.h | 29 + .../crypto_Aes128CbcEncryptor_TestClass.cpp | 570 + .../crypto_Aes128CbcEncryptor_TestClass.h | 33 + ...pto_Aes128CtrEncryptedStream_TestClass.cpp | 265 + ...rypto_Aes128CtrEncryptedStream_TestClass.h | 29 + .../crypto_Aes128CtrEncryptor_TestClass.cpp | 543 + .../crypto_Aes128CtrEncryptor_TestClass.h | 34 + .../crypto_Aes128EcbEncryptor_TestClass.cpp | 523 + .../crypto_Aes128EcbEncryptor_TestClass.h | 32 + .../test/crypto_Aes128Encryptor_TestClass.cpp | 1016 ++ .../test/crypto_Aes128Encryptor_TestClass.h | 30 + .../crypto_Aes128XtsEncryptor_TestClass.cpp | 691 ++ .../crypto_Aes128XtsEncryptor_TestClass.h | 35 + .../crypto_Aes192CbcEncryptor_TestClass.cpp | 570 + .../crypto_Aes192CbcEncryptor_TestClass.h | 33 + .../crypto_Aes192CtrEncryptor_TestClass.cpp | 543 + .../crypto_Aes192CtrEncryptor_TestClass.h | 34 + .../crypto_Aes192EcbEncryptor_TestClass.cpp | 523 + .../crypto_Aes192EcbEncryptor_TestClass.h | 32 + .../test/crypto_Aes192Encryptor_TestClass.cpp | 1336 +++ .../test/crypto_Aes192Encryptor_TestClass.h | 30 + .../crypto_Aes256CbcEncryptor_TestClass.cpp | 570 + .../crypto_Aes256CbcEncryptor_TestClass.h | 33 + .../crypto_Aes256CtrEncryptor_TestClass.cpp | 543 + .../crypto_Aes256CtrEncryptor_TestClass.h | 34 + .../crypto_Aes256EcbEncryptor_TestClass.cpp | 523 + .../crypto_Aes256EcbEncryptor_TestClass.h | 32 + .../test/crypto_Aes256Encryptor_TestClass.cpp | 1656 +++ .../test/crypto_Aes256Encryptor_TestClass.h | 30 + .../crypto_Aes256XtsEncryptor_TestClass.cpp | 575 + .../crypto_Aes256XtsEncryptor_TestClass.h | 35 + .../crypto_HmacMd5Generator_TestClass.cpp | 547 + .../test/crypto_HmacMd5Generator_TestClass.h | 34 + .../crypto_HmacSha1Generator_TestClass.cpp | 547 + .../test/crypto_HmacSha1Generator_TestClass.h | 34 + .../crypto_HmacSha256Generator_TestClass.cpp | 547 + .../crypto_HmacSha256Generator_TestClass.h | 34 + .../crypto_HmacSha512Generator_TestClass.cpp | 547 + .../crypto_HmacSha512Generator_TestClass.h | 34 + .../test/crypto_Md5Generator_TestClass.cpp | 490 + .../test/crypto_Md5Generator_TestClass.h | 18 + .../crypto_Pbkdf1Md5KeyDeriver_TestClass.cpp | 285 + .../crypto_Pbkdf1Md5KeyDeriver_TestClass.h | 15 + .../crypto_Pbkdf1Sha1KeyDeriver_TestClass.cpp | 285 + .../crypto_Pbkdf1Sha1KeyDeriver_TestClass.h | 15 + .../crypto_Pbkdf2Sha1KeyDeriver_TestClass.cpp | 286 + .../crypto_Pbkdf2Sha1KeyDeriver_TestClass.h | 15 + ...rypto_Pbkdf2Sha256KeyDeriver_TestClass.cpp | 287 + .../crypto_Pbkdf2Sha256KeyDeriver_TestClass.h | 15 + ...rypto_Pbkdf2Sha512KeyDeriver_TestClass.cpp | 286 + .../crypto_Pbkdf2Sha512KeyDeriver_TestClass.h | 15 + ...to_PseudoRandomByteGenerator_TestClass.cpp | 226 + ...ypto_PseudoRandomByteGenerator_TestClass.h | 14 + ...o_Rsa1024OaepSha256Encryptor_TestClass.cpp | 673 ++ ...pto_Rsa1024OaepSha256Encryptor_TestClass.h | 23 + ...crypto_Rsa1024Pkcs1Md5Signer_TestClass.cpp | 498 + .../crypto_Rsa1024Pkcs1Md5Signer_TestClass.h | 22 + ...rypto_Rsa1024Pkcs1Sha1Signer_TestClass.cpp | 498 + .../crypto_Rsa1024Pkcs1Sha1Signer_TestClass.h | 22 + ...pto_Rsa1024Pkcs1Sha256Signer_TestClass.cpp | 498 + ...rypto_Rsa1024Pkcs1Sha256Signer_TestClass.h | 22 + ...pto_Rsa1024Pkcs1Sha512Signer_TestClass.cpp | 498 + ...rypto_Rsa1024Pkcs1Sha512Signer_TestClass.h | 22 + ...rypto_Rsa1024PssSha256Signer_TestClass.cpp | 502 + .../crypto_Rsa1024PssSha256Signer_TestClass.h | 22 + ...rypto_Rsa1024PssSha512Signer_TestClass.cpp | 503 + .../crypto_Rsa1024PssSha512Signer_TestClass.h | 22 + ...o_Rsa2048OaepSha256Encryptor_TestClass.cpp | 673 ++ ...pto_Rsa2048OaepSha256Encryptor_TestClass.h | 23 + ...o_Rsa2048OaepSha512Encryptor_TestClass.cpp | 673 ++ ...pto_Rsa2048OaepSha512Encryptor_TestClass.h | 23 + ...crypto_Rsa2048Pkcs1Md5Signer_TestClass.cpp | 498 + .../crypto_Rsa2048Pkcs1Md5Signer_TestClass.h | 22 + ...rypto_Rsa2048Pkcs1Sha1Signer_TestClass.cpp | 498 + .../crypto_Rsa2048Pkcs1Sha1Signer_TestClass.h | 22 + ...pto_Rsa2048Pkcs1Sha256Signer_TestClass.cpp | 498 + ...rypto_Rsa2048Pkcs1Sha256Signer_TestClass.h | 22 + ...pto_Rsa2048Pkcs1Sha512Signer_TestClass.cpp | 498 + ...rypto_Rsa2048Pkcs1Sha512Signer_TestClass.h | 22 + ...rypto_Rsa2048PssSha256Signer_TestClass.cpp | 502 + .../crypto_Rsa2048PssSha256Signer_TestClass.h | 22 + ...rypto_Rsa2048PssSha512Signer_TestClass.cpp | 502 + .../crypto_Rsa2048PssSha512Signer_TestClass.h | 22 + ...o_Rsa4096OaepSha256Encryptor_TestClass.cpp | 673 ++ ...pto_Rsa4096OaepSha256Encryptor_TestClass.h | 23 + ...o_Rsa4096OaepSha512Encryptor_TestClass.cpp | 673 ++ ...pto_Rsa4096OaepSha512Encryptor_TestClass.h | 23 + ...crypto_Rsa4096Pkcs1Md5Signer_TestClass.cpp | 498 + .../crypto_Rsa4096Pkcs1Md5Signer_TestClass.h | 22 + ...rypto_Rsa4096Pkcs1Sha1Signer_TestClass.cpp | 498 + .../crypto_Rsa4096Pkcs1Sha1Signer_TestClass.h | 22 + ...pto_Rsa4096Pkcs1Sha256Signer_TestClass.cpp | 498 + ...rypto_Rsa4096Pkcs1Sha256Signer_TestClass.h | 22 + ...pto_Rsa4096Pkcs1Sha512Signer_TestClass.cpp | 498 + ...rypto_Rsa4096Pkcs1Sha512Signer_TestClass.h | 22 + ...rypto_Rsa4096PssSha256Signer_TestClass.cpp | 502 + .../crypto_Rsa4096PssSha256Signer_TestClass.h | 22 + ...rypto_Rsa4096PssSha512Signer_TestClass.cpp | 502 + .../crypto_Rsa4096PssSha512Signer_TestClass.h | 22 + .../test/crypto_Sha1Generator_TestClass.cpp | 462 + .../test/crypto_Sha1Generator_TestClass.h | 18 + .../test/crypto_Sha256Generator_TestClass.cpp | 462 + .../test/crypto_Sha256Generator_TestClass.h | 18 + .../test/crypto_Sha512Generator_TestClass.cpp | 462 + .../test/crypto_Sha512Generator_TestClass.h | 18 + .../test/io_BasicPathResolver_TestClass.cpp | 292 + .../test/io_BasicPathResolver_TestClass.h | 20 + .../test/io_ConcatenatedStream_TestClass.cpp | 2645 +++++ .../test/io_ConcatenatedStream_TestClass.h | 50 + .../test/io_FileStream_TestClass.cpp | 2070 ++++ .../test/io_FileStream_TestClass.h | 94 + .../test/io_LocalFileSystem_TestClass.cpp | 535 + .../test/io_LocalFileSystem_TestClass.h | 35 + .../test/io_MemorySource_TestClass.cpp | 200 + .../test/io_MemorySource_TestClass.h | 17 + .../test/io_MemoryStream_TestClass.cpp | 1028 ++ .../test/io_MemoryStream_TestClass.h | 43 + .../test/io_OverlayedSource_TestClass.cpp | 377 + .../test/io_OverlayedSource_TestClass.h | 21 + .../test/io_PaddingSource_TestClass.cpp | 134 + .../test/io_PaddingSource_TestClass.h | 13 + .../libtoolchain/test/io_Path_TestClass.cpp | 1197 ++ .../libtoolchain/test/io_Path_TestClass.h | 35 + .../test/io_StreamSink_TestClass.cpp | 307 + .../test/io_StreamSink_TestClass.h | 23 + .../test/io_StreamSource_TestClass.cpp | 206 + .../test/io_StreamSource_TestClass.h | 16 + .../test/io_SubFileSystem_TestClass.cpp | 736 ++ .../test/io_SubFileSystem_TestClass.h | 19 + .../test/io_SubSink_TestClass.cpp | 352 + .../libtoolchain/test/io_SubSink_TestClass.h | 24 + .../test/io_SubSource_TestClass.cpp | 141 + .../test/io_SubSource_TestClass.h | 13 + .../test/io_SubStream_TestClass.cpp | 344 + .../test/io_SubStream_TestClass.h | 18 + .../test/io_VirtualFileSystem_TestClass.cpp | 2543 +++++ .../test/io_VirtualFileSystem_TestClass.h | 21 + ctrtool/deps/libtoolchain/test/main.cpp | 195 + .../test/string_TranscodeUtil_TestClass.cpp | 69 + .../test/string_TranscodeUtil_TestClass.h | 13 + ctrtool/makefile | 177 + ctrtool/src/CciProcess.cpp | 567 + ctrtool/src/CciProcess.h | 70 + ctrtool/src/CiaProcess.cpp | 913 ++ ctrtool/src/CiaProcess.h | 128 + ctrtool/src/CrrProcess.cpp | 192 + ctrtool/src/CrrProcess.h | 46 + ctrtool/src/ExHeaderProcess.cpp | 993 ++ ctrtool/src/ExHeaderProcess.h | 92 + ctrtool/src/ExeFsProcess.cpp | 275 + ctrtool/src/ExeFsProcess.h | 49 + ctrtool/src/FirmProcess.cpp | 396 + ctrtool/src/FirmProcess.h | 71 + ctrtool/src/IvfcProcess.cpp | 199 + ctrtool/src/IvfcProcess.h | 50 + ctrtool/src/KeyBag.cpp | 945 ++ ctrtool/src/KeyBag.h | 128 + ctrtool/src/LzssProcess.cpp | 54 + ctrtool/src/LzssProcess.h | 25 + ctrtool/src/NcchProcess.cpp | 968 ++ ctrtool/src/NcchProcess.h | 92 + ctrtool/src/RomFsProcess.cpp | 231 + ctrtool/src/RomFsProcess.h | 48 + ctrtool/src/Settings.cpp | 704 ++ ctrtool/src/Settings.h | 175 + ctrtool/src/cwav.h | 152 + ctrtool/src/lzss.c | 107 + ctrtool/src/lzss.h | 13 + ctrtool/src/main.cpp | 245 + ctrtool/src/types.h | 15 + ctrtool/src/version.h | 7 + 681 files changed, 219734 insertions(+) create mode 100644 ctrtool/build/visualstudio/CTRTool.sln create mode 100644 ctrtool/build/visualstudio/CTRTool/CTRTool.vcxproj create mode 100644 ctrtool/build/visualstudio/CTRTool/CTRTool.vcxproj.filters create mode 100644 ctrtool/deps/libbroadon-es/LICENSE create mode 100644 ctrtool/deps/libbroadon-es/README.md create mode 100644 ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es.sln create mode 100644 ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es/libbroadon-es.vcxproj create mode 100644 ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es/libbroadon-es.vcxproj.filters create mode 100644 ctrtool/deps/libbroadon-es/include/brd/es.h create mode 100644 ctrtool/deps/libbroadon-es/include/brd/es/es_cert.h create mode 100644 ctrtool/deps/libbroadon-es/include/brd/es/es_sign.h create mode 100644 ctrtool/deps/libbroadon-es/include/brd/es/es_ticket.h create mode 100644 ctrtool/deps/libbroadon-es/include/brd/es/es_tmd.h create mode 100644 ctrtool/deps/libbroadon-es/include/brd/es/types.h create mode 100644 ctrtool/deps/libbroadon-es/makefile create mode 100644 ctrtool/deps/libbroadon-es/src/Dummy.cpp create mode 100644 ctrtool/deps/libfmt/LICENSE.rst create mode 100644 ctrtool/deps/libfmt/README.md create mode 100644 ctrtool/deps/libfmt/build/visualstudio/libfmt.sln create mode 100644 ctrtool/deps/libfmt/build/visualstudio/libfmt/libfmt.vcxproj create mode 100644 ctrtool/deps/libfmt/build/visualstudio/libfmt/libfmt.vcxproj.filters create mode 100644 ctrtool/deps/libfmt/include/fmt/args.h create mode 100644 ctrtool/deps/libfmt/include/fmt/chrono.h create mode 100644 ctrtool/deps/libfmt/include/fmt/color.h create mode 100644 ctrtool/deps/libfmt/include/fmt/compile.h create mode 100644 ctrtool/deps/libfmt/include/fmt/core.h create mode 100644 ctrtool/deps/libfmt/include/fmt/format-inl.h create mode 100644 ctrtool/deps/libfmt/include/fmt/format.h create mode 100644 ctrtool/deps/libfmt/include/fmt/locale.h create mode 100644 ctrtool/deps/libfmt/include/fmt/os.h create mode 100644 ctrtool/deps/libfmt/include/fmt/ostream.h create mode 100644 ctrtool/deps/libfmt/include/fmt/printf.h create mode 100644 ctrtool/deps/libfmt/include/fmt/ranges.h create mode 100644 ctrtool/deps/libfmt/include/fmt/xchar.h create mode 100644 ctrtool/deps/libfmt/makefile create mode 100644 ctrtool/deps/libfmt/src/format.cc create mode 100644 ctrtool/deps/libfmt/src/os.cc create mode 100644 ctrtool/deps/libmbedtls/BUILDING.md create mode 100644 ctrtool/deps/libmbedtls/LICENSE create mode 100644 ctrtool/deps/libmbedtls/README.md create mode 100644 ctrtool/deps/libmbedtls/apache-2.0.txt create mode 100644 ctrtool/deps/libmbedtls/build/visualstudio/libmbedtls.sln create mode 100644 ctrtool/deps/libmbedtls/build/visualstudio/libmbedtls/libmbedtls.vcxproj create mode 100644 ctrtool/deps/libmbedtls/build/visualstudio/libmbedtls/libmbedtls.vcxproj.filters create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/aes.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/aesni.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/arc4.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/aria.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/asn1.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/asn1write.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/base64.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/bignum.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/blowfish.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/bn_mul.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/camellia.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/ccm.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/certs.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/chacha20.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/chachapoly.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/check_config.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/cipher.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/cipher_internal.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/cmac.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/compat-1.3.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/config.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/ctr_drbg.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/debug.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/des.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/dhm.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/ecdh.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/ecdsa.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/ecjpake.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/ecp.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/ecp_internal.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/entropy.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/entropy_poll.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/error.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/gcm.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/havege.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/hkdf.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/hmac_drbg.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/md.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/md2.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/md4.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/md5.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/md_internal.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/memory_buffer_alloc.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/net.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/net_sockets.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/nist_kw.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/oid.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/padlock.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/pem.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/pk.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/pk_internal.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/pkcs11.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/pkcs12.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/pkcs5.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/platform.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/platform_time.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/platform_util.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/poly1305.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/ripemd160.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/rsa.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/rsa_internal.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/sha1.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/sha256.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/sha512.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/ssl.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/ssl_cache.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/ssl_ciphersuites.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/ssl_cookie.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/ssl_internal.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/ssl_ticket.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/threading.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/timing.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/version.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/x509.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/x509_crl.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/x509_crt.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/x509_csr.h create mode 100644 ctrtool/deps/libmbedtls/include/mbedtls/xtea.h create mode 100644 ctrtool/deps/libmbedtls/makefile create mode 100644 ctrtool/deps/libmbedtls/src/aes.c create mode 100644 ctrtool/deps/libmbedtls/src/aesni.c create mode 100644 ctrtool/deps/libmbedtls/src/arc4.c create mode 100644 ctrtool/deps/libmbedtls/src/aria.c create mode 100644 ctrtool/deps/libmbedtls/src/asn1parse.c create mode 100644 ctrtool/deps/libmbedtls/src/asn1write.c create mode 100644 ctrtool/deps/libmbedtls/src/base64.c create mode 100644 ctrtool/deps/libmbedtls/src/bignum.c create mode 100644 ctrtool/deps/libmbedtls/src/blowfish.c create mode 100644 ctrtool/deps/libmbedtls/src/camellia.c create mode 100644 ctrtool/deps/libmbedtls/src/ccm.c create mode 100644 ctrtool/deps/libmbedtls/src/certs.c create mode 100644 ctrtool/deps/libmbedtls/src/chacha20.c create mode 100644 ctrtool/deps/libmbedtls/src/chachapoly.c create mode 100644 ctrtool/deps/libmbedtls/src/cipher.c create mode 100644 ctrtool/deps/libmbedtls/src/cipher_wrap.c create mode 100644 ctrtool/deps/libmbedtls/src/cmac.c create mode 100644 ctrtool/deps/libmbedtls/src/ctr_drbg.c create mode 100644 ctrtool/deps/libmbedtls/src/debug.c create mode 100644 ctrtool/deps/libmbedtls/src/des.c create mode 100644 ctrtool/deps/libmbedtls/src/dhm.c create mode 100644 ctrtool/deps/libmbedtls/src/ecdh.c create mode 100644 ctrtool/deps/libmbedtls/src/ecdsa.c create mode 100644 ctrtool/deps/libmbedtls/src/ecjpake.c create mode 100644 ctrtool/deps/libmbedtls/src/ecp.c create mode 100644 ctrtool/deps/libmbedtls/src/ecp_curves.c create mode 100644 ctrtool/deps/libmbedtls/src/entropy.c create mode 100644 ctrtool/deps/libmbedtls/src/entropy_poll.c create mode 100644 ctrtool/deps/libmbedtls/src/error.c create mode 100644 ctrtool/deps/libmbedtls/src/gcm.c create mode 100644 ctrtool/deps/libmbedtls/src/havege.c create mode 100644 ctrtool/deps/libmbedtls/src/hkdf.c create mode 100644 ctrtool/deps/libmbedtls/src/hmac_drbg.c create mode 100644 ctrtool/deps/libmbedtls/src/md.c create mode 100644 ctrtool/deps/libmbedtls/src/md2.c create mode 100644 ctrtool/deps/libmbedtls/src/md4.c create mode 100644 ctrtool/deps/libmbedtls/src/md5.c create mode 100644 ctrtool/deps/libmbedtls/src/md_wrap.c create mode 100644 ctrtool/deps/libmbedtls/src/memory_buffer_alloc.c create mode 100644 ctrtool/deps/libmbedtls/src/net_sockets.c create mode 100644 ctrtool/deps/libmbedtls/src/nist_kw.c create mode 100644 ctrtool/deps/libmbedtls/src/oid.c create mode 100644 ctrtool/deps/libmbedtls/src/padlock.c create mode 100644 ctrtool/deps/libmbedtls/src/pem.c create mode 100644 ctrtool/deps/libmbedtls/src/pk.c create mode 100644 ctrtool/deps/libmbedtls/src/pk_wrap.c create mode 100644 ctrtool/deps/libmbedtls/src/pkcs11.c create mode 100644 ctrtool/deps/libmbedtls/src/pkcs12.c create mode 100644 ctrtool/deps/libmbedtls/src/pkcs5.c create mode 100644 ctrtool/deps/libmbedtls/src/pkparse.c create mode 100644 ctrtool/deps/libmbedtls/src/pkwrite.c create mode 100644 ctrtool/deps/libmbedtls/src/platform.c create mode 100644 ctrtool/deps/libmbedtls/src/platform_util.c create mode 100644 ctrtool/deps/libmbedtls/src/poly1305.c create mode 100644 ctrtool/deps/libmbedtls/src/ripemd160.c create mode 100644 ctrtool/deps/libmbedtls/src/rsa.c create mode 100644 ctrtool/deps/libmbedtls/src/rsa_internal.c create mode 100644 ctrtool/deps/libmbedtls/src/sha1.c create mode 100644 ctrtool/deps/libmbedtls/src/sha256.c create mode 100644 ctrtool/deps/libmbedtls/src/sha512.c create mode 100644 ctrtool/deps/libmbedtls/src/ssl_cache.c create mode 100644 ctrtool/deps/libmbedtls/src/ssl_ciphersuites.c create mode 100644 ctrtool/deps/libmbedtls/src/ssl_cli.c create mode 100644 ctrtool/deps/libmbedtls/src/ssl_cookie.c create mode 100644 ctrtool/deps/libmbedtls/src/ssl_srv.c create mode 100644 ctrtool/deps/libmbedtls/src/ssl_ticket.c create mode 100644 ctrtool/deps/libmbedtls/src/ssl_tls.c create mode 100644 ctrtool/deps/libmbedtls/src/threading.c create mode 100644 ctrtool/deps/libmbedtls/src/timing.c create mode 100644 ctrtool/deps/libmbedtls/src/version.c create mode 100644 ctrtool/deps/libmbedtls/src/version_features.c create mode 100644 ctrtool/deps/libmbedtls/src/x509.c create mode 100644 ctrtool/deps/libmbedtls/src/x509_create.c create mode 100644 ctrtool/deps/libmbedtls/src/x509_crl.c create mode 100644 ctrtool/deps/libmbedtls/src/x509_crt.c create mode 100644 ctrtool/deps/libmbedtls/src/x509_csr.c create mode 100644 ctrtool/deps/libmbedtls/src/x509write_crt.c create mode 100644 ctrtool/deps/libmbedtls/src/x509write_csr.c create mode 100644 ctrtool/deps/libmbedtls/src/xtea.c create mode 100644 ctrtool/deps/libnintendo-n3ds/LICENSE create mode 100644 ctrtool/deps/libnintendo-n3ds/README.md create mode 100644 ctrtool/deps/libnintendo-n3ds/build/visualstudio/libnintendo-n3ds.sln create mode 100644 ctrtool/deps/libnintendo-n3ds/build/visualstudio/libnintendo-n3ds/libnintendo-n3ds.vcxproj create mode 100644 ctrtool/deps/libnintendo-n3ds/build/visualstudio/libnintendo-n3ds/libnintendo-n3ds.vcxproj.filters create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/CciFsSnapshotGenerator.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/CiaFsSnapshotGenerator.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/CtrKeyGenerator.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/ExeFsSnapshotGenerator.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/IvfcStream.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/RomFsSnapshotGenerator.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/bcwav.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/cci.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/cia.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/cro.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/crr.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/es.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/es/Certificate.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/es/ISigner.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/es/RsaSigner.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/es/Signature.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/es/Ticket.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/es/TitleMetaData.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/exefs.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/exheader.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/firm.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/ivfc.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/ncch.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/romfs.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/smdh.h create mode 100644 ctrtool/deps/libnintendo-n3ds/include/ntd/n3ds/systemupdater.h create mode 100644 ctrtool/deps/libnintendo-n3ds/makefile create mode 100644 ctrtool/deps/libnintendo-n3ds/src/CciFsSnapshotGenerator.cpp create mode 100644 ctrtool/deps/libnintendo-n3ds/src/CiaFsSnapshotGenerator.cpp create mode 100644 ctrtool/deps/libnintendo-n3ds/src/CtrKeyGenerator.cpp create mode 100644 ctrtool/deps/libnintendo-n3ds/src/ExeFsSnapshotGenerator.cpp create mode 100644 ctrtool/deps/libnintendo-n3ds/src/IvfcStream.cpp create mode 100644 ctrtool/deps/libnintendo-n3ds/src/RomFsSnapshotGenerator.cpp create mode 100644 ctrtool/deps/libnintendo-n3ds/src/es/Certificate.cpp create mode 100644 ctrtool/deps/libnintendo-n3ds/src/es/RsaSigner.cpp create mode 100644 ctrtool/deps/libnintendo-n3ds/src/es/Signature.cpp create mode 100644 ctrtool/deps/libnintendo-n3ds/src/es/Ticket.cpp create mode 100644 ctrtool/deps/libnintendo-n3ds/src/es/TitleMetaData.cpp create mode 100644 ctrtool/deps/libtoolchain/BUILDING.md create mode 100644 ctrtool/deps/libtoolchain/Doxyfile create mode 100644 ctrtool/deps/libtoolchain/DoxygenMainpage.md create mode 100644 ctrtool/deps/libtoolchain/LICENSE create mode 100644 ctrtool/deps/libtoolchain/README.md create mode 100644 ctrtool/deps/libtoolchain/build/visualstudio/libtoolchain-test/libtoolchain-test.vcxproj create mode 100644 ctrtool/deps/libtoolchain/build/visualstudio/libtoolchain-test/libtoolchain-test.vcxproj.filters create mode 100644 ctrtool/deps/libtoolchain/build/visualstudio/libtoolchain.sln create mode 100644 ctrtool/deps/libtoolchain/build/visualstudio/libtoolchain/libtoolchain.vcxproj create mode 100644 ctrtool/deps/libtoolchain/build/visualstudio/libtoolchain/libtoolchain.vcxproj.filters create mode 100644 ctrtool/deps/libtoolchain/include/tc.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/AccessViolationException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/ArgumentException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/ArgumentNullException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/ArgumentOutOfRangeException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/ArithmeticException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/ByteData.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/Exception.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/InvalidOperationException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/NotImplementedException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/NotSupportedException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/ObjectDisposedException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/Optional.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/OutOfMemoryException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/OverflowException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/PlatformErrorHandlingUtil.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/ResourceStatus.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/SecurityException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/UnauthorisedAccessException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/bn.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/bn/binary_utils.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/bn/bitarray.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/bn/endian_types.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/bn/pad.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/bn/string.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/cli.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/cli/FormatUtil.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/cli/OptionParser.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Aes128CbcEncryptedStream.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Aes128CbcEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Aes128CtrEncryptedStream.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Aes128CtrEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Aes128EcbEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Aes128XtsEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Aes192CbcEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Aes192CtrEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Aes192EcbEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Aes256CbcEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Aes256CtrEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Aes256EcbEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Aes256XtsEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/AesEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/CbcEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/CryptoException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/CtrEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/EcbEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/HmacGenerator.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/HmacMd5Generator.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/HmacSha1Generator.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/HmacSha256Generator.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/HmacSha512Generator.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Md5Generator.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Pbkdf1KeyDeriver.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Pbkdf1Md5KeyDeriver.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Pbkdf1Sha1KeyDeriver.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Pbkdf2KeyDeriver.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Pbkdf2Sha1KeyDeriver.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Pbkdf2Sha256KeyDeriver.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Pbkdf2Sha512KeyDeriver.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/PseudoRandomByteGenerator.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/RsaKey.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/RsaKeyGenerator.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/RsaOaepEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/RsaOaepSha256Encryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/RsaOaepSha512Encryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/RsaPkcs1Md5Signer.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/RsaPkcs1Sha1Signer.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/RsaPkcs1Sha256Signer.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/RsaPkcs1Sha512Signer.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/RsaPkcs1Signer.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/RsaPssSha256Signer.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/RsaPssSha512Signer.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/RsaPssSigner.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Sha1Generator.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Sha256Generator.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/Sha512Generator.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/XtsEncryptor.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/AesImpl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/BlockUtilImpl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/CbcModeImpl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/CtrModeImpl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/EcbModeImpl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/HmacImpl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/Md5Impl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/Pbkdf1Impl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/Pbkdf2Impl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/PrbgImpl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/RsaImpl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/RsaKeyGeneratorImpl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/RsaOaepPadding.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/RsaPkcs1Padding.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/RsaPssPadding.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/Sha1Impl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/Sha2Impl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/crypto/detail/XtsModeImpl.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/BasicPathResolver.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/ConcatenatedStream.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/DirectoryNotEmptyException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/DirectoryNotFoundException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/FileAccess.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/FileExistsException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/FileMode.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/FileNotFoundException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/FileStream.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/IFileSystem.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/IOException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/IOUtil.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/IPathResolver.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/IPortablePathResolver.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/IReadableSink.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/ISink.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/ISource.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/IStream.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/LocalFileSystem.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/MemorySource.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/MemoryStream.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/OverlayedSource.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/PaddingSource.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/Path.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/PathTooLongException.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/PathUtil.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/SeekOrigin.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/StreamSink.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/StreamSource.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/StreamUtil.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/SubFileSystem.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/SubSink.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/SubSource.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/SubStream.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/io/VirtualFileSystem.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/os.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/os/Environment.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/os/UnicodeMain.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/string.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/string/TranscodeUtil.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/string/detail/utf16.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/string/detail/utf8.h create mode 100644 ctrtool/deps/libtoolchain/include/tc/types.h create mode 100644 ctrtool/deps/libtoolchain/makefile create mode 100644 ctrtool/deps/libtoolchain/src/ByteData.cpp create mode 100644 ctrtool/deps/libtoolchain/src/Exception.cpp create mode 100644 ctrtool/deps/libtoolchain/src/PlatformErrorHandlingUtil.cpp create mode 100644 ctrtool/deps/libtoolchain/src/cli/FormatUtil.cpp create mode 100644 ctrtool/deps/libtoolchain/src/cli/OptionParser.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Aes128CbcEncryptedStream.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Aes128CbcEncryptor.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Aes128CtrEncryptedStream.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Aes128CtrEncryptor.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Aes128EcbEncryptor.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Aes128XtsEncryptor.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Aes192CbcEncryptor.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Aes192CtrEncryptor.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Aes192EcbEncryptor.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Aes256CbcEncryptor.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Aes256CtrEncryptor.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Aes256EcbEncryptor.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Aes256XtsEncryptor.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/HmacMd5Generator.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/HmacSha1Generator.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/HmacSha256Generator.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/HmacSha512Generator.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Md5Generator.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Pbkdf1Md5KeyDeriver.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Pbkdf1Sha1KeyDeriver.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Pbkdf2Sha1KeyDeriver.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Pbkdf2Sha256KeyDeriver.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Pbkdf2Sha512KeyDeriver.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/PseudoRandomByteGenerator.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/RsaKey.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/RsaKeyGenerator.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/RsaOaepSha256Encryptor.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/RsaOaepSha512Encryptor.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/RsaPkcs1Md5Signer.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/RsaPkcs1Sha1Signer.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/RsaPkcs1Sha256Signer.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/RsaPkcs1Sha512Signer.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/RsaPssSha256Signer.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/RsaPssSha512Signer.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Sha1Generator.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Sha256Generator.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/Sha512Generator.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/detail/AesImpl.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/detail/Md5Impl.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/detail/PrbgImpl.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/detail/RsaImpl.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/detail/RsaKeyGeneratorImpl.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/detail/Sha1Impl.cpp create mode 100644 ctrtool/deps/libtoolchain/src/crypto/detail/Sha2Impl.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/BasicPathResolver.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/ConcatenatedStream.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/FileStream.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/IOUtil.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/LocalFileSystem.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/MemorySource.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/MemoryStream.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/OverlayedSource.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/PaddingSource.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/Path.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/PathUtil.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/StreamSink.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/StreamSource.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/StreamUtil.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/SubFileSystem.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/SubSink.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/SubSource.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/SubStream.cpp create mode 100644 ctrtool/deps/libtoolchain/src/io/VirtualFileSystem.cpp create mode 100644 ctrtool/deps/libtoolchain/src/os/Environment.cpp create mode 100644 ctrtool/deps/libtoolchain/src/string/TranscodeUtil.cpp create mode 100644 ctrtool/deps/libtoolchain/src/types.cpp create mode 100644 ctrtool/deps/libtoolchain/test/ByteData_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/ByteData_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/FileSystemTestUtil.cpp create mode 100644 ctrtool/deps/libtoolchain/test/FileSystemTestUtil.h create mode 100644 ctrtool/deps/libtoolchain/test/ITestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/Optional_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/Optional_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/PbkdfUtil.cpp create mode 100644 ctrtool/deps/libtoolchain/test/PbkdfUtil.h create mode 100644 ctrtool/deps/libtoolchain/test/RsaOaepUtil.cpp create mode 100644 ctrtool/deps/libtoolchain/test/RsaOaepUtil.h create mode 100644 ctrtool/deps/libtoolchain/test/RsaPkcs1Util.cpp create mode 100644 ctrtool/deps/libtoolchain/test/RsaPkcs1Util.h create mode 100644 ctrtool/deps/libtoolchain/test/RsaPssUtil.cpp create mode 100644 ctrtool/deps/libtoolchain/test/RsaPssUtil.h create mode 100644 ctrtool/deps/libtoolchain/test/SinkTestUtil.cpp create mode 100644 ctrtool/deps/libtoolchain/test/SinkTestUtil.h create mode 100644 ctrtool/deps/libtoolchain/test/SourceTestUtil.cpp create mode 100644 ctrtool/deps/libtoolchain/test/SourceTestUtil.h create mode 100644 ctrtool/deps/libtoolchain/test/StreamTestUtil.cpp create mode 100644 ctrtool/deps/libtoolchain/test/StreamTestUtil.h create mode 100644 ctrtool/deps/libtoolchain/test/bn_binaryutils_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/bn_binaryutils_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/bn_bitarrayByteBEBitBE_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/bn_bitarrayByteBEBitBE_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/bn_bitarrayByteBEBitLE_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/bn_bitarrayByteBEBitLE_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/bn_bitarrayByteLEBitBE_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/bn_bitarrayByteLEBitBE_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/bn_bitarrayByteLEBitLE_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/bn_bitarrayByteLEBitLE_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/bn_endian_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/bn_endian_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/bn_pad_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/bn_pad_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/bn_string_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/bn_string_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/cli_FormatUtil_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/cli_FormatUtil_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/cli_OptionParser_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/cli_OptionParser_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes128CbcEncryptedStream_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes128CbcEncryptedStream_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes128CbcEncryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes128CbcEncryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes128CtrEncryptedStream_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes128CtrEncryptedStream_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes128CtrEncryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes128CtrEncryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes128EcbEncryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes128EcbEncryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes128Encryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes128Encryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes128XtsEncryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes128XtsEncryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes192CbcEncryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes192CbcEncryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes192CtrEncryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes192CtrEncryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes192EcbEncryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes192EcbEncryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes192Encryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes192Encryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes256CbcEncryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes256CbcEncryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes256CtrEncryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes256CtrEncryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes256EcbEncryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes256EcbEncryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes256Encryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes256Encryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes256XtsEncryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Aes256XtsEncryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_HmacMd5Generator_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_HmacMd5Generator_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_HmacSha1Generator_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_HmacSha1Generator_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_HmacSha256Generator_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_HmacSha256Generator_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_HmacSha512Generator_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_HmacSha512Generator_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Md5Generator_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Md5Generator_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Pbkdf1Md5KeyDeriver_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Pbkdf1Md5KeyDeriver_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Pbkdf1Sha1KeyDeriver_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Pbkdf1Sha1KeyDeriver_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Pbkdf2Sha1KeyDeriver_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Pbkdf2Sha1KeyDeriver_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Pbkdf2Sha256KeyDeriver_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Pbkdf2Sha256KeyDeriver_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Pbkdf2Sha512KeyDeriver_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Pbkdf2Sha512KeyDeriver_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_PseudoRandomByteGenerator_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_PseudoRandomByteGenerator_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa1024OaepSha256Encryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa1024OaepSha256Encryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa1024Pkcs1Md5Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa1024Pkcs1Md5Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa1024Pkcs1Sha1Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa1024Pkcs1Sha1Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa1024Pkcs1Sha256Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa1024Pkcs1Sha256Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa1024Pkcs1Sha512Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa1024Pkcs1Sha512Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa1024PssSha256Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa1024PssSha256Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa1024PssSha512Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa1024PssSha512Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048OaepSha256Encryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048OaepSha256Encryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048OaepSha512Encryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048OaepSha512Encryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048Pkcs1Md5Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048Pkcs1Md5Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048Pkcs1Sha1Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048Pkcs1Sha1Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048Pkcs1Sha256Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048Pkcs1Sha256Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048Pkcs1Sha512Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048Pkcs1Sha512Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048PssSha256Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048PssSha256Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048PssSha512Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa2048PssSha512Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096OaepSha256Encryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096OaepSha256Encryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096OaepSha512Encryptor_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096OaepSha512Encryptor_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096Pkcs1Md5Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096Pkcs1Md5Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096Pkcs1Sha1Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096Pkcs1Sha1Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096Pkcs1Sha256Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096Pkcs1Sha256Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096Pkcs1Sha512Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096Pkcs1Sha512Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096PssSha256Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096PssSha256Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096PssSha512Signer_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Rsa4096PssSha512Signer_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Sha1Generator_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Sha1Generator_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Sha256Generator_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Sha256Generator_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Sha512Generator_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/crypto_Sha512Generator_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_BasicPathResolver_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_BasicPathResolver_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_ConcatenatedStream_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_ConcatenatedStream_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_FileStream_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_FileStream_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_LocalFileSystem_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_LocalFileSystem_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_MemorySource_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_MemorySource_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_MemoryStream_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_MemoryStream_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_OverlayedSource_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_OverlayedSource_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_PaddingSource_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_PaddingSource_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_Path_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_Path_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_StreamSink_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_StreamSink_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_StreamSource_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_StreamSource_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_SubFileSystem_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_SubFileSystem_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_SubSink_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_SubSink_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_SubSource_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_SubSource_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_SubStream_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_SubStream_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/io_VirtualFileSystem_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/io_VirtualFileSystem_TestClass.h create mode 100644 ctrtool/deps/libtoolchain/test/main.cpp create mode 100644 ctrtool/deps/libtoolchain/test/string_TranscodeUtil_TestClass.cpp create mode 100644 ctrtool/deps/libtoolchain/test/string_TranscodeUtil_TestClass.h create mode 100644 ctrtool/makefile create mode 100644 ctrtool/src/CciProcess.cpp create mode 100644 ctrtool/src/CciProcess.h create mode 100644 ctrtool/src/CiaProcess.cpp create mode 100644 ctrtool/src/CiaProcess.h create mode 100644 ctrtool/src/CrrProcess.cpp create mode 100644 ctrtool/src/CrrProcess.h create mode 100644 ctrtool/src/ExHeaderProcess.cpp create mode 100644 ctrtool/src/ExHeaderProcess.h create mode 100644 ctrtool/src/ExeFsProcess.cpp create mode 100644 ctrtool/src/ExeFsProcess.h create mode 100644 ctrtool/src/FirmProcess.cpp create mode 100644 ctrtool/src/FirmProcess.h create mode 100644 ctrtool/src/IvfcProcess.cpp create mode 100644 ctrtool/src/IvfcProcess.h create mode 100644 ctrtool/src/KeyBag.cpp create mode 100644 ctrtool/src/KeyBag.h create mode 100644 ctrtool/src/LzssProcess.cpp create mode 100644 ctrtool/src/LzssProcess.h create mode 100644 ctrtool/src/NcchProcess.cpp create mode 100644 ctrtool/src/NcchProcess.h create mode 100644 ctrtool/src/RomFsProcess.cpp create mode 100644 ctrtool/src/RomFsProcess.h create mode 100644 ctrtool/src/Settings.cpp create mode 100644 ctrtool/src/Settings.h create mode 100644 ctrtool/src/cwav.h create mode 100644 ctrtool/src/lzss.c create mode 100644 ctrtool/src/lzss.h create mode 100644 ctrtool/src/main.cpp create mode 100644 ctrtool/src/types.h create mode 100644 ctrtool/src/version.h diff --git a/ctrtool/build/visualstudio/CTRTool.sln b/ctrtool/build/visualstudio/CTRTool.sln new file mode 100644 index 0000000..0612a16 --- /dev/null +++ b/ctrtool/build/visualstudio/CTRTool.sln @@ -0,0 +1,90 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31229.75 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CTRTool", "CTRTool\CTRTool.vcxproj", "{CADDA22C-5FED-4DAB-A87E-AFBD279DB367}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfmt", "..\..\deps\libfmt\build\visualstudio\libfmt\libfmt.vcxproj", "{F4B0540E-0AAE-4006-944B-356944EF61FA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmbedtls", "..\..\deps\libmbedtls\build\visualstudio\libmbedtls\libmbedtls.vcxproj", "{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtoolchain", "..\..\deps\libtoolchain\build\visualstudio\libtoolchain\libtoolchain.vcxproj", "{E194E4B8-1482-40A2-901B-75D4387822E9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbroadon-es", "..\..\deps\libbroadon-es\build\visualstudio\libbroadon-es\libbroadon-es.vcxproj", "{8A35D7DC-293A-4669-9C1E-4F45ABFE8838}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-n3ds", "..\..\deps\libnintendo-n3ds\build\visualstudio\libnintendo-n3ds\libnintendo-n3ds.vcxproj", "{7789491C-5403-4613-B06B-DB0C58E19A01}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deps", "deps", "{1AF77D36-45A2-412E-A540-F559B78A6471}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Debug|x64.ActiveCfg = Debug|x64 + {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Debug|x64.Build.0 = Debug|x64 + {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Debug|x86.ActiveCfg = Debug|Win32 + {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Debug|x86.Build.0 = Debug|Win32 + {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Release|x64.ActiveCfg = Release|x64 + {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Release|x64.Build.0 = Release|x64 + {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Release|x86.ActiveCfg = Release|Win32 + {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Release|x86.Build.0 = Release|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x64.ActiveCfg = Debug|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x64.Build.0 = Debug|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x86.ActiveCfg = Debug|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x86.Build.0 = Debug|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.ActiveCfg = Release|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.Build.0 = Release|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.ActiveCfg = Release|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.Build.0 = Release|Win32 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x64.ActiveCfg = Debug|x64 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x64.Build.0 = Debug|x64 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x86.ActiveCfg = Debug|Win32 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x86.Build.0 = Debug|Win32 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x64.ActiveCfg = Release|x64 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x64.Build.0 = Release|x64 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x86.ActiveCfg = Release|Win32 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x86.Build.0 = Release|Win32 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x64.ActiveCfg = Debug|x64 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x64.Build.0 = Debug|x64 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x86.ActiveCfg = Debug|Win32 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x86.Build.0 = Debug|Win32 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x64.ActiveCfg = Release|x64 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x64.Build.0 = Release|x64 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x86.ActiveCfg = Release|Win32 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x86.Build.0 = Release|Win32 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x64.ActiveCfg = Debug|x64 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x64.Build.0 = Debug|x64 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x86.ActiveCfg = Debug|Win32 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x86.Build.0 = Debug|Win32 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x64.ActiveCfg = Release|x64 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x64.Build.0 = Release|x64 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x86.ActiveCfg = Release|Win32 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x86.Build.0 = Release|Win32 + {7789491C-5403-4613-B06B-DB0C58E19A01}.Debug|x64.ActiveCfg = Debug|x64 + {7789491C-5403-4613-B06B-DB0C58E19A01}.Debug|x64.Build.0 = Debug|x64 + {7789491C-5403-4613-B06B-DB0C58E19A01}.Debug|x86.ActiveCfg = Debug|Win32 + {7789491C-5403-4613-B06B-DB0C58E19A01}.Debug|x86.Build.0 = Debug|Win32 + {7789491C-5403-4613-B06B-DB0C58E19A01}.Release|x64.ActiveCfg = Release|x64 + {7789491C-5403-4613-B06B-DB0C58E19A01}.Release|x64.Build.0 = Release|x64 + {7789491C-5403-4613-B06B-DB0C58E19A01}.Release|x86.ActiveCfg = Release|Win32 + {7789491C-5403-4613-B06B-DB0C58E19A01}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {F4B0540E-0AAE-4006-944B-356944EF61FA} = {1AF77D36-45A2-412E-A540-F559B78A6471} + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C} = {1AF77D36-45A2-412E-A540-F559B78A6471} + {E194E4B8-1482-40A2-901B-75D4387822E9} = {1AF77D36-45A2-412E-A540-F559B78A6471} + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838} = {1AF77D36-45A2-412E-A540-F559B78A6471} + {7789491C-5403-4613-B06B-DB0C58E19A01} = {1AF77D36-45A2-412E-A540-F559B78A6471} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {10D725B5-08F6-43F3-A28F-7B034F1ADEFC} + EndGlobalSection +EndGlobal diff --git a/ctrtool/build/visualstudio/CTRTool/CTRTool.vcxproj b/ctrtool/build/visualstudio/CTRTool/CTRTool.vcxproj new file mode 100644 index 0000000..69ff2fe --- /dev/null +++ b/ctrtool/build/visualstudio/CTRTool/CTRTool.vcxproj @@ -0,0 +1,192 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {cadda22c-5fed-4dab-a87e-afbd279db367} + CTRTool + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libbroadon-es\include;$(SolutionDir)..\..\deps\libnintendo-n3ds\include;$(ProjectDir)..\..\..\include + MultiThreadedDebug + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libbroadon-es\include;$(SolutionDir)..\..\deps\libnintendo-n3ds\include;$(ProjectDir)..\..\..\include + MultiThreaded + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libbroadon-es\include;$(SolutionDir)..\..\deps\libnintendo-n3ds\include;$(ProjectDir)..\..\..\include + MultiThreadedDebug + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libbroadon-es\include;$(SolutionDir)..\..\deps\libnintendo-n3ds\include;$(ProjectDir)..\..\..\include + MultiThreaded + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {f4b0540e-0aae-4006-944b-356944ef61fa} + + + {7a7c66f3-2b5b-4e23-85d8-2a74fedad92c} + + + {8a35d7dc-293a-4669-9c1e-4f45abfe8838} + + + {7789491c-5403-4613-b06b-db0c58e19a01} + + + {e194e4b8-1482-40a2-901b-75d4387822e9} + + + + + + \ No newline at end of file diff --git a/ctrtool/build/visualstudio/CTRTool/CTRTool.vcxproj.filters b/ctrtool/build/visualstudio/CTRTool/CTRTool.vcxproj.filters new file mode 100644 index 0000000..947c47c --- /dev/null +++ b/ctrtool/build/visualstudio/CTRTool/CTRTool.vcxproj.filters @@ -0,0 +1,111 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/ctrtool/deps/libbroadon-es/LICENSE b/ctrtool/deps/libbroadon-es/LICENSE new file mode 100644 index 0000000..38e64e9 --- /dev/null +++ b/ctrtool/deps/libbroadon-es/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Jack + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ctrtool/deps/libbroadon-es/README.md b/ctrtool/deps/libbroadon-es/README.md new file mode 100644 index 0000000..8066897 --- /dev/null +++ b/ctrtool/deps/libbroadon-es/README.md @@ -0,0 +1,2 @@ +# libbroadon-es +C++ Library for processing Nintendo's ES DRM formats. diff --git a/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es.sln b/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es.sln new file mode 100644 index 0000000..d1cc8fc --- /dev/null +++ b/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es.sln @@ -0,0 +1,62 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31229.75 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbroadon-es", "libbroadon-es\libbroadon-es.vcxproj", "{8A35D7DC-293A-4669-9C1E-4F45ABFE8838}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfmt", "..\..\deps\libfmt\build\visualstudio\libfmt\libfmt.vcxproj", "{F4B0540E-0AAE-4006-944B-356944EF61FA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmbedtls", "..\..\deps\libmbedtls\build\visualstudio\libmbedtls\libmbedtls.vcxproj", "{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtoolchain", "..\..\deps\libtoolchain\build\visualstudio\libtoolchain\libtoolchain.vcxproj", "{E194E4B8-1482-40A2-901B-75D4387822E9}" +EndProject + +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x64.ActiveCfg = Debug|x64 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x64.Build.0 = Debug|x64 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x86.ActiveCfg = Debug|Win32 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x86.Build.0 = Debug|Win32 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x64.ActiveCfg = Release|x64 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x64.Build.0 = Release|x64 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x86.ActiveCfg = Release|Win32 + {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x86.Build.0 = Release|Win32 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x64.ActiveCfg = Debug|x64 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x64.Build.0 = Debug|x64 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x86.ActiveCfg = Debug|Win32 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x86.Build.0 = Debug|Win32 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x64.ActiveCfg = Release|x64 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x64.Build.0 = Release|x64 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x86.ActiveCfg = Release|Win32 + {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x86.Build.0 = Release|Win32 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x64.ActiveCfg = Debug|x64 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x64.Build.0 = Debug|x64 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x86.ActiveCfg = Debug|Win32 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x86.Build.0 = Debug|Win32 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x64.ActiveCfg = Release|x64 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x64.Build.0 = Release|x64 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x86.ActiveCfg = Release|Win32 + {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x86.Build.0 = Release|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x64.ActiveCfg = Debug|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x64.Build.0 = Debug|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x86.ActiveCfg = Debug|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x86.Build.0 = Debug|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.ActiveCfg = Release|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.Build.0 = Release|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.ActiveCfg = Release|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {76A6C1B6-F1C0-467F-B3A1-D7BDCBAA4FC0} + EndGlobalSection +EndGlobal diff --git a/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es/libbroadon-es.vcxproj b/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es/libbroadon-es.vcxproj new file mode 100644 index 0000000..a83e05a --- /dev/null +++ b/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es/libbroadon-es.vcxproj @@ -0,0 +1,151 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {8a35d7dc-293a-4669-9c1e-4f45abfe8838} + libnintendoesdrm + 10.0 + + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + true + $(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(ProjectDir)..\..\..\include + MultiThreadedDebug + + + + + Level3 + Disabled + true + true + $(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(ProjectDir)..\..\..\include + MultiThreadedDebug + + + + + Level3 + MaxSpeed + true + true + true + true + $(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(ProjectDir)..\..\..\include + MultiThreaded + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + true + $(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(ProjectDir)..\..\..\include + MultiThreaded + + + true + true + + + + + + + + + + + + + + + + {7a7c66f3-2b5b-4e23-85d8-2a74fedad92c} + + + {e194e4b8-1482-40a2-901b-75d4387822e9} + + + {f4b0540e-0aae-4006-944b-356944ef61fa} + + + + + + \ No newline at end of file diff --git a/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es/libbroadon-es.vcxproj.filters b/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es/libbroadon-es.vcxproj.filters new file mode 100644 index 0000000..ec5de4d --- /dev/null +++ b/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es/libbroadon-es.vcxproj.filters @@ -0,0 +1,48 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {ba10896d-aa46-41de-9331-2c89a9ddf64a} + + + {c67a3de1-eb64-4733-a6e6-cdcb7be43b60} + + + + + Source Files + + + + + Header Files\brd\es + + + Header Files\brd\es + + + Header Files\brd\es + + + Header Files\brd\es + + + Header Files\brd\es + + + Header Files\brd + + + \ No newline at end of file diff --git a/ctrtool/deps/libbroadon-es/include/brd/es.h b/ctrtool/deps/libbroadon-es/include/brd/es.h new file mode 100644 index 0000000..1ccf8f8 --- /dev/null +++ b/ctrtool/deps/libbroadon-es/include/brd/es.h @@ -0,0 +1,7 @@ +#pragma once + +// definitions +#include +#include +#include +#include \ No newline at end of file diff --git a/ctrtool/deps/libbroadon-es/include/brd/es/es_cert.h b/ctrtool/deps/libbroadon-es/include/brd/es/es_cert.h new file mode 100644 index 0000000..f5a7a05 --- /dev/null +++ b/ctrtool/deps/libbroadon-es/include/brd/es/es_cert.h @@ -0,0 +1,101 @@ +#pragma once +#include + +namespace brd { namespace es { + /** + @enum ESCertPubKeyType + @brief ES Certificate public key type definition + */ +enum class ESCertPubKeyType : uint32_t +{ + RSA4096 = 0, /* RSA 4096 bit key */ + RSA2048 = 1, /* RSA 2048 bit key */ + ECC = 2, /* ECC pub key 512 bits */ +}; + +static const size_t ES_CERT_NAME_SIZE = 64; +using ESCertName = tc::bn::string; +using ESServerId = ESCertName; +using ESDeviceId = ESCertName; + +template +using ESPubKeyPad = std::array; + +/* pack to 4 byte boundaries */ +#pragma pack(push,4) + +struct ESCertHeader +{ + tc::bn::be32 pubKeyType; // ESCertPubKeyType + union { + ESServerId serverId; + ESDeviceId deviceId; + } name; + tc::bn::be32 date; // unix time-stamp +}; +static_assert(sizeof(ESCertHeader) == 72, "ESCertHeader size"); + +struct ESCertRsa2048PublicKey +{ + Rsa2048PublicKey pubKey; + ESPubKeyPad<52> pad; +}; +static_assert(sizeof(ESCertRsa2048PublicKey) == 312, "ESCertRsa2048PublicKey size"); + +struct ESCertRsa4096PublicKey +{ + Rsa4096PublicKey pubKey; + ESPubKeyPad<52> pad; +}; +static_assert(sizeof(ESCertRsa4096PublicKey) == 568, "ESCertRsa4096PublicKey size"); + +struct ESCertEcc233PublicKey +{ + Ecc233PublicKey pubKey; + ESPubKeyPad<60> pad; +}; +static_assert(sizeof(ESCertEcc233PublicKey) == 120, "ESCertEcc233PublicKey size"); + +struct ESRootCert +{ + ESSigRsa4096 sig; + ESCertHeader head; + ESCertRsa4096PublicKey body; +}; +static_assert(sizeof(ESRootCert) == 1280, "ESRootCert size"); + +struct ESCACert +{ + ESSigRsa4096 sig; + ESCertHeader head; + ESCertRsa2048PublicKey body; +}; +static_assert(sizeof(ESCACert) == 1024, "ESCACert size"); + +struct ESCASignedCert +{ + ESSigRsa2048 sig; + ESCertHeader head; + ESCertRsa2048PublicKey body; +}; +static_assert(sizeof(ESCASignedCert) == 768, "ESCASignedCert size"); + +struct ESDeviceCert +{ + ESSigRsa2048 sig; + ESCertHeader head; + ESCertEcc233PublicKey body; +}; +static_assert(sizeof(ESDeviceCert) == 576, "ESDeviceCert size"); + +struct ESDeviceSignedCert +{ + ESSigEcc233 sig; + ESCertHeader head; + ESCertEcc233PublicKey body; +}; +static_assert(sizeof(ESDeviceSignedCert) == 384, "ESDeviceSignedCert size"); + +#pragma pack(pop) + +}} // namespace brd::es diff --git a/ctrtool/deps/libbroadon-es/include/brd/es/es_sign.h b/ctrtool/deps/libbroadon-es/include/brd/es/es_sign.h new file mode 100644 index 0000000..4f313ea --- /dev/null +++ b/ctrtool/deps/libbroadon-es/include/brd/es/es_sign.h @@ -0,0 +1,73 @@ +#pragma once +#include + +namespace brd { namespace es { + /** + @enum ESSigType + @brief ES Signature type definition + */ +enum class ESSigType : uint32_t +{ + RSA4096_SHA1 = 0x00010000, /* RSA 4096 bit signature */ + RSA2048_SHA1 = 0x00010001, /* RSA 2048 bit signature */ + ECC_SHA1 = 0x00010002, /* ECC signature 512 bits */ + RSA4096_SHA256 = 0x00010003, /* RSA 4096 bit sig using SHA-256 */ + RSA2048_SHA256 = 0x00010004, /* RSA 2048 bit sig using SHA-256 */ // note that Switch Ticket has this word swapped + ECC_SHA256 = 0x00010005, /* ECC sig 512 bits using SHA-256 */ + HMAC_SHA1 = 0x00010006, /* HMAC-SHA1 160 bit signature */ +}; + +static const size_t ES_ISSUER_SIZE = 64; + + /** + * @class ESIssuer + * @brief The signature issuer ASCII encoded certificate hierarchy. Padded with nulls. + * + * Examples: + * Root (issued by Root) + * Root-CAxxxxxxxx (issued by Certifcate Authority server xxxxxxxx) + * Root-CAxxxxxxxx-XSxxxxxxxx (issued by Ticket/Transaction server xxxxxxxx) + * Root-CAxxxxxxxx-CPxxxxxxxx (issued by Content Publishing server xxxxxxxx) + * Root-CAxxxxxxxx-MSxxxxxxxx (issued by Manufacturing server xxxxxxxx) + * Root-CAxxxxxxxx-MSxxxxxxxx-YYxxxxxxxx (issued by Device with of type YY and serial number xxxxxxxx) + * + * xxxxxxxx represents the server/device serial number encoded in hex. (e.g. XS0000000f is ticket server 15). + */ +using ESIssuer = tc::bn::string; + +template +using ESSigPad = tc::bn::pad<_size>; + +/* pack to 4 byte boundaries */ +#pragma pack(push,4) + +struct ESSigRsa2048 +{ + tc::bn::be32 sigType; + Rsa2048Sig sig; + ESSigPad<60> pad; + ESIssuer issuer; +}; +static_assert(sizeof(ESSigRsa2048) == 384, "ESSigRsa2048 size"); + +struct ESSigRsa4096 +{ + tc::bn::be32 sigType; + Rsa4096Sig sig; + ESSigPad<60> pad; + ESIssuer issuer; +}; +static_assert(sizeof(ESSigRsa4096) == 640, "ESSigRsa4096 size"); + +struct ESSigEcc233 +{ + tc::bn::be32 sigType; + Ecc233Sig sig; + ESSigPad<64> pad; + ESIssuer issuer; +}; +static_assert(sizeof(ESSigEcc233) == 192, "ESSigEcc233 size"); + +#pragma pack(pop) + +}} // namespace brd::es \ No newline at end of file diff --git a/ctrtool/deps/libbroadon-es/include/brd/es/es_ticket.h b/ctrtool/deps/libbroadon-es/include/brd/es/es_ticket.h new file mode 100644 index 0000000..e9a38fe --- /dev/null +++ b/ctrtool/deps/libbroadon-es/include/brd/es/es_ticket.h @@ -0,0 +1,232 @@ +#pragma once +#include + +namespace brd { namespace es { + +// ES license types +enum class ESLicenseType : uint8_t +{ + PERMANENT = 0, + DEMO = 1, + TRIAL = 2, + RENTAL = 3, + SUBSCRIPTION = 4, + SERVICE = 5, +}; +static const uint8_t ES_LICENSE_MASK = 0xf; + +// ES title-level limit codes +enum class ESLimitCode : uint32_t +{ + DURATION_TIME = 1, + ABSOLUTE_TIME = 2, + NUM_TITLES = 3, + NUM_LAUNCH = 4, + ELAPSED_TIME = 5, +}; +static const uint32_t ES_MAX_LIMIT_TYPE = 8; + +// ES item-level rights +enum class ESItemType : uint32_t +{ + PERMANENT = 1, + SUBSCRIPTION = 2, + CONTENT = 3, + CONTENT_CONSUMPTION = 4, + ACCESS_TITLE = 5, + LIMITED_RESOURCE = 6, +}; + +enum class ESPropertyMaskFlag : uint16_t +{ + PRE_INSTALL = 0x1, // bit0 + SHARED_TITLE = 0x2, // bit1 + ALLOW_ALL_CONTENT = 0x4, // bit2 + DEVICE_LINK_INDEPENDENT = 0x8, // bit3 + VOLATILE = 0x10, // bit4 + ELICENSE_REQUIRED = 0x20, // bit5 +}; + +enum class ESV1SectionHeaderFlag : uint16_t +{ + COMPRESSED = 0x1 // ironically this is defined but not supported, probably for future use +}; + +enum class ESV2TitleKekType : byte_t +{ + AES128_CBC, + RSA2048 +}; + +#pragma pack(push, 4) + +#ifdef _WIN32 +#pragma warning(disable : 4200) // silence warnings for usage of empty arrays in stucts +#endif + +struct ESLimitedPlayEntry +{ + tc::bn::be32 code; //ESLimitCode + tc::bn::be32 limit; +}; +static_assert(sizeof(ESLimitedPlayEntry) == 8, "ESLimitedPlayEntry size"); + +using ESSysAccessMask = std::array; +using ESTicketCustomData = std::array; +using ESTicketReserved = std::array; +using ESCidxMask = std::array; +using ESLimitedPlayArray = std::array; + +using ESReferenceId = std::array; + +using ESV1CidxMask = std::array; + +using ESV2TitleKey = std::array; +using ESRightsId = std::array; +using ESV2TicketReserved = std::array; + +struct ESTicket +{ + ESSigRsa2048 sig; // RSA 2048-bit sign of the ticket + Ecc233PublicKey serverPubKey; // Ticketing server public key + uint8_t version; // Ticket data structure version number + uint8_t caCrlVersion; // CA CRL version number + uint8_t signerCrlVersion; // Signer CRL version number + Aes128Key titleKey; // Published title key + /* 1 byte alignment padding */ + tc::bn::be64 ticketId; // Unique 64bit ticket ID + tc::bn::be32 deviceId; // Unique 32bit device ID + tc::bn::be64 titleId; // Unique 64bit title ID + ESSysAccessMask sysAccessMask; // 16-bit cidx mask to indicate which + // of the first 16 pieces of contents + // can be accessed by the system app + tc::bn::be16 ticketVersion; // 16-bit ticket version + tc::bn::be32 accessTitleId; // 32-bit title ID for access control + tc::bn::be32 accessTitleMask; // 32-bit title ID mask + uint8_t licenseType; // + uint8_t keyId; // Common key ID + tc::bn::be16 propertyMask; // 16-bit property mask + ESTicketCustomData customData; // 20-byte custom data + ESTicketReserved reserved; // 25-byte reserved info + uint8_t audit; // + /* 2 bytes alignment padding */ + ESCidxMask cidxMask; // Bit-mask of the content indices + ESLimitedPlayArray limits; // Limited play entries +}; +static_assert(sizeof(ESTicket) == 676, "ESTicket size"); + +struct ESV1TicketHeader +{ + tc::bn::be16 hdrVersion; // Version of the ticket header + tc::bn::be16 hdrSize; // Size of ticket header + tc::bn::be32 ticketSize; // Size of the v1 portion of the ticket + tc::bn::be32 sectHdrOfst; // Offset of the section header table + tc::bn::be16 nSectHdrs; // Number of section headers + tc::bn::be16 sectHdrEntrySize; // Size of each section header + tc::bn::be32 flags; // Miscellaneous attributes +}; +static_assert(sizeof(ESV1TicketHeader) == 20, "ESV1TicketHeader size"); + +struct ESV1SectionHeader +{ + tc::bn::be32 sectOfst; // Offset of this section + tc::bn::be32 nRecords; // Number of records in this section + tc::bn::be32 recordSize; // Size of each record + tc::bn::be32 sectionSize; // Total size of this section + tc::bn::be16 sectionType; // Type code of this section + tc::bn::be16 flags; // Miscellaneous attributes +}; +static_assert(sizeof(ESV1SectionHeader) == 20, "ESV1SectionHeader size"); + +struct ESV1Ticket +{ + ESTicket head; + ESV1TicketHeader v1Head; + ESV1SectionHeader sectHdrs[]; +}; +static_assert(sizeof(ESV1Ticket) == 696, "ESV1Ticket size"); + +struct ESV1PermanentRecord +{ + ESReferenceId referenceId; // Reference ID + tc::bn::be32 referenceIdAttr; // Reference ID attributes +}; +static_assert(sizeof(ESV1PermanentRecord) == 20, "ESV1PermanentRecord size"); + +struct ESV1SubscriptionRecord +{ + tc::bn::be32 limit; // Expiration time + ESReferenceId referenceId; // Reference ID + tc::bn::be32 referenceIdAttr; // Reference ID attributes +}; +static_assert(sizeof(ESV1SubscriptionRecord) == 24, "ESV1SubscriptionRecord size"); + +struct ESV1ContentRecord +{ + tc::bn::be32 offset; // Offset content index + ESV1CidxMask accessMask; // Access mask +}; +static_assert(sizeof(ESV1ContentRecord) == 132, "ESV1ContentRecord size"); + +struct ESV1ContentConsumptionRecord +{ + tc::bn::be16 index; // Content index + tc::bn::be16 code; // Limit code + tc::bn::be32 limit; // Limit value +}; +static_assert(sizeof(ESV1ContentConsumptionRecord) == 8, "ESV1ContentConsumptionRecord size"); + +struct ESV1AccessTitleRecord +{ + tc::bn::be64 accessTitleId; // Access title ID + tc::bn::be64 accessTitleMask; // Access title mask +}; +static_assert(sizeof(ESV1AccessTitleRecord) == 16, "ESV1AccessTitleRecord size"); + +struct ESV1LimitedResourceRecord +{ + tc::bn::be32 limit; // Expiration time + ESReferenceId referenceId; // Reference ID + tc::bn::be32 referenceIdAttr; // Reference ID attributes +}; +static_assert(sizeof(ESV1LimitedResourceRecord) == 24, "ESV1LimitedResourceRecord size"); + +struct ESV2Ticket +{ + ESSigRsa2048 sig; // RSA 2048-bit sign of the ticket + ESV2TitleKey titleKey; // Published title key + uint8_t version; // Ticket data structure version number + uint8_t keyType; // Title key encryption key type + tc::bn::le16 ticketVersion; // 16-bit ticket version + uint8_t licenseType; + uint8_t keyId; // Common key ID + tc::bn::le16 propertyMask; // 16-bit property mask + ESV2TicketReserved reservedRegion; // probably the accessTitleId & mask + tc::bn::le64 ticketId; // Unique 64bit ticket ID + tc::bn::le64 deviceId; // Unique 64bit device ID + ESRightsId rightsId; // Unique 128bit rights ID + tc::bn::le32 accountId; // Unique 32bit account ID + tc::bn::le32 sectTotalSize; // Total size of sections + tc::bn::le32 sectHdrOffset; // Offset of the section header table + tc::bn::le16 nSectHdrs; // Number of section headers + tc::bn::le16 nSectHdrEntrySize; // Size of each section header +}; +static_assert(sizeof(ESV2Ticket) == 704, "ESV2Ticket size"); + +struct ESV2SectionHeader +{ + tc::bn::le32 sectOfst; // Offset of this section + tc::bn::le32 recordSize; // Size of each record + tc::bn::le32 sectionSize; // Total size of this section + tc::bn::le16 nRecords; // Number of records in this section + tc::bn::le16 sectionType; // Type code of this section +}; +static_assert(sizeof(ESV2SectionHeader) == 16, "ESV2SectionHeader size"); + +#ifdef _WIN32 +#pragma warning(default : 4200) +#endif + +#pragma pack(pop) + +}} // namespace brd::es \ No newline at end of file diff --git a/ctrtool/deps/libbroadon-es/include/brd/es/es_tmd.h b/ctrtool/deps/libbroadon-es/include/brd/es/es_tmd.h new file mode 100644 index 0000000..8bab843 --- /dev/null +++ b/ctrtool/deps/libbroadon-es/include/brd/es/es_tmd.h @@ -0,0 +1,129 @@ +#pragma once +#include + +namespace brd { namespace es { + +// ES title type +enum class ESTitleType : uint32_t +{ + NC_TITLE = 0x1, // bit0 NetCard - End-of-life + NG_TITLE = 0x2, // bit1 Wii/NDEV + DS_TITLE = 0x4, // bit2 TWL/DSi + DATA = 0x8, // bit3 boring data title + CT_TITLE = 0x40, // bit6 CTR/3DS + GVM_TITLE = 0x80, // bit7 GVM = ? (from BroadOn libraries) + CAFE_TITLE = 0x100, // bit8 WiiU (from WiiU sdk) +}; + +// ES content type +enum ESContentType : uint16_t +{ + ESContentType_ENCRYPTED = 0x1, // bit0 (from broadOn & b4) + ESContentType_DISC = 0x2, // bit1 (from broadOn & b4) + ESContentType_HASHED = 0x2, // bit1 (from b4) + ESContentType_CFM = 0x4, // bit3 (from broadOn & b4) + ESContentType_SHA1_HASH = 0x2000, // bit13 from b4 (wiiu sdk) + ESContentType_OPTIONAL = 0x4000, // bit14 (from broadOn & b4) + ESContentType_SHARED = 0x8000, // bit15 (from broadOn & b4) +}; + +// +// Maximum possible content index value is 64K - 2, since +// the maximum number of contents per title is 64K - 1 +// +static const size_t ES_CONTENT_INDEX_MAX = 65534; + + +// There are a maximum of 64 CMD groups, each with a maximum of 1K CMDs +static const size_t ES_MAX_CMDS_IN_GROUP = 1024; +static const size_t ES_MAX_CMD_GROUPS = 64; + +#pragma pack(push, 4) + +#ifdef _WIN32 +#pragma warning(disable : 4200) // silence warnings for usage of empty arrays in stucts +#endif + +struct ESContentMeta +{ + tc::bn::be32 cid; // 32-bit content ID + tc::bn::be16 index; // Content index, unique per title + tc::bn::be16 type; // Content type + tc::bn::be64 size; // Unencrypted content size in bytes + Sha1Hash hash; // Hash of the content +}; +static_assert(sizeof(ESContentMeta) == 36, "ESContentMeta size"); + +struct ESV1ContentMeta +{ + tc::bn::be32 cid; // 32-bit content ID + tc::bn::be16 index; // Content index, unique per title + tc::bn::be16 type; // Content type + tc::bn::be64 size; // Unencrypted content size in bytes + Sha256Hash hash; // Hash of the content +}; +static_assert(sizeof(ESV1ContentMeta) == 48, "ESV1ContentMeta size"); + +struct ESTitleMetaHeader +{ + using ESTmdCustomData = std::array; + using ESTmdReserved = std::array; + + uint8_t version; // TMD version number + uint8_t caCrlVersion; // CA CRL version number + uint8_t signerCrlVersion; // Signer CRL version number + tc::bn::be64 sysVersion; // System software version number + tc::bn::be64 titleId; // 64-bit title id + tc::bn::be32 type; // 32-bit title type + tc::bn::be16 groupId; + ESTmdCustomData customData; // 32-byte custom data + ESTmdReserved reserved; // 30-byte reserved info + tc::bn::be32 accessRights; // Rights to system resources + tc::bn::be16 titleVersion; // 16-bit title version + tc::bn::be16 numContents; // Number of contents + tc::bn::be16 bootIndex; // Boot content index + tc::bn::be16 minorTitleVersion; // 16-bit minor title version +}; +static_assert(sizeof(ESTitleMetaHeader) == 100, "ESTitleMetaHeader size"); + +struct ESV1ContentMetaGroup +{ + tc::bn::be16 offset; // Offset content index + tc::bn::be16 nCmds; // Number of CMDs in this group + Sha256Hash groupHash; // Hash for this group of CMDs +}; +static_assert(sizeof(ESV1ContentMetaGroup) == 36, "ESV1ContentMetaGroup size"); + +struct ESV1TitleMetaHeader +{ + using ESV1ContentMetaGroupArray = std::array; + + Sha256Hash hash; // Hash for the CMD groups + ESV1ContentMetaGroupArray cmdGroups; +}; +static_assert(sizeof(ESV1TitleMetaHeader) == 2336, "ESV1TitleMetaHeader size"); + +struct ESTitleMeta +{ + ESSigRsa2048 sig; // RSA 2048-bit sign of the TMD header + ESTitleMetaHeader head; + ESContentMeta contents[]; // CMD array sorted by content index +}; +static_assert(sizeof(ESTitleMeta) == 484, "ESTitleMeta size"); + +struct ESV1TitleMeta +{ + ESSigRsa2048 sig; // RSA 2048-bit sign of the TMD header + ESTitleMetaHeader head; + ESV1TitleMetaHeader v1Head; // Extension to the v0 TMD header + ESV1ContentMeta contents[]; // CMD array sorted by content index +}; +static_assert(sizeof(ESV1TitleMeta) == 2820, "ESV1TitleMeta size"); + +#ifdef _WIN32 +#pragma warning(default : 4200) +#endif + +#pragma pack(pop) + +}} // namespace brd::es \ No newline at end of file diff --git a/ctrtool/deps/libbroadon-es/include/brd/es/types.h b/ctrtool/deps/libbroadon-es/include/brd/es/types.h new file mode 100644 index 0000000..2a94407 --- /dev/null +++ b/ctrtool/deps/libbroadon-es/include/brd/es/types.h @@ -0,0 +1,73 @@ +#pragma once +#include + +namespace brd { namespace es { + +#pragma pack(push,4) + +static const size_t kAes128KeySize = 16; +using Aes128Key = std::array; + +static const size_t kAes192KeySize = 24; +using Aes192Key = std::array; + +static const size_t kAes256KeySize = 32; +using Aes256Key = std::array; + +static const size_t kSha1Size = 20; +using Sha1Hash = std::array; +using Sha1Hmac = std::array; + +static const size_t kSha256Size = 32; +using Sha256Hash = std::array; +using Sha256Hmac = std::array; + +static const size_t kRsaPublicExponentSize = 4; +using RsaPublicExponent = std::array; + +static const size_t kRsa2048Size = 0x100; +using Rsa2048Integer = std::array; +struct Rsa2048PublicKey +{ + Rsa2048Integer m; // modulus + RsaPublicExponent e; // public_exponent +}; +struct Rsa2048PrivateKey +{ + Rsa2048Integer m; // modulus + Rsa2048Integer d; // private_exponent +}; +using Rsa2048Sig = Rsa2048Integer; + +static const size_t kRsa4096Size = 0x200; +using Rsa4096Integer = std::array; +struct Rsa4096PublicKey +{ + Rsa4096Integer m; // modulus + RsaPublicExponent e; // public_exponent +}; +struct Rsa4096PrivateKey +{ + Rsa4096Integer m; // modulus + Rsa4096Integer d; // private_exponent +}; +using Rsa4096Sig = Rsa4096Integer; + +static const size_t kEcc233Size = 60; +using Ecc233Integer = std::array; +struct Ecc233Point +{ + Ecc233Integer x; + Ecc233Integer y; +}; +using Ecc233PrivateKey = Ecc233Integer; +using Ecc233PublicKey = Ecc233Point; +struct Ecc233Sig +{ + Ecc233Integer r; + Ecc233Integer s; +}; + +#pragma pack(pop) + +}} // namespace brd::es \ No newline at end of file diff --git a/ctrtool/deps/libbroadon-es/makefile b/ctrtool/deps/libbroadon-es/makefile new file mode 100644 index 0000000..87521a4 --- /dev/null +++ b/ctrtool/deps/libbroadon-es/makefile @@ -0,0 +1,193 @@ +# C++/C Recursive Project Makefile +# (c) Jack +# Version 5 + +# Project Name +PROJECT_NAME = libbroadon-es + +# Project Relative Paths +PROJECT_PATH = $(CURDIR) +PROJECT_SRC_PATH = src +PROJECT_SRC_SUBDIRS = $(PROJECT_SRC_PATH) +PROJECT_INCLUDE_PATH = include +#PROJECT_TESTSRC_PATH = test +#PROJECT_TESTSRC_SUBDIRS = $(PROJECT_TESTSRC_PATH) +PROJECT_BIN_PATH = bin +#PROJECT_DOCS_PATH = docs +#PROJECT_DOXYFILE_PATH = Doxyfile + +# Determine if the root makefile has been established, and if not establish this makefile as the root makefile +ifeq ($(ROOT_PROJECT_NAME),) + export ROOT_PROJECT_NAME = $(PROJECT_NAME) + export ROOT_PROJECT_PATH = $(PROJECT_PATH) + export ROOT_PROJECT_DEPENDENCY_PATH = $(ROOT_PROJECT_PATH)/deps +endif + +# Shared Library Definitions +PROJECT_SO_VER_MAJOR = 0 +PROJECT_SO_VER_MINOR = 1 +PROJECT_SO_VER_PATCH = 0 +PROJECT_SONAME = $(PROJECT_NAME).so.$(PROJECT_SO_VER_MAJOR) +PROJECT_SO_FILENAME = $(PROJECT_SONAME).$(PROJECT_SO_VER_MINOR).$(PROJECT_SO_VER_PATCH) + +# Project Dependencies +PROJECT_DEPEND = mbedtls toolchain +PROJECT_DEPEND_LOCAL_DIR = libmbedtls libtoolchain + +# Generate compiler flags for including project include path +ifneq ($(PROJECT_INCLUDE_PATH),) + INC += -I"$(PROJECT_INCLUDE_PATH)" +endif + +# Generate compiler flags for local included dependencies +ifneq ($(PROJECT_DEPEND_LOCAL_DIR),) + LIB += $(foreach dep,$(PROJECT_DEPEND_LOCAL_DIR), -L"$(ROOT_PROJECT_DEPENDENCY_PATH)/$(dep)/bin") + INC += $(foreach dep,$(PROJECT_DEPEND_LOCAL_DIR), -I"$(ROOT_PROJECT_DEPENDENCY_PATH)/$(dep)/include") +endif + +# Generate compiler flags for external dependencies +ifneq ($(PROJECT_DEPEND),) + LIB += $(foreach dep,$(PROJECT_DEPEND), -l$(dep)) +endif + +# Detect Platform +ifeq ($(PROJECT_PLATFORM),) + ifeq ($(OS), Windows_NT) + export PROJECT_PLATFORM = WIN32 + else + UNAME = $(shell uname -s) + ifeq ($(UNAME), Darwin) + export PROJECT_PLATFORM = MACOS + else + export PROJECT_PLATFORM = GNU + endif + endif +endif + +# Detect Architecture +ifeq ($(PROJECT_PLATFORM_ARCH),) + ifeq ($(PROJECT_PLATFORM), WIN32) + export PROJECT_PLATFORM_ARCH = x86_64 + else ifeq ($(PROJECT_PLATFORM), GNU) + export PROJECT_PLATFORM_ARCH = $(shell uname -m) + else ifeq ($(PROJECT_PLATFORM), MACOS) + export PROJECT_PLATFORM_ARCH = $(shell uname -m) + else + export PROJECT_PLATFORM_ARCH = x86_64 + endif +endif + +# Generate platform specific compiler flags +ifeq ($(PROJECT_PLATFORM), WIN32) + # Windows Flags/Libs + CC = x86_64-w64-mingw32-gcc + CXX = x86_64-w64-mingw32-g++ + WARNFLAGS = -Wall -Wno-unused-value -Wno-unused-but-set-variable + ARCHFLAGS = + INC += + LIB += -static + ARFLAGS = cr -o +else ifeq ($(PROJECT_PLATFORM), GNU) + # GNU/Linux Flags/Libs + #CC = + #CXX = + WARNFLAGS = -Wall -Wno-unused-value -Wno-unused-but-set-variable + ARCHFLAGS = + INC += + LIB += + ARFLAGS = cr -o +else ifeq ($(PROJECT_PLATFORM), MACOS) + # MacOS Flags/Libs + #CC = + #CXX = + WARNFLAGS = -Wall -Wno-unused-value -Wno-unused-private-field + ARCHFLAGS = -arch $(PROJECT_PLATFORM_ARCH) + INC += + LIB += + ARFLAGS = rc +endif + +# Compiler Flags +CXXFLAGS = -std=c++11 $(INC) $(WARNFLAGS) $(ARCHFLAGS) -fPIC +CFLAGS = -std=c11 $(INC) $(WARNFLAGS) $(ARCHFLAGS) -fPIC + +# Object Files +SRC_OBJ = $(foreach dir,$(PROJECT_SRC_SUBDIRS),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) $(foreach dir,$(PROJECT_SRC_SUBDIRS),$(subst .c,.o,$(wildcard $(dir)/*.c))) +TESTSRC_OBJ = $(foreach dir,$(PROJECT_TESTSRC_SUBDIRS),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) $(foreach dir,$(PROJECT_TESTSRC_SUBDIRS),$(subst .c,.o,$(wildcard $(dir)/*.c))) + +# all is the default, user should specify what the default should do +# - 'static_lib' for building static library +# - 'shared_lib' for building shared library +# - 'program' for building the program +# - 'test_program' for building the test program +# These can typically be used together however *_lib and program should not be used together +all: static_lib + +clean: clean_object_files remove_binary_dir + +# Object Compile Rules +%.o: %.c + @echo CC $< + @$(CC) $(CFLAGS) -c $< -o $@ + +%.o: %.cpp + @echo CXX $< + @$(CXX) $(CXXFLAGS) -c $< -o $@ + +# Binary Directory +.PHONY: create_binary_dir +create_binary_dir: + @mkdir -p "$(PROJECT_BIN_PATH)" + +.PHONY: remove_binary_dir +remove_binary_dir: +ifneq ($(PROJECT_BIN_PATH),) + @rm -rf "$(PROJECT_BIN_PATH)" +endif + +.PHONY: clean_object_files +clean_object_files: + @rm -f $(SRC_OBJ) $(TESTSRC_OBJ) + +# Build Library +static_lib: $(SRC_OBJ) create_binary_dir + @echo LINK $(PROJECT_BIN_PATH)/$(PROJECT_NAME).a + @ar $(ARFLAGS) "$(PROJECT_BIN_PATH)/$(PROJECT_NAME).a" $(SRC_OBJ) + +shared_lib: $(SRC_OBJ) create_binary_dir + @echo LINK $(PROJECT_BIN_PATH)/$(PROJECT_SO_FILENAME) + @gcc -shared -Wl,-soname,$(PROJECT_SONAME) -o "$(PROJECT_BIN_PATH)/$(PROJECT_SO_FILENAME)" $(SRC_OBJ) + +# Build Program +program: $(SRC_OBJ) create_binary_dir + @echo LINK $(PROJECT_BIN_PATH)/$(PROJECT_NAME) + @$(CXX) $(SRC_OBJ) $(LIB) -o "$(PROJECT_BIN_PATH)/$(PROJECT_NAME)" + +# Build Test Program +test_program: $(TESTSRC_OBJ) $(SRC_OBJ) create_binary_dir +ifneq ($(PROJECT_TESTSRC_PATH),) + @echo LINK $(PROJECT_BIN_PATH)/$(PROJECT_NAME)_test + @$(CXX) $(TESTSRC_OBJ) $(SRC_OBJ) $(LIB) -o "$(PROJECT_BIN_PATH)/$(PROJECT_NAME)_test" +endif + +# Documentation +.PHONY: docs +docs: +ifneq ($(PROJECT_DOCS_PATH),) + doxygen "$(PROJECT_DOXYFILE_PATH)" +endif + +.PHONY: clean_docs +clean_docs: +ifneq ($(PROJECT_DOCS_PATH),) + @rm -rf "$(PROJECT_DOCS_PATH)" +endif + +# Dependencies +.PHONY: deps +deps: + @$(foreach lib,$(PROJECT_DEPEND_LOCAL_DIR), cd "$(ROOT_PROJECT_DEPENDENCY_PATH)/$(lib)" && $(MAKE) static_lib && cd "$(PROJECT_PATH)";) + +.PHONY: clean_deps +clean_deps: + @$(foreach lib,$(PROJECT_DEPEND_LOCAL_DIR), cd "$(ROOT_PROJECT_DEPENDENCY_PATH)/$(lib)" && $(MAKE) clean && cd "$(PROJECT_PATH)";) \ No newline at end of file diff --git a/ctrtool/deps/libbroadon-es/src/Dummy.cpp b/ctrtool/deps/libbroadon-es/src/Dummy.cpp new file mode 100644 index 0000000..0e29ff2 --- /dev/null +++ b/ctrtool/deps/libbroadon-es/src/Dummy.cpp @@ -0,0 +1,138 @@ +#include +#include + +#ifdef _WIN32 +#pragma warning(disable : 4101) // silence warnings for unused local variables +#endif + +namespace brd { + namespace es { + + int dummy_method1a() + { + // types + brd::es::Aes128Key Aes128Key_var; + brd::es::Aes192Key Aes192Key_var; + brd::es::Aes256Key Aes256Key_var; + brd::es::Sha1Hash Sha1Hash_var; + brd::es::Sha1Hmac Sha1Hmac_var; + brd::es::Sha256Hash Sha256Hash_var; + brd::es::Sha256Hmac Sha256Hmac_var; + brd::es::RsaPublicExponent RsaPublicExponent_var; + brd::es::Rsa2048Integer Rsa2048Integer_var; + brd::es::Rsa2048PublicKey Rsa2048PublicKey_var; + brd::es::Rsa2048PrivateKey Rsa2048PrivateKey_var; + brd::es::Rsa2048Sig Rsa2048Sig_var; + return 11; + } + + int dummy_method1b() + { + // types + brd::es::Rsa4096Integer Rsa4096Integer_var; + brd::es::Rsa4096PublicKey Rsa4096PublicKey_var; + brd::es::Rsa4096PrivateKey Rsa4096PrivateKey_var; + brd::es::Rsa4096Sig Rsa4096Sig_var; + brd::es::Ecc233Integer Ecc233Integer_var; + brd::es::Ecc233Point Ecc233Point_var; + brd::es::Ecc233PrivateKey Ecc233PrivateKey_var; + brd::es::Ecc233PublicKey Ecc233PublicKey_var; + brd::es::Ecc233Sig Ecc233Sig_var; + + return 01323; + } + + int dummy_method2() + { + // sign + brd::es::ESSigType ESSigType_var; + size_t ES_ISSUER_SIZE_var = brd::es::ES_ISSUER_SIZE; + brd::es::ESIssuer ESIssuer_var; + brd::es::ESSigRsa2048 ESSigRsa2048_struct; + brd::es::ESSigRsa4096 ESSigRsa4096_struct; + brd::es::ESSigEcc233 ESSigEcc233_struct; + + return 1232; + } + + int dummy_method3() + { + // cert + brd::es::ESCertPubKeyType ESCertPubKeyType_var; + size_t ES_CERT_NAME_SIZE_var = brd::es::ES_CERT_NAME_SIZE; + brd::es::ESCertName ESCertName_var; + brd::es::ESServerId ESServerId_var; + brd::es::ESDeviceId ESDeviceId_var; + brd::es::ESCertHeader ESCertHeader_struct; + brd::es::ESCertRsa2048PublicKey ESCertRsa2048PublicKey_struct; + brd::es::ESCertRsa4096PublicKey ESCertRsa4096PublicKey_struct; + brd::es::ESCertEcc233PublicKey ESCertEcc233PublicKey_struct; + brd::es::ESRootCert ESRootCert_struct; + brd::es::ESCACert ESCACert_struct; + brd::es::ESCASignedCert ESCASignedCert_struct; + brd::es::ESDeviceCert ESDeviceCert_struct; + brd::es::ESDeviceSignedCert ESDeviceSignedCert_struct; + + return 55; + } + + int dummy_method4() + { + // tik + brd::es::ESLicenseType ESLicenseType_var; + uint8_t ES_LICENSE_MASK_var = brd::es::ES_LICENSE_MASK; + brd::es::ESLimitCode ESLimitCode_var; + uint32_t ES_MAX_LIMIT_TYPE_var = brd::es::ES_MAX_LIMIT_TYPE; + brd::es::ESItemType ESItemType_var; + brd::es::ESPropertyMaskFlag ESPropertyMaskFlag_var; + brd::es::ESV1SectionHeaderFlag ESV1SectionHeaderFlag_var; + brd::es::ESV2TitleKekType ESV2TitleKekType_var; + brd::es::ESLimitedPlayEntry ESLimitedPlayEntry_struct; + brd::es::ESSysAccessMask ESSysAccessMask_var; + brd::es::ESTicketCustomData ESTicketCustomData_var; + brd::es::ESTicketReserved ESTicketReserved_var; + brd::es::ESCidxMask ESCidxMask_var; + brd::es::ESLimitedPlayArray ESLimitedPlayArray_var; + brd::es::ESReferenceId ESReferenceId_var; + brd::es::ESV1CidxMask ESV1CidxMask_var; + brd::es::ESV2TitleKey ESV2TitleKey_var; + brd::es::ESRightsId ESRightsId_var; + brd::es::ESV2TicketReserved ESV2TicketReserved_var; + brd::es::ESTicket ESTicket_struct; + brd::es::ESV1TicketHeader ESV1TicketHeader_struct; + brd::es::ESV1SectionHeader ESV1SectionHeader_struct; + brd::es::ESV1Ticket ESV1Ticket_struct; + brd::es::ESV1PermanentRecord ESV1PermanentRecord_struct; + brd::es::ESV1SubscriptionRecord ESV1SubscriptionRecord_struct; + brd::es::ESV1ContentRecord ESV1ContentRecord_struct; + brd::es::ESV1ContentConsumptionRecord ESV1ContentConsumptionRecord_struct; + brd::es::ESV1AccessTitleRecord ESV1AccessTitleRecord_struct; + brd::es::ESV1LimitedResourceRecord ESV1LimitedResourceRecord_struct; + brd::es::ESV2Ticket ESV2Ticket_struct; + brd::es::ESV2SectionHeader ESV2SectionHeader_struct; + + return 0; + } + + int dummy_method5() + { + // tmd + brd::es::ESTitleType ESTitleType_var; + brd::es::ESContentType ESContentType_var; + size_t ES_CONTENT_INDEX_MAX_var = brd::es::ES_CONTENT_INDEX_MAX; + size_t ES_MAX_CMDS_IN_GROUP_var = brd::es::ES_MAX_CMDS_IN_GROUP; + brd::es::ESContentMeta ESContentMeta_struct; + brd::es::ESV1ContentMeta ESV1ContentMeta_struct; + brd::es::ESTitleMetaHeader ESTitleMetaHeader_struct; + brd::es::ESV1ContentMetaGroup ESV1ContentMetaGroup_struct; + brd::es::ESV1TitleMetaHeader ESV1TitleMetaHeader_struct; + brd::es::ESTitleMeta ESTitleMeta_struct; + brd::es::ESV1TitleMeta ESV1TitleMeta_struct; + return 54; + } + + } +} +#ifdef _WIN32 +#pragma warning(default : 4101) +#endif \ No newline at end of file diff --git a/ctrtool/deps/libfmt/LICENSE.rst b/ctrtool/deps/libfmt/LICENSE.rst new file mode 100644 index 0000000..8f92168 --- /dev/null +++ b/ctrtool/deps/libfmt/LICENSE.rst @@ -0,0 +1,27 @@ +Copyright (c) 2012 - present, Victor Zverovich + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--- Optional exception to the license --- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into a machine-executable object form of such +source code, you may redistribute such embedded portions in such object form +without including the above copyright and permission notices. \ No newline at end of file diff --git a/ctrtool/deps/libfmt/README.md b/ctrtool/deps/libfmt/README.md new file mode 100644 index 0000000..ce8069f --- /dev/null +++ b/ctrtool/deps/libfmt/README.md @@ -0,0 +1,2 @@ +# libfmt +Clone of {fmt} (https://github.com/fmtlib/fmt) diff --git a/ctrtool/deps/libfmt/build/visualstudio/libfmt.sln b/ctrtool/deps/libfmt/build/visualstudio/libfmt.sln new file mode 100644 index 0000000..368aee4 --- /dev/null +++ b/ctrtool/deps/libfmt/build/visualstudio/libfmt.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31229.75 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfmt", "libfmt\libfmt.vcxproj", "{F4B0540E-0AAE-4006-944B-356944EF61FA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x64.ActiveCfg = Debug|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x64.Build.0 = Debug|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x86.ActiveCfg = Debug|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x86.Build.0 = Debug|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.ActiveCfg = Release|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.Build.0 = Release|x64 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.ActiveCfg = Release|Win32 + {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EA4E4F87-6367-4723-8641-6767757CD6DD} + EndGlobalSection +EndGlobal diff --git a/ctrtool/deps/libfmt/build/visualstudio/libfmt/libfmt.vcxproj b/ctrtool/deps/libfmt/build/visualstudio/libfmt/libfmt.vcxproj new file mode 100644 index 0000000..61a5ca3 --- /dev/null +++ b/ctrtool/deps/libfmt/build/visualstudio/libfmt/libfmt.vcxproj @@ -0,0 +1,171 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {f4b0540e-0aae-4006-944b-356944ef61fa} + libfmt + 10.0 + + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDebug + $(ProjectDir)..\..\..\include + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + $(ProjectDir)..\..\..\include + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDebug + $(ProjectDir)..\..\..\include + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + $(ProjectDir)..\..\..\include + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ctrtool/deps/libfmt/build/visualstudio/libfmt/libfmt.vcxproj.filters b/ctrtool/deps/libfmt/build/visualstudio/libfmt/libfmt.vcxproj.filters new file mode 100644 index 0000000..61b8ad1 --- /dev/null +++ b/ctrtool/deps/libfmt/build/visualstudio/libfmt/libfmt.vcxproj.filters @@ -0,0 +1,66 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/ctrtool/deps/libfmt/include/fmt/args.h b/ctrtool/deps/libfmt/include/fmt/args.h new file mode 100644 index 0000000..9a8e4ed --- /dev/null +++ b/ctrtool/deps/libfmt/include/fmt/args.h @@ -0,0 +1,234 @@ +// Formatting library for C++ - dynamic format arguments +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_ARGS_H_ +#define FMT_ARGS_H_ + +#include // std::reference_wrapper +#include // std::unique_ptr +#include + +#include "core.h" + +FMT_BEGIN_NAMESPACE + +namespace detail { + +template struct is_reference_wrapper : std::false_type {}; +template +struct is_reference_wrapper> : std::true_type {}; + +template const T& unwrap(const T& v) { return v; } +template const T& unwrap(const std::reference_wrapper& v) { + return static_cast(v); +} + +class dynamic_arg_list { + // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for + // templates it doesn't complain about inability to deduce single translation + // unit for placing vtable. So storage_node_base is made a fake template. + template struct node { + virtual ~node() = default; + std::unique_ptr> next; + }; + + template struct typed_node : node<> { + T value; + + template + FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} + + template + FMT_CONSTEXPR typed_node(const basic_string_view& arg) + : value(arg.data(), arg.size()) {} + }; + + std::unique_ptr> head_; + + public: + template const T& push(const Arg& arg) { + auto new_node = std::unique_ptr>(new typed_node(arg)); + auto& value = new_node->value; + new_node->next = std::move(head_); + head_ = std::move(new_node); + return value; + } +}; +} // namespace detail + +/** + \rst + A dynamic version of `fmt::format_arg_store`. + It's equipped with a storage to potentially temporary objects which lifetimes + could be shorter than the format arguments object. + + It can be implicitly converted into `~fmt::basic_format_args` for passing + into type-erased formatting functions such as `~fmt::vformat`. + \endrst + */ +template +class dynamic_format_arg_store +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 + // Workaround a GCC template argument substitution bug. + : public basic_format_args +#endif +{ + private: + using char_type = typename Context::char_type; + + template struct need_copy { + static constexpr detail::type mapped_type = + detail::mapped_type_constant::value; + + enum { + value = !(detail::is_reference_wrapper::value || + std::is_same>::value || + std::is_same>::value || + (mapped_type != detail::type::cstring_type && + mapped_type != detail::type::string_type && + mapped_type != detail::type::custom_type)) + }; + }; + + template + using stored_type = conditional_t::value && + !has_formatter::value && + !detail::is_reference_wrapper::value, + std::basic_string, T>; + + // Storage of basic_format_arg must be contiguous. + std::vector> data_; + std::vector> named_info_; + + // Storage of arguments not fitting into basic_format_arg must grow + // without relocation because items in data_ refer to it. + detail::dynamic_arg_list dynamic_args_; + + friend class basic_format_args; + + unsigned long long get_types() const { + return detail::is_unpacked_bit | data_.size() | + (named_info_.empty() + ? 0ULL + : static_cast(detail::has_named_args_bit)); + } + + const basic_format_arg* data() const { + return named_info_.empty() ? data_.data() : data_.data() + 1; + } + + template void emplace_arg(const T& arg) { + data_.emplace_back(detail::make_arg(arg)); + } + + template + void emplace_arg(const detail::named_arg& arg) { + if (named_info_.empty()) { + constexpr const detail::named_arg_info* zero_ptr{nullptr}; + data_.insert(data_.begin(), {zero_ptr, 0}); + } + data_.emplace_back(detail::make_arg(detail::unwrap(arg.value))); + auto pop_one = [](std::vector>* data) { + data->pop_back(); + }; + std::unique_ptr>, decltype(pop_one)> + guard{&data_, pop_one}; + named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); + data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; + guard.release(); + } + + public: + constexpr dynamic_format_arg_store() = default; + + /** + \rst + Adds an argument into the dynamic store for later passing to a formatting + function. + + Note that custom types and string types (but not string views) are copied + into the store dynamically allocating memory if necessary. + + **Example**:: + + fmt::dynamic_format_arg_store store; + store.push_back(42); + store.push_back("abc"); + store.push_back(1.5f); + std::string result = fmt::vformat("{} and {} and {}", store); + \endrst + */ + template void push_back(const T& arg) { + if (detail::const_check(need_copy::value)) + emplace_arg(dynamic_args_.push>(arg)); + else + emplace_arg(detail::unwrap(arg)); + } + + /** + \rst + Adds a reference to the argument into the dynamic store for later passing to + a formatting function. + + **Example**:: + + fmt::dynamic_format_arg_store store; + char band[] = "Rolling Stones"; + store.push_back(std::cref(band)); + band[9] = 'c'; // Changing str affects the output. + std::string result = fmt::vformat("{}", store); + // result == "Rolling Scones" + \endrst + */ + template void push_back(std::reference_wrapper arg) { + static_assert( + need_copy::value, + "objects of built-in types and string views are always copied"); + emplace_arg(arg.get()); + } + + /** + Adds named argument into the dynamic store for later passing to a formatting + function. ``std::reference_wrapper`` is supported to avoid copying of the + argument. The name is always copied into the store. + */ + template + void push_back(const detail::named_arg& arg) { + const char_type* arg_name = + dynamic_args_.push>(arg.name).c_str(); + if (detail::const_check(need_copy::value)) { + emplace_arg( + fmt::arg(arg_name, dynamic_args_.push>(arg.value))); + } else { + emplace_arg(fmt::arg(arg_name, arg.value)); + } + } + + /** Erase all elements from the store */ + void clear() { + data_.clear(); + named_info_.clear(); + dynamic_args_ = detail::dynamic_arg_list(); + } + + /** + \rst + Reserves space to store at least *new_cap* arguments including + *new_cap_named* named arguments. + \endrst + */ + void reserve(size_t new_cap, size_t new_cap_named) { + FMT_ASSERT(new_cap >= new_cap_named, + "Set of arguments includes set of named arguments"); + data_.reserve(new_cap); + named_info_.reserve(new_cap_named); + } +}; + +FMT_END_NAMESPACE + +#endif // FMT_ARGS_H_ diff --git a/ctrtool/deps/libfmt/include/fmt/chrono.h b/ctrtool/deps/libfmt/include/fmt/chrono.h new file mode 100644 index 0000000..682efd8 --- /dev/null +++ b/ctrtool/deps/libfmt/include/fmt/chrono.h @@ -0,0 +1,2067 @@ +// Formatting library for C++ - chrono support +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_CHRONO_H_ +#define FMT_CHRONO_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "format.h" + +FMT_BEGIN_NAMESPACE + +// Enable tzset. +#ifndef FMT_USE_TZSET +// UWP doesn't provide _tzset. +# if FMT_HAS_INCLUDE("winapifamily.h") +# include +# endif +# if defined(_WIN32) && (!defined(WINAPI_FAMILY) || \ + (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) +# define FMT_USE_TZSET 1 +# else +# define FMT_USE_TZSET 0 +# endif +#endif + +// Enable safe chrono durations, unless explicitly disabled. +#ifndef FMT_SAFE_DURATION_CAST +# define FMT_SAFE_DURATION_CAST 1 +#endif +#if FMT_SAFE_DURATION_CAST + +// For conversion between std::chrono::durations without undefined +// behaviour or erroneous results. +// This is a stripped down version of duration_cast, for inclusion in fmt. +// See https://github.com/pauldreik/safe_duration_cast +// +// Copyright Paul Dreik 2019 +namespace safe_duration_cast { + +template ::value && + std::numeric_limits::is_signed == + std::numeric_limits::is_signed)> +FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { + ec = 0; + using F = std::numeric_limits; + using T = std::numeric_limits; + static_assert(F::is_integer, "From must be integral"); + static_assert(T::is_integer, "To must be integral"); + + // A and B are both signed, or both unsigned. + if (detail::const_check(F::digits <= T::digits)) { + // From fits in To without any problem. + } else { + // From does not always fit in To, resort to a dynamic check. + if (from < (T::min)() || from > (T::max)()) { + // outside range. + ec = 1; + return {}; + } + } + return static_cast(from); +} + +/** + * converts From to To, without loss. If the dynamic value of from + * can't be converted to To without loss, ec is set. + */ +template ::value && + std::numeric_limits::is_signed != + std::numeric_limits::is_signed)> +FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { + ec = 0; + using F = std::numeric_limits; + using T = std::numeric_limits; + static_assert(F::is_integer, "From must be integral"); + static_assert(T::is_integer, "To must be integral"); + + if (detail::const_check(F::is_signed && !T::is_signed)) { + // From may be negative, not allowed! + if (fmt::detail::is_negative(from)) { + ec = 1; + return {}; + } + // From is positive. Can it always fit in To? + if (detail::const_check(F::digits > T::digits) && + from > static_cast(detail::max_value())) { + ec = 1; + return {}; + } + } + + if (detail::const_check(!F::is_signed && T::is_signed && + F::digits >= T::digits) && + from > static_cast(detail::max_value())) { + ec = 1; + return {}; + } + return static_cast(from); // Lossless conversion. +} + +template ::value)> +FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { + ec = 0; + return from; +} // function + +// clang-format off +/** + * converts From to To if possible, otherwise ec is set. + * + * input | output + * ---------------------------------|--------------- + * NaN | NaN + * Inf | Inf + * normal, fits in output | converted (possibly lossy) + * normal, does not fit in output | ec is set + * subnormal | best effort + * -Inf | -Inf + */ +// clang-format on +template ::value)> +FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) { + ec = 0; + using T = std::numeric_limits; + static_assert(std::is_floating_point::value, "From must be floating"); + static_assert(std::is_floating_point::value, "To must be floating"); + + // catch the only happy case + if (std::isfinite(from)) { + if (from >= T::lowest() && from <= (T::max)()) { + return static_cast(from); + } + // not within range. + ec = 1; + return {}; + } + + // nan and inf will be preserved + return static_cast(from); +} // function + +template ::value)> +FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) { + ec = 0; + static_assert(std::is_floating_point::value, "From must be floating"); + return from; +} + +/** + * safe duration cast between integral durations + */ +template ::value), + FMT_ENABLE_IF(std::is_integral::value)> +To safe_duration_cast(std::chrono::duration from, + int& ec) { + using From = std::chrono::duration; + ec = 0; + // the basic idea is that we need to convert from count() in the from type + // to count() in the To type, by multiplying it with this: + struct Factor + : std::ratio_divide {}; + + static_assert(Factor::num > 0, "num must be positive"); + static_assert(Factor::den > 0, "den must be positive"); + + // the conversion is like this: multiply from.count() with Factor::num + // /Factor::den and convert it to To::rep, all this without + // overflow/underflow. let's start by finding a suitable type that can hold + // both To, From and Factor::num + using IntermediateRep = + typename std::common_type::type; + + // safe conversion to IntermediateRep + IntermediateRep count = + lossless_integral_conversion(from.count(), ec); + if (ec) return {}; + // multiply with Factor::num without overflow or underflow + if (detail::const_check(Factor::num != 1)) { + const auto max1 = detail::max_value() / Factor::num; + if (count > max1) { + ec = 1; + return {}; + } + const auto min1 = + (std::numeric_limits::min)() / Factor::num; + if (count < min1) { + ec = 1; + return {}; + } + count *= Factor::num; + } + + if (detail::const_check(Factor::den != 1)) count /= Factor::den; + auto tocount = lossless_integral_conversion(count, ec); + return ec ? To() : To(tocount); +} + +/** + * safe duration_cast between floating point durations + */ +template ::value), + FMT_ENABLE_IF(std::is_floating_point::value)> +To safe_duration_cast(std::chrono::duration from, + int& ec) { + using From = std::chrono::duration; + ec = 0; + if (std::isnan(from.count())) { + // nan in, gives nan out. easy. + return To{std::numeric_limits::quiet_NaN()}; + } + // maybe we should also check if from is denormal, and decide what to do about + // it. + + // +-inf should be preserved. + if (std::isinf(from.count())) { + return To{from.count()}; + } + + // the basic idea is that we need to convert from count() in the from type + // to count() in the To type, by multiplying it with this: + struct Factor + : std::ratio_divide {}; + + static_assert(Factor::num > 0, "num must be positive"); + static_assert(Factor::den > 0, "den must be positive"); + + // the conversion is like this: multiply from.count() with Factor::num + // /Factor::den and convert it to To::rep, all this without + // overflow/underflow. let's start by finding a suitable type that can hold + // both To, From and Factor::num + using IntermediateRep = + typename std::common_type::type; + + // force conversion of From::rep -> IntermediateRep to be safe, + // even if it will never happen be narrowing in this context. + IntermediateRep count = + safe_float_conversion(from.count(), ec); + if (ec) { + return {}; + } + + // multiply with Factor::num without overflow or underflow + if (detail::const_check(Factor::num != 1)) { + constexpr auto max1 = detail::max_value() / + static_cast(Factor::num); + if (count > max1) { + ec = 1; + return {}; + } + constexpr auto min1 = std::numeric_limits::lowest() / + static_cast(Factor::num); + if (count < min1) { + ec = 1; + return {}; + } + count *= static_cast(Factor::num); + } + + // this can't go wrong, right? den>0 is checked earlier. + if (detail::const_check(Factor::den != 1)) { + using common_t = typename std::common_type::type; + count /= static_cast(Factor::den); + } + + // convert to the to type, safely + using ToRep = typename To::rep; + + const ToRep tocount = safe_float_conversion(count, ec); + if (ec) { + return {}; + } + return To{tocount}; +} +} // namespace safe_duration_cast +#endif + +// Prevents expansion of a preceding token as a function-style macro. +// Usage: f FMT_NOMACRO() +#define FMT_NOMACRO + +namespace detail { +template struct null {}; +inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); } +inline null<> localtime_s(...) { return null<>(); } +inline null<> gmtime_r(...) { return null<>(); } +inline null<> gmtime_s(...) { return null<>(); } + +inline const std::locale& get_classic_locale() { + static const auto& locale = std::locale::classic(); + return locale; +} + +template struct codecvt_result { + static constexpr const size_t max_size = 32; + CodeUnit buf[max_size]; + CodeUnit* end; +}; +template +constexpr const size_t codecvt_result::max_size; + +template +void write_codecvt(codecvt_result& out, string_view in_buf, + const std::locale& loc) { + using codecvt = std::codecvt; +#if FMT_CLANG_VERSION +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated" + auto& f = std::use_facet(loc); +# pragma clang diagnostic pop +#else + auto& f = std::use_facet(loc); +#endif + auto mb = std::mbstate_t(); + const char* from_next = nullptr; + auto result = f.in(mb, in_buf.begin(), in_buf.end(), from_next, + std::begin(out.buf), std::end(out.buf), out.end); + if (result != std::codecvt_base::ok) + FMT_THROW(format_error("failed to format time")); +} + +template +auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc) + -> OutputIt { + if (detail::is_utf8() && loc != get_classic_locale()) { + // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and + // gcc-4. +#if FMT_MSC_VER != 0 || \ + (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI)) + // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5 + // and newer. + using code_unit = wchar_t; +#else + using code_unit = char32_t; +#endif + + using unit_t = codecvt_result; + unit_t unit; + write_codecvt(unit, in, loc); + // In UTF-8 is used one to four one-byte code units. + auto&& buf = basic_memory_buffer(); + for (code_unit* p = unit.buf; p != unit.end; ++p) { + uint32_t c = static_cast(*p); + if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) { + // surrogate pair + ++p; + if (p == unit.end || (c & 0xfc00) != 0xd800 || + (*p & 0xfc00) != 0xdc00) { + FMT_THROW(format_error("failed to format time")); + } + c = (c << 10) + static_cast(*p) - 0x35fdc00; + } + if (c < 0x80) { + buf.push_back(static_cast(c)); + } else if (c < 0x800) { + buf.push_back(static_cast(0xc0 | (c >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) { + buf.push_back(static_cast(0xe0 | (c >> 12))); + buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else if (c >= 0x10000 && c <= 0x10ffff) { + buf.push_back(static_cast(0xf0 | (c >> 18))); + buf.push_back(static_cast(0x80 | ((c & 0x3ffff) >> 12))); + buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else { + FMT_THROW(format_error("failed to format time")); + } + } + return copy_str(buf.data(), buf.data() + buf.size(), out); + } + return copy_str(in.data(), in.data() + in.size(), out); +} + +template ::value)> +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { + codecvt_result unit; + write_codecvt(unit, sv, loc); + return copy_str(unit.buf, unit.end, out); +} + +template ::value)> +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { + return write_encoded_tm_str(out, sv, loc); +} + +template +inline void do_write(buffer& buf, const std::tm& time, + const std::locale& loc, char format, char modifier) { + auto&& format_buf = formatbuf>(buf); + auto&& os = std::basic_ostream(&format_buf); + os.imbue(loc); + using iterator = std::ostreambuf_iterator; + const auto& facet = std::use_facet>(loc); + auto end = facet.put(os, os, Char(' '), &time, format, modifier); + if (end.failed()) FMT_THROW(format_error("failed to format time")); +} + +template ::value)> +auto write(OutputIt out, const std::tm& time, const std::locale& loc, + char format, char modifier = 0) -> OutputIt { + auto&& buf = get_buffer(out); + do_write(buf, time, loc, format, modifier); + return buf.out(); +} + +template ::value)> +auto write(OutputIt out, const std::tm& time, const std::locale& loc, + char format, char modifier = 0) -> OutputIt { + auto&& buf = basic_memory_buffer(); + do_write(buf, time, loc, format, modifier); + return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc); +} + +} // namespace detail + +FMT_MODULE_EXPORT_BEGIN + +/** + Converts given time since epoch as ``std::time_t`` value into calendar time, + expressed in local time. Unlike ``std::localtime``, this function is + thread-safe on most platforms. + */ +inline std::tm localtime(std::time_t time) { + struct dispatcher { + std::time_t time_; + std::tm tm_; + + dispatcher(std::time_t t) : time_(t) {} + + bool run() { + using namespace fmt::detail; + return handle(localtime_r(&time_, &tm_)); + } + + bool handle(std::tm* tm) { return tm != nullptr; } + + bool handle(detail::null<>) { + using namespace fmt::detail; + return fallback(localtime_s(&tm_, &time_)); + } + + bool fallback(int res) { return res == 0; } + +#if !FMT_MSC_VER + bool fallback(detail::null<>) { + using namespace fmt::detail; + std::tm* tm = std::localtime(&time_); + if (tm) tm_ = *tm; + return tm != nullptr; + } +#endif + }; + dispatcher lt(time); + // Too big time values may be unsupported. + if (!lt.run()) FMT_THROW(format_error("time_t value out of range")); + return lt.tm_; +} + +inline std::tm localtime( + std::chrono::time_point time_point) { + return localtime(std::chrono::system_clock::to_time_t(time_point)); +} + +/** + Converts given time since epoch as ``std::time_t`` value into calendar time, + expressed in Coordinated Universal Time (UTC). Unlike ``std::gmtime``, this + function is thread-safe on most platforms. + */ +inline std::tm gmtime(std::time_t time) { + struct dispatcher { + std::time_t time_; + std::tm tm_; + + dispatcher(std::time_t t) : time_(t) {} + + bool run() { + using namespace fmt::detail; + return handle(gmtime_r(&time_, &tm_)); + } + + bool handle(std::tm* tm) { return tm != nullptr; } + + bool handle(detail::null<>) { + using namespace fmt::detail; + return fallback(gmtime_s(&tm_, &time_)); + } + + bool fallback(int res) { return res == 0; } + +#if !FMT_MSC_VER + bool fallback(detail::null<>) { + std::tm* tm = std::gmtime(&time_); + if (tm) tm_ = *tm; + return tm != nullptr; + } +#endif + }; + dispatcher gt(time); + // Too big time values may be unsupported. + if (!gt.run()) FMT_THROW(format_error("time_t value out of range")); + return gt.tm_; +} + +inline std::tm gmtime( + std::chrono::time_point time_point) { + return gmtime(std::chrono::system_clock::to_time_t(time_point)); +} + +FMT_BEGIN_DETAIL_NAMESPACE + +// Writes two-digit numbers a, b and c separated by sep to buf. +// The method by Pavel Novikov based on +// https://johnnylee-sde.github.io/Fast-unsigned-integer-to-time-string/. +inline void write_digit2_separated(char* buf, unsigned a, unsigned b, + unsigned c, char sep) { + unsigned long long digits = + a | (b << 24) | (static_cast(c) << 48); + // Convert each value to BCD. + // We have x = a * 10 + b and we want to convert it to BCD y = a * 16 + b. + // The difference is + // y - x = a * 6 + // a can be found from x: + // a = floor(x / 10) + // then + // y = x + a * 6 = x + floor(x / 10) * 6 + // floor(x / 10) is (x * 205) >> 11 (needs 16 bits). + digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6; + // Put low nibbles to high bytes and high nibbles to low bytes. + digits = ((digits & 0x00f00000f00000f0) >> 4) | + ((digits & 0x000f00000f00000f) << 8); + auto usep = static_cast(sep); + // Add ASCII '0' to each digit byte and insert separators. + digits |= 0x3030003030003030 | (usep << 16) | (usep << 40); + + constexpr const size_t len = 8; + if (const_check(is_big_endian())) { + char tmp[len]; + memcpy(tmp, &digits, len); + std::reverse_copy(tmp, tmp + len, buf); + } else { + memcpy(buf, &digits, len); + } +} + +template FMT_CONSTEXPR inline const char* get_units() { + if (std::is_same::value) return "as"; + if (std::is_same::value) return "fs"; + if (std::is_same::value) return "ps"; + if (std::is_same::value) return "ns"; + if (std::is_same::value) return "µs"; + if (std::is_same::value) return "ms"; + if (std::is_same::value) return "cs"; + if (std::is_same::value) return "ds"; + if (std::is_same>::value) return "s"; + if (std::is_same::value) return "das"; + if (std::is_same::value) return "hs"; + if (std::is_same::value) return "ks"; + if (std::is_same::value) return "Ms"; + if (std::is_same::value) return "Gs"; + if (std::is_same::value) return "Ts"; + if (std::is_same::value) return "Ps"; + if (std::is_same::value) return "Es"; + if (std::is_same>::value) return "m"; + if (std::is_same>::value) return "h"; + return nullptr; +} + +enum class numeric_system { + standard, + // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale. + alternative +}; + +// Parses a put_time-like format string and invokes handler actions. +template +FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, + const Char* end, + Handler&& handler) { + auto ptr = begin; + while (ptr != end) { + auto c = *ptr; + if (c == '}') break; + if (c != '%') { + ++ptr; + continue; + } + if (begin != ptr) handler.on_text(begin, ptr); + ++ptr; // consume '%' + if (ptr == end) FMT_THROW(format_error("invalid format")); + c = *ptr++; + switch (c) { + case '%': + handler.on_text(ptr - 1, ptr); + break; + case 'n': { + const Char newline[] = {'\n'}; + handler.on_text(newline, newline + 1); + break; + } + case 't': { + const Char tab[] = {'\t'}; + handler.on_text(tab, tab + 1); + break; + } + // Year: + case 'Y': + handler.on_year(numeric_system::standard); + break; + case 'y': + handler.on_short_year(numeric_system::standard); + break; + case 'C': + handler.on_century(numeric_system::standard); + break; + case 'G': + handler.on_iso_week_based_year(); + break; + case 'g': + handler.on_iso_week_based_short_year(); + break; + // Day of the week: + case 'a': + handler.on_abbr_weekday(); + break; + case 'A': + handler.on_full_weekday(); + break; + case 'w': + handler.on_dec0_weekday(numeric_system::standard); + break; + case 'u': + handler.on_dec1_weekday(numeric_system::standard); + break; + // Month: + case 'b': + case 'h': + handler.on_abbr_month(); + break; + case 'B': + handler.on_full_month(); + break; + case 'm': + handler.on_dec_month(numeric_system::standard); + break; + // Day of the year/month: + case 'U': + handler.on_dec0_week_of_year(numeric_system::standard); + break; + case 'W': + handler.on_dec1_week_of_year(numeric_system::standard); + break; + case 'V': + handler.on_iso_week_of_year(numeric_system::standard); + break; + case 'j': + handler.on_day_of_year(); + break; + case 'd': + handler.on_day_of_month(numeric_system::standard); + break; + case 'e': + handler.on_day_of_month_space(numeric_system::standard); + break; + // Hour, minute, second: + case 'H': + handler.on_24_hour(numeric_system::standard); + break; + case 'I': + handler.on_12_hour(numeric_system::standard); + break; + case 'M': + handler.on_minute(numeric_system::standard); + break; + case 'S': + handler.on_second(numeric_system::standard); + break; + // Other: + case 'c': + handler.on_datetime(numeric_system::standard); + break; + case 'x': + handler.on_loc_date(numeric_system::standard); + break; + case 'X': + handler.on_loc_time(numeric_system::standard); + break; + case 'D': + handler.on_us_date(); + break; + case 'F': + handler.on_iso_date(); + break; + case 'r': + handler.on_12_hour_time(); + break; + case 'R': + handler.on_24_hour_time(); + break; + case 'T': + handler.on_iso_time(); + break; + case 'p': + handler.on_am_pm(); + break; + case 'Q': + handler.on_duration_value(); + break; + case 'q': + handler.on_duration_unit(); + break; + case 'z': + handler.on_utc_offset(); + break; + case 'Z': + handler.on_tz_name(); + break; + // Alternative representation: + case 'E': { + if (ptr == end) FMT_THROW(format_error("invalid format")); + c = *ptr++; + switch (c) { + case 'Y': + handler.on_year(numeric_system::alternative); + break; + case 'y': + handler.on_offset_year(); + break; + case 'C': + handler.on_century(numeric_system::alternative); + break; + case 'c': + handler.on_datetime(numeric_system::alternative); + break; + case 'x': + handler.on_loc_date(numeric_system::alternative); + break; + case 'X': + handler.on_loc_time(numeric_system::alternative); + break; + default: + FMT_THROW(format_error("invalid format")); + } + break; + } + case 'O': + if (ptr == end) FMT_THROW(format_error("invalid format")); + c = *ptr++; + switch (c) { + case 'y': + handler.on_short_year(numeric_system::alternative); + break; + case 'm': + handler.on_dec_month(numeric_system::alternative); + break; + case 'U': + handler.on_dec0_week_of_year(numeric_system::alternative); + break; + case 'W': + handler.on_dec1_week_of_year(numeric_system::alternative); + break; + case 'V': + handler.on_iso_week_of_year(numeric_system::alternative); + break; + case 'd': + handler.on_day_of_month(numeric_system::alternative); + break; + case 'e': + handler.on_day_of_month_space(numeric_system::alternative); + break; + case 'w': + handler.on_dec0_weekday(numeric_system::alternative); + break; + case 'u': + handler.on_dec1_weekday(numeric_system::alternative); + break; + case 'H': + handler.on_24_hour(numeric_system::alternative); + break; + case 'I': + handler.on_12_hour(numeric_system::alternative); + break; + case 'M': + handler.on_minute(numeric_system::alternative); + break; + case 'S': + handler.on_second(numeric_system::alternative); + break; + default: + FMT_THROW(format_error("invalid format")); + } + break; + default: + FMT_THROW(format_error("invalid format")); + } + begin = ptr; + } + if (begin != ptr) handler.on_text(begin, ptr); + return ptr; +} + +template struct null_chrono_spec_handler { + FMT_CONSTEXPR void unsupported() { + static_cast(this)->unsupported(); + } + FMT_CONSTEXPR void on_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_short_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_offset_year() { unsupported(); } + FMT_CONSTEXPR void on_century(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_iso_week_based_year() { unsupported(); } + FMT_CONSTEXPR void on_iso_week_based_short_year() { unsupported(); } + FMT_CONSTEXPR void on_abbr_weekday() { unsupported(); } + FMT_CONSTEXPR void on_full_weekday() { unsupported(); } + FMT_CONSTEXPR void on_dec0_weekday(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec1_weekday(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_abbr_month() { unsupported(); } + FMT_CONSTEXPR void on_full_month() { unsupported(); } + FMT_CONSTEXPR void on_dec_month(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_day_of_year() { unsupported(); } + FMT_CONSTEXPR void on_day_of_month(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_day_of_month_space(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_24_hour(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_12_hour(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_minute(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_second(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_datetime(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_loc_date(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_loc_time(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_us_date() { unsupported(); } + FMT_CONSTEXPR void on_iso_date() { unsupported(); } + FMT_CONSTEXPR void on_12_hour_time() { unsupported(); } + FMT_CONSTEXPR void on_24_hour_time() { unsupported(); } + FMT_CONSTEXPR void on_iso_time() { unsupported(); } + FMT_CONSTEXPR void on_am_pm() { unsupported(); } + FMT_CONSTEXPR void on_duration_value() { unsupported(); } + FMT_CONSTEXPR void on_duration_unit() { unsupported(); } + FMT_CONSTEXPR void on_utc_offset() { unsupported(); } + FMT_CONSTEXPR void on_tz_name() { unsupported(); } +}; + +struct tm_format_checker : null_chrono_spec_handler { + FMT_NORETURN void unsupported() { FMT_THROW(format_error("no format")); } + + template + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + FMT_CONSTEXPR void on_year(numeric_system) {} + FMT_CONSTEXPR void on_short_year(numeric_system) {} + FMT_CONSTEXPR void on_offset_year() {} + FMT_CONSTEXPR void on_century(numeric_system) {} + FMT_CONSTEXPR void on_iso_week_based_year() {} + FMT_CONSTEXPR void on_iso_week_based_short_year() {} + FMT_CONSTEXPR void on_abbr_weekday() {} + FMT_CONSTEXPR void on_full_weekday() {} + FMT_CONSTEXPR void on_dec0_weekday(numeric_system) {} + FMT_CONSTEXPR void on_dec1_weekday(numeric_system) {} + FMT_CONSTEXPR void on_abbr_month() {} + FMT_CONSTEXPR void on_full_month() {} + FMT_CONSTEXPR void on_dec_month(numeric_system) {} + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system) {} + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system) {} + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system) {} + FMT_CONSTEXPR void on_day_of_year() {} + FMT_CONSTEXPR void on_day_of_month(numeric_system) {} + FMT_CONSTEXPR void on_day_of_month_space(numeric_system) {} + FMT_CONSTEXPR void on_24_hour(numeric_system) {} + FMT_CONSTEXPR void on_12_hour(numeric_system) {} + FMT_CONSTEXPR void on_minute(numeric_system) {} + FMT_CONSTEXPR void on_second(numeric_system) {} + FMT_CONSTEXPR void on_datetime(numeric_system) {} + FMT_CONSTEXPR void on_loc_date(numeric_system) {} + FMT_CONSTEXPR void on_loc_time(numeric_system) {} + FMT_CONSTEXPR void on_us_date() {} + FMT_CONSTEXPR void on_iso_date() {} + FMT_CONSTEXPR void on_12_hour_time() {} + FMT_CONSTEXPR void on_24_hour_time() {} + FMT_CONSTEXPR void on_iso_time() {} + FMT_CONSTEXPR void on_am_pm() {} + FMT_CONSTEXPR void on_utc_offset() {} + FMT_CONSTEXPR void on_tz_name() {} +}; + +inline const char* tm_wday_full_name(int wday) { + static constexpr const char* full_name_list[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday"}; + return wday >= 0 && wday <= 6 ? full_name_list[wday] : "?"; +} +inline const char* tm_wday_short_name(int wday) { + static constexpr const char* short_name_list[] = {"Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat"}; + return wday >= 0 && wday <= 6 ? short_name_list[wday] : "???"; +} + +inline const char* tm_mon_full_name(int mon) { + static constexpr const char* full_name_list[] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"}; + return mon >= 0 && mon <= 11 ? full_name_list[mon] : "?"; +} +inline const char* tm_mon_short_name(int mon) { + static constexpr const char* short_name_list[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + }; + return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???"; +} + +template +struct has_member_data_tm_gmtoff : std::false_type {}; +template +struct has_member_data_tm_gmtoff> + : std::true_type {}; + +template +struct has_member_data_tm_zone : std::false_type {}; +template +struct has_member_data_tm_zone> + : std::true_type {}; + +#if FMT_USE_TZSET +inline void tzset_once() { + static bool init = []() -> bool { + _tzset(); + return true; + }(); + ignore_unused(init); +} +#endif + +template class tm_writer { + private: + static constexpr int days_per_week = 7; + + const std::locale& loc_; + const bool is_classic_; + OutputIt out_; + const std::tm& tm_; + + auto tm_sec() const noexcept -> int { + FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61, ""); + return tm_.tm_sec; + } + auto tm_min() const noexcept -> int { + FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59, ""); + return tm_.tm_min; + } + auto tm_hour() const noexcept -> int { + FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23, ""); + return tm_.tm_hour; + } + auto tm_mday() const noexcept -> int { + FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31, ""); + return tm_.tm_mday; + } + auto tm_mon() const noexcept -> int { + FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11, ""); + return tm_.tm_mon; + } + auto tm_year() const noexcept -> long long { return 1900ll + tm_.tm_year; } + auto tm_wday() const noexcept -> int { + FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6, ""); + return tm_.tm_wday; + } + auto tm_yday() const noexcept -> int { + FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365, ""); + return tm_.tm_yday; + } + + auto tm_hour12() const noexcept -> int { + const auto h = tm_hour(); + const auto z = h < 12 ? h : h - 12; + return z == 0 ? 12 : z; + } + + // POSIX and the C Standard are unclear or inconsistent about what %C and %y + // do if the year is negative or exceeds 9999. Use the convention that %C + // concatenated with %y yields the same output as %Y, and that %Y contains at + // least 4 characters, with more only if necessary. + auto split_year_lower(long long year) const noexcept -> int { + auto l = year % 100; + if (l < 0) l = -l; // l in [0, 99] + return static_cast(l); + } + + // Algorithm: + // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_from_a_month_and_day_of_the_month_or_ordinal_date + auto iso_year_weeks(long long curr_year) const noexcept -> int { + const auto prev_year = curr_year - 1; + const auto curr_p = + (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) % + days_per_week; + const auto prev_p = + (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) % + days_per_week; + return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0); + } + auto iso_week_num(int tm_yday, int tm_wday) const noexcept -> int { + return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) / + days_per_week; + } + auto tm_iso_week_year() const noexcept -> long long { + const auto year = tm_year(); + const auto w = iso_week_num(tm_yday(), tm_wday()); + if (w < 1) return year - 1; + if (w > iso_year_weeks(year)) return year + 1; + return year; + } + auto tm_iso_week_of_year() const noexcept -> int { + const auto year = tm_year(); + const auto w = iso_week_num(tm_yday(), tm_wday()); + if (w < 1) return iso_year_weeks(year - 1); + if (w > iso_year_weeks(year)) return 1; + return w; + } + + void write1(int value) { + *out_++ = static_cast('0' + to_unsigned(value) % 10); + } + void write2(int value) { + const char* d = digits2(to_unsigned(value) % 100); + *out_++ = *d++; + *out_++ = *d; + } + + void write_year_extended(long long year) { + // At least 4 characters. + int width = 4; + if (year < 0) { + *out_++ = '-'; + year = 0 - year; + --width; + } + uint32_or_64_or_128_t n = to_unsigned(year); + const int num_digits = count_digits(n); + if (width > num_digits) out_ = std::fill_n(out_, width - num_digits, '0'); + out_ = format_decimal(out_, n, num_digits).end; + } + void write_year(long long year) { + if (year >= 0 && year < 10000) { + write2(static_cast(year / 100)); + write2(static_cast(year % 100)); + } else { + write_year_extended(year); + } + } + + void write_utc_offset(long offset) { + if (offset < 0) { + *out_++ = '-'; + offset = -offset; + } else { + *out_++ = '+'; + } + offset /= 60; + write2(static_cast(offset / 60)); + write2(static_cast(offset % 60)); + } + template ::value)> + void format_utc_offset_impl(const T& tm) { + write_utc_offset(tm.tm_gmtoff); + } + template ::value)> + void format_utc_offset_impl(const T& tm) { +#if defined(_WIN32) && defined(_UCRT) +# if FMT_USE_TZSET + tzset_once(); +# endif + long offset = 0; + _get_timezone(&offset); + if (tm.tm_isdst) { + long dstbias = 0; + _get_dstbias(&dstbias); + offset += dstbias; + } + write_utc_offset(-offset); +#else + ignore_unused(tm); + format_localized('z'); +#endif + } + + template ::value)> + void format_tz_name_impl(const T& tm) { + if (is_classic_) + out_ = write_tm_str(out_, tm.tm_zone, loc_); + else + format_localized('Z'); + } + template ::value)> + void format_tz_name_impl(const T&) { + format_localized('Z'); + } + + void format_localized(char format, char modifier = 0) { + out_ = write(out_, tm_, loc_, format, modifier); + } + + public: + tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm) + : loc_(loc), + is_classic_(loc_ == get_classic_locale()), + out_(out), + tm_(tm) {} + + OutputIt out() const { return out_; } + + FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { + out_ = copy_str(begin, end, out_); + } + + void on_abbr_weekday() { + if (is_classic_) + out_ = write(out_, tm_wday_short_name(tm_wday())); + else + format_localized('a'); + } + void on_full_weekday() { + if (is_classic_) + out_ = write(out_, tm_wday_full_name(tm_wday())); + else + format_localized('A'); + } + void on_dec0_weekday(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write1(tm_wday()); + format_localized('w', 'O'); + } + void on_dec1_weekday(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto wday = tm_wday(); + write1(wday == 0 ? days_per_week : wday); + } else { + format_localized('u', 'O'); + } + } + + void on_abbr_month() { + if (is_classic_) + out_ = write(out_, tm_mon_short_name(tm_mon())); + else + format_localized('b'); + } + void on_full_month() { + if (is_classic_) + out_ = write(out_, tm_mon_full_name(tm_mon())); + else + format_localized('B'); + } + + void on_datetime(numeric_system ns) { + if (is_classic_) { + on_abbr_weekday(); + *out_++ = ' '; + on_abbr_month(); + *out_++ = ' '; + on_day_of_month_space(numeric_system::standard); + *out_++ = ' '; + on_iso_time(); + *out_++ = ' '; + on_year(numeric_system::standard); + } else { + format_localized('c', ns == numeric_system::standard ? '\0' : 'E'); + } + } + void on_loc_date(numeric_system ns) { + if (is_classic_) + on_us_date(); + else + format_localized('x', ns == numeric_system::standard ? '\0' : 'E'); + } + void on_loc_time(numeric_system ns) { + if (is_classic_) + on_iso_time(); + else + format_localized('X', ns == numeric_system::standard ? '\0' : 'E'); + } + void on_us_date() { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_mon() + 1), + to_unsigned(tm_mday()), + to_unsigned(split_year_lower(tm_year())), '/'); + out_ = copy_str(std::begin(buf), std::end(buf), out_); + } + void on_iso_date() { + auto year = tm_year(); + char buf[10]; + size_t offset = 0; + if (year >= 0 && year < 10000) { + copy2(buf, digits2(to_unsigned(year / 100))); + } else { + offset = 4; + write_year_extended(year); + year = 0; + } + write_digit2_separated(buf + 2, static_cast(year % 100), + to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()), + '-'); + out_ = copy_str(std::begin(buf) + offset, std::end(buf), out_); + } + + void on_utc_offset() { format_utc_offset_impl(tm_); } + void on_tz_name() { format_tz_name_impl(tm_); } + + void on_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write_year(tm_year()); + format_localized('Y', 'E'); + } + void on_short_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(split_year_lower(tm_year())); + format_localized('y', 'O'); + } + void on_offset_year() { + if (is_classic_) return write2(split_year_lower(tm_year())); + format_localized('y', 'E'); + } + + void on_century(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto year = tm_year(); + auto upper = year / 100; + if (year >= -99 && year < 0) { + // Zero upper on negative year. + *out_++ = '-'; + *out_++ = '0'; + } else if (upper >= 0 && upper < 100) { + write2(static_cast(upper)); + } else { + out_ = write(out_, upper); + } + } else { + format_localized('C', 'E'); + } + } + + void on_dec_month(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_mon() + 1); + format_localized('m', 'O'); + } + + void on_dec0_week_of_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week); + format_localized('U', 'O'); + } + void on_dec1_week_of_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto wday = tm_wday(); + write2((tm_yday() + days_per_week - + (wday == 0 ? (days_per_week - 1) : (wday - 1))) / + days_per_week); + } else { + format_localized('W', 'O'); + } + } + void on_iso_week_of_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_iso_week_of_year()); + format_localized('V', 'O'); + } + + void on_iso_week_based_year() { write_year(tm_iso_week_year()); } + void on_iso_week_based_short_year() { + write2(split_year_lower(tm_iso_week_year())); + } + + void on_day_of_year() { + auto yday = tm_yday() + 1; + write1(yday / 100); + write2(yday % 100); + } + void on_day_of_month(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write2(tm_mday()); + format_localized('d', 'O'); + } + void on_day_of_month_space(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto mday = to_unsigned(tm_mday()) % 100; + const char* d2 = digits2(mday); + *out_++ = mday < 10 ? ' ' : d2[0]; + *out_++ = d2[1]; + } else { + format_localized('e', 'O'); + } + } + + void on_24_hour(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write2(tm_hour()); + format_localized('H', 'O'); + } + void on_12_hour(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_hour12()); + format_localized('I', 'O'); + } + void on_minute(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write2(tm_min()); + format_localized('M', 'O'); + } + void on_second(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write2(tm_sec()); + format_localized('S', 'O'); + } + + void on_12_hour_time() { + if (is_classic_) { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_hour12()), + to_unsigned(tm_min()), to_unsigned(tm_sec()), ':'); + out_ = copy_str(std::begin(buf), std::end(buf), out_); + *out_++ = ' '; + on_am_pm(); + } else { + format_localized('r'); + } + } + void on_24_hour_time() { + write2(tm_hour()); + *out_++ = ':'; + write2(tm_min()); + } + void on_iso_time() { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_hour()), to_unsigned(tm_min()), + to_unsigned(tm_sec()), ':'); + out_ = copy_str(std::begin(buf), std::end(buf), out_); + } + + void on_am_pm() { + if (is_classic_) { + *out_++ = tm_hour() < 12 ? 'A' : 'P'; + *out_++ = 'M'; + } else { + format_localized('p'); + } + } + + // These apply to chrono durations but not tm. + void on_duration_value() {} + void on_duration_unit() {} +}; + +struct chrono_format_checker : null_chrono_spec_handler { + FMT_NORETURN void unsupported() { FMT_THROW(format_error("no date")); } + + template + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + FMT_CONSTEXPR void on_24_hour(numeric_system) {} + FMT_CONSTEXPR void on_12_hour(numeric_system) {} + FMT_CONSTEXPR void on_minute(numeric_system) {} + FMT_CONSTEXPR void on_second(numeric_system) {} + FMT_CONSTEXPR void on_12_hour_time() {} + FMT_CONSTEXPR void on_24_hour_time() {} + FMT_CONSTEXPR void on_iso_time() {} + FMT_CONSTEXPR void on_am_pm() {} + FMT_CONSTEXPR void on_duration_value() {} + FMT_CONSTEXPR void on_duration_unit() {} +}; + +template ::value)> +inline bool isnan(T) { + return false; +} +template ::value)> +inline bool isnan(T value) { + return std::isnan(value); +} + +template ::value)> +inline bool isfinite(T) { + return true; +} + +// Converts value to Int and checks that it's in the range [0, upper). +template ::value)> +inline Int to_nonnegative_int(T value, Int upper) { + FMT_ASSERT(value >= 0 && to_unsigned(value) <= to_unsigned(upper), + "invalid value"); + (void)upper; + return static_cast(value); +} +template ::value)> +inline Int to_nonnegative_int(T value, Int upper) { + if (value < 0 || value > static_cast(upper)) + FMT_THROW(format_error("invalid value")); + return static_cast(value); +} + +template ::value)> +inline T mod(T x, int y) { + return x % static_cast(y); +} +template ::value)> +inline T mod(T x, int y) { + return std::fmod(x, static_cast(y)); +} + +// If T is an integral type, maps T to its unsigned counterpart, otherwise +// leaves it unchanged (unlike std::make_unsigned). +template ::value> +struct make_unsigned_or_unchanged { + using type = T; +}; + +template struct make_unsigned_or_unchanged { + using type = typename std::make_unsigned::type; +}; + +#if FMT_SAFE_DURATION_CAST +// throwing version of safe_duration_cast +template +To fmt_safe_duration_cast(std::chrono::duration from) { + int ec; + To to = safe_duration_cast::safe_duration_cast(from, ec); + if (ec) FMT_THROW(format_error("cannot format duration")); + return to; +} +#endif + +template ::value)> +inline std::chrono::duration get_milliseconds( + std::chrono::duration d) { + // this may overflow and/or the result may not fit in the + // target type. +#if FMT_SAFE_DURATION_CAST + using CommonSecondsType = + typename std::common_type::type; + const auto d_as_common = fmt_safe_duration_cast(d); + const auto d_as_whole_seconds = + fmt_safe_duration_cast(d_as_common); + // this conversion should be nonproblematic + const auto diff = d_as_common - d_as_whole_seconds; + const auto ms = + fmt_safe_duration_cast>(diff); + return ms; +#else + auto s = std::chrono::duration_cast(d); + return std::chrono::duration_cast(d - s); +#endif +} + +// Returns the number of fractional digits in the range [0, 18] according to the +// C++20 spec. If more than 18 fractional digits are required then returns 6 for +// microseconds precision. +constexpr int count_fractional_digits(long long num, long long den, int n = 0) { + return num % den == 0 + ? n + : (n > 18 ? 6 : count_fractional_digits(num * 10, den, n + 1)); +} + +constexpr long long pow10(std::uint32_t n) { + return n == 0 ? 1 : 10 * pow10(n - 1); +} + +template ::is_signed)> +constexpr std::chrono::duration abs( + std::chrono::duration d) { + // We need to compare the duration using the count() method directly + // due to a compiler bug in clang-11 regarding the spaceship operator, + // when -Wzero-as-null-pointer-constant is enabled. + // In clang-12 the bug has been fixed. See + // https://bugs.llvm.org/show_bug.cgi?id=46235 and the reproducible example: + // https://www.godbolt.org/z/Knbb5joYx. + return d.count() >= d.zero().count() ? d : -d; +} + +template ::is_signed)> +constexpr std::chrono::duration abs( + std::chrono::duration d) { + return d; +} + +template ::value)> +OutputIt format_duration_value(OutputIt out, Rep val, int) { + return write(out, val); +} + +template ::value)> +OutputIt format_duration_value(OutputIt out, Rep val, int precision) { + auto specs = basic_format_specs(); + specs.precision = precision; + specs.type = precision >= 0 ? presentation_type::fixed_lower + : presentation_type::general_lower; + return write(out, val, specs); +} + +template +OutputIt copy_unit(string_view unit, OutputIt out, Char) { + return std::copy(unit.begin(), unit.end(), out); +} + +template +OutputIt copy_unit(string_view unit, OutputIt out, wchar_t) { + // This works when wchar_t is UTF-32 because units only contain characters + // that have the same representation in UTF-16 and UTF-32. + utf8_to_utf16 u(unit); + return std::copy(u.c_str(), u.c_str() + u.size(), out); +} + +template +OutputIt format_duration_unit(OutputIt out) { + if (const char* unit = get_units()) + return copy_unit(string_view(unit), out, Char()); + *out++ = '['; + out = write(out, Period::num); + if (const_check(Period::den != 1)) { + *out++ = '/'; + out = write(out, Period::den); + } + *out++ = ']'; + *out++ = 's'; + return out; +} + +class get_locale { + private: + union { + std::locale locale_; + }; + bool has_locale_ = false; + + public: + get_locale(bool localized, locale_ref loc) : has_locale_(localized) { + if (localized) + ::new (&locale_) std::locale(loc.template get()); + } + ~get_locale() { + if (has_locale_) locale_.~locale(); + } + operator const std::locale&() const { + return has_locale_ ? locale_ : get_classic_locale(); + } +}; + +template +struct chrono_formatter { + FormatContext& context; + OutputIt out; + int precision; + bool localized = false; + // rep is unsigned to avoid overflow. + using rep = + conditional_t::value && sizeof(Rep) < sizeof(int), + unsigned, typename make_unsigned_or_unchanged::type>; + rep val; + using seconds = std::chrono::duration; + seconds s; + using milliseconds = std::chrono::duration; + bool negative; + + using char_type = typename FormatContext::char_type; + using tm_writer_type = tm_writer; + + chrono_formatter(FormatContext& ctx, OutputIt o, + std::chrono::duration d) + : context(ctx), + out(o), + val(static_cast(d.count())), + negative(false) { + if (d.count() < 0) { + val = 0 - val; + negative = true; + } + + // this may overflow and/or the result may not fit in the + // target type. +#if FMT_SAFE_DURATION_CAST + // might need checked conversion (rep!=Rep) + auto tmpval = std::chrono::duration(val); + s = fmt_safe_duration_cast(tmpval); +#else + s = std::chrono::duration_cast( + std::chrono::duration(val)); +#endif + } + + // returns true if nan or inf, writes to out. + bool handle_nan_inf() { + if (isfinite(val)) { + return false; + } + if (isnan(val)) { + write_nan(); + return true; + } + // must be +-inf + if (val > 0) { + write_pinf(); + } else { + write_ninf(); + } + return true; + } + + Rep hour() const { return static_cast(mod((s.count() / 3600), 24)); } + + Rep hour12() const { + Rep hour = static_cast(mod((s.count() / 3600), 12)); + return hour <= 0 ? 12 : hour; + } + + Rep minute() const { return static_cast(mod((s.count() / 60), 60)); } + Rep second() const { return static_cast(mod(s.count(), 60)); } + + std::tm time() const { + auto time = std::tm(); + time.tm_hour = to_nonnegative_int(hour(), 24); + time.tm_min = to_nonnegative_int(minute(), 60); + time.tm_sec = to_nonnegative_int(second(), 60); + return time; + } + + void write_sign() { + if (negative) { + *out++ = '-'; + negative = false; + } + } + + void write(Rep value, int width) { + write_sign(); + if (isnan(value)) return write_nan(); + uint32_or_64_or_128_t n = + to_unsigned(to_nonnegative_int(value, max_value())); + int num_digits = detail::count_digits(n); + if (width > num_digits) out = std::fill_n(out, width - num_digits, '0'); + out = format_decimal(out, n, num_digits).end; + } + + template void write_fractional_seconds(Duration d) { + constexpr auto num_fractional_digits = + count_fractional_digits(Duration::period::num, Duration::period::den); + + using subsecond_precision = std::chrono::duration< + typename std::common_type::type, + std::ratio<1, detail::pow10(num_fractional_digits)>>; + if (std::ratio_less::value) { + *out++ = '.'; + // Don't convert long double to integer seconds to avoid overflow. + using sec = conditional_t< + std::is_same::value, + std::chrono::duration, std::chrono::seconds>; + auto fractional = detail::abs(d) - std::chrono::duration_cast(d); + const auto subseconds = + std::chrono::treat_as_floating_point< + typename subsecond_precision::rep>::value + ? fractional.count() + : std::chrono::duration_cast(fractional) + .count(); + uint32_or_64_or_128_t n = + to_unsigned(to_nonnegative_int(subseconds, max_value())); + int num_digits = detail::count_digits(n); + if (num_fractional_digits > num_digits) + out = std::fill_n(out, num_fractional_digits - num_digits, '0'); + out = format_decimal(out, n, num_digits).end; + } + } + + void write_nan() { std::copy_n("nan", 3, out); } + void write_pinf() { std::copy_n("inf", 3, out); } + void write_ninf() { std::copy_n("-inf", 4, out); } + + template + void format_tm(const tm& time, Callback cb, Args... args) { + if (isnan(val)) return write_nan(); + get_locale loc(localized, context.locale()); + auto w = tm_writer_type(loc, out, time); + (w.*cb)(args...); + out = w.out(); + } + + void on_text(const char_type* begin, const char_type* end) { + std::copy(begin, end, out); + } + + // These are not implemented because durations don't have date information. + void on_abbr_weekday() {} + void on_full_weekday() {} + void on_dec0_weekday(numeric_system) {} + void on_dec1_weekday(numeric_system) {} + void on_abbr_month() {} + void on_full_month() {} + void on_datetime(numeric_system) {} + void on_loc_date(numeric_system) {} + void on_loc_time(numeric_system) {} + void on_us_date() {} + void on_iso_date() {} + void on_utc_offset() {} + void on_tz_name() {} + void on_year(numeric_system) {} + void on_short_year(numeric_system) {} + void on_offset_year() {} + void on_century(numeric_system) {} + void on_iso_week_based_year() {} + void on_iso_week_based_short_year() {} + void on_dec_month(numeric_system) {} + void on_dec0_week_of_year(numeric_system) {} + void on_dec1_week_of_year(numeric_system) {} + void on_iso_week_of_year(numeric_system) {} + void on_day_of_year() {} + void on_day_of_month(numeric_system) {} + void on_day_of_month_space(numeric_system) {} + + void on_24_hour(numeric_system ns) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) return write(hour(), 2); + auto time = tm(); + time.tm_hour = to_nonnegative_int(hour(), 24); + format_tm(time, &tm_writer_type::on_24_hour, ns); + } + + void on_12_hour(numeric_system ns) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) return write(hour12(), 2); + auto time = tm(); + time.tm_hour = to_nonnegative_int(hour12(), 12); + format_tm(time, &tm_writer_type::on_12_hour, ns); + } + + void on_minute(numeric_system ns) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) return write(minute(), 2); + auto time = tm(); + time.tm_min = to_nonnegative_int(minute(), 60); + format_tm(time, &tm_writer_type::on_minute, ns); + } + + void on_second(numeric_system ns) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) { + write(second(), 2); + write_fractional_seconds(std::chrono::duration{val}); + return; + } + auto time = tm(); + time.tm_sec = to_nonnegative_int(second(), 60); + format_tm(time, &tm_writer_type::on_second, ns); + } + + void on_12_hour_time() { + if (handle_nan_inf()) return; + format_tm(time(), &tm_writer_type::on_12_hour_time); + } + + void on_24_hour_time() { + if (handle_nan_inf()) { + *out++ = ':'; + handle_nan_inf(); + return; + } + + write(hour(), 2); + *out++ = ':'; + write(minute(), 2); + } + + void on_iso_time() { + on_24_hour_time(); + *out++ = ':'; + if (handle_nan_inf()) return; + on_second(numeric_system::standard); + } + + void on_am_pm() { + if (handle_nan_inf()) return; + format_tm(time(), &tm_writer_type::on_am_pm); + } + + void on_duration_value() { + if (handle_nan_inf()) return; + write_sign(); + out = format_duration_value(out, val, precision); + } + + void on_duration_unit() { + out = format_duration_unit(out); + } +}; + +FMT_END_DETAIL_NAMESPACE + +#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907 +using weekday = std::chrono::weekday; +#else +// A fallback version of weekday. +class weekday { + private: + unsigned char value; + + public: + weekday() = default; + explicit constexpr weekday(unsigned wd) noexcept + : value(static_cast(wd != 7 ? wd : 0)) {} + constexpr unsigned c_encoding() const noexcept { return value; } +}; + +class year_month_day {}; +#endif + +// A rudimentary weekday formatter. +template struct formatter { + private: + bool localized = false; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto begin = ctx.begin(), end = ctx.end(); + if (begin != end && *begin == 'L') { + ++begin; + localized = true; + } + return begin; + } + + template + auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_wday = static_cast(wd.c_encoding()); + detail::get_locale loc(localized, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_abbr_weekday(); + return w.out(); + } +}; + +template +struct formatter, Char> { + private: + basic_format_specs specs; + int precision = -1; + using arg_ref_type = detail::arg_ref; + arg_ref_type width_ref; + arg_ref_type precision_ref; + bool localized = false; + basic_string_view format_str; + using duration = std::chrono::duration; + + struct spec_handler { + formatter& f; + basic_format_parse_context& context; + basic_string_view format_str; + + template FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) { + context.check_arg_id(arg_id); + return arg_ref_type(arg_id); + } + + FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view arg_id) { + context.check_arg_id(arg_id); + return arg_ref_type(arg_id); + } + + FMT_CONSTEXPR arg_ref_type make_arg_ref(detail::auto_id) { + return arg_ref_type(context.next_arg_id()); + } + + void on_error(const char* msg) { FMT_THROW(format_error(msg)); } + FMT_CONSTEXPR void on_fill(basic_string_view fill) { + f.specs.fill = fill; + } + FMT_CONSTEXPR void on_align(align_t align) { f.specs.align = align; } + FMT_CONSTEXPR void on_width(int width) { f.specs.width = width; } + FMT_CONSTEXPR void on_precision(int _precision) { + f.precision = _precision; + } + FMT_CONSTEXPR void end_precision() {} + + template FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { + f.width_ref = make_arg_ref(arg_id); + } + + template FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) { + f.precision_ref = make_arg_ref(arg_id); + } + }; + + using iterator = typename basic_format_parse_context::iterator; + struct parse_range { + iterator begin; + iterator end; + }; + + FMT_CONSTEXPR parse_range do_parse(basic_format_parse_context& ctx) { + auto begin = ctx.begin(), end = ctx.end(); + if (begin == end || *begin == '}') return {begin, begin}; + spec_handler handler{*this, ctx, format_str}; + begin = detail::parse_align(begin, end, handler); + if (begin == end) return {begin, begin}; + begin = detail::parse_width(begin, end, handler); + if (begin == end) return {begin, begin}; + if (*begin == '.') { + if (std::is_floating_point::value) + begin = detail::parse_precision(begin, end, handler); + else + handler.on_error("precision not allowed for this argument type"); + } + if (begin != end && *begin == 'L') { + ++begin; + localized = true; + } + end = detail::parse_chrono_format(begin, end, + detail::chrono_format_checker()); + return {begin, end}; + } + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto range = do_parse(ctx); + format_str = basic_string_view( + &*range.begin, detail::to_unsigned(range.end - range.begin)); + return range.end; + } + + template + auto format(const duration& d, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto specs_copy = specs; + auto precision_copy = precision; + auto begin = format_str.begin(), end = format_str.end(); + // As a possible future optimization, we could avoid extra copying if width + // is not specified. + basic_memory_buffer buf; + auto out = std::back_inserter(buf); + detail::handle_dynamic_spec(specs_copy.width, + width_ref, ctx); + detail::handle_dynamic_spec(precision_copy, + precision_ref, ctx); + if (begin == end || *begin == '}') { + out = detail::format_duration_value(out, d.count(), precision_copy); + detail::format_duration_unit(out); + } else { + detail::chrono_formatter f( + ctx, out, d); + f.precision = precision_copy; + f.localized = localized; + detail::parse_chrono_format(begin, end, f); + } + return detail::write( + ctx.out(), basic_string_view(buf.data(), buf.size()), specs_copy); + } +}; + +template +struct formatter, + Char> : formatter { + FMT_CONSTEXPR formatter() { + this->do_parse(default_specs, + default_specs + sizeof(default_specs) / sizeof(Char)); + } + + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return this->do_parse(ctx.begin(), ctx.end(), true); + } + + template + auto format(std::chrono::time_point val, + FormatContext& ctx) const -> decltype(ctx.out()) { + return formatter::format(localtime(val), ctx); + } + + static constexpr const Char default_specs[] = {'%', 'F', ' ', '%', 'T'}; +}; + +template +constexpr const Char + formatter, + Char>::default_specs[]; + +template struct formatter { + private: + enum class spec { + unknown, + year_month_day, + hh_mm_ss, + }; + spec spec_ = spec::unknown; + basic_string_view specs; + + protected: + template + FMT_CONSTEXPR auto do_parse(It begin, It end, bool with_default = false) + -> It { + if (begin != end && *begin == ':') ++begin; + end = detail::parse_chrono_format(begin, end, detail::tm_format_checker()); + if (!with_default || end != begin) + specs = {begin, detail::to_unsigned(end - begin)}; + // basic_string_view<>::compare isn't constexpr before C++17. + if (specs.size() == 2 && specs[0] == Char('%')) { + if (specs[1] == Char('F')) + spec_ = spec::year_month_day; + else if (specs[1] == Char('T')) + spec_ = spec::hh_mm_ss; + } + return end; + } + + public: + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return this->do_parse(ctx.begin(), ctx.end()); + } + + template + auto format(const std::tm& tm, FormatContext& ctx) const + -> decltype(ctx.out()) { + const auto loc_ref = ctx.locale(); + detail::get_locale loc(static_cast(loc_ref), loc_ref); + auto w = detail::tm_writer(loc, ctx.out(), tm); + if (spec_ == spec::year_month_day) + w.on_iso_date(); + else if (spec_ == spec::hh_mm_ss) + w.on_iso_time(); + else + detail::parse_chrono_format(specs.begin(), specs.end(), w); + return w.out(); + } +}; + +FMT_MODULE_EXPORT_END +FMT_END_NAMESPACE + +#endif // FMT_CHRONO_H_ diff --git a/ctrtool/deps/libfmt/include/fmt/color.h b/ctrtool/deps/libfmt/include/fmt/color.h new file mode 100644 index 0000000..dfbe482 --- /dev/null +++ b/ctrtool/deps/libfmt/include/fmt/color.h @@ -0,0 +1,638 @@ +// Formatting library for C++ - color support +// +// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_COLOR_H_ +#define FMT_COLOR_H_ + +#include "format.h" + +// __declspec(deprecated) is broken in some MSVC versions. +#if FMT_MSC_VER +# define FMT_DEPRECATED_NONMSVC +#else +# define FMT_DEPRECATED_NONMSVC FMT_DEPRECATED +#endif + +FMT_BEGIN_NAMESPACE +FMT_MODULE_EXPORT_BEGIN + +enum class color : uint32_t { + alice_blue = 0xF0F8FF, // rgb(240,248,255) + antique_white = 0xFAEBD7, // rgb(250,235,215) + aqua = 0x00FFFF, // rgb(0,255,255) + aquamarine = 0x7FFFD4, // rgb(127,255,212) + azure = 0xF0FFFF, // rgb(240,255,255) + beige = 0xF5F5DC, // rgb(245,245,220) + bisque = 0xFFE4C4, // rgb(255,228,196) + black = 0x000000, // rgb(0,0,0) + blanched_almond = 0xFFEBCD, // rgb(255,235,205) + blue = 0x0000FF, // rgb(0,0,255) + blue_violet = 0x8A2BE2, // rgb(138,43,226) + brown = 0xA52A2A, // rgb(165,42,42) + burly_wood = 0xDEB887, // rgb(222,184,135) + cadet_blue = 0x5F9EA0, // rgb(95,158,160) + chartreuse = 0x7FFF00, // rgb(127,255,0) + chocolate = 0xD2691E, // rgb(210,105,30) + coral = 0xFF7F50, // rgb(255,127,80) + cornflower_blue = 0x6495ED, // rgb(100,149,237) + cornsilk = 0xFFF8DC, // rgb(255,248,220) + crimson = 0xDC143C, // rgb(220,20,60) + cyan = 0x00FFFF, // rgb(0,255,255) + dark_blue = 0x00008B, // rgb(0,0,139) + dark_cyan = 0x008B8B, // rgb(0,139,139) + dark_golden_rod = 0xB8860B, // rgb(184,134,11) + dark_gray = 0xA9A9A9, // rgb(169,169,169) + dark_green = 0x006400, // rgb(0,100,0) + dark_khaki = 0xBDB76B, // rgb(189,183,107) + dark_magenta = 0x8B008B, // rgb(139,0,139) + dark_olive_green = 0x556B2F, // rgb(85,107,47) + dark_orange = 0xFF8C00, // rgb(255,140,0) + dark_orchid = 0x9932CC, // rgb(153,50,204) + dark_red = 0x8B0000, // rgb(139,0,0) + dark_salmon = 0xE9967A, // rgb(233,150,122) + dark_sea_green = 0x8FBC8F, // rgb(143,188,143) + dark_slate_blue = 0x483D8B, // rgb(72,61,139) + dark_slate_gray = 0x2F4F4F, // rgb(47,79,79) + dark_turquoise = 0x00CED1, // rgb(0,206,209) + dark_violet = 0x9400D3, // rgb(148,0,211) + deep_pink = 0xFF1493, // rgb(255,20,147) + deep_sky_blue = 0x00BFFF, // rgb(0,191,255) + dim_gray = 0x696969, // rgb(105,105,105) + dodger_blue = 0x1E90FF, // rgb(30,144,255) + fire_brick = 0xB22222, // rgb(178,34,34) + floral_white = 0xFFFAF0, // rgb(255,250,240) + forest_green = 0x228B22, // rgb(34,139,34) + fuchsia = 0xFF00FF, // rgb(255,0,255) + gainsboro = 0xDCDCDC, // rgb(220,220,220) + ghost_white = 0xF8F8FF, // rgb(248,248,255) + gold = 0xFFD700, // rgb(255,215,0) + golden_rod = 0xDAA520, // rgb(218,165,32) + gray = 0x808080, // rgb(128,128,128) + green = 0x008000, // rgb(0,128,0) + green_yellow = 0xADFF2F, // rgb(173,255,47) + honey_dew = 0xF0FFF0, // rgb(240,255,240) + hot_pink = 0xFF69B4, // rgb(255,105,180) + indian_red = 0xCD5C5C, // rgb(205,92,92) + indigo = 0x4B0082, // rgb(75,0,130) + ivory = 0xFFFFF0, // rgb(255,255,240) + khaki = 0xF0E68C, // rgb(240,230,140) + lavender = 0xE6E6FA, // rgb(230,230,250) + lavender_blush = 0xFFF0F5, // rgb(255,240,245) + lawn_green = 0x7CFC00, // rgb(124,252,0) + lemon_chiffon = 0xFFFACD, // rgb(255,250,205) + light_blue = 0xADD8E6, // rgb(173,216,230) + light_coral = 0xF08080, // rgb(240,128,128) + light_cyan = 0xE0FFFF, // rgb(224,255,255) + light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210) + light_gray = 0xD3D3D3, // rgb(211,211,211) + light_green = 0x90EE90, // rgb(144,238,144) + light_pink = 0xFFB6C1, // rgb(255,182,193) + light_salmon = 0xFFA07A, // rgb(255,160,122) + light_sea_green = 0x20B2AA, // rgb(32,178,170) + light_sky_blue = 0x87CEFA, // rgb(135,206,250) + light_slate_gray = 0x778899, // rgb(119,136,153) + light_steel_blue = 0xB0C4DE, // rgb(176,196,222) + light_yellow = 0xFFFFE0, // rgb(255,255,224) + lime = 0x00FF00, // rgb(0,255,0) + lime_green = 0x32CD32, // rgb(50,205,50) + linen = 0xFAF0E6, // rgb(250,240,230) + magenta = 0xFF00FF, // rgb(255,0,255) + maroon = 0x800000, // rgb(128,0,0) + medium_aquamarine = 0x66CDAA, // rgb(102,205,170) + medium_blue = 0x0000CD, // rgb(0,0,205) + medium_orchid = 0xBA55D3, // rgb(186,85,211) + medium_purple = 0x9370DB, // rgb(147,112,219) + medium_sea_green = 0x3CB371, // rgb(60,179,113) + medium_slate_blue = 0x7B68EE, // rgb(123,104,238) + medium_spring_green = 0x00FA9A, // rgb(0,250,154) + medium_turquoise = 0x48D1CC, // rgb(72,209,204) + medium_violet_red = 0xC71585, // rgb(199,21,133) + midnight_blue = 0x191970, // rgb(25,25,112) + mint_cream = 0xF5FFFA, // rgb(245,255,250) + misty_rose = 0xFFE4E1, // rgb(255,228,225) + moccasin = 0xFFE4B5, // rgb(255,228,181) + navajo_white = 0xFFDEAD, // rgb(255,222,173) + navy = 0x000080, // rgb(0,0,128) + old_lace = 0xFDF5E6, // rgb(253,245,230) + olive = 0x808000, // rgb(128,128,0) + olive_drab = 0x6B8E23, // rgb(107,142,35) + orange = 0xFFA500, // rgb(255,165,0) + orange_red = 0xFF4500, // rgb(255,69,0) + orchid = 0xDA70D6, // rgb(218,112,214) + pale_golden_rod = 0xEEE8AA, // rgb(238,232,170) + pale_green = 0x98FB98, // rgb(152,251,152) + pale_turquoise = 0xAFEEEE, // rgb(175,238,238) + pale_violet_red = 0xDB7093, // rgb(219,112,147) + papaya_whip = 0xFFEFD5, // rgb(255,239,213) + peach_puff = 0xFFDAB9, // rgb(255,218,185) + peru = 0xCD853F, // rgb(205,133,63) + pink = 0xFFC0CB, // rgb(255,192,203) + plum = 0xDDA0DD, // rgb(221,160,221) + powder_blue = 0xB0E0E6, // rgb(176,224,230) + purple = 0x800080, // rgb(128,0,128) + rebecca_purple = 0x663399, // rgb(102,51,153) + red = 0xFF0000, // rgb(255,0,0) + rosy_brown = 0xBC8F8F, // rgb(188,143,143) + royal_blue = 0x4169E1, // rgb(65,105,225) + saddle_brown = 0x8B4513, // rgb(139,69,19) + salmon = 0xFA8072, // rgb(250,128,114) + sandy_brown = 0xF4A460, // rgb(244,164,96) + sea_green = 0x2E8B57, // rgb(46,139,87) + sea_shell = 0xFFF5EE, // rgb(255,245,238) + sienna = 0xA0522D, // rgb(160,82,45) + silver = 0xC0C0C0, // rgb(192,192,192) + sky_blue = 0x87CEEB, // rgb(135,206,235) + slate_blue = 0x6A5ACD, // rgb(106,90,205) + slate_gray = 0x708090, // rgb(112,128,144) + snow = 0xFFFAFA, // rgb(255,250,250) + spring_green = 0x00FF7F, // rgb(0,255,127) + steel_blue = 0x4682B4, // rgb(70,130,180) + tan = 0xD2B48C, // rgb(210,180,140) + teal = 0x008080, // rgb(0,128,128) + thistle = 0xD8BFD8, // rgb(216,191,216) + tomato = 0xFF6347, // rgb(255,99,71) + turquoise = 0x40E0D0, // rgb(64,224,208) + violet = 0xEE82EE, // rgb(238,130,238) + wheat = 0xF5DEB3, // rgb(245,222,179) + white = 0xFFFFFF, // rgb(255,255,255) + white_smoke = 0xF5F5F5, // rgb(245,245,245) + yellow = 0xFFFF00, // rgb(255,255,0) + yellow_green = 0x9ACD32 // rgb(154,205,50) +}; // enum class color + +enum class terminal_color : uint8_t { + black = 30, + red, + green, + yellow, + blue, + magenta, + cyan, + white, + bright_black = 90, + bright_red, + bright_green, + bright_yellow, + bright_blue, + bright_magenta, + bright_cyan, + bright_white +}; + +enum class emphasis : uint8_t { + bold = 1, + faint = 1 << 1, + italic = 1 << 2, + underline = 1 << 3, + blink = 1 << 4, + reverse = 1 << 5, + conceal = 1 << 6, + strikethrough = 1 << 7, +}; + +// rgb is a struct for red, green and blue colors. +// Using the name "rgb" makes some editors show the color in a tooltip. +struct rgb { + FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {} + FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {} + FMT_CONSTEXPR rgb(uint32_t hex) + : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {} + FMT_CONSTEXPR rgb(color hex) + : r((uint32_t(hex) >> 16) & 0xFF), + g((uint32_t(hex) >> 8) & 0xFF), + b(uint32_t(hex) & 0xFF) {} + uint8_t r; + uint8_t g; + uint8_t b; +}; + +FMT_BEGIN_DETAIL_NAMESPACE + +// color is a struct of either a rgb color or a terminal color. +struct color_type { + FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {} + FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true), + value{} { + value.rgb_color = static_cast(rgb_color); + } + FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} { + value.rgb_color = (static_cast(rgb_color.r) << 16) | + (static_cast(rgb_color.g) << 8) | rgb_color.b; + } + FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(), + value{} { + value.term_color = static_cast(term_color); + } + bool is_rgb; + union color_union { + uint8_t term_color; + uint32_t rgb_color; + } value; +}; + +FMT_END_DETAIL_NAMESPACE + +/** A text style consisting of foreground and background colors and emphasis. */ +class text_style { + public: + FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT + : set_foreground_color(), + set_background_color(), + ems(em) {} + + FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) { + if (!set_foreground_color) { + set_foreground_color = rhs.set_foreground_color; + foreground_color = rhs.foreground_color; + } else if (rhs.set_foreground_color) { + if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) + FMT_THROW(format_error("can't OR a terminal color")); + foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; + } + + if (!set_background_color) { + set_background_color = rhs.set_background_color; + background_color = rhs.background_color; + } else if (rhs.set_background_color) { + if (!background_color.is_rgb || !rhs.background_color.is_rgb) + FMT_THROW(format_error("can't OR a terminal color")); + background_color.value.rgb_color |= rhs.background_color.value.rgb_color; + } + + ems = static_cast(static_cast(ems) | + static_cast(rhs.ems)); + return *this; + } + + friend FMT_CONSTEXPR text_style operator|(text_style lhs, + const text_style& rhs) { + return lhs |= rhs; + } + + FMT_DEPRECATED_NONMSVC FMT_CONSTEXPR text_style& operator&=( + const text_style& rhs) { + return and_assign(rhs); + } + + FMT_DEPRECATED_NONMSVC friend FMT_CONSTEXPR text_style + operator&(text_style lhs, const text_style& rhs) { + return lhs.and_assign(rhs); + } + + FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT { + return set_foreground_color; + } + FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT { + return set_background_color; + } + FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT { + return static_cast(ems) != 0; + } + FMT_CONSTEXPR detail::color_type get_foreground() const FMT_NOEXCEPT { + FMT_ASSERT(has_foreground(), "no foreground specified for this style"); + return foreground_color; + } + FMT_CONSTEXPR detail::color_type get_background() const FMT_NOEXCEPT { + FMT_ASSERT(has_background(), "no background specified for this style"); + return background_color; + } + FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT { + FMT_ASSERT(has_emphasis(), "no emphasis specified for this style"); + return ems; + } + + private: + FMT_CONSTEXPR text_style(bool is_foreground, + detail::color_type text_color) FMT_NOEXCEPT + : set_foreground_color(), + set_background_color(), + ems() { + if (is_foreground) { + foreground_color = text_color; + set_foreground_color = true; + } else { + background_color = text_color; + set_background_color = true; + } + } + + // DEPRECATED! + FMT_CONSTEXPR text_style& and_assign(const text_style& rhs) { + if (!set_foreground_color) { + set_foreground_color = rhs.set_foreground_color; + foreground_color = rhs.foreground_color; + } else if (rhs.set_foreground_color) { + if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) + FMT_THROW(format_error("can't AND a terminal color")); + foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color; + } + + if (!set_background_color) { + set_background_color = rhs.set_background_color; + background_color = rhs.background_color; + } else if (rhs.set_background_color) { + if (!background_color.is_rgb || !rhs.background_color.is_rgb) + FMT_THROW(format_error("can't AND a terminal color")); + background_color.value.rgb_color &= rhs.background_color.value.rgb_color; + } + + ems = static_cast(static_cast(ems) & + static_cast(rhs.ems)); + return *this; + } + + friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground) + FMT_NOEXCEPT; + + friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background) + FMT_NOEXCEPT; + + detail::color_type foreground_color; + detail::color_type background_color; + bool set_foreground_color; + bool set_background_color; + emphasis ems; +}; + +/** Creates a text style from the foreground (text) color. */ +FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) FMT_NOEXCEPT { + return text_style(true, foreground); +} + +/** Creates a text style from the background color. */ +FMT_CONSTEXPR inline text_style bg(detail::color_type background) FMT_NOEXCEPT { + return text_style(false, background); +} + +FMT_CONSTEXPR inline text_style operator|(emphasis lhs, + emphasis rhs) FMT_NOEXCEPT { + return text_style(lhs) | rhs; +} + +FMT_BEGIN_DETAIL_NAMESPACE + +template struct ansi_color_escape { + FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color, + const char* esc) FMT_NOEXCEPT { + // If we have a terminal color, we need to output another escape code + // sequence. + if (!text_color.is_rgb) { + bool is_background = esc == string_view("\x1b[48;2;"); + uint32_t value = text_color.value.term_color; + // Background ASCII codes are the same as the foreground ones but with + // 10 more. + if (is_background) value += 10u; + + size_t index = 0; + buffer[index++] = static_cast('\x1b'); + buffer[index++] = static_cast('['); + + if (value >= 100u) { + buffer[index++] = static_cast('1'); + value %= 100u; + } + buffer[index++] = static_cast('0' + value / 10u); + buffer[index++] = static_cast('0' + value % 10u); + + buffer[index++] = static_cast('m'); + buffer[index++] = static_cast('\0'); + return; + } + + for (int i = 0; i < 7; i++) { + buffer[i] = static_cast(esc[i]); + } + rgb color(text_color.value.rgb_color); + to_esc(color.r, buffer + 7, ';'); + to_esc(color.g, buffer + 11, ';'); + to_esc(color.b, buffer + 15, 'm'); + buffer[19] = static_cast(0); + } + FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT { + uint8_t em_codes[num_emphases] = {}; + if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1; + if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2; + if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3; + if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4; + if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5; + if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7; + if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8; + if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9; + + size_t index = 0; + for (size_t i = 0; i < num_emphases; ++i) { + if (!em_codes[i]) continue; + buffer[index++] = static_cast('\x1b'); + buffer[index++] = static_cast('['); + buffer[index++] = static_cast('0' + em_codes[i]); + buffer[index++] = static_cast('m'); + } + buffer[index++] = static_cast(0); + } + FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; } + + FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; } + FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const FMT_NOEXCEPT { + return buffer + std::char_traits::length(buffer); + } + + private: + static constexpr size_t num_emphases = 8; + Char buffer[7u + 3u * num_emphases + 1u]; + + static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, + char delimiter) FMT_NOEXCEPT { + out[0] = static_cast('0' + c / 100); + out[1] = static_cast('0' + c / 10 % 10); + out[2] = static_cast('0' + c % 10); + out[3] = static_cast(delimiter); + } + static FMT_CONSTEXPR bool has_emphasis(emphasis em, + emphasis mask) FMT_NOEXCEPT { + return static_cast(em) & static_cast(mask); + } +}; + +template +FMT_CONSTEXPR ansi_color_escape make_foreground_color( + detail::color_type foreground) FMT_NOEXCEPT { + return ansi_color_escape(foreground, "\x1b[38;2;"); +} + +template +FMT_CONSTEXPR ansi_color_escape make_background_color( + detail::color_type background) FMT_NOEXCEPT { + return ansi_color_escape(background, "\x1b[48;2;"); +} + +template +FMT_CONSTEXPR ansi_color_escape make_emphasis(emphasis em) FMT_NOEXCEPT { + return ansi_color_escape(em); +} + +template +inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT { + std::fputs(chars, stream); +} + +template <> +inline void fputs(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT { + std::fputws(chars, stream); +} + +template inline void reset_color(FILE* stream) FMT_NOEXCEPT { + fputs("\x1b[0m", stream); +} + +template <> inline void reset_color(FILE* stream) FMT_NOEXCEPT { + fputs(L"\x1b[0m", stream); +} + +template +inline void reset_color(buffer& buffer) FMT_NOEXCEPT { + auto reset_color = string_view("\x1b[0m"); + buffer.append(reset_color.begin(), reset_color.end()); +} + +template +void vformat_to(buffer& buf, const text_style& ts, + basic_string_view format_str, + basic_format_args>> args) { + bool has_style = false; + if (ts.has_emphasis()) { + has_style = true; + auto emphasis = detail::make_emphasis(ts.get_emphasis()); + buf.append(emphasis.begin(), emphasis.end()); + } + if (ts.has_foreground()) { + has_style = true; + auto foreground = detail::make_foreground_color(ts.get_foreground()); + buf.append(foreground.begin(), foreground.end()); + } + if (ts.has_background()) { + has_style = true; + auto background = detail::make_background_color(ts.get_background()); + buf.append(background.begin(), background.end()); + } + detail::vformat_to(buf, format_str, args, {}); + if (has_style) detail::reset_color(buf); +} + +FMT_END_DETAIL_NAMESPACE + +template > +void vprint(std::FILE* f, const text_style& ts, const S& format, + basic_format_args>> args) { + basic_memory_buffer buf; + detail::vformat_to(buf, ts, to_string_view(format), args); + buf.push_back(Char(0)); + detail::fputs(buf.data(), f); +} + +/** + \rst + Formats a string and prints it to the specified file stream using ANSI + escape sequences to specify text formatting. + + **Example**:: + + fmt::print(fmt::emphasis::bold | fg(fmt::color::red), + "Elapsed time: {0:.2f} seconds", 1.23); + \endrst + */ +template ::value)> +void print(std::FILE* f, const text_style& ts, const S& format_str, + const Args&... args) { + vprint(f, ts, format_str, + fmt::make_args_checked(format_str, args...)); +} + +/** + \rst + Formats a string and prints it to stdout using ANSI escape sequences to + specify text formatting. + + **Example**:: + + fmt::print(fmt::emphasis::bold | fg(fmt::color::red), + "Elapsed time: {0:.2f} seconds", 1.23); + \endrst + */ +template ::value)> +void print(const text_style& ts, const S& format_str, const Args&... args) { + return print(stdout, ts, format_str, args...); +} + +template > +inline std::basic_string vformat( + const text_style& ts, const S& format_str, + basic_format_args>> args) { + basic_memory_buffer buf; + detail::vformat_to(buf, ts, to_string_view(format_str), args); + return fmt::to_string(buf); +} + +/** + \rst + Formats arguments and returns the result as a string using ANSI + escape sequences to specify text formatting. + + **Example**:: + + #include + std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), + "The answer is {}", 42); + \endrst +*/ +template > +inline std::basic_string format(const text_style& ts, const S& format_str, + const Args&... args) { + return fmt::vformat(ts, to_string_view(format_str), + fmt::make_args_checked(format_str, args...)); +} + +/** + Formats a string with the given text_style and writes the output to ``out``. + */ +template ::value)> +OutputIt vformat_to( + OutputIt out, const text_style& ts, basic_string_view format_str, + basic_format_args>> args) { + auto&& buf = detail::get_buffer(out); + detail::vformat_to(buf, ts, format_str, args); + return detail::get_iterator(buf); +} + +/** + \rst + Formats arguments with the given text_style, writes the result to the output + iterator ``out`` and returns the iterator past the end of the output range. + + **Example**:: + + std::vector out; + fmt::format_to(std::back_inserter(out), + fmt::emphasis::bold | fg(fmt::color::red), "{}", 42); + \endrst +*/ +template >::value&& + detail::is_string::value> +inline auto format_to(OutputIt out, const text_style& ts, const S& format_str, + Args&&... args) -> + typename std::enable_if::type { + return vformat_to(out, ts, to_string_view(format_str), + fmt::make_args_checked(format_str, args...)); +} + +FMT_MODULE_EXPORT_END +FMT_END_NAMESPACE + +#endif // FMT_COLOR_H_ diff --git a/ctrtool/deps/libfmt/include/fmt/compile.h b/ctrtool/deps/libfmt/include/fmt/compile.h new file mode 100644 index 0000000..1dba3dd --- /dev/null +++ b/ctrtool/deps/libfmt/include/fmt/compile.h @@ -0,0 +1,642 @@ +// Formatting library for C++ - experimental format string compilation +// +// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_COMPILE_H_ +#define FMT_COMPILE_H_ + +#include "format.h" + +FMT_BEGIN_NAMESPACE +namespace detail { + +// An output iterator that counts the number of objects written to it and +// discards them. +class counting_iterator { + private: + size_t count_; + + public: + using iterator_category = std::output_iterator_tag; + using difference_type = std::ptrdiff_t; + using pointer = void; + using reference = void; + using _Unchecked_type = counting_iterator; // Mark iterator as checked. + + struct value_type { + template void operator=(const T&) {} + }; + + counting_iterator() : count_(0) {} + + size_t count() const { return count_; } + + counting_iterator& operator++() { + ++count_; + return *this; + } + counting_iterator operator++(int) { + auto it = *this; + ++*this; + return it; + } + + friend counting_iterator operator+(counting_iterator it, difference_type n) { + it.count_ += static_cast(n); + return it; + } + + value_type operator*() const { return {}; } +}; + +template +inline counting_iterator copy_str(InputIt begin, InputIt end, + counting_iterator it) { + return it + (end - begin); +} + +template class truncating_iterator_base { + protected: + OutputIt out_; + size_t limit_; + size_t count_ = 0; + + truncating_iterator_base() : out_(), limit_(0) {} + + truncating_iterator_base(OutputIt out, size_t limit) + : out_(out), limit_(limit) {} + + public: + using iterator_category = std::output_iterator_tag; + using value_type = typename std::iterator_traits::value_type; + using difference_type = std::ptrdiff_t; + using pointer = void; + using reference = void; + using _Unchecked_type = + truncating_iterator_base; // Mark iterator as checked. + + OutputIt base() const { return out_; } + size_t count() const { return count_; } +}; + +// An output iterator that truncates the output and counts the number of objects +// written to it. +template ::value_type>::type> +class truncating_iterator; + +template +class truncating_iterator + : public truncating_iterator_base { + mutable typename truncating_iterator_base::value_type blackhole_; + + public: + using value_type = typename truncating_iterator_base::value_type; + + truncating_iterator() = default; + + truncating_iterator(OutputIt out, size_t limit) + : truncating_iterator_base(out, limit) {} + + truncating_iterator& operator++() { + if (this->count_++ < this->limit_) ++this->out_; + return *this; + } + + truncating_iterator operator++(int) { + auto it = *this; + ++*this; + return it; + } + + value_type& operator*() const { + return this->count_ < this->limit_ ? *this->out_ : blackhole_; + } +}; + +template +class truncating_iterator + : public truncating_iterator_base { + public: + truncating_iterator() = default; + + truncating_iterator(OutputIt out, size_t limit) + : truncating_iterator_base(out, limit) {} + + template truncating_iterator& operator=(T val) { + if (this->count_++ < this->limit_) *this->out_++ = val; + return *this; + } + + truncating_iterator& operator++() { return *this; } + truncating_iterator& operator++(int) { return *this; } + truncating_iterator& operator*() { return *this; } +}; + +// A compile-time string which is compiled into fast formatting code. +class compiled_string {}; + +template +struct is_compiled_string : std::is_base_of {}; + +/** + \rst + Converts a string literal *s* into a format string that will be parsed at + compile time and converted into efficient formatting code. Requires C++17 + ``constexpr if`` compiler support. + + **Example**:: + + // Converts 42 into std::string using the most efficient method and no + // runtime format string processing. + std::string s = fmt::format(FMT_COMPILE("{}"), 42); + \endrst + */ +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +# define FMT_COMPILE(s) \ + FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit) +#else +# define FMT_COMPILE(s) FMT_STRING(s) +#endif + +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +template Str> +struct udl_compiled_string : compiled_string { + using char_type = Char; + constexpr operator basic_string_view() const { + return {Str.data, N - 1}; + } +}; +#endif + +template +const T& first(const T& value, const Tail&...) { + return value; +} + +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +template struct type_list {}; + +// Returns a reference to the argument at index N from [first, rest...]. +template +constexpr const auto& get([[maybe_unused]] const T& first, + [[maybe_unused]] const Args&... rest) { + static_assert(N < 1 + sizeof...(Args), "index is out of bounds"); + if constexpr (N == 0) + return first; + else + return detail::get(rest...); +} + +template +constexpr int get_arg_index_by_name(basic_string_view name, + type_list) { + return get_arg_index_by_name(name); +} + +template struct get_type_impl; + +template struct get_type_impl> { + using type = + remove_cvref_t(std::declval()...))>; +}; + +template +using get_type = typename get_type_impl::type; + +template struct is_compiled_format : std::false_type {}; + +template struct text { + basic_string_view data; + using char_type = Char; + + template + constexpr OutputIt format(OutputIt out, const Args&...) const { + return write(out, data); + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +template +constexpr text make_text(basic_string_view s, size_t pos, + size_t size) { + return {{&s[pos], size}}; +} + +template struct code_unit { + Char value; + using char_type = Char; + + template + constexpr OutputIt format(OutputIt out, const Args&...) const { + return write(out, value); + } +}; + +// This ensures that the argument type is convertible to `const T&`. +template +constexpr const T& get_arg_checked(const Args&... args) { + const auto& arg = detail::get(args...); + if constexpr (detail::is_named_arg>()) { + return arg.value; + } else { + return arg; + } +} + +template +struct is_compiled_format> : std::true_type {}; + +// A replacement field that refers to argument N. +template struct field { + using char_type = Char; + + template + constexpr OutputIt format(OutputIt out, const Args&... args) const { + return write(out, get_arg_checked(args...)); + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +// A replacement field that refers to argument with name. +template struct runtime_named_field { + using char_type = Char; + basic_string_view name; + + template + constexpr static bool try_format_argument( + OutputIt& out, + // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9 + [[maybe_unused]] basic_string_view arg_name, const T& arg) { + if constexpr (is_named_arg::type>::value) { + if (arg_name == arg.name) { + out = write(out, arg.value); + return true; + } + } + return false; + } + + template + constexpr OutputIt format(OutputIt out, const Args&... args) const { + bool found = (try_format_argument(out, name, args) || ...); + if (!found) { + FMT_THROW(format_error("argument with specified name is not found")); + } + return out; + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +// A replacement field that refers to argument N and has format specifiers. +template struct spec_field { + using char_type = Char; + formatter fmt; + + template + constexpr FMT_INLINE OutputIt format(OutputIt out, + const Args&... args) const { + const auto& vargs = + fmt::make_format_args>(args...); + basic_format_context ctx(out, vargs); + return fmt.format(get_arg_checked(args...), ctx); + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +template struct concat { + L lhs; + R rhs; + using char_type = typename L::char_type; + + template + constexpr OutputIt format(OutputIt out, const Args&... args) const { + out = lhs.format(out, args...); + return rhs.format(out, args...); + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +template +constexpr concat make_concat(L lhs, R rhs) { + return {lhs, rhs}; +} + +struct unknown_format {}; + +template +constexpr size_t parse_text(basic_string_view str, size_t pos) { + for (size_t size = str.size(); pos != size; ++pos) { + if (str[pos] == '{' || str[pos] == '}') break; + } + return pos; +} + +template +constexpr auto compile_format_string(S format_str); + +template +constexpr auto parse_tail(T head, S format_str) { + if constexpr (POS != + basic_string_view(format_str).size()) { + constexpr auto tail = compile_format_string(format_str); + if constexpr (std::is_same, + unknown_format>()) + return tail; + else + return make_concat(head, tail); + } else { + return head; + } +} + +template struct parse_specs_result { + formatter fmt; + size_t end; + int next_arg_id; +}; + +constexpr int manual_indexing_id = -1; + +template +constexpr parse_specs_result parse_specs(basic_string_view str, + size_t pos, int next_arg_id) { + str.remove_prefix(pos); + auto ctx = basic_format_parse_context(str, {}, next_arg_id); + auto f = formatter(); + auto end = f.parse(ctx); + return {f, pos + fmt::detail::to_unsigned(end - str.data()) + 1, + next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; +} + +template struct arg_id_handler { + arg_ref arg_id; + + constexpr int operator()() { + FMT_ASSERT(false, "handler cannot be used with automatic indexing"); + return 0; + } + constexpr int operator()(int id) { + arg_id = arg_ref(id); + return 0; + } + constexpr int operator()(basic_string_view id) { + arg_id = arg_ref(id); + return 0; + } + + constexpr void on_error(const char* message) { + FMT_THROW(format_error(message)); + } +}; + +template struct parse_arg_id_result { + arg_ref arg_id; + const Char* arg_id_end; +}; + +template +constexpr auto parse_arg_id(const Char* begin, const Char* end) { + auto handler = arg_id_handler{arg_ref{}}; + auto arg_id_end = parse_arg_id(begin, end, handler); + return parse_arg_id_result{handler.arg_id, arg_id_end}; +} + +template struct field_type { + using type = remove_cvref_t; +}; + +template +struct field_type::value>> { + using type = remove_cvref_t; +}; + +template +constexpr auto parse_replacement_field_then_tail(S format_str) { + using char_type = typename S::char_type; + constexpr auto str = basic_string_view(format_str); + constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); + if constexpr (c == '}') { + return parse_tail( + field::type, ARG_INDEX>(), + format_str); + } else if constexpr (c == ':') { + constexpr auto result = parse_specs::type>( + str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); + return parse_tail( + spec_field::type, ARG_INDEX>{ + result.fmt}, + format_str); + } +} + +// Compiles a non-empty format string and returns the compiled representation +// or unknown_format() on unrecognized input. +template +constexpr auto compile_format_string(S format_str) { + using char_type = typename S::char_type; + constexpr auto str = basic_string_view(format_str); + if constexpr (str[POS] == '{') { + if constexpr (POS + 1 == str.size()) + FMT_THROW(format_error("unmatched '{' in format string")); + if constexpr (str[POS + 1] == '{') { + return parse_tail(make_text(str, POS, 1), format_str); + } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { + static_assert(ID != manual_indexing_id, + "cannot switch from manual to automatic argument indexing"); + constexpr auto next_id = + ID != manual_indexing_id ? ID + 1 : manual_indexing_id; + return parse_replacement_field_then_tail, Args, + POS + 1, ID, next_id>( + format_str); + } else { + constexpr auto arg_id_result = + parse_arg_id(str.data() + POS + 1, str.data() + str.size()); + constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data(); + constexpr char_type c = + arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type(); + static_assert(c == '}' || c == ':', "missing '}' in format string"); + if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) { + static_assert( + ID == manual_indexing_id || ID == 0, + "cannot switch from automatic to manual argument indexing"); + constexpr auto arg_index = arg_id_result.arg_id.val.index; + return parse_replacement_field_then_tail, + Args, arg_id_end_pos, + arg_index, manual_indexing_id>( + format_str); + } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) { + constexpr auto arg_index = + get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{}); + if constexpr (arg_index != invalid_arg_index) { + constexpr auto next_id = + ID != manual_indexing_id ? ID + 1 : manual_indexing_id; + return parse_replacement_field_then_tail< + decltype(get_type::value), Args, arg_id_end_pos, + arg_index, next_id>(format_str); + } else { + if constexpr (c == '}') { + return parse_tail( + runtime_named_field{arg_id_result.arg_id.val.name}, + format_str); + } else if constexpr (c == ':') { + return unknown_format(); // no type info for specs parsing + } + } + } + } + } else if constexpr (str[POS] == '}') { + if constexpr (POS + 1 == str.size()) + FMT_THROW(format_error("unmatched '}' in format string")); + return parse_tail(make_text(str, POS, 1), format_str); + } else { + constexpr auto end = parse_text(str, POS + 1); + if constexpr (end - POS > 1) { + return parse_tail(make_text(str, POS, end - POS), + format_str); + } else { + return parse_tail(code_unit{str[POS]}, + format_str); + } + } +} + +template ::value)> +constexpr auto compile(S format_str) { + constexpr auto str = basic_string_view(format_str); + if constexpr (str.size() == 0) { + return detail::make_text(str, 0, 0); + } else { + constexpr auto result = + detail::compile_format_string, 0, 0>( + format_str); + return result; + } +} +#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +} // namespace detail + +FMT_MODULE_EXPORT_BEGIN + +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) + +template ::value)> +FMT_INLINE std::basic_string format(const CompiledFormat& cf, + const Args&... args) { + auto s = std::basic_string(); + cf.format(std::back_inserter(s), args...); + return s; +} + +template ::value)> +constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf, + const Args&... args) { + return cf.format(out, args...); +} + +template ::value)> +FMT_INLINE std::basic_string format(const S&, + Args&&... args) { + if constexpr (std::is_same::value) { + constexpr auto str = basic_string_view(S()); + if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { + const auto& first = detail::first(args...); + if constexpr (detail::is_named_arg< + remove_cvref_t>::value) { + return fmt::to_string(first.value); + } else { + return fmt::to_string(first); + } + } + } + constexpr auto compiled = detail::compile(S()); + if constexpr (std::is_same, + detail::unknown_format>()) { + return format(static_cast>(S()), + std::forward(args)...); + } else { + return format(compiled, std::forward(args)...); + } +} + +template ::value)> +FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { + constexpr auto compiled = detail::compile(S()); + if constexpr (std::is_same, + detail::unknown_format>()) { + return format_to(out, + static_cast>(S()), + std::forward(args)...); + } else { + return format_to(out, compiled, std::forward(args)...); + } +} +#endif + +template ::value)> +format_to_n_result format_to_n(OutputIt out, size_t n, + const S& format_str, Args&&... args) { + auto it = format_to(detail::truncating_iterator(out, n), format_str, + std::forward(args)...); + return {it.base(), it.count()}; +} + +template ::value)> +size_t formatted_size(const S& format_str, const Args&... args) { + return format_to(detail::counting_iterator(), format_str, args...).count(); +} + +template ::value)> +void print(std::FILE* f, const S& format_str, const Args&... args) { + memory_buffer buffer; + format_to(std::back_inserter(buffer), format_str, args...); + detail::print(f, {buffer.data(), buffer.size()}); +} + +template ::value)> +void print(const S& format_str, const Args&... args) { + print(stdout, format_str, args...); +} + +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +inline namespace literals { +template +constexpr detail::udl_compiled_string< + remove_cvref_t, + sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str> +operator""_cf() { + return {}; +} +} // namespace literals +#endif + +FMT_MODULE_EXPORT_END +FMT_END_NAMESPACE + +#endif // FMT_COMPILE_H_ diff --git a/ctrtool/deps/libfmt/include/fmt/core.h b/ctrtool/deps/libfmt/include/fmt/core.h new file mode 100644 index 0000000..92a7aa1 --- /dev/null +++ b/ctrtool/deps/libfmt/include/fmt/core.h @@ -0,0 +1,3236 @@ +// Formatting library for C++ - the core API for char/UTF-8 +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_CORE_H_ +#define FMT_CORE_H_ + +#include // std::byte +#include // std::FILE +#include +#include +#include +#include +#include + +// The fmt library version in the form major * 10000 + minor * 100 + patch. +#define FMT_VERSION 80101 + +#if defined(__clang__) && !defined(__ibmxl__) +# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) +#else +# define FMT_CLANG_VERSION 0 +#endif + +#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && \ + !defined(__NVCOMPILER) +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#else +# define FMT_GCC_VERSION 0 +#endif + +#ifndef FMT_GCC_PRAGMA +// Workaround _Pragma bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59884. +# if FMT_GCC_VERSION >= 504 +# define FMT_GCC_PRAGMA(arg) _Pragma(arg) +# else +# define FMT_GCC_PRAGMA(arg) +# endif +#endif + +#ifdef __ICL +# define FMT_ICC_VERSION __ICL +#elif defined(__INTEL_COMPILER) +# define FMT_ICC_VERSION __INTEL_COMPILER +#else +# define FMT_ICC_VERSION 0 +#endif + +#ifdef __NVCC__ +# define FMT_NVCC __NVCC__ +#else +# define FMT_NVCC 0 +#endif + +#ifdef _MSC_VER +# define FMT_MSC_VER _MSC_VER +# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) +#else +# define FMT_MSC_VER 0 +# define FMT_MSC_WARNING(...) +#endif + +#ifdef __has_feature +# define FMT_HAS_FEATURE(x) __has_feature(x) +#else +# define FMT_HAS_FEATURE(x) 0 +#endif + +#if defined(__has_include) && \ + (!defined(__INTELLISENSE__) || FMT_MSC_VER > 1900) && \ + (!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1600) +# define FMT_HAS_INCLUDE(x) __has_include(x) +#else +# define FMT_HAS_INCLUDE(x) 0 +#endif + +#ifdef __has_cpp_attribute +# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define FMT_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +#ifdef _MSVC_LANG +# define FMT_CPLUSPLUS _MSVC_LANG +#else +# define FMT_CPLUSPLUS __cplusplus +#endif + +#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \ + (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + +#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \ + (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + +// Check if relaxed C++14 constexpr is supported. +// GCC doesn't allow throw in constexpr until version 6 (bug 67371). +#ifndef FMT_USE_CONSTEXPR +# define FMT_USE_CONSTEXPR \ + (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1912 || \ + (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \ + !FMT_NVCC && !FMT_ICC_VERSION +#endif +#if FMT_USE_CONSTEXPR +# define FMT_CONSTEXPR constexpr +# define FMT_CONSTEXPR_DECL constexpr +#else +# define FMT_CONSTEXPR +# define FMT_CONSTEXPR_DECL +#endif + +#if ((__cplusplus >= 202002L) && \ + (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE > 9)) || \ + (__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002) +# define FMT_CONSTEXPR20 constexpr +#else +# define FMT_CONSTEXPR20 +#endif + +// Check if constexpr std::char_traits<>::compare,length is supported. +#if defined(__GLIBCXX__) +# if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \ + _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE. +# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +# endif +#elif defined(_LIBCPP_VERSION) && __cplusplus >= 201703L && \ + _LIBCPP_VERSION >= 4000 +# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +#elif FMT_MSC_VER >= 1914 && _MSVC_LANG >= 201703L +# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +#endif +#ifndef FMT_CONSTEXPR_CHAR_TRAITS +# define FMT_CONSTEXPR_CHAR_TRAITS +#endif + +// Check if exceptions are disabled. +#ifndef FMT_EXCEPTIONS +# if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ + FMT_MSC_VER && !_HAS_EXCEPTIONS +# define FMT_EXCEPTIONS 0 +# else +# define FMT_EXCEPTIONS 1 +# endif +#endif + +// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). +#ifndef FMT_USE_NOEXCEPT +# define FMT_USE_NOEXCEPT 0 +#endif + +#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ + FMT_GCC_VERSION >= 408 || FMT_MSC_VER >= 1900 +# define FMT_DETECTED_NOEXCEPT noexcept +# define FMT_HAS_CXX11_NOEXCEPT 1 +#else +# define FMT_DETECTED_NOEXCEPT throw() +# define FMT_HAS_CXX11_NOEXCEPT 0 +#endif + +#ifndef FMT_NOEXCEPT +# if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT +# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT +# else +# define FMT_NOEXCEPT +# endif +#endif + +// [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code +// warnings. +#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \ + !FMT_NVCC +# define FMT_NORETURN [[noreturn]] +#else +# define FMT_NORETURN +#endif + +#if __cplusplus == 201103L || __cplusplus == 201402L +# if defined(__INTEL_COMPILER) || defined(__PGI) +# define FMT_FALLTHROUGH +# elif defined(__clang__) +# define FMT_FALLTHROUGH [[clang::fallthrough]] +# elif FMT_GCC_VERSION >= 700 && \ + (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) +# define FMT_FALLTHROUGH [[gnu::fallthrough]] +# else +# define FMT_FALLTHROUGH +# endif +#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) +# define FMT_FALLTHROUGH [[fallthrough]] +#else +# define FMT_FALLTHROUGH +#endif + +#ifndef FMT_NODISCARD +# if FMT_HAS_CPP17_ATTRIBUTE(nodiscard) +# define FMT_NODISCARD [[nodiscard]] +# else +# define FMT_NODISCARD +# endif +#endif + +#ifndef FMT_USE_FLOAT +# define FMT_USE_FLOAT 1 +#endif +#ifndef FMT_USE_DOUBLE +# define FMT_USE_DOUBLE 1 +#endif +#ifndef FMT_USE_LONG_DOUBLE +# define FMT_USE_LONG_DOUBLE 1 +#endif + +#ifndef FMT_INLINE +# if FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_INLINE inline __attribute__((always_inline)) +# else +# define FMT_INLINE inline +# endif +#endif + +#ifndef FMT_DEPRECATED +# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900 +# define FMT_DEPRECATED [[deprecated]] +# else +# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__) +# define FMT_DEPRECATED __attribute__((deprecated)) +# elif FMT_MSC_VER +# define FMT_DEPRECATED __declspec(deprecated) +# else +# define FMT_DEPRECATED /* deprecated */ +# endif +# endif +#endif + +#ifndef FMT_BEGIN_NAMESPACE +# define FMT_BEGIN_NAMESPACE \ + namespace fmt { \ + inline namespace v8 { +# define FMT_END_NAMESPACE \ + } \ + } +#endif + +#ifndef FMT_MODULE_EXPORT +# define FMT_MODULE_EXPORT +# define FMT_MODULE_EXPORT_BEGIN +# define FMT_MODULE_EXPORT_END +# define FMT_BEGIN_DETAIL_NAMESPACE namespace detail { +# define FMT_END_DETAIL_NAMESPACE } +#endif + +#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) +# define FMT_CLASS_API FMT_MSC_WARNING(suppress : 4275) +# ifdef FMT_EXPORT +# define FMT_API __declspec(dllexport) +# elif defined(FMT_SHARED) +# define FMT_API __declspec(dllimport) +# endif +#else +# define FMT_CLASS_API +# if defined(FMT_EXPORT) || defined(FMT_SHARED) +# if defined(__GNUC__) || defined(__clang__) +# define FMT_API __attribute__((visibility("default"))) +# endif +# endif +#endif +#ifndef FMT_API +# define FMT_API +#endif + +// libc++ supports string_view in pre-c++17. +#if (FMT_HAS_INCLUDE() && \ + (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \ + (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) +# include +# define FMT_USE_STRING_VIEW +#elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L +# include +# define FMT_USE_EXPERIMENTAL_STRING_VIEW +#endif + +#ifndef FMT_UNICODE +# define FMT_UNICODE !FMT_MSC_VER +#endif + +#ifndef FMT_CONSTEVAL +# if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \ + __cplusplus > 201703L && !defined(__apple_build_version__)) || \ + (defined(__cpp_consteval) && \ + (!FMT_MSC_VER || _MSC_FULL_VER >= 193030704)) +// consteval is broken in MSVC before VS2022 and Apple clang 13. +# define FMT_CONSTEVAL consteval +# define FMT_HAS_CONSTEVAL +# else +# define FMT_CONSTEVAL +# endif +#endif + +#ifndef FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +# if defined(__cpp_nontype_template_args) && \ + ((FMT_GCC_VERSION >= 903 && __cplusplus >= 201709L) || \ + __cpp_nontype_template_args >= 201911L) +# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 1 +# else +# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 0 +# endif +#endif + +// Enable minimal optimizations for more compact code in debug mode. +FMT_GCC_PRAGMA("GCC push_options") +#ifndef __OPTIMIZE__ +FMT_GCC_PRAGMA("GCC optimize(\"Og\")") +#endif + +FMT_BEGIN_NAMESPACE +FMT_MODULE_EXPORT_BEGIN + +// Implementations of enable_if_t and other metafunctions for older systems. +template +using enable_if_t = typename std::enable_if::type; +template +using conditional_t = typename std::conditional::type; +template using bool_constant = std::integral_constant; +template +using remove_reference_t = typename std::remove_reference::type; +template +using remove_const_t = typename std::remove_const::type; +template +using remove_cvref_t = typename std::remove_cv>::type; +template struct type_identity { using type = T; }; +template using type_identity_t = typename type_identity::type; + +struct monostate { + constexpr monostate() {} +}; + +// An enable_if helper to be used in template parameters which results in much +// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed +// to workaround a bug in MSVC 2019 (see #1140 and #1186). +#ifdef FMT_DOC +# define FMT_ENABLE_IF(...) +#else +# define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0 +#endif + +FMT_BEGIN_DETAIL_NAMESPACE + +// Suppress "unused variable" warnings with the method described in +// https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/. +// (void)var does not work on many Intel compilers. +template FMT_CONSTEXPR void ignore_unused(const T&...) {} + +constexpr FMT_INLINE auto is_constant_evaluated(bool default_value = false) + FMT_NOEXCEPT -> bool { +#ifdef __cpp_lib_is_constant_evaluated + ignore_unused(default_value); + return std::is_constant_evaluated(); +#else + return default_value; +#endif +} + +// A function to suppress "conditional expression is constant" warnings. +template constexpr FMT_INLINE auto const_check(T value) -> T { + return value; +} + +FMT_NORETURN FMT_API void assert_fail(const char* file, int line, + const char* message); + +#ifndef FMT_ASSERT +# ifdef NDEBUG +// FMT_ASSERT is not empty to avoid -Werror=empty-body. +# define FMT_ASSERT(condition, message) \ + ::fmt::detail::ignore_unused((condition), (message)) +# else +# define FMT_ASSERT(condition, message) \ + ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \ + ? (void)0 \ + : ::fmt::detail::assert_fail(__FILE__, __LINE__, (message))) +# endif +#endif + +#ifdef __cpp_lib_byte +using byte = std::byte; +#else +enum class byte : unsigned char {}; +#endif + +#if defined(FMT_USE_STRING_VIEW) +template using std_string_view = std::basic_string_view; +#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) +template +using std_string_view = std::experimental::basic_string_view; +#else +template struct std_string_view {}; +#endif + +#ifdef FMT_USE_INT128 +// Do nothing. +#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \ + !(FMT_CLANG_VERSION && FMT_MSC_VER) +# define FMT_USE_INT128 1 +using int128_t = __int128_t; +using uint128_t = __uint128_t; +template inline auto convert_for_visit(T value) -> T { + return value; +} +#else +# define FMT_USE_INT128 0 +#endif +#if !FMT_USE_INT128 +enum class int128_t {}; +enum class uint128_t {}; +// Reduce template instantiations. +template inline auto convert_for_visit(T) -> monostate { + return {}; +} +#endif + +// Casts a nonnegative integer to unsigned. +template +FMT_CONSTEXPR auto to_unsigned(Int value) -> + typename std::make_unsigned::type { + FMT_ASSERT(value >= 0, "negative value"); + return static_cast::type>(value); +} + +FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5"; + +constexpr auto is_utf8() -> bool { + // Avoid buggy sign extensions in MSVC's constant evaluation mode. + // https://developercommunity.visualstudio.com/t/C-difference-in-behavior-for-unsigned/1233612 + using uchar = unsigned char; + return FMT_UNICODE || (sizeof(micro) == 3 && uchar(micro[0]) == 0xC2 && + uchar(micro[1]) == 0xB5); +} +FMT_END_DETAIL_NAMESPACE + +/** + An implementation of ``std::basic_string_view`` for pre-C++17. It provides a + subset of the API. ``fmt::basic_string_view`` is used for format strings even + if ``std::string_view`` is available to prevent issues when a library is + compiled with a different ``-std`` option than the client code (which is not + recommended). + */ +template class basic_string_view { + private: + const Char* data_; + size_t size_; + + public: + using value_type = Char; + using iterator = const Char*; + + constexpr basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {} + + /** Constructs a string reference object from a C string and a size. */ + constexpr basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT + : data_(s), + size_(count) {} + + /** + \rst + Constructs a string reference object from a C string computing + the size with ``std::char_traits::length``. + \endrst + */ + FMT_CONSTEXPR_CHAR_TRAITS + FMT_INLINE + basic_string_view(const Char* s) + : data_(s), + size_(detail::const_check(std::is_same::value && + !detail::is_constant_evaluated(true)) + ? std::strlen(reinterpret_cast(s)) + : std::char_traits::length(s)) {} + + /** Constructs a string reference from a ``std::basic_string`` object. */ + template + FMT_CONSTEXPR basic_string_view( + const std::basic_string& s) FMT_NOEXCEPT + : data_(s.data()), + size_(s.size()) {} + + template >::value)> + FMT_CONSTEXPR basic_string_view(S s) FMT_NOEXCEPT : data_(s.data()), + size_(s.size()) {} + + /** Returns a pointer to the string data. */ + constexpr auto data() const FMT_NOEXCEPT -> const Char* { return data_; } + + /** Returns the string size. */ + constexpr auto size() const FMT_NOEXCEPT -> size_t { return size_; } + + constexpr auto begin() const FMT_NOEXCEPT -> iterator { return data_; } + constexpr auto end() const FMT_NOEXCEPT -> iterator { return data_ + size_; } + + constexpr auto operator[](size_t pos) const FMT_NOEXCEPT -> const Char& { + return data_[pos]; + } + + FMT_CONSTEXPR void remove_prefix(size_t n) FMT_NOEXCEPT { + data_ += n; + size_ -= n; + } + + // Lexicographically compare this string reference to other. + FMT_CONSTEXPR_CHAR_TRAITS auto compare(basic_string_view other) const -> int { + size_t str_size = size_ < other.size_ ? size_ : other.size_; + int result = std::char_traits::compare(data_, other.data_, str_size); + if (result == 0) + result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); + return result; + } + + FMT_CONSTEXPR_CHAR_TRAITS friend auto operator==(basic_string_view lhs, + basic_string_view rhs) + -> bool { + return lhs.compare(rhs) == 0; + } + friend auto operator!=(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) != 0; + } + friend auto operator<(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) < 0; + } + friend auto operator<=(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) <= 0; + } + friend auto operator>(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) > 0; + } + friend auto operator>=(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) >= 0; + } +}; + +using string_view = basic_string_view; + +/** Specifies if ``T`` is a character type. Can be specialized by users. */ +template struct is_char : std::false_type {}; +template <> struct is_char : std::true_type {}; + +// Returns a string view of `s`. +template ::value)> +FMT_INLINE auto to_string_view(const Char* s) -> basic_string_view { + return s; +} +template +inline auto to_string_view(const std::basic_string& s) + -> basic_string_view { + return s; +} +template +constexpr auto to_string_view(basic_string_view s) + -> basic_string_view { + return s; +} +template >::value)> +inline auto to_string_view(detail::std_string_view s) + -> basic_string_view { + return s; +} + +// A base class for compile-time strings. It is defined in the fmt namespace to +// make formatting functions visible via ADL, e.g. format(FMT_STRING("{}"), 42). +struct compile_string {}; + +template +struct is_compile_string : std::is_base_of {}; + +template ::value)> +constexpr auto to_string_view(const S& s) + -> basic_string_view { + return basic_string_view(s); +} + +FMT_BEGIN_DETAIL_NAMESPACE + +void to_string_view(...); +using fmt::to_string_view; + +// Specifies whether S is a string type convertible to fmt::basic_string_view. +// It should be a constexpr function but MSVC 2017 fails to compile it in +// enable_if and MSVC 2015 fails to compile it as an alias template. +template +struct is_string : std::is_class()))> { +}; + +template struct char_t_impl {}; +template struct char_t_impl::value>> { + using result = decltype(to_string_view(std::declval())); + using type = typename result::value_type; +}; + +// Reports a compile-time error if S is not a valid format string. +template ::value)> +FMT_INLINE void check_format_string(const S&) { +#ifdef FMT_ENFORCE_COMPILE_STRING + static_assert(is_compile_string::value, + "FMT_ENFORCE_COMPILE_STRING requires all format strings to use " + "FMT_STRING."); +#endif +} +template ::value)> +void check_format_string(S); + +FMT_NORETURN FMT_API void throw_format_error(const char* message); + +struct error_handler { + constexpr error_handler() = default; + constexpr error_handler(const error_handler&) = default; + + // This function is intentionally not constexpr to give a compile-time error. + FMT_NORETURN FMT_API void on_error(const char* message); +}; +FMT_END_DETAIL_NAMESPACE + +/** String's character type. */ +template using char_t = typename detail::char_t_impl::type; + +/** + \rst + Parsing context consisting of a format string range being parsed and an + argument counter for automatic indexing. + You can use the ``format_parse_context`` type alias for ``char`` instead. + \endrst + */ +template +class basic_format_parse_context : private ErrorHandler { + private: + basic_string_view format_str_; + int next_arg_id_; + + public: + using char_type = Char; + using iterator = typename basic_string_view::iterator; + + explicit constexpr basic_format_parse_context( + basic_string_view format_str, ErrorHandler eh = {}, + int next_arg_id = 0) + : ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {} + + /** + Returns an iterator to the beginning of the format string range being + parsed. + */ + constexpr auto begin() const FMT_NOEXCEPT -> iterator { + return format_str_.begin(); + } + + /** + Returns an iterator past the end of the format string range being parsed. + */ + constexpr auto end() const FMT_NOEXCEPT -> iterator { + return format_str_.end(); + } + + /** Advances the begin iterator to ``it``. */ + FMT_CONSTEXPR void advance_to(iterator it) { + format_str_.remove_prefix(detail::to_unsigned(it - begin())); + } + + /** + Reports an error if using the manual argument indexing; otherwise returns + the next argument index and switches to the automatic indexing. + */ + FMT_CONSTEXPR auto next_arg_id() -> int { + // Don't check if the argument id is valid to avoid overhead and because it + // will be checked during formatting anyway. + if (next_arg_id_ >= 0) return next_arg_id_++; + on_error("cannot switch from manual to automatic argument indexing"); + return 0; + } + + /** + Reports an error if using the automatic argument indexing; otherwise + switches to the manual indexing. + */ + FMT_CONSTEXPR void check_arg_id(int) { + if (next_arg_id_ > 0) + on_error("cannot switch from automatic to manual argument indexing"); + else + next_arg_id_ = -1; + } + + FMT_CONSTEXPR void check_arg_id(basic_string_view) {} + + FMT_CONSTEXPR void on_error(const char* message) { + ErrorHandler::on_error(message); + } + + constexpr auto error_handler() const -> ErrorHandler { return *this; } +}; + +using format_parse_context = basic_format_parse_context; + +template class basic_format_arg; +template class basic_format_args; +template class dynamic_format_arg_store; + +// A formatter for objects of type T. +template +struct formatter { + // A deleted default constructor indicates a disabled formatter. + formatter() = delete; +}; + +// Specifies if T has an enabled formatter specialization. A type can be +// formattable even if it doesn't have a formatter e.g. via a conversion. +template +using has_formatter = + std::is_constructible>; + +// Checks whether T is a container with contiguous storage. +template struct is_contiguous : std::false_type {}; +template +struct is_contiguous> : std::true_type {}; + +class appender; + +FMT_BEGIN_DETAIL_NAMESPACE + +template +constexpr auto has_const_formatter_impl(T*) + -> decltype(typename Context::template formatter_type().format( + std::declval(), std::declval()), + true) { + return true; +} +template +constexpr auto has_const_formatter_impl(...) -> bool { + return false; +} +template +constexpr auto has_const_formatter() -> bool { + return has_const_formatter_impl(static_cast(nullptr)); +} + +// Extracts a reference to the container from back_insert_iterator. +template +inline auto get_container(std::back_insert_iterator it) + -> Container& { + using bi_iterator = std::back_insert_iterator; + struct accessor : bi_iterator { + accessor(bi_iterator iter) : bi_iterator(iter) {} + using bi_iterator::container; + }; + return *accessor(it).container; +} + +template +FMT_CONSTEXPR auto copy_str(InputIt begin, InputIt end, OutputIt out) + -> OutputIt { + while (begin != end) *out++ = static_cast(*begin++); + return out; +} + +template , U>::value&& is_char::value)> +FMT_CONSTEXPR auto copy_str(T* begin, T* end, U* out) -> U* { + if (is_constant_evaluated()) return copy_str(begin, end, out); + auto size = to_unsigned(end - begin); + memcpy(out, begin, size * sizeof(U)); + return out + size; +} + +/** + \rst + A contiguous memory buffer with an optional growing ability. It is an internal + class and shouldn't be used directly, only via `~fmt::basic_memory_buffer`. + \endrst + */ +template class buffer { + private: + T* ptr_; + size_t size_; + size_t capacity_; + + protected: + // Don't initialize ptr_ since it is not accessed to save a few cycles. + FMT_MSC_WARNING(suppress : 26495) + buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {} + + FMT_CONSTEXPR20 buffer(T* p = nullptr, size_t sz = 0, + size_t cap = 0) FMT_NOEXCEPT : ptr_(p), + size_(sz), + capacity_(cap) {} + + FMT_CONSTEXPR20 ~buffer() = default; + buffer(buffer&&) = default; + + /** Sets the buffer data and capacity. */ + FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT { + ptr_ = buf_data; + capacity_ = buf_capacity; + } + + /** Increases the buffer capacity to hold at least *capacity* elements. */ + virtual FMT_CONSTEXPR20 void grow(size_t capacity) = 0; + + public: + using value_type = T; + using const_reference = const T&; + + buffer(const buffer&) = delete; + void operator=(const buffer&) = delete; + + auto begin() FMT_NOEXCEPT -> T* { return ptr_; } + auto end() FMT_NOEXCEPT -> T* { return ptr_ + size_; } + + auto begin() const FMT_NOEXCEPT -> const T* { return ptr_; } + auto end() const FMT_NOEXCEPT -> const T* { return ptr_ + size_; } + + /** Returns the size of this buffer. */ + constexpr auto size() const FMT_NOEXCEPT -> size_t { return size_; } + + /** Returns the capacity of this buffer. */ + constexpr auto capacity() const FMT_NOEXCEPT -> size_t { return capacity_; } + + /** Returns a pointer to the buffer data. */ + FMT_CONSTEXPR auto data() FMT_NOEXCEPT -> T* { return ptr_; } + + /** Returns a pointer to the buffer data. */ + FMT_CONSTEXPR auto data() const FMT_NOEXCEPT -> const T* { return ptr_; } + + /** Clears this buffer. */ + void clear() { size_ = 0; } + + // Tries resizing the buffer to contain *count* elements. If T is a POD type + // the new elements may not be initialized. + FMT_CONSTEXPR20 void try_resize(size_t count) { + try_reserve(count); + size_ = count <= capacity_ ? count : capacity_; + } + + // Tries increasing the buffer capacity to *new_capacity*. It can increase the + // capacity by a smaller amount than requested but guarantees there is space + // for at least one additional element either by increasing the capacity or by + // flushing the buffer if it is full. + FMT_CONSTEXPR20 void try_reserve(size_t new_capacity) { + if (new_capacity > capacity_) grow(new_capacity); + } + + FMT_CONSTEXPR20 void push_back(const T& value) { + try_reserve(size_ + 1); + ptr_[size_++] = value; + } + + /** Appends data to the end of the buffer. */ + template void append(const U* begin, const U* end); + + template FMT_CONSTEXPR auto operator[](I index) -> T& { + return ptr_[index]; + } + template + FMT_CONSTEXPR auto operator[](I index) const -> const T& { + return ptr_[index]; + } +}; + +struct buffer_traits { + explicit buffer_traits(size_t) {} + auto count() const -> size_t { return 0; } + auto limit(size_t size) -> size_t { return size; } +}; + +class fixed_buffer_traits { + private: + size_t count_ = 0; + size_t limit_; + + public: + explicit fixed_buffer_traits(size_t limit) : limit_(limit) {} + auto count() const -> size_t { return count_; } + auto limit(size_t size) -> size_t { + size_t n = limit_ > count_ ? limit_ - count_ : 0; + count_ += size; + return size < n ? size : n; + } +}; + +// A buffer that writes to an output iterator when flushed. +template +class iterator_buffer final : public Traits, public buffer { + private: + OutputIt out_; + enum { buffer_size = 256 }; + T data_[buffer_size]; + + protected: + FMT_CONSTEXPR20 void grow(size_t) override { + if (this->size() == buffer_size) flush(); + } + + void flush() { + auto size = this->size(); + this->clear(); + out_ = copy_str(data_, data_ + this->limit(size), out_); + } + + public: + explicit iterator_buffer(OutputIt out, size_t n = buffer_size) + : Traits(n), buffer(data_, 0, buffer_size), out_(out) {} + iterator_buffer(iterator_buffer&& other) + : Traits(other), buffer(data_, 0, buffer_size), out_(other.out_) {} + ~iterator_buffer() { flush(); } + + auto out() -> OutputIt { + flush(); + return out_; + } + auto count() const -> size_t { return Traits::count() + this->size(); } +}; + +template +class iterator_buffer final + : public fixed_buffer_traits, + public buffer { + private: + T* out_; + enum { buffer_size = 256 }; + T data_[buffer_size]; + + protected: + FMT_CONSTEXPR20 void grow(size_t) override { + if (this->size() == this->capacity()) flush(); + } + + void flush() { + size_t n = this->limit(this->size()); + if (this->data() == out_) { + out_ += n; + this->set(data_, buffer_size); + } + this->clear(); + } + + public: + explicit iterator_buffer(T* out, size_t n = buffer_size) + : fixed_buffer_traits(n), buffer(out, 0, n), out_(out) {} + iterator_buffer(iterator_buffer&& other) + : fixed_buffer_traits(other), + buffer(std::move(other)), + out_(other.out_) { + if (this->data() != out_) { + this->set(data_, buffer_size); + this->clear(); + } + } + ~iterator_buffer() { flush(); } + + auto out() -> T* { + flush(); + return out_; + } + auto count() const -> size_t { + return fixed_buffer_traits::count() + this->size(); + } +}; + +template class iterator_buffer final : public buffer { + protected: + FMT_CONSTEXPR20 void grow(size_t) override {} + + public: + explicit iterator_buffer(T* out, size_t = 0) : buffer(out, 0, ~size_t()) {} + + auto out() -> T* { return &*this->end(); } +}; + +// A buffer that writes to a container with the contiguous storage. +template +class iterator_buffer, + enable_if_t::value, + typename Container::value_type>> + final : public buffer { + private: + Container& container_; + + protected: + FMT_CONSTEXPR20 void grow(size_t capacity) override { + container_.resize(capacity); + this->set(&container_[0], capacity); + } + + public: + explicit iterator_buffer(Container& c) + : buffer(c.size()), container_(c) {} + explicit iterator_buffer(std::back_insert_iterator out, size_t = 0) + : iterator_buffer(get_container(out)) {} + auto out() -> std::back_insert_iterator { + return std::back_inserter(container_); + } +}; + +// A buffer that counts the number of code units written discarding the output. +template class counting_buffer final : public buffer { + private: + enum { buffer_size = 256 }; + T data_[buffer_size]; + size_t count_ = 0; + + protected: + FMT_CONSTEXPR20 void grow(size_t) override { + if (this->size() != buffer_size) return; + count_ += this->size(); + this->clear(); + } + + public: + counting_buffer() : buffer(data_, 0, buffer_size) {} + + auto count() -> size_t { return count_ + this->size(); } +}; + +template +using buffer_appender = conditional_t::value, appender, + std::back_insert_iterator>>; + +// Maps an output iterator to a buffer. +template +auto get_buffer(OutputIt out) -> iterator_buffer { + return iterator_buffer(out); +} + +template +auto get_iterator(Buffer& buf) -> decltype(buf.out()) { + return buf.out(); +} +template auto get_iterator(buffer& buf) -> buffer_appender { + return buffer_appender(buf); +} + +template +struct fallback_formatter { + fallback_formatter() = delete; +}; + +// Specifies if T has an enabled fallback_formatter specialization. +template +using has_fallback_formatter = + std::is_constructible>; + +struct view {}; + +template struct named_arg : view { + const Char* name; + const T& value; + named_arg(const Char* n, const T& v) : name(n), value(v) {} +}; + +template struct named_arg_info { + const Char* name; + int id; +}; + +template +struct arg_data { + // args_[0].named_args points to named_args_ to avoid bloating format_args. + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)]; + named_arg_info named_args_[NUM_NAMED_ARGS]; + + template + arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {} + arg_data(const arg_data& other) = delete; + auto args() const -> const T* { return args_ + 1; } + auto named_args() -> named_arg_info* { return named_args_; } +}; + +template +struct arg_data { + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + T args_[NUM_ARGS != 0 ? NUM_ARGS : +1]; + + template + FMT_CONSTEXPR FMT_INLINE arg_data(const U&... init) : args_{init...} {} + FMT_CONSTEXPR FMT_INLINE auto args() const -> const T* { return args_; } + FMT_CONSTEXPR FMT_INLINE auto named_args() -> std::nullptr_t { + return nullptr; + } +}; + +template +inline void init_named_args(named_arg_info*, int, int) {} + +template struct is_named_arg : std::false_type {}; +template struct is_statically_named_arg : std::false_type {}; + +template +struct is_named_arg> : std::true_type {}; + +template ::value)> +void init_named_args(named_arg_info* named_args, int arg_count, + int named_arg_count, const T&, const Tail&... args) { + init_named_args(named_args, arg_count + 1, named_arg_count, args...); +} + +template ::value)> +void init_named_args(named_arg_info* named_args, int arg_count, + int named_arg_count, const T& arg, const Tail&... args) { + named_args[named_arg_count++] = {arg.name, arg_count}; + init_named_args(named_args, arg_count + 1, named_arg_count, args...); +} + +template +FMT_CONSTEXPR FMT_INLINE void init_named_args(std::nullptr_t, int, int, + const Args&...) {} + +template constexpr auto count() -> size_t { return B ? 1 : 0; } +template constexpr auto count() -> size_t { + return (B1 ? 1 : 0) + count(); +} + +template constexpr auto count_named_args() -> size_t { + return count::value...>(); +} + +template +constexpr auto count_statically_named_args() -> size_t { + return count::value...>(); +} + +enum class type { + none_type, + // Integer types should go first, + int_type, + uint_type, + long_long_type, + ulong_long_type, + int128_type, + uint128_type, + bool_type, + char_type, + last_integer_type = char_type, + // followed by floating-point types. + float_type, + double_type, + long_double_type, + last_numeric_type = long_double_type, + cstring_type, + string_type, + pointer_type, + custom_type +}; + +// Maps core type T to the corresponding type enum constant. +template +struct type_constant : std::integral_constant {}; + +#define FMT_TYPE_CONSTANT(Type, constant) \ + template \ + struct type_constant \ + : std::integral_constant {} + +FMT_TYPE_CONSTANT(int, int_type); +FMT_TYPE_CONSTANT(unsigned, uint_type); +FMT_TYPE_CONSTANT(long long, long_long_type); +FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); +FMT_TYPE_CONSTANT(int128_t, int128_type); +FMT_TYPE_CONSTANT(uint128_t, uint128_type); +FMT_TYPE_CONSTANT(bool, bool_type); +FMT_TYPE_CONSTANT(Char, char_type); +FMT_TYPE_CONSTANT(float, float_type); +FMT_TYPE_CONSTANT(double, double_type); +FMT_TYPE_CONSTANT(long double, long_double_type); +FMT_TYPE_CONSTANT(const Char*, cstring_type); +FMT_TYPE_CONSTANT(basic_string_view, string_type); +FMT_TYPE_CONSTANT(const void*, pointer_type); + +constexpr bool is_integral_type(type t) { + return t > type::none_type && t <= type::last_integer_type; +} + +constexpr bool is_arithmetic_type(type t) { + return t > type::none_type && t <= type::last_numeric_type; +} + +struct unformattable {}; +struct unformattable_char : unformattable {}; +struct unformattable_const : unformattable {}; +struct unformattable_pointer : unformattable {}; + +template struct string_value { + const Char* data; + size_t size; +}; + +template struct named_arg_value { + const named_arg_info* data; + size_t size; +}; + +template struct custom_value { + using parse_context = typename Context::parse_context_type; + void* value; + void (*format)(void* arg, parse_context& parse_ctx, Context& ctx); +}; + +// A formatting argument value. +template class value { + public: + using char_type = typename Context::char_type; + + union { + monostate no_value; + int int_value; + unsigned uint_value; + long long long_long_value; + unsigned long long ulong_long_value; + int128_t int128_value; + uint128_t uint128_value; + bool bool_value; + char_type char_value; + float float_value; + double double_value; + long double long_double_value; + const void* pointer; + string_value string; + custom_value custom; + named_arg_value named_args; + }; + + constexpr FMT_INLINE value() : no_value() {} + constexpr FMT_INLINE value(int val) : int_value(val) {} + constexpr FMT_INLINE value(unsigned val) : uint_value(val) {} + constexpr FMT_INLINE value(long long val) : long_long_value(val) {} + constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {} + FMT_INLINE value(int128_t val) : int128_value(val) {} + FMT_INLINE value(uint128_t val) : uint128_value(val) {} + constexpr FMT_INLINE value(float val) : float_value(val) {} + constexpr FMT_INLINE value(double val) : double_value(val) {} + FMT_INLINE value(long double val) : long_double_value(val) {} + constexpr FMT_INLINE value(bool val) : bool_value(val) {} + constexpr FMT_INLINE value(char_type val) : char_value(val) {} + FMT_CONSTEXPR FMT_INLINE value(const char_type* val) { + string.data = val; + if (is_constant_evaluated()) string.size = {}; + } + FMT_CONSTEXPR FMT_INLINE value(basic_string_view val) { + string.data = val.data(); + string.size = val.size(); + } + FMT_INLINE value(const void* val) : pointer(val) {} + FMT_INLINE value(const named_arg_info* args, size_t size) + : named_args{args, size} {} + + template FMT_CONSTEXPR FMT_INLINE value(T& val) { + using value_type = remove_cvref_t; + custom.value = const_cast(&val); + // Get the formatter type through the context to allow different contexts + // have different extension points, e.g. `formatter` for `format` and + // `printf_formatter` for `printf`. + custom.format = format_custom_arg< + value_type, + conditional_t::value, + typename Context::template formatter_type, + fallback_formatter>>; + } + value(unformattable); + value(unformattable_char); + value(unformattable_const); + value(unformattable_pointer); + + private: + // Formats an argument of a custom type, such as a user-defined class. + template + static void format_custom_arg(void* arg, + typename Context::parse_context_type& parse_ctx, + Context& ctx) { + auto f = Formatter(); + parse_ctx.advance_to(f.parse(parse_ctx)); + using qualified_type = + conditional_t(), const T, T>; + ctx.advance_to(f.format(*static_cast(arg), ctx)); + } +}; + +template +FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg; + +// To minimize the number of types we need to deal with, long is translated +// either to int or to long long depending on its size. +enum { long_short = sizeof(long) == sizeof(int) }; +using long_type = conditional_t; +using ulong_type = conditional_t; + +// Maps formatting arguments to core types. +// arg_mapper reports errors by returning unformattable instead of using +// static_assert because it's used in the is_formattable trait. +template struct arg_mapper { + using char_type = typename Context::char_type; + + FMT_CONSTEXPR FMT_INLINE auto map(signed char val) -> int { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(unsigned char val) -> unsigned { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(short val) -> int { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(unsigned short val) -> unsigned { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(int val) -> int { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(unsigned val) -> unsigned { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(long val) -> long_type { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(unsigned long val) -> ulong_type { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(long long val) -> long long { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(unsigned long long val) + -> unsigned long long { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(int128_t val) -> int128_t { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(uint128_t val) -> uint128_t { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(bool val) -> bool { return val; } + + template ::value || + std::is_same::value)> + FMT_CONSTEXPR FMT_INLINE auto map(T val) -> char_type { + return val; + } + template ::value || +#ifdef __cpp_char8_t + std::is_same::value || +#endif + std::is_same::value || + std::is_same::value) && + !std::is_same::value, + int> = 0> + FMT_CONSTEXPR FMT_INLINE auto map(T) -> unformattable_char { + return {}; + } + + FMT_CONSTEXPR FMT_INLINE auto map(float val) -> float { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(double val) -> double { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(long double val) -> long double { + return val; + } + + FMT_CONSTEXPR FMT_INLINE auto map(char_type* val) -> const char_type* { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(const char_type* val) -> const char_type* { + return val; + } + template ::value && !std::is_pointer::value && + std::is_same>::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T& val) + -> basic_string_view { + return to_string_view(val); + } + template ::value && !std::is_pointer::value && + !std::is_same>::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T&) -> unformattable_char { + return {}; + } + template , T>::value && + !is_string::value && !has_formatter::value && + !has_fallback_formatter::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T& val) + -> basic_string_view { + return basic_string_view(val); + } + template < + typename T, + FMT_ENABLE_IF( + std::is_constructible, T>::value && + !std::is_constructible, T>::value && + !is_string::value && !has_formatter::value && + !has_fallback_formatter::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T& val) + -> basic_string_view { + return std_string_view(val); + } + + using cstring_result = conditional_t::value, + const char*, unformattable_pointer>; + + FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val) + -> cstring_result { + return map(reinterpret_cast(val)); + } + FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val) + -> cstring_result { + return map(reinterpret_cast(val)); + } + FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(signed char* val) + -> cstring_result { + return map(reinterpret_cast(val)); + } + FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(unsigned char* val) + -> cstring_result { + return map(reinterpret_cast(val)); + } + + FMT_CONSTEXPR FMT_INLINE auto map(void* val) -> const void* { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(const void* val) -> const void* { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(std::nullptr_t val) -> const void* { + return val; + } + + // We use SFINAE instead of a const T* parameter to avoid conflicting with + // the C array overload. + template < + typename T, + FMT_ENABLE_IF( + std::is_member_pointer::value || + std::is_function::type>::value || + (std::is_convertible::value && + !std::is_convertible::value))> + FMT_CONSTEXPR auto map(const T&) -> unformattable_pointer { + return {}; + } + + template ::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T (&values)[N]) -> const T (&)[N] { + return values; + } + + template ::value&& std::is_convertible::value && + !has_formatter::value && + !has_fallback_formatter::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T& val) + -> decltype(std::declval().map( + static_cast::type>(val))) { + return map(static_cast::type>(val)); + } + + FMT_CONSTEXPR FMT_INLINE auto map(detail::byte val) -> unsigned { + return map(static_cast(val)); + } + + template > + struct formattable + : bool_constant() || + !std::is_const>::value || + has_fallback_formatter::value> {}; + +#if FMT_MSC_VER != 0 && FMT_MSC_VER < 1910 + // Workaround a bug in MSVC. + template FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& { + return val; + } +#else + template ::value)> + FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& { + return val; + } + template ::value)> + FMT_CONSTEXPR FMT_INLINE auto do_map(T&&) -> unformattable_const { + return {}; + } +#endif + + template , + FMT_ENABLE_IF(!is_string::value && !is_char::value && + !std::is_array::value && + (has_formatter::value || + has_fallback_formatter::value))> + FMT_CONSTEXPR FMT_INLINE auto map(T&& val) + -> decltype(this->do_map(std::forward(val))) { + return do_map(std::forward(val)); + } + + template ::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T& named_arg) + -> decltype(std::declval().map(named_arg.value)) { + return map(named_arg.value); + } + + auto map(...) -> unformattable { return {}; } +}; + +// A type constant after applying arg_mapper. +template +using mapped_type_constant = + type_constant().map(std::declval())), + typename Context::char_type>; + +enum { packed_arg_bits = 4 }; +// Maximum number of arguments with packed types. +enum { max_packed_args = 62 / packed_arg_bits }; +enum : unsigned long long { is_unpacked_bit = 1ULL << 63 }; +enum : unsigned long long { has_named_args_bit = 1ULL << 62 }; + +FMT_END_DETAIL_NAMESPACE + +// An output iterator that appends to a buffer. +// It is used to reduce symbol sizes for the common case. +class appender : public std::back_insert_iterator> { + using base = std::back_insert_iterator>; + + template + friend auto get_buffer(appender out) -> detail::buffer& { + return detail::get_container(out); + } + + public: + using std::back_insert_iterator>::back_insert_iterator; + appender(base it) FMT_NOEXCEPT : base(it) {} + using _Unchecked_type = appender; // Mark iterator as checked. + + auto operator++() FMT_NOEXCEPT -> appender& { return *this; } + + auto operator++(int) FMT_NOEXCEPT -> appender { return *this; } +}; + +// A formatting argument. It is a trivially copyable/constructible type to +// allow storage in basic_memory_buffer. +template class basic_format_arg { + private: + detail::value value_; + detail::type type_; + + template + friend FMT_CONSTEXPR auto detail::make_arg(const T& value) + -> basic_format_arg; + + template + friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis, + const basic_format_arg& arg) + -> decltype(vis(0)); + + friend class basic_format_args; + friend class dynamic_format_arg_store; + + using char_type = typename Context::char_type; + + template + friend struct detail::arg_data; + + basic_format_arg(const detail::named_arg_info* args, size_t size) + : value_(args, size) {} + + public: + class handle { + public: + explicit handle(detail::custom_value custom) : custom_(custom) {} + + void format(typename Context::parse_context_type& parse_ctx, + Context& ctx) const { + custom_.format(custom_.value, parse_ctx, ctx); + } + + private: + detail::custom_value custom_; + }; + + constexpr basic_format_arg() : type_(detail::type::none_type) {} + + constexpr explicit operator bool() const FMT_NOEXCEPT { + return type_ != detail::type::none_type; + } + + auto type() const -> detail::type { return type_; } + + auto is_integral() const -> bool { return detail::is_integral_type(type_); } + auto is_arithmetic() const -> bool { + return detail::is_arithmetic_type(type_); + } +}; + +/** + \rst + Visits an argument dispatching to the appropriate visit method based on + the argument type. For example, if the argument type is ``double`` then + ``vis(value)`` will be called with the value of type ``double``. + \endrst + */ +template +FMT_CONSTEXPR FMT_INLINE auto visit_format_arg( + Visitor&& vis, const basic_format_arg& arg) -> decltype(vis(0)) { + switch (arg.type_) { + case detail::type::none_type: + break; + case detail::type::int_type: + return vis(arg.value_.int_value); + case detail::type::uint_type: + return vis(arg.value_.uint_value); + case detail::type::long_long_type: + return vis(arg.value_.long_long_value); + case detail::type::ulong_long_type: + return vis(arg.value_.ulong_long_value); + case detail::type::int128_type: + return vis(detail::convert_for_visit(arg.value_.int128_value)); + case detail::type::uint128_type: + return vis(detail::convert_for_visit(arg.value_.uint128_value)); + case detail::type::bool_type: + return vis(arg.value_.bool_value); + case detail::type::char_type: + return vis(arg.value_.char_value); + case detail::type::float_type: + return vis(arg.value_.float_value); + case detail::type::double_type: + return vis(arg.value_.double_value); + case detail::type::long_double_type: + return vis(arg.value_.long_double_value); + case detail::type::cstring_type: + return vis(arg.value_.string.data); + case detail::type::string_type: + using sv = basic_string_view; + return vis(sv(arg.value_.string.data, arg.value_.string.size)); + case detail::type::pointer_type: + return vis(arg.value_.pointer); + case detail::type::custom_type: + return vis(typename basic_format_arg::handle(arg.value_.custom)); + } + return vis(monostate()); +} + +FMT_BEGIN_DETAIL_NAMESPACE + +template +auto copy_str(InputIt begin, InputIt end, appender out) -> appender { + get_container(out).append(begin, end); + return out; +} + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 +// A workaround for gcc 4.8 to make void_t work in a SFINAE context. +template struct void_t_impl { using type = void; }; +template +using void_t = typename detail::void_t_impl::type; +#else +template using void_t = void; +#endif + +template +struct is_output_iterator : std::false_type {}; + +template +struct is_output_iterator< + It, T, + void_t::iterator_category, + decltype(*std::declval() = std::declval())>> + : std::true_type {}; + +template +struct is_back_insert_iterator : std::false_type {}; +template +struct is_back_insert_iterator> + : std::true_type {}; + +template +struct is_contiguous_back_insert_iterator : std::false_type {}; +template +struct is_contiguous_back_insert_iterator> + : is_contiguous {}; +template <> +struct is_contiguous_back_insert_iterator : std::true_type {}; + +// A type-erased reference to an std::locale to avoid heavy include. +class locale_ref { + private: + const void* locale_; // A type-erased pointer to std::locale. + + public: + constexpr locale_ref() : locale_(nullptr) {} + template explicit locale_ref(const Locale& loc); + + explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; } + + template auto get() const -> Locale; +}; + +template constexpr auto encode_types() -> unsigned long long { + return 0; +} + +template +constexpr auto encode_types() -> unsigned long long { + return static_cast(mapped_type_constant::value) | + (encode_types() << packed_arg_bits); +} + +template +FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg { + basic_format_arg arg; + arg.type_ = mapped_type_constant::value; + arg.value_ = arg_mapper().map(value); + return arg; +} + +// The type template parameter is there to avoid an ODR violation when using +// a fallback formatter in one translation unit and an implicit conversion in +// another (not recommended). +template +FMT_CONSTEXPR FMT_INLINE auto make_arg(T&& val) -> value { + const auto& arg = arg_mapper().map(std::forward(val)); + + constexpr bool formattable_char = + !std::is_same::value; + static_assert(formattable_char, "Mixing character types is disallowed."); + + constexpr bool formattable_const = + !std::is_same::value; + static_assert(formattable_const, "Cannot format a const argument."); + + // Formatting of arbitrary pointers is disallowed. If you want to output + // a pointer cast it to "void *" or "const void *". In particular, this + // forbids formatting of "[const] volatile char *" which is printed as bool + // by iostreams. + constexpr bool formattable_pointer = + !std::is_same::value; + static_assert(formattable_pointer, + "Formatting of non-void pointers is disallowed."); + + constexpr bool formattable = + !std::is_same::value; + static_assert( + formattable, + "Cannot format an argument. To make type T formattable provide a " + "formatter specialization: https://fmt.dev/latest/api.html#udt"); + return {arg}; +} + +template +inline auto make_arg(const T& value) -> basic_format_arg { + return make_arg(value); +} +FMT_END_DETAIL_NAMESPACE + +// Formatting context. +template class basic_format_context { + public: + /** The character type for the output. */ + using char_type = Char; + + private: + OutputIt out_; + basic_format_args args_; + detail::locale_ref loc_; + + public: + using iterator = OutputIt; + using format_arg = basic_format_arg; + using parse_context_type = basic_format_parse_context; + template using formatter_type = formatter; + + basic_format_context(basic_format_context&&) = default; + basic_format_context(const basic_format_context&) = delete; + void operator=(const basic_format_context&) = delete; + /** + Constructs a ``basic_format_context`` object. References to the arguments are + stored in the object so make sure they have appropriate lifetimes. + */ + constexpr basic_format_context( + OutputIt out, basic_format_args ctx_args, + detail::locale_ref loc = detail::locale_ref()) + : out_(out), args_(ctx_args), loc_(loc) {} + + constexpr auto arg(int id) const -> format_arg { return args_.get(id); } + FMT_CONSTEXPR auto arg(basic_string_view name) -> format_arg { + return args_.get(name); + } + FMT_CONSTEXPR auto arg_id(basic_string_view name) -> int { + return args_.get_id(name); + } + auto args() const -> const basic_format_args& { + return args_; + } + + FMT_CONSTEXPR auto error_handler() -> detail::error_handler { return {}; } + void on_error(const char* message) { error_handler().on_error(message); } + + // Returns an iterator to the beginning of the output range. + FMT_CONSTEXPR auto out() -> iterator { return out_; } + + // Advances the begin iterator to ``it``. + void advance_to(iterator it) { + if (!detail::is_back_insert_iterator()) out_ = it; + } + + FMT_CONSTEXPR auto locale() -> detail::locale_ref { return loc_; } +}; + +template +using buffer_context = + basic_format_context, Char>; +using format_context = buffer_context; + +// Workaround an alias issue: https://stackoverflow.com/q/62767544/471164. +#define FMT_BUFFER_CONTEXT(Char) \ + basic_format_context, Char> + +template +using is_formattable = bool_constant< + !std::is_base_of>().map( + std::declval()))>::value && + !detail::has_fallback_formatter::value>; + +/** + \rst + An array of references to arguments. It can be implicitly converted into + `~fmt::basic_format_args` for passing into type-erased formatting functions + such as `~fmt::vformat`. + \endrst + */ +template +class format_arg_store +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 + // Workaround a GCC template argument substitution bug. + : public basic_format_args +#endif +{ + private: + static const size_t num_args = sizeof...(Args); + static const size_t num_named_args = detail::count_named_args(); + static const bool is_packed = num_args <= detail::max_packed_args; + + using value_type = conditional_t, + basic_format_arg>; + + detail::arg_data + data_; + + friend class basic_format_args; + + static constexpr unsigned long long desc = + (is_packed ? detail::encode_types() + : detail::is_unpacked_bit | num_args) | + (num_named_args != 0 + ? static_cast(detail::has_named_args_bit) + : 0); + + public: + template + FMT_CONSTEXPR FMT_INLINE format_arg_store(T&&... args) + : +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 + basic_format_args(*this), +#endif + data_{detail::make_arg< + is_packed, Context, + detail::mapped_type_constant, Context>::value>( + std::forward(args))...} { + detail::init_named_args(data_.named_args(), 0, 0, args...); + } +}; + +/** + \rst + Constructs a `~fmt::format_arg_store` object that contains references to + arguments and can be implicitly converted to `~fmt::format_args`. `Context` + can be omitted in which case it defaults to `~fmt::context`. + See `~fmt::arg` for lifetime considerations. + \endrst + */ +template +constexpr auto make_format_args(Args&&... args) + -> format_arg_store...> { + return {std::forward(args)...}; +} + +/** + \rst + Returns a named argument to be used in a formatting function. + It should only be used in a call to a formatting function or + `dynamic_format_arg_store::push_back`. + + **Example**:: + + fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)); + \endrst + */ +template +inline auto arg(const Char* name, const T& arg) -> detail::named_arg { + static_assert(!detail::is_named_arg(), "nested named arguments"); + return {name, arg}; +} + +/** + \rst + A view of a collection of formatting arguments. To avoid lifetime issues it + should only be used as a parameter type in type-erased functions such as + ``vformat``:: + + void vlog(string_view format_str, format_args args); // OK + format_args args = make_format_args(42); // Error: dangling reference + \endrst + */ +template class basic_format_args { + public: + using size_type = int; + using format_arg = basic_format_arg; + + private: + // A descriptor that contains information about formatting arguments. + // If the number of arguments is less or equal to max_packed_args then + // argument types are passed in the descriptor. This reduces binary code size + // per formatting function call. + unsigned long long desc_; + union { + // If is_packed() returns true then argument values are stored in values_; + // otherwise they are stored in args_. This is done to improve cache + // locality and reduce compiled code size since storing larger objects + // may require more code (at least on x86-64) even if the same amount of + // data is actually copied to stack. It saves ~10% on the bloat test. + const detail::value* values_; + const format_arg* args_; + }; + + constexpr auto is_packed() const -> bool { + return (desc_ & detail::is_unpacked_bit) == 0; + } + auto has_named_args() const -> bool { + return (desc_ & detail::has_named_args_bit) != 0; + } + + FMT_CONSTEXPR auto type(int index) const -> detail::type { + int shift = index * detail::packed_arg_bits; + unsigned int mask = (1 << detail::packed_arg_bits) - 1; + return static_cast((desc_ >> shift) & mask); + } + + constexpr FMT_INLINE basic_format_args(unsigned long long desc, + const detail::value* values) + : desc_(desc), values_(values) {} + constexpr basic_format_args(unsigned long long desc, const format_arg* args) + : desc_(desc), args_(args) {} + + public: + constexpr basic_format_args() : desc_(0), args_(nullptr) {} + + /** + \rst + Constructs a `basic_format_args` object from `~fmt::format_arg_store`. + \endrst + */ + template + constexpr FMT_INLINE basic_format_args( + const format_arg_store& store) + : basic_format_args(format_arg_store::desc, + store.data_.args()) {} + + /** + \rst + Constructs a `basic_format_args` object from + `~fmt::dynamic_format_arg_store`. + \endrst + */ + constexpr FMT_INLINE basic_format_args( + const dynamic_format_arg_store& store) + : basic_format_args(store.get_types(), store.data()) {} + + /** + \rst + Constructs a `basic_format_args` object from a dynamic set of arguments. + \endrst + */ + constexpr basic_format_args(const format_arg* args, int count) + : basic_format_args(detail::is_unpacked_bit | detail::to_unsigned(count), + args) {} + + /** Returns the argument with the specified id. */ + FMT_CONSTEXPR auto get(int id) const -> format_arg { + format_arg arg; + if (!is_packed()) { + if (id < max_size()) arg = args_[id]; + return arg; + } + if (id >= detail::max_packed_args) return arg; + arg.type_ = type(id); + if (arg.type_ == detail::type::none_type) return arg; + arg.value_ = values_[id]; + return arg; + } + + template + auto get(basic_string_view name) const -> format_arg { + int id = get_id(name); + return id >= 0 ? get(id) : format_arg(); + } + + template + auto get_id(basic_string_view name) const -> int { + if (!has_named_args()) return -1; + const auto& named_args = + (is_packed() ? values_[-1] : args_[-1].value_).named_args; + for (size_t i = 0; i < named_args.size; ++i) { + if (named_args.data[i].name == name) return named_args.data[i].id; + } + return -1; + } + + auto max_size() const -> int { + unsigned long long max_packed = detail::max_packed_args; + return static_cast(is_packed() ? max_packed + : desc_ & ~detail::is_unpacked_bit); + } +}; + +/** An alias to ``basic_format_args``. */ +// A separate type would result in shorter symbols but break ABI compatibility +// between clang and gcc on ARM (#1919). +using format_args = basic_format_args; + +// We cannot use enum classes as bit fields because of a gcc bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414. +namespace align { +enum type { none, left, right, center, numeric }; +} +using align_t = align::type; +namespace sign { +enum type { none, minus, plus, space }; +} +using sign_t = sign::type; + +FMT_BEGIN_DETAIL_NAMESPACE + +// Workaround an array initialization issue in gcc 4.8. +template struct fill_t { + private: + enum { max_size = 4 }; + Char data_[max_size] = {Char(' '), Char(0), Char(0), Char(0)}; + unsigned char size_ = 1; + + public: + FMT_CONSTEXPR void operator=(basic_string_view s) { + auto size = s.size(); + if (size > max_size) return throw_format_error("invalid fill"); + for (size_t i = 0; i < size; ++i) data_[i] = s[i]; + size_ = static_cast(size); + } + + constexpr auto size() const -> size_t { return size_; } + constexpr auto data() const -> const Char* { return data_; } + + FMT_CONSTEXPR auto operator[](size_t index) -> Char& { return data_[index]; } + FMT_CONSTEXPR auto operator[](size_t index) const -> const Char& { + return data_[index]; + } +}; +FMT_END_DETAIL_NAMESPACE + +enum class presentation_type : unsigned char { + none, + // Integer types should go first, + dec, // 'd' + oct, // 'o' + hex_lower, // 'x' + hex_upper, // 'X' + bin_lower, // 'b' + bin_upper, // 'B' + hexfloat_lower, // 'a' + hexfloat_upper, // 'A' + exp_lower, // 'e' + exp_upper, // 'E' + fixed_lower, // 'f' + fixed_upper, // 'F' + general_lower, // 'g' + general_upper, // 'G' + chr, // 'c' + string, // 's' + pointer // 'p' +}; + +// Format specifiers for built-in and string types. +template struct basic_format_specs { + int width; + int precision; + presentation_type type; + align_t align : 4; + sign_t sign : 3; + bool alt : 1; // Alternate form ('#'). + bool localized : 1; + detail::fill_t fill; + + constexpr basic_format_specs() + : width(0), + precision(-1), + type(presentation_type::none), + align(align::none), + sign(sign::none), + alt(false), + localized(false) {} +}; + +using format_specs = basic_format_specs; + +FMT_BEGIN_DETAIL_NAMESPACE + +enum class arg_id_kind { none, index, name }; + +// An argument reference. +template struct arg_ref { + FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {} + + FMT_CONSTEXPR explicit arg_ref(int index) + : kind(arg_id_kind::index), val(index) {} + FMT_CONSTEXPR explicit arg_ref(basic_string_view name) + : kind(arg_id_kind::name), val(name) {} + + FMT_CONSTEXPR auto operator=(int idx) -> arg_ref& { + kind = arg_id_kind::index; + val.index = idx; + return *this; + } + + arg_id_kind kind; + union value { + FMT_CONSTEXPR value(int id = 0) : index{id} {} + FMT_CONSTEXPR value(basic_string_view n) : name(n) {} + + int index; + basic_string_view name; + } val; +}; + +// Format specifiers with width and precision resolved at formatting rather +// than parsing time to allow re-using the same parsed specifiers with +// different sets of arguments (precompilation of format strings). +template +struct dynamic_format_specs : basic_format_specs { + arg_ref width_ref; + arg_ref precision_ref; +}; + +struct auto_id {}; + +// A format specifier handler that sets fields in basic_format_specs. +template class specs_setter { + protected: + basic_format_specs& specs_; + + public: + explicit FMT_CONSTEXPR specs_setter(basic_format_specs& specs) + : specs_(specs) {} + + FMT_CONSTEXPR specs_setter(const specs_setter& other) + : specs_(other.specs_) {} + + FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; } + FMT_CONSTEXPR void on_fill(basic_string_view fill) { + specs_.fill = fill; + } + FMT_CONSTEXPR void on_sign(sign_t s) { specs_.sign = s; } + FMT_CONSTEXPR void on_hash() { specs_.alt = true; } + FMT_CONSTEXPR void on_localized() { specs_.localized = true; } + + FMT_CONSTEXPR void on_zero() { + if (specs_.align == align::none) specs_.align = align::numeric; + specs_.fill[0] = Char('0'); + } + + FMT_CONSTEXPR void on_width(int width) { specs_.width = width; } + FMT_CONSTEXPR void on_precision(int precision) { + specs_.precision = precision; + } + FMT_CONSTEXPR void end_precision() {} + + FMT_CONSTEXPR void on_type(presentation_type type) { specs_.type = type; } +}; + +// Format spec handler that saves references to arguments representing dynamic +// width and precision to be resolved at formatting time. +template +class dynamic_specs_handler + : public specs_setter { + public: + using char_type = typename ParseContext::char_type; + + FMT_CONSTEXPR dynamic_specs_handler(dynamic_format_specs& specs, + ParseContext& ctx) + : specs_setter(specs), specs_(specs), context_(ctx) {} + + FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler& other) + : specs_setter(other), + specs_(other.specs_), + context_(other.context_) {} + + template FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { + specs_.width_ref = make_arg_ref(arg_id); + } + + template FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) { + specs_.precision_ref = make_arg_ref(arg_id); + } + + FMT_CONSTEXPR void on_error(const char* message) { + context_.on_error(message); + } + + private: + dynamic_format_specs& specs_; + ParseContext& context_; + + using arg_ref_type = arg_ref; + + FMT_CONSTEXPR auto make_arg_ref(int arg_id) -> arg_ref_type { + context_.check_arg_id(arg_id); + return arg_ref_type(arg_id); + } + + FMT_CONSTEXPR auto make_arg_ref(auto_id) -> arg_ref_type { + return arg_ref_type(context_.next_arg_id()); + } + + FMT_CONSTEXPR auto make_arg_ref(basic_string_view arg_id) + -> arg_ref_type { + context_.check_arg_id(arg_id); + basic_string_view format_str( + context_.begin(), to_unsigned(context_.end() - context_.begin())); + return arg_ref_type(arg_id); + } +}; + +template constexpr bool is_ascii_letter(Char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +// Converts a character to ASCII. Returns a number > 127 on conversion failure. +template ::value)> +constexpr auto to_ascii(Char value) -> Char { + return value; +} +template ::value)> +constexpr auto to_ascii(Char value) -> + typename std::underlying_type::type { + return value; +} + +template +FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int { + if (const_check(sizeof(Char) != 1)) return 1; + auto lengths = + "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4"; + int len = lengths[static_cast(*begin) >> 3]; + + // Compute the pointer to the next character early so that the next + // iteration can start working on the next character. Neither Clang + // nor GCC figure out this reordering on their own. + return len + !len; +} + +// Return the result via the out param to workaround gcc bug 77539. +template +FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool { + for (out = first; out != last; ++out) { + if (*out == value) return true; + } + return false; +} + +template <> +inline auto find(const char* first, const char* last, char value, + const char*& out) -> bool { + out = static_cast( + std::memchr(first, value, to_unsigned(last - first))); + return out != nullptr; +} + +// Parses the range [begin, end) as an unsigned integer. This function assumes +// that the range is non-empty and the first character is a digit. +template +FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end, + int error_value) noexcept -> int { + FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', ""); + unsigned value = 0, prev = 0; + auto p = begin; + do { + prev = value; + value = value * 10 + unsigned(*p - '0'); + ++p; + } while (p != end && '0' <= *p && *p <= '9'); + auto num_digits = p - begin; + begin = p; + if (num_digits <= std::numeric_limits::digits10) + return static_cast(value); + // Check for overflow. + const unsigned max = to_unsigned((std::numeric_limits::max)()); + return num_digits == std::numeric_limits::digits10 + 1 && + prev * 10ull + unsigned(p[-1] - '0') <= max + ? static_cast(value) + : error_value; +} + +// Parses fill and alignment. +template +FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + FMT_ASSERT(begin != end, ""); + auto align = align::none; + auto p = begin + code_point_length(begin); + if (p >= end) p = begin; + for (;;) { + switch (to_ascii(*p)) { + case '<': + align = align::left; + break; + case '>': + align = align::right; + break; + case '^': + align = align::center; + break; + default: + break; + } + if (align != align::none) { + if (p != begin) { + auto c = *begin; + if (c == '{') + return handler.on_error("invalid fill character '{'"), begin; + handler.on_fill(basic_string_view(begin, to_unsigned(p - begin))); + begin = p + 1; + } else + ++begin; + handler.on_align(align); + break; + } else if (p == begin) { + break; + } + p = begin; + } + return begin; +} + +template FMT_CONSTEXPR bool is_name_start(Char c) { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; +} + +template +FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end, + IDHandler&& handler) -> const Char* { + FMT_ASSERT(begin != end, ""); + Char c = *begin; + if (c >= '0' && c <= '9') { + int index = 0; + if (c != '0') + index = + parse_nonnegative_int(begin, end, (std::numeric_limits::max)()); + else + ++begin; + if (begin == end || (*begin != '}' && *begin != ':')) + handler.on_error("invalid format string"); + else + handler(index); + return begin; + } + if (!is_name_start(c)) { + handler.on_error("invalid format string"); + return begin; + } + auto it = begin; + do { + ++it; + } while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9'))); + handler(basic_string_view(begin, to_unsigned(it - begin))); + return it; +} + +template +FMT_CONSTEXPR FMT_INLINE auto parse_arg_id(const Char* begin, const Char* end, + IDHandler&& handler) -> const Char* { + Char c = *begin; + if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler); + handler(); + return begin; +} + +template +FMT_CONSTEXPR auto parse_width(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + using detail::auto_id; + struct width_adapter { + Handler& handler; + + FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); } + FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); } + FMT_CONSTEXPR void operator()(basic_string_view id) { + handler.on_dynamic_width(id); + } + FMT_CONSTEXPR void on_error(const char* message) { + if (message) handler.on_error(message); + } + }; + + FMT_ASSERT(begin != end, ""); + if ('0' <= *begin && *begin <= '9') { + int width = parse_nonnegative_int(begin, end, -1); + if (width != -1) + handler.on_width(width); + else + handler.on_error("number is too big"); + } else if (*begin == '{') { + ++begin; + if (begin != end) begin = parse_arg_id(begin, end, width_adapter{handler}); + if (begin == end || *begin != '}') + return handler.on_error("invalid format string"), begin; + ++begin; + } + return begin; +} + +template +FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + using detail::auto_id; + struct precision_adapter { + Handler& handler; + + FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); } + FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); } + FMT_CONSTEXPR void operator()(basic_string_view id) { + handler.on_dynamic_precision(id); + } + FMT_CONSTEXPR void on_error(const char* message) { + if (message) handler.on_error(message); + } + }; + + ++begin; + auto c = begin != end ? *begin : Char(); + if ('0' <= c && c <= '9') { + auto precision = parse_nonnegative_int(begin, end, -1); + if (precision != -1) + handler.on_precision(precision); + else + handler.on_error("number is too big"); + } else if (c == '{') { + ++begin; + if (begin != end) + begin = parse_arg_id(begin, end, precision_adapter{handler}); + if (begin == end || *begin++ != '}') + return handler.on_error("invalid format string"), begin; + } else { + return handler.on_error("missing precision specifier"), begin; + } + handler.end_precision(); + return begin; +} + +template +FMT_CONSTEXPR auto parse_presentation_type(Char type) -> presentation_type { + switch (to_ascii(type)) { + case 'd': + return presentation_type::dec; + case 'o': + return presentation_type::oct; + case 'x': + return presentation_type::hex_lower; + case 'X': + return presentation_type::hex_upper; + case 'b': + return presentation_type::bin_lower; + case 'B': + return presentation_type::bin_upper; + case 'a': + return presentation_type::hexfloat_lower; + case 'A': + return presentation_type::hexfloat_upper; + case 'e': + return presentation_type::exp_lower; + case 'E': + return presentation_type::exp_upper; + case 'f': + return presentation_type::fixed_lower; + case 'F': + return presentation_type::fixed_upper; + case 'g': + return presentation_type::general_lower; + case 'G': + return presentation_type::general_upper; + case 'c': + return presentation_type::chr; + case 's': + return presentation_type::string; + case 'p': + return presentation_type::pointer; + default: + return presentation_type::none; + } +} + +// Parses standard format specifiers and sends notifications about parsed +// components to handler. +template +FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(const Char* begin, + const Char* end, + SpecHandler&& handler) + -> const Char* { + if (1 < end - begin && begin[1] == '}' && is_ascii_letter(*begin) && + *begin != 'L') { + presentation_type type = parse_presentation_type(*begin++); + if (type == presentation_type::none) + handler.on_error("invalid type specifier"); + handler.on_type(type); + return begin; + } + + if (begin == end) return begin; + + begin = parse_align(begin, end, handler); + if (begin == end) return begin; + + // Parse sign. + switch (to_ascii(*begin)) { + case '+': + handler.on_sign(sign::plus); + ++begin; + break; + case '-': + handler.on_sign(sign::minus); + ++begin; + break; + case ' ': + handler.on_sign(sign::space); + ++begin; + break; + default: + break; + } + if (begin == end) return begin; + + if (*begin == '#') { + handler.on_hash(); + if (++begin == end) return begin; + } + + // Parse zero flag. + if (*begin == '0') { + handler.on_zero(); + if (++begin == end) return begin; + } + + begin = parse_width(begin, end, handler); + if (begin == end) return begin; + + // Parse precision. + if (*begin == '.') { + begin = parse_precision(begin, end, handler); + if (begin == end) return begin; + } + + if (*begin == 'L') { + handler.on_localized(); + ++begin; + } + + // Parse type. + if (begin != end && *begin != '}') { + presentation_type type = parse_presentation_type(*begin++); + if (type == presentation_type::none) + handler.on_error("invalid type specifier"); + handler.on_type(type); + } + return begin; +} + +template +FMT_CONSTEXPR auto parse_replacement_field(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + struct id_adapter { + Handler& handler; + int arg_id; + + FMT_CONSTEXPR void operator()() { arg_id = handler.on_arg_id(); } + FMT_CONSTEXPR void operator()(int id) { arg_id = handler.on_arg_id(id); } + FMT_CONSTEXPR void operator()(basic_string_view id) { + arg_id = handler.on_arg_id(id); + } + FMT_CONSTEXPR void on_error(const char* message) { + if (message) handler.on_error(message); + } + }; + + ++begin; + if (begin == end) return handler.on_error("invalid format string"), end; + if (*begin == '}') { + handler.on_replacement_field(handler.on_arg_id(), begin); + } else if (*begin == '{') { + handler.on_text(begin, begin + 1); + } else { + auto adapter = id_adapter{handler, 0}; + begin = parse_arg_id(begin, end, adapter); + Char c = begin != end ? *begin : Char(); + if (c == '}') { + handler.on_replacement_field(adapter.arg_id, begin); + } else if (c == ':') { + begin = handler.on_format_specs(adapter.arg_id, begin + 1, end); + if (begin == end || *begin != '}') + return handler.on_error("unknown format specifier"), end; + } else { + return handler.on_error("missing '}' in format string"), end; + } + } + return begin + 1; +} + +template +FMT_CONSTEXPR FMT_INLINE void parse_format_string( + basic_string_view format_str, Handler&& handler) { + // Workaround a name-lookup bug in MSVC's modules implementation. + using detail::find; + + auto begin = format_str.data(); + auto end = begin + format_str.size(); + if (end - begin < 32) { + // Use a simple loop instead of memchr for small strings. + const Char* p = begin; + while (p != end) { + auto c = *p++; + if (c == '{') { + handler.on_text(begin, p - 1); + begin = p = parse_replacement_field(p - 1, end, handler); + } else if (c == '}') { + if (p == end || *p != '}') + return handler.on_error("unmatched '}' in format string"); + handler.on_text(begin, p); + begin = ++p; + } + } + handler.on_text(begin, end); + return; + } + struct writer { + FMT_CONSTEXPR void operator()(const Char* pbegin, const Char* pend) { + if (pbegin == pend) return; + for (;;) { + const Char* p = nullptr; + if (!find(pbegin, pend, Char('}'), p)) + return handler_.on_text(pbegin, pend); + ++p; + if (p == pend || *p != '}') + return handler_.on_error("unmatched '}' in format string"); + handler_.on_text(pbegin, p); + pbegin = p + 1; + } + } + Handler& handler_; + } write{handler}; + while (begin != end) { + // Doing two passes with memchr (one for '{' and another for '}') is up to + // 2.5x faster than the naive one-pass implementation on big format strings. + const Char* p = begin; + if (*begin != '{' && !find(begin + 1, end, Char('{'), p)) + return write(begin, end); + write(begin, p); + begin = parse_replacement_field(p, end, handler); + } +} + +template +FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx) + -> decltype(ctx.begin()) { + using char_type = typename ParseContext::char_type; + using context = buffer_context; + using mapped_type = conditional_t< + mapped_type_constant::value != type::custom_type, + decltype(arg_mapper().map(std::declval())), T>; + auto f = conditional_t::value, + formatter, + fallback_formatter>(); + return f.parse(ctx); +} + +// A parse context with extra argument id checks. It is only used at compile +// time because adding checks at runtime would introduce substantial overhead +// and would be redundant since argument ids are checked when arguments are +// retrieved anyway. +template +class compile_parse_context + : public basic_format_parse_context { + private: + int num_args_; + using base = basic_format_parse_context; + + public: + explicit FMT_CONSTEXPR compile_parse_context( + basic_string_view format_str, + int num_args = (std::numeric_limits::max)(), ErrorHandler eh = {}) + : base(format_str, eh), num_args_(num_args) {} + + FMT_CONSTEXPR auto next_arg_id() -> int { + int id = base::next_arg_id(); + if (id >= num_args_) this->on_error("argument not found"); + return id; + } + + FMT_CONSTEXPR void check_arg_id(int id) { + base::check_arg_id(id); + if (id >= num_args_) this->on_error("argument not found"); + } + using base::check_arg_id; +}; + +template +FMT_CONSTEXPR void check_int_type_spec(presentation_type type, + ErrorHandler&& eh) { + if (type > presentation_type::bin_upper && type != presentation_type::chr) + eh.on_error("invalid type specifier"); +} + +// Checks char specs and returns true if the type spec is char (and not int). +template +FMT_CONSTEXPR auto check_char_specs(const basic_format_specs& specs, + ErrorHandler&& eh = {}) -> bool { + if (specs.type != presentation_type::none && + specs.type != presentation_type::chr) { + check_int_type_spec(specs.type, eh); + return false; + } + if (specs.align == align::numeric || specs.sign != sign::none || specs.alt) + eh.on_error("invalid format specifier for char"); + return true; +} + +// A floating-point presentation format. +enum class float_format : unsigned char { + general, // General: exponent notation or fixed point based on magnitude. + exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3. + fixed, // Fixed point with the default precision of 6, e.g. 0.0012. + hex +}; + +struct float_specs { + int precision; + float_format format : 8; + sign_t sign : 8; + bool upper : 1; + bool locale : 1; + bool binary32 : 1; + bool fallback : 1; + bool showpoint : 1; +}; + +template +FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs& specs, + ErrorHandler&& eh = {}) + -> float_specs { + auto result = float_specs(); + result.showpoint = specs.alt; + result.locale = specs.localized; + switch (specs.type) { + case presentation_type::none: + result.format = float_format::general; + break; + case presentation_type::general_upper: + result.upper = true; + FMT_FALLTHROUGH; + case presentation_type::general_lower: + result.format = float_format::general; + break; + case presentation_type::exp_upper: + result.upper = true; + FMT_FALLTHROUGH; + case presentation_type::exp_lower: + result.format = float_format::exp; + result.showpoint |= specs.precision != 0; + break; + case presentation_type::fixed_upper: + result.upper = true; + FMT_FALLTHROUGH; + case presentation_type::fixed_lower: + result.format = float_format::fixed; + result.showpoint |= specs.precision != 0; + break; + case presentation_type::hexfloat_upper: + result.upper = true; + FMT_FALLTHROUGH; + case presentation_type::hexfloat_lower: + result.format = float_format::hex; + break; + default: + eh.on_error("invalid type specifier"); + break; + } + return result; +} + +template +FMT_CONSTEXPR auto check_cstring_type_spec(presentation_type type, + ErrorHandler&& eh = {}) -> bool { + if (type == presentation_type::none || type == presentation_type::string) + return true; + if (type != presentation_type::pointer) eh.on_error("invalid type specifier"); + return false; +} + +template +FMT_CONSTEXPR void check_string_type_spec(presentation_type type, + ErrorHandler&& eh = {}) { + if (type != presentation_type::none && type != presentation_type::string) + eh.on_error("invalid type specifier"); +} + +template +FMT_CONSTEXPR void check_pointer_type_spec(presentation_type type, + ErrorHandler&& eh) { + if (type != presentation_type::none && type != presentation_type::pointer) + eh.on_error("invalid type specifier"); +} + +// A parse_format_specs handler that checks if specifiers are consistent with +// the argument type. +template class specs_checker : public Handler { + private: + detail::type arg_type_; + + FMT_CONSTEXPR void require_numeric_argument() { + if (!is_arithmetic_type(arg_type_)) + this->on_error("format specifier requires numeric argument"); + } + + public: + FMT_CONSTEXPR specs_checker(const Handler& handler, detail::type arg_type) + : Handler(handler), arg_type_(arg_type) {} + + FMT_CONSTEXPR void on_align(align_t align) { + if (align == align::numeric) require_numeric_argument(); + Handler::on_align(align); + } + + FMT_CONSTEXPR void on_sign(sign_t s) { + require_numeric_argument(); + if (is_integral_type(arg_type_) && arg_type_ != type::int_type && + arg_type_ != type::long_long_type && arg_type_ != type::char_type) { + this->on_error("format specifier requires signed argument"); + } + Handler::on_sign(s); + } + + FMT_CONSTEXPR void on_hash() { + require_numeric_argument(); + Handler::on_hash(); + } + + FMT_CONSTEXPR void on_localized() { + require_numeric_argument(); + Handler::on_localized(); + } + + FMT_CONSTEXPR void on_zero() { + require_numeric_argument(); + Handler::on_zero(); + } + + FMT_CONSTEXPR void end_precision() { + if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type) + this->on_error("precision not allowed for this argument type"); + } +}; + +constexpr int invalid_arg_index = -1; + +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +template +constexpr auto get_arg_index_by_name(basic_string_view name) -> int { + if constexpr (detail::is_statically_named_arg()) { + if (name == T::name) return N; + } + if constexpr (sizeof...(Args) > 0) + return get_arg_index_by_name(name); + (void)name; // Workaround an MSVC bug about "unused" parameter. + return invalid_arg_index; +} +#endif + +template +FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view name) -> int { +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS + if constexpr (sizeof...(Args) > 0) + return get_arg_index_by_name<0, Args...>(name); +#endif + (void)name; + return invalid_arg_index; +} + +template +class format_string_checker { + private: + using parse_context_type = compile_parse_context; + enum { num_args = sizeof...(Args) }; + + // Format specifier parsing function. + using parse_func = const Char* (*)(parse_context_type&); + + parse_context_type context_; + parse_func parse_funcs_[num_args > 0 ? num_args : 1]; + + public: + explicit FMT_CONSTEXPR format_string_checker( + basic_string_view format_str, ErrorHandler eh) + : context_(format_str, num_args, eh), + parse_funcs_{&parse_format_specs...} {} + + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + + FMT_CONSTEXPR auto on_arg_id() -> int { return context_.next_arg_id(); } + FMT_CONSTEXPR auto on_arg_id(int id) -> int { + return context_.check_arg_id(id), id; + } + FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS + auto index = get_arg_index_by_name(id); + if (index == invalid_arg_index) on_error("named argument is not found"); + return context_.check_arg_id(index), index; +#else + (void)id; + on_error("compile-time checks for named arguments require C++20 support"); + return 0; +#endif + } + + FMT_CONSTEXPR void on_replacement_field(int, const Char*) {} + + FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char*) + -> const Char* { + context_.advance_to(context_.begin() + (begin - &*context_.begin())); + // id >= 0 check is a workaround for gcc 10 bug (#2065). + return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin; + } + + FMT_CONSTEXPR void on_error(const char* message) { + context_.on_error(message); + } +}; + +template ::value), int>> +void check_format_string(S format_str) { + FMT_CONSTEXPR auto s = to_string_view(format_str); + using checker = format_string_checker...>; + FMT_CONSTEXPR bool invalid_format = + (parse_format_string(s, checker(s, {})), true); + ignore_unused(invalid_format); +} + +template +void vformat_to( + buffer& buf, basic_string_view fmt, + basic_format_args)> args, + locale_ref loc = {}); + +FMT_API void vprint_mojibake(std::FILE*, string_view, format_args); +#ifndef _WIN32 +inline void vprint_mojibake(std::FILE*, string_view, format_args) {} +#endif +FMT_END_DETAIL_NAMESPACE + +// A formatter specialization for the core types corresponding to detail::type +// constants. +template +struct formatter::value != + detail::type::custom_type>> { + private: + detail::dynamic_format_specs specs_; + + public: + // Parses format specifiers stopping either at the end of the range or at the + // terminating '}'. + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + auto begin = ctx.begin(), end = ctx.end(); + if (begin == end) return begin; + using handler_type = detail::dynamic_specs_handler; + auto type = detail::type_constant::value; + auto checker = + detail::specs_checker(handler_type(specs_, ctx), type); + auto it = detail::parse_format_specs(begin, end, checker); + auto eh = ctx.error_handler(); + switch (type) { + case detail::type::none_type: + FMT_ASSERT(false, "invalid argument type"); + break; + case detail::type::bool_type: + if (specs_.type == presentation_type::none || + specs_.type == presentation_type::string) { + break; + } + FMT_FALLTHROUGH; + case detail::type::int_type: + case detail::type::uint_type: + case detail::type::long_long_type: + case detail::type::ulong_long_type: + case detail::type::int128_type: + case detail::type::uint128_type: + detail::check_int_type_spec(specs_.type, eh); + break; + case detail::type::char_type: + detail::check_char_specs(specs_, eh); + break; + case detail::type::float_type: + if (detail::const_check(FMT_USE_FLOAT)) + detail::parse_float_type_spec(specs_, eh); + else + FMT_ASSERT(false, "float support disabled"); + break; + case detail::type::double_type: + if (detail::const_check(FMT_USE_DOUBLE)) + detail::parse_float_type_spec(specs_, eh); + else + FMT_ASSERT(false, "double support disabled"); + break; + case detail::type::long_double_type: + if (detail::const_check(FMT_USE_LONG_DOUBLE)) + detail::parse_float_type_spec(specs_, eh); + else + FMT_ASSERT(false, "long double support disabled"); + break; + case detail::type::cstring_type: + detail::check_cstring_type_spec(specs_.type, eh); + break; + case detail::type::string_type: + detail::check_string_type_spec(specs_.type, eh); + break; + case detail::type::pointer_type: + detail::check_pointer_type_spec(specs_.type, eh); + break; + case detail::type::custom_type: + // Custom format specifiers are checked in parse functions of + // formatter specializations. + break; + } + return it; + } + + template + FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const + -> decltype(ctx.out()); +}; + +template struct basic_runtime { basic_string_view str; }; + +/** A compile-time format string. */ +template class basic_format_string { + private: + basic_string_view str_; + + public: + template >::value)> + FMT_CONSTEVAL FMT_INLINE basic_format_string(const S& s) : str_(s) { + static_assert( + detail::count< + (std::is_base_of>::value && + std::is_reference::value)...>() == 0, + "passing views as lvalues is disallowed"); +#ifdef FMT_HAS_CONSTEVAL + if constexpr (detail::count_named_args() == + detail::count_statically_named_args()) { + using checker = detail::format_string_checker...>; + detail::parse_format_string(str_, checker(s, {})); + } +#else + detail::check_format_string(s); +#endif + } + basic_format_string(basic_runtime r) : str_(r.str) {} + + FMT_INLINE operator basic_string_view() const { return str_; } +}; + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +// Workaround broken conversion on older gcc. +template using format_string = string_view; +template auto runtime(const S& s) -> basic_string_view> { + return s; +} +#else +template +using format_string = basic_format_string...>; +/** + \rst + Creates a runtime format string. + + **Example**:: + + // Check format string at runtime instead of compile-time. + fmt::print(fmt::runtime("{:d}"), "I am not a number"); + \endrst + */ +template auto runtime(const S& s) -> basic_runtime> { + return {{s}}; +} +#endif + +FMT_API auto vformat(string_view fmt, format_args args) -> std::string; + +/** + \rst + Formats ``args`` according to specifications in ``fmt`` and returns the result + as a string. + + **Example**:: + + #include + std::string message = fmt::format("The answer is {}.", 42); + \endrst +*/ +template +FMT_NODISCARD FMT_INLINE auto format(format_string fmt, T&&... args) + -> std::string { + return vformat(fmt, fmt::make_format_args(args...)); +} + +/** Formats a string and writes the output to ``out``. */ +template ::value)> +auto vformat_to(OutputIt out, string_view fmt, format_args args) -> OutputIt { + using detail::get_buffer; + auto&& buf = get_buffer(out); + detail::vformat_to(buf, fmt, args, {}); + return detail::get_iterator(buf); +} + +/** + \rst + Formats ``args`` according to specifications in ``fmt``, writes the result to + the output iterator ``out`` and returns the iterator past the end of the output + range. `format_to` does not append a terminating null character. + + **Example**:: + + auto out = std::vector(); + fmt::format_to(std::back_inserter(out), "{}", 42); + \endrst + */ +template ::value)> +FMT_INLINE auto format_to(OutputIt out, format_string fmt, T&&... args) + -> OutputIt { + return vformat_to(out, fmt, fmt::make_format_args(args...)); +} + +template struct format_to_n_result { + /** Iterator past the end of the output range. */ + OutputIt out; + /** Total (not truncated) output size. */ + size_t size; +}; + +template ::value)> +auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args) + -> format_to_n_result { + using traits = detail::fixed_buffer_traits; + auto buf = detail::iterator_buffer(out, n); + detail::vformat_to(buf, fmt, args, {}); + return {buf.out(), buf.count()}; +} + +/** + \rst + Formats ``args`` according to specifications in ``fmt``, writes up to ``n`` + characters of the result to the output iterator ``out`` and returns the total + (not truncated) output size and the iterator past the end of the output range. + `format_to_n` does not append a terminating null character. + \endrst + */ +template ::value)> +FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string fmt, + T&&... args) -> format_to_n_result { + return vformat_to_n(out, n, fmt, fmt::make_format_args(args...)); +} + +/** Returns the number of chars in the output of ``format(fmt, args...)``. */ +template +FMT_NODISCARD FMT_INLINE auto formatted_size(format_string fmt, + T&&... args) -> size_t { + auto buf = detail::counting_buffer<>(); + detail::vformat_to(buf, string_view(fmt), fmt::make_format_args(args...), {}); + return buf.count(); +} + +FMT_API void vprint(string_view fmt, format_args args); +FMT_API void vprint(std::FILE* f, string_view fmt, format_args args); + +/** + \rst + Formats ``args`` according to specifications in ``fmt`` and writes the output + to ``stdout``. + + **Example**:: + + fmt::print("Elapsed time: {0:.2f} seconds", 1.23); + \endrst + */ +template +FMT_INLINE void print(format_string fmt, T&&... args) { + const auto& vargs = fmt::make_format_args(args...); + return detail::is_utf8() ? vprint(fmt, vargs) + : detail::vprint_mojibake(stdout, fmt, vargs); +} + +/** + \rst + Formats ``args`` according to specifications in ``fmt`` and writes the + output to the file ``f``. + + **Example**:: + + fmt::print(stderr, "Don't {}!", "panic"); + \endrst + */ +template +FMT_INLINE void print(std::FILE* f, format_string fmt, T&&... args) { + const auto& vargs = fmt::make_format_args(args...); + return detail::is_utf8() ? vprint(f, fmt, vargs) + : detail::vprint_mojibake(f, fmt, vargs); +} + +FMT_MODULE_EXPORT_END +FMT_GCC_PRAGMA("GCC pop_options") +FMT_END_NAMESPACE + +#ifdef FMT_HEADER_ONLY +# include "format.h" +#endif +#endif // FMT_CORE_H_ diff --git a/ctrtool/deps/libfmt/include/fmt/format-inl.h b/ctrtool/deps/libfmt/include/fmt/format-inl.h new file mode 100644 index 0000000..2c51c50 --- /dev/null +++ b/ctrtool/deps/libfmt/include/fmt/format-inl.h @@ -0,0 +1,2643 @@ +// Formatting library for C++ - implementation +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_FORMAT_INL_H_ +#define FMT_FORMAT_INL_H_ + +#include +#include +#include // errno +#include +#include +#include +#include // std::memmove +#include +#include + +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +# include +#endif + +#ifdef _WIN32 +# include // _isatty +#endif + +#include "format.h" + +FMT_BEGIN_NAMESPACE +namespace detail { + +FMT_FUNC void assert_fail(const char* file, int line, const char* message) { + // Use unchecked std::fprintf to avoid triggering another assertion when + // writing to stderr fails + std::fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message); + // Chosen instead of std::abort to satisfy Clang in CUDA mode during device + // code pass. + std::terminate(); +} + +FMT_FUNC void throw_format_error(const char* message) { + FMT_THROW(format_error(message)); +} + +#ifndef _MSC_VER +# define FMT_SNPRINTF snprintf +#else // _MSC_VER +inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) { + va_list args; + va_start(args, format); + int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); + va_end(args); + return result; +} +# define FMT_SNPRINTF fmt_snprintf +#endif // _MSC_VER + +FMT_FUNC void format_error_code(detail::buffer& out, int error_code, + string_view message) FMT_NOEXCEPT { + // Report error code making sure that the output fits into + // inline_buffer_size to avoid dynamic memory allocation and potential + // bad_alloc. + out.try_resize(0); + static const char SEP[] = ": "; + static const char ERROR_STR[] = "error "; + // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. + size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; + auto abs_value = static_cast>(error_code); + if (detail::is_negative(error_code)) { + abs_value = 0 - abs_value; + ++error_code_size; + } + error_code_size += detail::to_unsigned(detail::count_digits(abs_value)); + auto it = buffer_appender(out); + if (message.size() <= inline_buffer_size - error_code_size) + format_to(it, FMT_STRING("{}{}"), message, SEP); + format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code); + FMT_ASSERT(out.size() <= inline_buffer_size, ""); +} + +FMT_FUNC void report_error(format_func func, int error_code, + const char* message) FMT_NOEXCEPT { + memory_buffer full_message; + func(full_message, error_code, message); + // Don't use fwrite_fully because the latter may throw. + if (std::fwrite(full_message.data(), full_message.size(), 1, stderr) > 0) + std::fputc('\n', stderr); +} + +// A wrapper around fwrite that throws on error. +inline void fwrite_fully(const void* ptr, size_t size, size_t count, + FILE* stream) { + size_t written = std::fwrite(ptr, size, count, stream); + if (written < count) FMT_THROW(system_error(errno, "cannot write to file")); +} + +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +template +locale_ref::locale_ref(const Locale& loc) : locale_(&loc) { + static_assert(std::is_same::value, ""); +} + +template Locale locale_ref::get() const { + static_assert(std::is_same::value, ""); + return locale_ ? *static_cast(locale_) : std::locale(); +} + +template +FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result { + auto& facet = std::use_facet>(loc.get()); + auto grouping = facet.grouping(); + auto thousands_sep = grouping.empty() ? Char() : facet.thousands_sep(); + return {std::move(grouping), thousands_sep}; +} +template FMT_FUNC Char decimal_point_impl(locale_ref loc) { + return std::use_facet>(loc.get()) + .decimal_point(); +} +#else +template +FMT_FUNC auto thousands_sep_impl(locale_ref) -> thousands_sep_result { + return {"\03", FMT_STATIC_THOUSANDS_SEPARATOR}; +} +template FMT_FUNC Char decimal_point_impl(locale_ref) { + return '.'; +} +#endif +} // namespace detail + +#if !FMT_MSC_VER +FMT_API FMT_FUNC format_error::~format_error() FMT_NOEXCEPT = default; +#endif + +FMT_FUNC std::system_error vsystem_error(int error_code, string_view format_str, + format_args args) { + auto ec = std::error_code(error_code, std::generic_category()); + return std::system_error(ec, vformat(format_str, args)); +} + +namespace detail { + +template <> FMT_FUNC int count_digits<4>(detail::fallback_uintptr n) { + // fallback_uintptr is always stored in little endian. + int i = static_cast(sizeof(void*)) - 1; + while (i > 0 && n.value[i] == 0) --i; + auto char_digits = std::numeric_limits::digits / 4; + return i >= 0 ? i * char_digits + count_digits<4, unsigned>(n.value[i]) : 1; +} + +// log10(2) = 0x0.4d104d427de7fbcc... +static constexpr uint64_t log10_2_significand = 0x4d104d427de7fbcc; + +template struct basic_impl_data { + // Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. + // These are generated by support/compute-powers.py. + static constexpr uint64_t pow10_significands[87] = { + 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, + 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, + 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c, + 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, + 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, + 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7, + 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e, + 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, + 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, + 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053, + 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f, + 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, + 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, + 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb, + 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000, + 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984, + 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, + 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, + 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758, + 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85, + 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, + 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25, + 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2, + 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a, + 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, + 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129, + 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85, + 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, + 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b, + }; + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnarrowing" +#endif + // Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding + // to significands above. + static constexpr int16_t pow10_exponents[87] = { + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, + -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, + -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, + -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, + -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, + 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, + 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, + 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066}; +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +# pragma GCC diagnostic pop +#endif + + static constexpr uint64_t power_of_10_64[20] = { + 1, FMT_POWERS_OF_10(1ULL), FMT_POWERS_OF_10(1000000000ULL), + 10000000000000000000ULL}; +}; + +// This is a struct rather than an alias to avoid shadowing warnings in gcc. +struct impl_data : basic_impl_data<> {}; + +#if __cplusplus < 201703L +template +constexpr uint64_t basic_impl_data::pow10_significands[]; +template constexpr int16_t basic_impl_data::pow10_exponents[]; +template constexpr uint64_t basic_impl_data::power_of_10_64[]; +#endif + +template struct bits { + static FMT_CONSTEXPR_DECL const int value = + static_cast(sizeof(T) * std::numeric_limits::digits); +}; + +// Returns the number of significand bits in Float excluding the implicit bit. +template constexpr int num_significand_bits() { + // Subtract 1 to account for an implicit most significant bit in the + // normalized form. + return std::numeric_limits::digits - 1; +} + +// A floating-point number f * pow(2, e). +struct fp { + uint64_t f; + int e; + + static constexpr const int num_significand_bits = bits::value; + + constexpr fp() : f(0), e(0) {} + constexpr fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} + + // Constructs fp from an IEEE754 floating-point number. It is a template to + // prevent compile errors on systems where n is not IEEE754. + template explicit FMT_CONSTEXPR fp(Float n) { assign(n); } + + template + using is_supported = bool_constant; + + // Assigns d to this and return true iff predecessor is closer than successor. + template ::value)> + FMT_CONSTEXPR bool assign(Float n) { + // Assume float is in the format [sign][exponent][significand]. + const int num_float_significand_bits = + detail::num_significand_bits(); + const uint64_t implicit_bit = 1ULL << num_float_significand_bits; + const uint64_t significand_mask = implicit_bit - 1; + constexpr bool is_double = sizeof(Float) == sizeof(uint64_t); + auto u = bit_cast>(n); + f = u & significand_mask; + const uint64_t exponent_mask = (~0ULL >> 1) & ~significand_mask; + int biased_e = + static_cast((u & exponent_mask) >> num_float_significand_bits); + // The predecessor is closer if n is a normalized power of 2 (f == 0) other + // than the smallest normalized number (biased_e > 1). + bool is_predecessor_closer = f == 0 && biased_e > 1; + if (biased_e != 0) + f += implicit_bit; + else + biased_e = 1; // Subnormals use biased exponent 1 (min exponent). + const int exponent_bias = std::numeric_limits::max_exponent - 1; + e = biased_e - exponent_bias - num_float_significand_bits; + return is_predecessor_closer; + } + + template ::value)> + bool assign(Float) { + FMT_ASSERT(false, ""); + return false; + } +}; + +// Normalizes the value converted from double and multiplied by (1 << SHIFT). +template FMT_CONSTEXPR fp normalize(fp value) { + // Handle subnormals. + const uint64_t implicit_bit = 1ULL << num_significand_bits(); + const auto shifted_implicit_bit = implicit_bit << SHIFT; + while ((value.f & shifted_implicit_bit) == 0) { + value.f <<= 1; + --value.e; + } + // Subtract 1 to account for hidden bit. + const auto offset = + fp::num_significand_bits - num_significand_bits() - SHIFT - 1; + value.f <<= offset; + value.e -= offset; + return value; +} + +inline bool operator==(fp x, fp y) { return x.f == y.f && x.e == y.e; } + +// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking. +FMT_CONSTEXPR inline uint64_t multiply(uint64_t lhs, uint64_t rhs) { +#if FMT_USE_INT128 + auto product = static_cast<__uint128_t>(lhs) * rhs; + auto f = static_cast(product >> 64); + return (static_cast(product) & (1ULL << 63)) != 0 ? f + 1 : f; +#else + // Multiply 32-bit parts of significands. + uint64_t mask = (1ULL << 32) - 1; + uint64_t a = lhs >> 32, b = lhs & mask; + uint64_t c = rhs >> 32, d = rhs & mask; + uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; + // Compute mid 64-bit of result and round. + uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); + return ac + (ad >> 32) + (bc >> 32) + (mid >> 32); +#endif +} + +FMT_CONSTEXPR inline fp operator*(fp x, fp y) { + return {multiply(x.f, y.f), x.e + y.e + 64}; +} + +// Returns a cached power of 10 `c_k = c_k.f * pow(2, c_k.e)` such that its +// (binary) exponent satisfies `min_exponent <= c_k.e <= min_exponent + 28`. +FMT_CONSTEXPR inline fp get_cached_power(int min_exponent, + int& pow10_exponent) { + const int shift = 32; + const auto significand = static_cast(log10_2_significand); + int index = static_cast( + ((min_exponent + fp::num_significand_bits - 1) * (significand >> shift) + + ((int64_t(1) << shift) - 1)) // ceil + >> 32 // arithmetic shift + ); + // Decimal exponent of the first (smallest) cached power of 10. + const int first_dec_exp = -348; + // Difference between 2 consecutive decimal exponents in cached powers of 10. + const int dec_exp_step = 8; + index = (index - first_dec_exp - 1) / dec_exp_step + 1; + pow10_exponent = first_dec_exp + index * dec_exp_step; + return {impl_data::pow10_significands[index], + impl_data::pow10_exponents[index]}; +} + +// A simple accumulator to hold the sums of terms in bigint::square if uint128_t +// is not available. +struct accumulator { + uint64_t lower; + uint64_t upper; + + constexpr accumulator() : lower(0), upper(0) {} + constexpr explicit operator uint32_t() const { + return static_cast(lower); + } + + FMT_CONSTEXPR void operator+=(uint64_t n) { + lower += n; + if (lower < n) ++upper; + } + FMT_CONSTEXPR void operator>>=(int shift) { + FMT_ASSERT(shift == 32, ""); + (void)shift; + lower = (upper << 32) | (lower >> 32); + upper >>= 32; + } +}; + +class bigint { + private: + // A bigint is stored as an array of bigits (big digits), with bigit at index + // 0 being the least significant one. + using bigit = uint32_t; + using double_bigit = uint64_t; + enum { bigits_capacity = 32 }; + basic_memory_buffer bigits_; + int exp_; + + FMT_CONSTEXPR20 bigit operator[](int index) const { + return bigits_[to_unsigned(index)]; + } + FMT_CONSTEXPR20 bigit& operator[](int index) { + return bigits_[to_unsigned(index)]; + } + + static FMT_CONSTEXPR_DECL const int bigit_bits = bits::value; + + friend struct formatter; + + FMT_CONSTEXPR20 void subtract_bigits(int index, bigit other, bigit& borrow) { + auto result = static_cast((*this)[index]) - other - borrow; + (*this)[index] = static_cast(result); + borrow = static_cast(result >> (bigit_bits * 2 - 1)); + } + + FMT_CONSTEXPR20 void remove_leading_zeros() { + int num_bigits = static_cast(bigits_.size()) - 1; + while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits; + bigits_.resize(to_unsigned(num_bigits + 1)); + } + + // Computes *this -= other assuming aligned bigints and *this >= other. + FMT_CONSTEXPR20 void subtract_aligned(const bigint& other) { + FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints"); + FMT_ASSERT(compare(*this, other) >= 0, ""); + bigit borrow = 0; + int i = other.exp_ - exp_; + for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j) + subtract_bigits(i, other.bigits_[j], borrow); + while (borrow > 0) subtract_bigits(i, 0, borrow); + remove_leading_zeros(); + } + + FMT_CONSTEXPR20 void multiply(uint32_t value) { + const double_bigit wide_value = value; + bigit carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) { + double_bigit result = bigits_[i] * wide_value + carry; + bigits_[i] = static_cast(result); + carry = static_cast(result >> bigit_bits); + } + if (carry != 0) bigits_.push_back(carry); + } + + FMT_CONSTEXPR20 void multiply(uint64_t value) { + const bigit mask = ~bigit(0); + const double_bigit lower = value & mask; + const double_bigit upper = value >> bigit_bits; + double_bigit carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) { + double_bigit result = bigits_[i] * lower + (carry & mask); + carry = + bigits_[i] * upper + (result >> bigit_bits) + (carry >> bigit_bits); + bigits_[i] = static_cast(result); + } + while (carry != 0) { + bigits_.push_back(carry & mask); + carry >>= bigit_bits; + } + } + + public: + FMT_CONSTEXPR20 bigint() : exp_(0) {} + explicit bigint(uint64_t n) { assign(n); } + FMT_CONSTEXPR20 ~bigint() { + FMT_ASSERT(bigits_.capacity() <= bigits_capacity, ""); + } + + bigint(const bigint&) = delete; + void operator=(const bigint&) = delete; + + FMT_CONSTEXPR20 void assign(const bigint& other) { + auto size = other.bigits_.size(); + bigits_.resize(size); + auto data = other.bigits_.data(); + std::copy(data, data + size, make_checked(bigits_.data(), size)); + exp_ = other.exp_; + } + + FMT_CONSTEXPR20 void assign(uint64_t n) { + size_t num_bigits = 0; + do { + bigits_[num_bigits++] = n & ~bigit(0); + n >>= bigit_bits; + } while (n != 0); + bigits_.resize(num_bigits); + exp_ = 0; + } + + FMT_CONSTEXPR20 int num_bigits() const { + return static_cast(bigits_.size()) + exp_; + } + + FMT_NOINLINE FMT_CONSTEXPR20 bigint& operator<<=(int shift) { + FMT_ASSERT(shift >= 0, ""); + exp_ += shift / bigit_bits; + shift %= bigit_bits; + if (shift == 0) return *this; + bigit carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) { + bigit c = bigits_[i] >> (bigit_bits - shift); + bigits_[i] = (bigits_[i] << shift) + carry; + carry = c; + } + if (carry != 0) bigits_.push_back(carry); + return *this; + } + + template FMT_CONSTEXPR20 bigint& operator*=(Int value) { + FMT_ASSERT(value > 0, ""); + multiply(uint32_or_64_or_128_t(value)); + return *this; + } + + friend FMT_CONSTEXPR20 int compare(const bigint& lhs, const bigint& rhs) { + int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits(); + if (num_lhs_bigits != num_rhs_bigits) + return num_lhs_bigits > num_rhs_bigits ? 1 : -1; + int i = static_cast(lhs.bigits_.size()) - 1; + int j = static_cast(rhs.bigits_.size()) - 1; + int end = i - j; + if (end < 0) end = 0; + for (; i >= end; --i, --j) { + bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j]; + if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1; + } + if (i != j) return i > j ? 1 : -1; + return 0; + } + + // Returns compare(lhs1 + lhs2, rhs). + friend FMT_CONSTEXPR20 int add_compare(const bigint& lhs1, const bigint& lhs2, + const bigint& rhs) { + int max_lhs_bigits = (std::max)(lhs1.num_bigits(), lhs2.num_bigits()); + int num_rhs_bigits = rhs.num_bigits(); + if (max_lhs_bigits + 1 < num_rhs_bigits) return -1; + if (max_lhs_bigits > num_rhs_bigits) return 1; + auto get_bigit = [](const bigint& n, int i) -> bigit { + return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0; + }; + double_bigit borrow = 0; + int min_exp = (std::min)((std::min)(lhs1.exp_, lhs2.exp_), rhs.exp_); + for (int i = num_rhs_bigits - 1; i >= min_exp; --i) { + double_bigit sum = + static_cast(get_bigit(lhs1, i)) + get_bigit(lhs2, i); + bigit rhs_bigit = get_bigit(rhs, i); + if (sum > rhs_bigit + borrow) return 1; + borrow = rhs_bigit + borrow - sum; + if (borrow > 1) return -1; + borrow <<= bigit_bits; + } + return borrow != 0 ? -1 : 0; + } + + // Assigns pow(10, exp) to this bigint. + FMT_CONSTEXPR20 void assign_pow10(int exp) { + FMT_ASSERT(exp >= 0, ""); + if (exp == 0) return assign(1); + // Find the top bit. + int bitmask = 1; + while (exp >= bitmask) bitmask <<= 1; + bitmask >>= 1; + // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by + // repeated squaring and multiplication. + assign(5); + bitmask >>= 1; + while (bitmask != 0) { + square(); + if ((exp & bitmask) != 0) *this *= 5; + bitmask >>= 1; + } + *this <<= exp; // Multiply by pow(2, exp) by shifting. + } + + FMT_CONSTEXPR20 void square() { + int num_bigits = static_cast(bigits_.size()); + int num_result_bigits = 2 * num_bigits; + basic_memory_buffer n(std::move(bigits_)); + bigits_.resize(to_unsigned(num_result_bigits)); + using accumulator_t = conditional_t; + auto sum = accumulator_t(); + for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) { + // Compute bigit at position bigit_index of the result by adding + // cross-product terms n[i] * n[j] such that i + j == bigit_index. + for (int i = 0, j = bigit_index; j >= 0; ++i, --j) { + // Most terms are multiplied twice which can be optimized in the future. + sum += static_cast(n[i]) * n[j]; + } + (*this)[bigit_index] = static_cast(sum); + sum >>= bits::value; // Compute the carry. + } + // Do the same for the top half. + for (int bigit_index = num_bigits; bigit_index < num_result_bigits; + ++bigit_index) { + for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;) + sum += static_cast(n[i++]) * n[j--]; + (*this)[bigit_index] = static_cast(sum); + sum >>= bits::value; + } + remove_leading_zeros(); + exp_ *= 2; + } + + // If this bigint has a bigger exponent than other, adds trailing zero to make + // exponents equal. This simplifies some operations such as subtraction. + FMT_CONSTEXPR20 void align(const bigint& other) { + int exp_difference = exp_ - other.exp_; + if (exp_difference <= 0) return; + int num_bigits = static_cast(bigits_.size()); + bigits_.resize(to_unsigned(num_bigits + exp_difference)); + for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j) + bigits_[j] = bigits_[i]; + std::uninitialized_fill_n(bigits_.data(), exp_difference, 0); + exp_ -= exp_difference; + } + + // Divides this bignum by divisor, assigning the remainder to this and + // returning the quotient. + FMT_CONSTEXPR20 int divmod_assign(const bigint& divisor) { + FMT_ASSERT(this != &divisor, ""); + if (compare(*this, divisor) < 0) return 0; + FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, ""); + align(divisor); + int quotient = 0; + do { + subtract_aligned(divisor); + ++quotient; + } while (compare(*this, divisor) >= 0); + return quotient; + } +}; + +enum class round_direction { unknown, up, down }; + +// Given the divisor (normally a power of 10), the remainder = v % divisor for +// some number v and the error, returns whether v should be rounded up, down, or +// whether the rounding direction can't be determined due to error. +// error should be less than divisor / 2. +FMT_CONSTEXPR inline round_direction get_round_direction(uint64_t divisor, + uint64_t remainder, + uint64_t error) { + FMT_ASSERT(remainder < divisor, ""); // divisor - remainder won't overflow. + FMT_ASSERT(error < divisor, ""); // divisor - error won't overflow. + FMT_ASSERT(error < divisor - error, ""); // error * 2 won't overflow. + // Round down if (remainder + error) * 2 <= divisor. + if (remainder <= divisor - remainder && error * 2 <= divisor - remainder * 2) + return round_direction::down; + // Round up if (remainder - error) * 2 >= divisor. + if (remainder >= error && + remainder - error >= divisor - (remainder - error)) { + return round_direction::up; + } + return round_direction::unknown; +} + +namespace digits { +enum result { + more, // Generate more digits. + done, // Done generating digits. + error // Digit generation cancelled due to an error. +}; +} + +struct gen_digits_handler { + char* buf; + int size; + int precision; + int exp10; + bool fixed; + + FMT_CONSTEXPR digits::result on_digit(char digit, uint64_t divisor, + uint64_t remainder, uint64_t error, + bool integral) { + FMT_ASSERT(remainder < divisor, ""); + buf[size++] = digit; + if (!integral && error >= remainder) return digits::error; + if (size < precision) return digits::more; + if (!integral) { + // Check if error * 2 < divisor with overflow prevention. + // The check is not needed for the integral part because error = 1 + // and divisor > (1 << 32) there. + if (error >= divisor || error >= divisor - error) return digits::error; + } else { + FMT_ASSERT(error == 1 && divisor > 2, ""); + } + auto dir = get_round_direction(divisor, remainder, error); + if (dir != round_direction::up) + return dir == round_direction::down ? digits::done : digits::error; + ++buf[size - 1]; + for (int i = size - 1; i > 0 && buf[i] > '9'; --i) { + buf[i] = '0'; + ++buf[i - 1]; + } + if (buf[0] > '9') { + buf[0] = '1'; + if (fixed) + buf[size++] = '0'; + else + ++exp10; + } + return digits::done; + } +}; + +// Generates output using the Grisu digit-gen algorithm. +// error: the size of the region (lower, upper) outside of which numbers +// definitely do not round to value (Delta in Grisu3). +FMT_INLINE FMT_CONSTEXPR20 digits::result grisu_gen_digits( + fp value, uint64_t error, int& exp, gen_digits_handler& handler) { + const fp one(1ULL << -value.e, value.e); + // The integral part of scaled value (p1 in Grisu) = value / one. It cannot be + // zero because it contains a product of two 64-bit numbers with MSB set (due + // to normalization) - 1, shifted right by at most 60 bits. + auto integral = static_cast(value.f >> -one.e); + FMT_ASSERT(integral != 0, ""); + FMT_ASSERT(integral == value.f >> -one.e, ""); + // The fractional part of scaled value (p2 in Grisu) c = value % one. + uint64_t fractional = value.f & (one.f - 1); + exp = count_digits(integral); // kappa in Grisu. + // Non-fixed formats require at least one digit and no precision adjustment. + if (handler.fixed) { + // Adjust fixed precision by exponent because it is relative to decimal + // point. + int precision_offset = exp + handler.exp10; + if (precision_offset > 0 && + handler.precision > max_value() - precision_offset) { + FMT_THROW(format_error("number is too big")); + } + handler.precision += precision_offset; + // Check if precision is satisfied just by leading zeros, e.g. + // format("{:.2f}", 0.001) gives "0.00" without generating any digits. + if (handler.precision <= 0) { + if (handler.precision < 0) return digits::done; + // Divide by 10 to prevent overflow. + uint64_t divisor = impl_data::power_of_10_64[exp - 1] << -one.e; + auto dir = get_round_direction(divisor, value.f / 10, error * 10); + if (dir == round_direction::unknown) return digits::error; + handler.buf[handler.size++] = dir == round_direction::up ? '1' : '0'; + return digits::done; + } + } + // Generate digits for the integral part. This can produce up to 10 digits. + do { + uint32_t digit = 0; + auto divmod_integral = [&](uint32_t divisor) { + digit = integral / divisor; + integral %= divisor; + }; + // This optimization by Milo Yip reduces the number of integer divisions by + // one per iteration. + switch (exp) { + case 10: + divmod_integral(1000000000); + break; + case 9: + divmod_integral(100000000); + break; + case 8: + divmod_integral(10000000); + break; + case 7: + divmod_integral(1000000); + break; + case 6: + divmod_integral(100000); + break; + case 5: + divmod_integral(10000); + break; + case 4: + divmod_integral(1000); + break; + case 3: + divmod_integral(100); + break; + case 2: + divmod_integral(10); + break; + case 1: + digit = integral; + integral = 0; + break; + default: + FMT_ASSERT(false, "invalid number of digits"); + } + --exp; + auto remainder = (static_cast(integral) << -one.e) + fractional; + auto result = handler.on_digit(static_cast('0' + digit), + impl_data::power_of_10_64[exp] << -one.e, + remainder, error, true); + if (result != digits::more) return result; + } while (exp > 0); + // Generate digits for the fractional part. + for (;;) { + fractional *= 10; + error *= 10; + char digit = static_cast('0' + (fractional >> -one.e)); + fractional &= one.f - 1; + --exp; + auto result = handler.on_digit(digit, one.f, fractional, error, false); + if (result != digits::more) return result; + } +} + +// A 128-bit integer type used internally, +struct uint128_wrapper { + uint128_wrapper() = default; + +#if FMT_USE_INT128 + uint128_t internal_; + + constexpr uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT + : internal_{static_cast(low) | + (static_cast(high) << 64)} {} + + constexpr uint128_wrapper(uint128_t u) : internal_{u} {} + + constexpr uint64_t high() const FMT_NOEXCEPT { + return uint64_t(internal_ >> 64); + } + constexpr uint64_t low() const FMT_NOEXCEPT { return uint64_t(internal_); } + + uint128_wrapper& operator+=(uint64_t n) FMT_NOEXCEPT { + internal_ += n; + return *this; + } +#else + uint64_t high_; + uint64_t low_; + + constexpr uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT + : high_{high}, + low_{low} {} + + constexpr uint64_t high() const FMT_NOEXCEPT { return high_; } + constexpr uint64_t low() const FMT_NOEXCEPT { return low_; } + + uint128_wrapper& operator+=(uint64_t n) FMT_NOEXCEPT { +# if defined(_MSC_VER) && defined(_M_X64) + unsigned char carry = _addcarry_u64(0, low_, n, &low_); + _addcarry_u64(carry, high_, 0, &high_); + return *this; +# else + uint64_t sum = low_ + n; + high_ += (sum < low_ ? 1 : 0); + low_ = sum; + return *this; +# endif + } +#endif +}; + +// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox. +namespace dragonbox { +// Computes 128-bit result of multiplication of two 64-bit unsigned integers. +inline uint128_wrapper umul128(uint64_t x, uint64_t y) FMT_NOEXCEPT { +#if FMT_USE_INT128 + return static_cast(x) * static_cast(y); +#elif defined(_MSC_VER) && defined(_M_X64) + uint128_wrapper result; + result.low_ = _umul128(x, y, &result.high_); + return result; +#else + const uint64_t mask = (uint64_t(1) << 32) - uint64_t(1); + + uint64_t a = x >> 32; + uint64_t b = x & mask; + uint64_t c = y >> 32; + uint64_t d = y & mask; + + uint64_t ac = a * c; + uint64_t bc = b * c; + uint64_t ad = a * d; + uint64_t bd = b * d; + + uint64_t intermediate = (bd >> 32) + (ad & mask) + (bc & mask); + + return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32), + (intermediate << 32) + (bd & mask)}; +#endif +} + +// Computes upper 64 bits of multiplication of two 64-bit unsigned integers. +inline uint64_t umul128_upper64(uint64_t x, uint64_t y) FMT_NOEXCEPT { +#if FMT_USE_INT128 + auto p = static_cast(x) * static_cast(y); + return static_cast(p >> 64); +#elif defined(_MSC_VER) && defined(_M_X64) + return __umulh(x, y); +#else + return umul128(x, y).high(); +#endif +} + +// Computes upper 64 bits of multiplication of a 64-bit unsigned integer and a +// 128-bit unsigned integer. +inline uint64_t umul192_upper64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT { + uint128_wrapper g0 = umul128(x, y.high()); + g0 += umul128_upper64(x, y.low()); + return g0.high(); +} + +// Computes upper 32 bits of multiplication of a 32-bit unsigned integer and a +// 64-bit unsigned integer. +inline uint32_t umul96_upper32(uint32_t x, uint64_t y) FMT_NOEXCEPT { + return static_cast(umul128_upper64(x, y)); +} + +// Computes middle 64 bits of multiplication of a 64-bit unsigned integer and a +// 128-bit unsigned integer. +inline uint64_t umul192_middle64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT { + uint64_t g01 = x * y.high(); + uint64_t g10 = umul128_upper64(x, y.low()); + return g01 + g10; +} + +// Computes lower 64 bits of multiplication of a 32-bit unsigned integer and a +// 64-bit unsigned integer. +inline uint64_t umul96_lower64(uint32_t x, uint64_t y) FMT_NOEXCEPT { + return x * y; +} + +// Computes floor(log10(pow(2, e))) for e in [-1700, 1700] using the method from +// https://fmt.dev/papers/Grisu-Exact.pdf#page=5, section 3.4. +inline int floor_log10_pow2(int e) FMT_NOEXCEPT { + FMT_ASSERT(e <= 1700 && e >= -1700, "too large exponent"); + const int shift = 22; + return (e * static_cast(log10_2_significand >> (64 - shift))) >> shift; +} + +// Various fast log computations. +inline int floor_log2_pow10(int e) FMT_NOEXCEPT { + FMT_ASSERT(e <= 1233 && e >= -1233, "too large exponent"); + const uint64_t log2_10_integer_part = 3; + const uint64_t log2_10_fractional_digits = 0x5269e12f346e2bf9; + const int shift_amount = 19; + return (e * static_cast( + (log2_10_integer_part << shift_amount) | + (log2_10_fractional_digits >> (64 - shift_amount)))) >> + shift_amount; +} +inline int floor_log10_pow2_minus_log10_4_over_3(int e) FMT_NOEXCEPT { + FMT_ASSERT(e <= 1700 && e >= -1700, "too large exponent"); + const uint64_t log10_4_over_3_fractional_digits = 0x1ffbfc2bbc780375; + const int shift_amount = 22; + return (e * static_cast(log10_2_significand >> (64 - shift_amount)) - + static_cast(log10_4_over_3_fractional_digits >> + (64 - shift_amount))) >> + shift_amount; +} + +// Returns true iff x is divisible by pow(2, exp). +inline bool divisible_by_power_of_2(uint32_t x, int exp) FMT_NOEXCEPT { + FMT_ASSERT(exp >= 1, ""); + FMT_ASSERT(x != 0, ""); +#ifdef FMT_BUILTIN_CTZ + return FMT_BUILTIN_CTZ(x) >= exp; +#else + return exp < num_bits() && x == ((x >> exp) << exp); +#endif +} +inline bool divisible_by_power_of_2(uint64_t x, int exp) FMT_NOEXCEPT { + FMT_ASSERT(exp >= 1, ""); + FMT_ASSERT(x != 0, ""); +#ifdef FMT_BUILTIN_CTZLL + return FMT_BUILTIN_CTZLL(x) >= exp; +#else + return exp < num_bits() && x == ((x >> exp) << exp); +#endif +} + +// Table entry type for divisibility test. +template struct divtest_table_entry { + T mod_inv; + T max_quotient; +}; + +// Returns true iff x is divisible by pow(5, exp). +inline bool divisible_by_power_of_5(uint32_t x, int exp) FMT_NOEXCEPT { + FMT_ASSERT(exp <= 10, "too large exponent"); + static constexpr const divtest_table_entry divtest_table[] = { + {0x00000001, 0xffffffff}, {0xcccccccd, 0x33333333}, + {0xc28f5c29, 0x0a3d70a3}, {0x26e978d5, 0x020c49ba}, + {0x3afb7e91, 0x0068db8b}, {0x0bcbe61d, 0x0014f8b5}, + {0x68c26139, 0x000431bd}, {0xae8d46a5, 0x0000d6bf}, + {0x22e90e21, 0x00002af3}, {0x3a2e9c6d, 0x00000897}, + {0x3ed61f49, 0x000001b7}}; + return x * divtest_table[exp].mod_inv <= divtest_table[exp].max_quotient; +} +inline bool divisible_by_power_of_5(uint64_t x, int exp) FMT_NOEXCEPT { + FMT_ASSERT(exp <= 23, "too large exponent"); + static constexpr const divtest_table_entry divtest_table[] = { + {0x0000000000000001, 0xffffffffffffffff}, + {0xcccccccccccccccd, 0x3333333333333333}, + {0x8f5c28f5c28f5c29, 0x0a3d70a3d70a3d70}, + {0x1cac083126e978d5, 0x020c49ba5e353f7c}, + {0xd288ce703afb7e91, 0x0068db8bac710cb2}, + {0x5d4e8fb00bcbe61d, 0x0014f8b588e368f0}, + {0x790fb65668c26139, 0x000431bde82d7b63}, + {0xe5032477ae8d46a5, 0x0000d6bf94d5e57a}, + {0xc767074b22e90e21, 0x00002af31dc46118}, + {0x8e47ce423a2e9c6d, 0x0000089705f4136b}, + {0x4fa7f60d3ed61f49, 0x000001b7cdfd9d7b}, + {0x0fee64690c913975, 0x00000057f5ff85e5}, + {0x3662e0e1cf503eb1, 0x000000119799812d}, + {0xa47a2cf9f6433fbd, 0x0000000384b84d09}, + {0x54186f653140a659, 0x00000000b424dc35}, + {0x7738164770402145, 0x0000000024075f3d}, + {0xe4a4d1417cd9a041, 0x000000000734aca5}, + {0xc75429d9e5c5200d, 0x000000000170ef54}, + {0xc1773b91fac10669, 0x000000000049c977}, + {0x26b172506559ce15, 0x00000000000ec1e4}, + {0xd489e3a9addec2d1, 0x000000000002f394}, + {0x90e860bb892c8d5d, 0x000000000000971d}, + {0x502e79bf1b6f4f79, 0x0000000000001e39}, + {0xdcd618596be30fe5, 0x000000000000060b}}; + return x * divtest_table[exp].mod_inv <= divtest_table[exp].max_quotient; +} + +// Replaces n by floor(n / pow(5, N)) returning true if and only if n is +// divisible by pow(5, N). +// Precondition: n <= 2 * pow(5, N + 1). +template +bool check_divisibility_and_divide_by_pow5(uint32_t& n) FMT_NOEXCEPT { + static constexpr struct { + uint32_t magic_number; + int bits_for_comparison; + uint32_t threshold; + int shift_amount; + } infos[] = {{0xcccd, 16, 0x3333, 18}, {0xa429, 8, 0x0a, 20}}; + constexpr auto info = infos[N - 1]; + n *= info.magic_number; + const uint32_t comparison_mask = (1u << info.bits_for_comparison) - 1; + bool result = (n & comparison_mask) <= info.threshold; + n >>= info.shift_amount; + return result; +} + +// Computes floor(n / pow(10, N)) for small n and N. +// Precondition: n <= pow(10, N + 1). +template uint32_t small_division_by_pow10(uint32_t n) FMT_NOEXCEPT { + static constexpr struct { + uint32_t magic_number; + int shift_amount; + uint32_t divisor_times_10; + } infos[] = {{0xcccd, 19, 100}, {0xa3d8, 22, 1000}}; + constexpr auto info = infos[N - 1]; + FMT_ASSERT(n <= info.divisor_times_10, "n is too large"); + return n * info.magic_number >> info.shift_amount; +} + +// Computes floor(n / 10^(kappa + 1)) (float) +inline uint32_t divide_by_10_to_kappa_plus_1(uint32_t n) FMT_NOEXCEPT { + return n / float_info::big_divisor; +} +// Computes floor(n / 10^(kappa + 1)) (double) +inline uint64_t divide_by_10_to_kappa_plus_1(uint64_t n) FMT_NOEXCEPT { + return umul128_upper64(n, 0x83126e978d4fdf3c) >> 9; +} + +// Various subroutines using pow10 cache +template struct cache_accessor; + +template <> struct cache_accessor { + using carrier_uint = float_info::carrier_uint; + using cache_entry_type = uint64_t; + + static uint64_t get_cached_power(int k) FMT_NOEXCEPT { + FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, + "k is out of range"); + static constexpr const uint64_t pow10_significands[] = { + 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3f, + 0xfd87b5f28300ca0e, 0x9e74d1b791e07e49, 0xc612062576589ddb, + 0xf79687aed3eec552, 0x9abe14cd44753b53, 0xc16d9a0095928a28, + 0xf1c90080baf72cb2, 0x971da05074da7bef, 0xbce5086492111aeb, + 0xec1e4a7db69561a6, 0x9392ee8e921d5d08, 0xb877aa3236a4b44a, + 0xe69594bec44de15c, 0x901d7cf73ab0acda, 0xb424dc35095cd810, + 0xe12e13424bb40e14, 0x8cbccc096f5088cc, 0xafebff0bcb24aaff, + 0xdbe6fecebdedd5bf, 0x89705f4136b4a598, 0xabcc77118461cefd, + 0xd6bf94d5e57a42bd, 0x8637bd05af6c69b6, 0xa7c5ac471b478424, + 0xd1b71758e219652c, 0x83126e978d4fdf3c, 0xa3d70a3d70a3d70b, + 0xcccccccccccccccd, 0x8000000000000000, 0xa000000000000000, + 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000, + 0xc350000000000000, 0xf424000000000000, 0x9896800000000000, + 0xbebc200000000000, 0xee6b280000000000, 0x9502f90000000000, + 0xba43b74000000000, 0xe8d4a51000000000, 0x9184e72a00000000, + 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000, + 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000, + 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000, + 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0, + 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940984, + 0xa18f07d736b90be5, 0xc9f2c9cd04674ede, 0xfc6f7c4045812296, + 0x9dc5ada82b70b59d, 0xc5371912364ce305, 0xf684df56c3e01bc6, + 0x9a130b963a6c115c, 0xc097ce7bc90715b3, 0xf0bdc21abb48db20, + 0x96769950b50d88f4, 0xbc143fa4e250eb31, 0xeb194f8e1ae525fd, + 0x92efd1b8d0cf37be, 0xb7abc627050305ad, 0xe596b7b0c643c719, + 0x8f7e32ce7bea5c6f, 0xb35dbf821ae4f38b, 0xe0352f62a19e306e}; + return pow10_significands[k - float_info::min_k]; + } + + static carrier_uint compute_mul(carrier_uint u, + const cache_entry_type& cache) FMT_NOEXCEPT { + return umul96_upper32(u, cache); + } + + static uint32_t compute_delta(const cache_entry_type& cache, + int beta_minus_1) FMT_NOEXCEPT { + return static_cast(cache >> (64 - 1 - beta_minus_1)); + } + + static bool compute_mul_parity(carrier_uint two_f, + const cache_entry_type& cache, + int beta_minus_1) FMT_NOEXCEPT { + FMT_ASSERT(beta_minus_1 >= 1, ""); + FMT_ASSERT(beta_minus_1 < 64, ""); + + return ((umul96_lower64(two_f, cache) >> (64 - beta_minus_1)) & 1) != 0; + } + + static carrier_uint compute_left_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { + return static_cast( + (cache - (cache >> (float_info::significand_bits + 2))) >> + (64 - float_info::significand_bits - 1 - beta_minus_1)); + } + + static carrier_uint compute_right_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { + return static_cast( + (cache + (cache >> (float_info::significand_bits + 1))) >> + (64 - float_info::significand_bits - 1 - beta_minus_1)); + } + + static carrier_uint compute_round_up_for_shorter_interval_case( + const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { + return (static_cast( + cache >> + (64 - float_info::significand_bits - 2 - beta_minus_1)) + + 1) / + 2; + } +}; + +template <> struct cache_accessor { + using carrier_uint = float_info::carrier_uint; + using cache_entry_type = uint128_wrapper; + + static uint128_wrapper get_cached_power(int k) FMT_NOEXCEPT { + FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, + "k is out of range"); + + static constexpr const uint128_wrapper pow10_significands[] = { +#if FMT_USE_FULL_CACHE_DRAGONBOX + {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, + {0x9faacf3df73609b1, 0x77b191618c54e9ad}, + {0xc795830d75038c1d, 0xd59df5b9ef6a2418}, + {0xf97ae3d0d2446f25, 0x4b0573286b44ad1e}, + {0x9becce62836ac577, 0x4ee367f9430aec33}, + {0xc2e801fb244576d5, 0x229c41f793cda740}, + {0xf3a20279ed56d48a, 0x6b43527578c11110}, + {0x9845418c345644d6, 0x830a13896b78aaaa}, + {0xbe5691ef416bd60c, 0x23cc986bc656d554}, + {0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9}, + {0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa}, + {0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54}, + {0xe858ad248f5c22c9, 0xd1b3400f8f9cff69}, + {0x91376c36d99995be, 0x23100809b9c21fa2}, + {0xb58547448ffffb2d, 0xabd40a0c2832a78b}, + {0xe2e69915b3fff9f9, 0x16c90c8f323f516d}, + {0x8dd01fad907ffc3b, 0xae3da7d97f6792e4}, + {0xb1442798f49ffb4a, 0x99cd11cfdf41779d}, + {0xdd95317f31c7fa1d, 0x40405643d711d584}, + {0x8a7d3eef7f1cfc52, 0x482835ea666b2573}, + {0xad1c8eab5ee43b66, 0xda3243650005eed0}, + {0xd863b256369d4a40, 0x90bed43e40076a83}, + {0x873e4f75e2224e68, 0x5a7744a6e804a292}, + {0xa90de3535aaae202, 0x711515d0a205cb37}, + {0xd3515c2831559a83, 0x0d5a5b44ca873e04}, + {0x8412d9991ed58091, 0xe858790afe9486c3}, + {0xa5178fff668ae0b6, 0x626e974dbe39a873}, + {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, + {0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a}, + {0xa139029f6a239f72, 0x1c1fffc1ebc44e81}, + {0xc987434744ac874e, 0xa327ffb266b56221}, + {0xfbe9141915d7a922, 0x4bf1ff9f0062baa9}, + {0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa}, + {0xc4ce17b399107c22, 0xcb550fb4384d21d4}, + {0xf6019da07f549b2b, 0x7e2a53a146606a49}, + {0x99c102844f94e0fb, 0x2eda7444cbfc426e}, + {0xc0314325637a1939, 0xfa911155fefb5309}, + {0xf03d93eebc589f88, 0x793555ab7eba27cb}, + {0x96267c7535b763b5, 0x4bc1558b2f3458df}, + {0xbbb01b9283253ca2, 0x9eb1aaedfb016f17}, + {0xea9c227723ee8bcb, 0x465e15a979c1cadd}, + {0x92a1958a7675175f, 0x0bfacd89ec191eca}, + {0xb749faed14125d36, 0xcef980ec671f667c}, + {0xe51c79a85916f484, 0x82b7e12780e7401b}, + {0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811}, + {0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16}, + {0xdfbdcece67006ac9, 0x67a791e093e1d49b}, + {0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1}, + {0xaecc49914078536d, 0x58fae9f773886e19}, + {0xda7f5bf590966848, 0xaf39a475506a899f}, + {0x888f99797a5e012d, 0x6d8406c952429604}, + {0xaab37fd7d8f58178, 0xc8e5087ba6d33b84}, + {0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65}, + {0x855c3be0a17fcd26, 0x5cf2eea09a550680}, + {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, + {0xd0601d8efc57b08b, 0xf13b94daf124da27}, + {0x823c12795db6ce57, 0x76c53d08d6b70859}, + {0xa2cb1717b52481ed, 0x54768c4b0c64ca6f}, + {0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a}, + {0xfe5d54150b090b02, 0xd3f93b35435d7c4d}, + {0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0}, + {0xc6b8e9b0709f109a, 0x359ab6419ca1091c}, + {0xf867241c8cc6d4c0, 0xc30163d203c94b63}, + {0x9b407691d7fc44f8, 0x79e0de63425dcf1e}, + {0xc21094364dfb5636, 0x985915fc12f542e5}, + {0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e}, + {0x979cf3ca6cec5b5a, 0xa705992ceecf9c43}, + {0xbd8430bd08277231, 0x50c6ff782a838354}, + {0xece53cec4a314ebd, 0xa4f8bf5635246429}, + {0x940f4613ae5ed136, 0x871b7795e136be9a}, + {0xb913179899f68584, 0x28e2557b59846e40}, + {0xe757dd7ec07426e5, 0x331aeada2fe589d0}, + {0x9096ea6f3848984f, 0x3ff0d2c85def7622}, + {0xb4bca50b065abe63, 0x0fed077a756b53aa}, + {0xe1ebce4dc7f16dfb, 0xd3e8495912c62895}, + {0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d}, + {0xb080392cc4349dec, 0xbd8d794d96aacfb4}, + {0xdca04777f541c567, 0xecf0d7a0fc5583a1}, + {0x89e42caaf9491b60, 0xf41686c49db57245}, + {0xac5d37d5b79b6239, 0x311c2875c522ced6}, + {0xd77485cb25823ac7, 0x7d633293366b828c}, + {0x86a8d39ef77164bc, 0xae5dff9c02033198}, + {0xa8530886b54dbdeb, 0xd9f57f830283fdfd}, + {0xd267caa862a12d66, 0xd072df63c324fd7c}, + {0x8380dea93da4bc60, 0x4247cb9e59f71e6e}, + {0xa46116538d0deb78, 0x52d9be85f074e609}, + {0xcd795be870516656, 0x67902e276c921f8c}, + {0x806bd9714632dff6, 0x00ba1cd8a3db53b7}, + {0xa086cfcd97bf97f3, 0x80e8a40eccd228a5}, + {0xc8a883c0fdaf7df0, 0x6122cd128006b2ce}, + {0xfad2a4b13d1b5d6c, 0x796b805720085f82}, + {0x9cc3a6eec6311a63, 0xcbe3303674053bb1}, + {0xc3f490aa77bd60fc, 0xbedbfc4411068a9d}, + {0xf4f1b4d515acb93b, 0xee92fb5515482d45}, + {0x991711052d8bf3c5, 0x751bdd152d4d1c4b}, + {0xbf5cd54678eef0b6, 0xd262d45a78a0635e}, + {0xef340a98172aace4, 0x86fb897116c87c35}, + {0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1}, + {0xbae0a846d2195712, 0x8974836059cca10a}, + {0xe998d258869facd7, 0x2bd1a438703fc94c}, + {0x91ff83775423cc06, 0x7b6306a34627ddd0}, + {0xb67f6455292cbf08, 0x1a3bc84c17b1d543}, + {0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94}, + {0x8e938662882af53e, 0x547eb47b7282ee9d}, + {0xb23867fb2a35b28d, 0xe99e619a4f23aa44}, + {0xdec681f9f4c31f31, 0x6405fa00e2ec94d5}, + {0x8b3c113c38f9f37e, 0xde83bc408dd3dd05}, + {0xae0b158b4738705e, 0x9624ab50b148d446}, + {0xd98ddaee19068c76, 0x3badd624dd9b0958}, + {0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7}, + {0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d}, + {0xd47487cc8470652b, 0x7647c32000696720}, + {0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074}, + {0xa5fb0a17c777cf09, 0xf468107100525891}, + {0xcf79cc9db955c2cc, 0x7182148d4066eeb5}, + {0x81ac1fe293d599bf, 0xc6f14cd848405531}, + {0xa21727db38cb002f, 0xb8ada00e5a506a7d}, + {0xca9cf1d206fdc03b, 0xa6d90811f0e4851d}, + {0xfd442e4688bd304a, 0x908f4a166d1da664}, + {0x9e4a9cec15763e2e, 0x9a598e4e043287ff}, + {0xc5dd44271ad3cdba, 0x40eff1e1853f29fe}, + {0xf7549530e188c128, 0xd12bee59e68ef47d}, + {0x9a94dd3e8cf578b9, 0x82bb74f8301958cf}, + {0xc13a148e3032d6e7, 0xe36a52363c1faf02}, + {0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2}, + {0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba}, + {0xbcb2b812db11a5de, 0x7415d448f6b6f0e8}, + {0xebdf661791d60f56, 0x111b495b3464ad22}, + {0x936b9fcebb25c995, 0xcab10dd900beec35}, + {0xb84687c269ef3bfb, 0x3d5d514f40eea743}, + {0xe65829b3046b0afa, 0x0cb4a5a3112a5113}, + {0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac}, + {0xb3f4e093db73a093, 0x59ed216765690f57}, + {0xe0f218b8d25088b8, 0x306869c13ec3532d}, + {0x8c974f7383725573, 0x1e414218c73a13fc}, + {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, + {0xdbac6c247d62a583, 0xdf45f746b74abf3a}, + {0x894bc396ce5da772, 0x6b8bba8c328eb784}, + {0xab9eb47c81f5114f, 0x066ea92f3f326565}, + {0xd686619ba27255a2, 0xc80a537b0efefebe}, + {0x8613fd0145877585, 0xbd06742ce95f5f37}, + {0xa798fc4196e952e7, 0x2c48113823b73705}, + {0xd17f3b51fca3a7a0, 0xf75a15862ca504c6}, + {0x82ef85133de648c4, 0x9a984d73dbe722fc}, + {0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb}, + {0xcc963fee10b7d1b3, 0x318df905079926a9}, + {0xffbbcfe994e5c61f, 0xfdf17746497f7053}, + {0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634}, + {0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1}, + {0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1}, + {0x9c1661a651213e2d, 0x06bea10ca65c084f}, + {0xc31bfa0fe5698db8, 0x486e494fcff30a63}, + {0xf3e2f893dec3f126, 0x5a89dba3c3efccfb}, + {0x986ddb5c6b3a76b7, 0xf89629465a75e01d}, + {0xbe89523386091465, 0xf6bbb397f1135824}, + {0xee2ba6c0678b597f, 0x746aa07ded582e2d}, + {0x94db483840b717ef, 0xa8c2a44eb4571cdd}, + {0xba121a4650e4ddeb, 0x92f34d62616ce414}, + {0xe896a0d7e51e1566, 0x77b020baf9c81d18}, + {0x915e2486ef32cd60, 0x0ace1474dc1d122f}, + {0xb5b5ada8aaff80b8, 0x0d819992132456bb}, + {0xe3231912d5bf60e6, 0x10e1fff697ed6c6a}, + {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, + {0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3}, + {0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf}, + {0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c}, + {0xad4ab7112eb3929d, 0x86c16c98d2c953c7}, + {0xd89d64d57a607744, 0xe871c7bf077ba8b8}, + {0x87625f056c7c4a8b, 0x11471cd764ad4973}, + {0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0}, + {0xd389b47879823479, 0x4aff1d108d4ec2c4}, + {0x843610cb4bf160cb, 0xcedf722a585139bb}, + {0xa54394fe1eedb8fe, 0xc2974eb4ee658829}, + {0xce947a3da6a9273e, 0x733d226229feea33}, + {0x811ccc668829b887, 0x0806357d5a3f5260}, + {0xa163ff802a3426a8, 0xca07c2dcb0cf26f8}, + {0xc9bcff6034c13052, 0xfc89b393dd02f0b6}, + {0xfc2c3f3841f17c67, 0xbbac2078d443ace3}, + {0x9d9ba7832936edc0, 0xd54b944b84aa4c0e}, + {0xc5029163f384a931, 0x0a9e795e65d4df12}, + {0xf64335bcf065d37d, 0x4d4617b5ff4a16d6}, + {0x99ea0196163fa42e, 0x504bced1bf8e4e46}, + {0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7}, + {0xf07da27a82c37088, 0x5d767327bb4e5a4d}, + {0x964e858c91ba2655, 0x3a6a07f8d510f870}, + {0xbbe226efb628afea, 0x890489f70a55368c}, + {0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f}, + {0x92c8ae6b464fc96f, 0x3b0b8bc90012929e}, + {0xb77ada0617e3bbcb, 0x09ce6ebb40173745}, + {0xe55990879ddcaabd, 0xcc420a6a101d0516}, + {0x8f57fa54c2a9eab6, 0x9fa946824a12232e}, + {0xb32df8e9f3546564, 0x47939822dc96abfa}, + {0xdff9772470297ebd, 0x59787e2b93bc56f8}, + {0x8bfbea76c619ef36, 0x57eb4edb3c55b65b}, + {0xaefae51477a06b03, 0xede622920b6b23f2}, + {0xdab99e59958885c4, 0xe95fab368e45ecee}, + {0x88b402f7fd75539b, 0x11dbcb0218ebb415}, + {0xaae103b5fcd2a881, 0xd652bdc29f26a11a}, + {0xd59944a37c0752a2, 0x4be76d3346f04960}, + {0x857fcae62d8493a5, 0x6f70a4400c562ddc}, + {0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953}, + {0xd097ad07a71f26b2, 0x7e2000a41346a7a8}, + {0x825ecc24c873782f, 0x8ed400668c0c28c9}, + {0xa2f67f2dfa90563b, 0x728900802f0f32fb}, + {0xcbb41ef979346bca, 0x4f2b40a03ad2ffba}, + {0xfea126b7d78186bc, 0xe2f610c84987bfa9}, + {0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca}, + {0xc6ede63fa05d3143, 0x91503d1c79720dbc}, + {0xf8a95fcf88747d94, 0x75a44c6397ce912b}, + {0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb}, + {0xc24452da229b021b, 0xfbe85badce996169}, + {0xf2d56790ab41c2a2, 0xfae27299423fb9c4}, + {0x97c560ba6b0919a5, 0xdccd879fc967d41b}, + {0xbdb6b8e905cb600f, 0x5400e987bbc1c921}, + {0xed246723473e3813, 0x290123e9aab23b69}, + {0x9436c0760c86e30b, 0xf9a0b6720aaf6522}, + {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, + {0xe7958cb87392c2c2, 0xb60b1d1230b20e05}, + {0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3}, + {0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4}, + {0xe2280b6c20dd5232, 0x25c6da63c38de1b1}, + {0x8d590723948a535f, 0x579c487e5a38ad0f}, + {0xb0af48ec79ace837, 0x2d835a9df0c6d852}, + {0xdcdb1b2798182244, 0xf8e431456cf88e66}, + {0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900}, + {0xac8b2d36eed2dac5, 0xe272467e3d222f40}, + {0xd7adf884aa879177, 0x5b0ed81dcc6abb10}, + {0x86ccbb52ea94baea, 0x98e947129fc2b4ea}, + {0xa87fea27a539e9a5, 0x3f2398d747b36225}, + {0xd29fe4b18e88640e, 0x8eec7f0d19a03aae}, + {0x83a3eeeef9153e89, 0x1953cf68300424ad}, + {0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8}, + {0xcdb02555653131b6, 0x3792f412cb06794e}, + {0x808e17555f3ebf11, 0xe2bbd88bbee40bd1}, + {0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5}, + {0xc8de047564d20a8b, 0xf245825a5a445276}, + {0xfb158592be068d2e, 0xeed6e2f0f0d56713}, + {0x9ced737bb6c4183d, 0x55464dd69685606c}, + {0xc428d05aa4751e4c, 0xaa97e14c3c26b887}, + {0xf53304714d9265df, 0xd53dd99f4b3066a9}, + {0x993fe2c6d07b7fab, 0xe546a8038efe402a}, + {0xbf8fdb78849a5f96, 0xde98520472bdd034}, + {0xef73d256a5c0f77c, 0x963e66858f6d4441}, + {0x95a8637627989aad, 0xdde7001379a44aa9}, + {0xbb127c53b17ec159, 0x5560c018580d5d53}, + {0xe9d71b689dde71af, 0xaab8f01e6e10b4a7}, + {0x9226712162ab070d, 0xcab3961304ca70e9}, + {0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23}, + {0xe45c10c42a2b3b05, 0x8cb89a7db77c506b}, + {0x8eb98a7a9a5b04e3, 0x77f3608e92adb243}, + {0xb267ed1940f1c61c, 0x55f038b237591ed4}, + {0xdf01e85f912e37a3, 0x6b6c46dec52f6689}, + {0x8b61313bbabce2c6, 0x2323ac4b3b3da016}, + {0xae397d8aa96c1b77, 0xabec975e0a0d081b}, + {0xd9c7dced53c72255, 0x96e7bd358c904a22}, + {0x881cea14545c7575, 0x7e50d64177da2e55}, + {0xaa242499697392d2, 0xdde50bd1d5d0b9ea}, + {0xd4ad2dbfc3d07787, 0x955e4ec64b44e865}, + {0x84ec3c97da624ab4, 0xbd5af13bef0b113f}, + {0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f}, + {0xcfb11ead453994ba, 0x67de18eda5814af3}, + {0x81ceb32c4b43fcf4, 0x80eacf948770ced8}, + {0xa2425ff75e14fc31, 0xa1258379a94d028e}, + {0xcad2f7f5359a3b3e, 0x096ee45813a04331}, + {0xfd87b5f28300ca0d, 0x8bca9d6e188853fd}, + {0x9e74d1b791e07e48, 0x775ea264cf55347e}, + {0xc612062576589dda, 0x95364afe032a819e}, + {0xf79687aed3eec551, 0x3a83ddbd83f52205}, + {0x9abe14cd44753b52, 0xc4926a9672793543}, + {0xc16d9a0095928a27, 0x75b7053c0f178294}, + {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, + {0x971da05074da7bee, 0xd3f6fc16ebca5e04}, + {0xbce5086492111aea, 0x88f4bb1ca6bcf585}, + {0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6}, + {0x9392ee8e921d5d07, 0x3aff322e62439fd0}, + {0xb877aa3236a4b449, 0x09befeb9fad487c3}, + {0xe69594bec44de15b, 0x4c2ebe687989a9b4}, + {0x901d7cf73ab0acd9, 0x0f9d37014bf60a11}, + {0xb424dc35095cd80f, 0x538484c19ef38c95}, + {0xe12e13424bb40e13, 0x2865a5f206b06fba}, + {0x8cbccc096f5088cb, 0xf93f87b7442e45d4}, + {0xafebff0bcb24aafe, 0xf78f69a51539d749}, + {0xdbe6fecebdedd5be, 0xb573440e5a884d1c}, + {0x89705f4136b4a597, 0x31680a88f8953031}, + {0xabcc77118461cefc, 0xfdc20d2b36ba7c3e}, + {0xd6bf94d5e57a42bc, 0x3d32907604691b4d}, + {0x8637bd05af6c69b5, 0xa63f9a49c2c1b110}, + {0xa7c5ac471b478423, 0x0fcf80dc33721d54}, + {0xd1b71758e219652b, 0xd3c36113404ea4a9}, + {0x83126e978d4fdf3b, 0x645a1cac083126ea}, + {0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4}, + {0xcccccccccccccccc, 0xcccccccccccccccd}, + {0x8000000000000000, 0x0000000000000000}, + {0xa000000000000000, 0x0000000000000000}, + {0xc800000000000000, 0x0000000000000000}, + {0xfa00000000000000, 0x0000000000000000}, + {0x9c40000000000000, 0x0000000000000000}, + {0xc350000000000000, 0x0000000000000000}, + {0xf424000000000000, 0x0000000000000000}, + {0x9896800000000000, 0x0000000000000000}, + {0xbebc200000000000, 0x0000000000000000}, + {0xee6b280000000000, 0x0000000000000000}, + {0x9502f90000000000, 0x0000000000000000}, + {0xba43b74000000000, 0x0000000000000000}, + {0xe8d4a51000000000, 0x0000000000000000}, + {0x9184e72a00000000, 0x0000000000000000}, + {0xb5e620f480000000, 0x0000000000000000}, + {0xe35fa931a0000000, 0x0000000000000000}, + {0x8e1bc9bf04000000, 0x0000000000000000}, + {0xb1a2bc2ec5000000, 0x0000000000000000}, + {0xde0b6b3a76400000, 0x0000000000000000}, + {0x8ac7230489e80000, 0x0000000000000000}, + {0xad78ebc5ac620000, 0x0000000000000000}, + {0xd8d726b7177a8000, 0x0000000000000000}, + {0x878678326eac9000, 0x0000000000000000}, + {0xa968163f0a57b400, 0x0000000000000000}, + {0xd3c21bcecceda100, 0x0000000000000000}, + {0x84595161401484a0, 0x0000000000000000}, + {0xa56fa5b99019a5c8, 0x0000000000000000}, + {0xcecb8f27f4200f3a, 0x0000000000000000}, + {0x813f3978f8940984, 0x4000000000000000}, + {0xa18f07d736b90be5, 0x5000000000000000}, + {0xc9f2c9cd04674ede, 0xa400000000000000}, + {0xfc6f7c4045812296, 0x4d00000000000000}, + {0x9dc5ada82b70b59d, 0xf020000000000000}, + {0xc5371912364ce305, 0x6c28000000000000}, + {0xf684df56c3e01bc6, 0xc732000000000000}, + {0x9a130b963a6c115c, 0x3c7f400000000000}, + {0xc097ce7bc90715b3, 0x4b9f100000000000}, + {0xf0bdc21abb48db20, 0x1e86d40000000000}, + {0x96769950b50d88f4, 0x1314448000000000}, + {0xbc143fa4e250eb31, 0x17d955a000000000}, + {0xeb194f8e1ae525fd, 0x5dcfab0800000000}, + {0x92efd1b8d0cf37be, 0x5aa1cae500000000}, + {0xb7abc627050305ad, 0xf14a3d9e40000000}, + {0xe596b7b0c643c719, 0x6d9ccd05d0000000}, + {0x8f7e32ce7bea5c6f, 0xe4820023a2000000}, + {0xb35dbf821ae4f38b, 0xdda2802c8a800000}, + {0xe0352f62a19e306e, 0xd50b2037ad200000}, + {0x8c213d9da502de45, 0x4526f422cc340000}, + {0xaf298d050e4395d6, 0x9670b12b7f410000}, + {0xdaf3f04651d47b4c, 0x3c0cdd765f114000}, + {0x88d8762bf324cd0f, 0xa5880a69fb6ac800}, + {0xab0e93b6efee0053, 0x8eea0d047a457a00}, + {0xd5d238a4abe98068, 0x72a4904598d6d880}, + {0x85a36366eb71f041, 0x47a6da2b7f864750}, + {0xa70c3c40a64e6c51, 0x999090b65f67d924}, + {0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d}, + {0x82818f1281ed449f, 0xbff8f10e7a8921a4}, + {0xa321f2d7226895c7, 0xaff72d52192b6a0d}, + {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490}, + {0xfee50b7025c36a08, 0x02f236d04753d5b4}, + {0x9f4f2726179a2245, 0x01d762422c946590}, + {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5}, + {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2}, + {0x9b934c3b330c8577, 0x63cc55f49f88eb2f}, + {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb}, + {0xf316271c7fc3908a, 0x8bef464e3945ef7a}, + {0x97edd871cfda3a56, 0x97758bf0e3cbb5ac}, + {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317}, + {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd}, + {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a}, + {0xb975d6b6ee39e436, 0xb3e2fd538e122b44}, + {0xe7d34c64a9c85d44, 0x60dbbca87196b616}, + {0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd}, + {0xb51d13aea4a488dd, 0x6babab6398bdbe41}, + {0xe264589a4dcdab14, 0xc696963c7eed2dd1}, + {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2}, + {0xb0de65388cc8ada8, 0x3b25a55f43294bcb}, + {0xdd15fe86affad912, 0x49ef0eb713f39ebe}, + {0x8a2dbf142dfcc7ab, 0x6e3569326c784337}, + {0xacb92ed9397bf996, 0x49c2c37f07965404}, + {0xd7e77a8f87daf7fb, 0xdc33745ec97be906}, + {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3}, + {0xa8acd7c0222311bc, 0xc40832ea0d68ce0c}, + {0xd2d80db02aabd62b, 0xf50a3fa490c30190}, + {0x83c7088e1aab65db, 0x792667c6da79e0fa}, + {0xa4b8cab1a1563f52, 0x577001b891185938}, + {0xcde6fd5e09abcf26, 0xed4c0226b55e6f86}, + {0x80b05e5ac60b6178, 0x544f8158315b05b4}, + {0xa0dc75f1778e39d6, 0x696361ae3db1c721}, + {0xc913936dd571c84c, 0x03bc3a19cd1e38e9}, + {0xfb5878494ace3a5f, 0x04ab48a04065c723}, + {0x9d174b2dcec0e47b, 0x62eb0d64283f9c76}, + {0xc45d1df942711d9a, 0x3ba5d0bd324f8394}, + {0xf5746577930d6500, 0xca8f44ec7ee36479}, + {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb}, + {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e}, + {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e}, + {0x95d04aee3b80ece5, 0xbba1f1d158724a12}, + {0xbb445da9ca61281f, 0x2a8a6e45ae8edc97}, + {0xea1575143cf97226, 0xf52d09d71a3293bd}, + {0x924d692ca61be758, 0x593c2626705f9c56}, + {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c}, + {0xe498f455c38b997a, 0x0b6dfb9c0f956447}, + {0x8edf98b59a373fec, 0x4724bd4189bd5eac}, + {0xb2977ee300c50fe7, 0x58edec91ec2cb657}, + {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed}, + {0x8b865b215899f46c, 0xbd79e0d20082ee74}, + {0xae67f1e9aec07187, 0xecd8590680a3aa11}, + {0xda01ee641a708de9, 0xe80e6f4820cc9495}, + {0x884134fe908658b2, 0x3109058d147fdcdd}, + {0xaa51823e34a7eede, 0xbd4b46f0599fd415}, + {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a}, + {0x850fadc09923329e, 0x03e2cf6bc604ddb0}, + {0xa6539930bf6bff45, 0x84db8346b786151c}, + {0xcfe87f7cef46ff16, 0xe612641865679a63}, + {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e}, + {0xa26da3999aef7749, 0xe3be5e330f38f09d}, + {0xcb090c8001ab551c, 0x5cadf5bfd3072cc5}, + {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6}, + {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa}, + {0xc646d63501a1511d, 0xb281e1fd541501b8}, + {0xf7d88bc24209a565, 0x1f225a7ca91a4226}, + {0x9ae757596946075f, 0x3375788de9b06958}, + {0xc1a12d2fc3978937, 0x0052d6b1641c83ae}, + {0xf209787bb47d6b84, 0xc0678c5dbd23a49a}, + {0x9745eb4d50ce6332, 0xf840b7ba963646e0}, + {0xbd176620a501fbff, 0xb650e5a93bc3d898}, + {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe}, + {0x93ba47c980e98cdf, 0xc66f336c36b10137}, + {0xb8a8d9bbe123f017, 0xb80b0047445d4184}, + {0xe6d3102ad96cec1d, 0xa60dc059157491e5}, + {0x9043ea1ac7e41392, 0x87c89837ad68db2f}, + {0xb454e4a179dd1877, 0x29babe4598c311fb}, + {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a}, + {0x8ce2529e2734bb1d, 0x1899e4a65f58660c}, + {0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f}, + {0xdc21a1171d42645d, 0x76707543f4fa1f73}, + {0x899504ae72497eba, 0x6a06494a791c53a8}, + {0xabfa45da0edbde69, 0x0487db9d17636892}, + {0xd6f8d7509292d603, 0x45a9d2845d3c42b6}, + {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b2}, + {0xa7f26836f282b732, 0x8e6cac7768d7141e}, + {0xd1ef0244af2364ff, 0x3207d795430cd926}, + {0x8335616aed761f1f, 0x7f44e6bd49e807b8}, + {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6}, + {0xcd036837130890a1, 0x36dba887c37a8c0f}, + {0x802221226be55a64, 0xc2494954da2c9789}, + {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c}, + {0xc83553c5c8965d3d, 0x6f92829494e5acc7}, + {0xfa42a8b73abbf48c, 0xcb772339ba1f17f9}, + {0x9c69a97284b578d7, 0xff2a760414536efb}, + {0xc38413cf25e2d70d, 0xfef5138519684aba}, + {0xf46518c2ef5b8cd1, 0x7eb258665fc25d69}, + {0x98bf2f79d5993802, 0xef2f773ffbd97a61}, + {0xbeeefb584aff8603, 0xaafb550ffacfd8fa}, + {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38}, + {0x952ab45cfa97a0b2, 0xdd945a747bf26183}, + {0xba756174393d88df, 0x94f971119aeef9e4}, + {0xe912b9d1478ceb17, 0x7a37cd5601aab85d}, + {0x91abb422ccb812ee, 0xac62e055c10ab33a}, + {0xb616a12b7fe617aa, 0x577b986b314d6009}, + {0xe39c49765fdf9d94, 0xed5a7e85fda0b80b}, + {0x8e41ade9fbebc27d, 0x14588f13be847307}, + {0xb1d219647ae6b31c, 0x596eb2d8ae258fc8}, + {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb}, + {0x8aec23d680043bee, 0x25de7bb9480d5854}, + {0xada72ccc20054ae9, 0xaf561aa79a10ae6a}, + {0xd910f7ff28069da4, 0x1b2ba1518094da04}, + {0x87aa9aff79042286, 0x90fb44d2f05d0842}, + {0xa99541bf57452b28, 0x353a1607ac744a53}, + {0xd3fa922f2d1675f2, 0x42889b8997915ce8}, + {0x847c9b5d7c2e09b7, 0x69956135febada11}, + {0xa59bc234db398c25, 0x43fab9837e699095}, + {0xcf02b2c21207ef2e, 0x94f967e45e03f4bb}, + {0x8161afb94b44f57d, 0x1d1be0eebac278f5}, + {0xa1ba1ba79e1632dc, 0x6462d92a69731732}, + {0xca28a291859bbf93, 0x7d7b8f7503cfdcfe}, + {0xfcb2cb35e702af78, 0x5cda735244c3d43e}, + {0x9defbf01b061adab, 0x3a0888136afa64a7}, + {0xc56baec21c7a1916, 0x088aaa1845b8fdd0}, + {0xf6c69a72a3989f5b, 0x8aad549e57273d45}, + {0x9a3c2087a63f6399, 0x36ac54e2f678864b}, + {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd}, + {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5}, + {0x969eb7c47859e743, 0x9f644ae5a4b1b325}, + {0xbc4665b596706114, 0x873d5d9f0dde1fee}, + {0xeb57ff22fc0c7959, 0xa90cb506d155a7ea}, + {0x9316ff75dd87cbd8, 0x09a7f12442d588f2}, + {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb2f}, + {0xe5d3ef282a242e81, 0x8f1668c8a86da5fa}, + {0x8fa475791a569d10, 0xf96e017d694487bc}, + {0xb38d92d760ec4455, 0x37c981dcc395a9ac}, + {0xe070f78d3927556a, 0x85bbe253f47b1417}, + {0x8c469ab843b89562, 0x93956d7478ccec8e}, + {0xaf58416654a6babb, 0x387ac8d1970027b2}, + {0xdb2e51bfe9d0696a, 0x06997b05fcc0319e}, + {0x88fcf317f22241e2, 0x441fece3bdf81f03}, + {0xab3c2fddeeaad25a, 0xd527e81cad7626c3}, + {0xd60b3bd56a5586f1, 0x8a71e223d8d3b074}, + {0x85c7056562757456, 0xf6872d5667844e49}, + {0xa738c6bebb12d16c, 0xb428f8ac016561db}, + {0xd106f86e69d785c7, 0xe13336d701beba52}, + {0x82a45b450226b39c, 0xecc0024661173473}, + {0xa34d721642b06084, 0x27f002d7f95d0190}, + {0xcc20ce9bd35c78a5, 0x31ec038df7b441f4}, + {0xff290242c83396ce, 0x7e67047175a15271}, + {0x9f79a169bd203e41, 0x0f0062c6e984d386}, + {0xc75809c42c684dd1, 0x52c07b78a3e60868}, + {0xf92e0c3537826145, 0xa7709a56ccdf8a82}, + {0x9bbcc7a142b17ccb, 0x88a66076400bb691}, + {0xc2abf989935ddbfe, 0x6acff893d00ea435}, + {0xf356f7ebf83552fe, 0x0583f6b8c4124d43}, + {0x98165af37b2153de, 0xc3727a337a8b704a}, + {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c}, + {0xeda2ee1c7064130c, 0x1162def06f79df73}, + {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8}, + {0xb9a74a0637ce2ee1, 0x6d953e2bd7173692}, + {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437}, + {0x910ab1d4db9914a0, 0x1d9c9892400a22a2}, + {0xb54d5e4a127f59c8, 0x2503beb6d00cab4b}, + {0xe2a0b5dc971f303a, 0x2e44ae64840fd61d}, + {0x8da471a9de737e24, 0x5ceaecfed289e5d2}, + {0xb10d8e1456105dad, 0x7425a83e872c5f47}, + {0xdd50f1996b947518, 0xd12f124e28f77719}, + {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f}, + {0xace73cbfdc0bfb7b, 0x636cc64d1001550b}, + {0xd8210befd30efa5a, 0x3c47f7e05401aa4e}, + {0x8714a775e3e95c78, 0x65acfaec34810a71}, + {0xa8d9d1535ce3b396, 0x7f1839a741a14d0d}, + {0xd31045a8341ca07c, 0x1ede48111209a050}, + {0x83ea2b892091e44d, 0x934aed0aab460432}, + {0xa4e4b66b68b65d60, 0xf81da84d5617853f}, + {0xce1de40642e3f4b9, 0x36251260ab9d668e}, + {0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019}, + {0xa1075a24e4421730, 0xb24cf65b8612f81f}, + {0xc94930ae1d529cfc, 0xdee033f26797b627}, + {0xfb9b7cd9a4a7443c, 0x169840ef017da3b1}, + {0x9d412e0806e88aa5, 0x8e1f289560ee864e}, + {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2}, + {0xf5b5d7ec8acb58a2, 0xae10af696774b1db}, + {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29}, + {0xbff610b0cc6edd3f, 0x17fd090a58d32af3}, + {0xeff394dcff8a948e, 0xddfc4b4cef07f5b0}, + {0x95f83d0a1fb69cd9, 0x4abdaf101564f98e}, + {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1}, + {0xea53df5fd18d5513, 0x84c86189216dc5ed}, + {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4}, + {0xb7118682dbb66a77, 0x3fbc8c33221dc2a1}, + {0xe4d5e82392a40515, 0x0fabaf3feaa5334a}, + {0x8f05b1163ba6832d, 0x29cb4d87f2a7400e}, + {0xb2c71d5bca9023f8, 0x743e20e9ef511012}, + {0xdf78e4b2bd342cf6, 0x914da9246b255416}, + {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e}, + {0xae9672aba3d0c320, 0xa184ac2473b529b1}, + {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e}, + {0x8865899617fb1871, 0x7e2fa67c7a658892}, + {0xaa7eebfb9df9de8d, 0xddbb901b98feeab7}, + {0xd51ea6fa85785631, 0x552a74227f3ea565}, + {0x8533285c936b35de, 0xd53a88958f87275f}, + {0xa67ff273b8460356, 0x8a892abaf368f137}, + {0xd01fef10a657842c, 0x2d2b7569b0432d85}, + {0x8213f56a67f6b29b, 0x9c3b29620e29fc73}, + {0xa298f2c501f45f42, 0x8349f3ba91b47b8f}, + {0xcb3f2f7642717713, 0x241c70a936219a73}, + {0xfe0efb53d30dd4d7, 0xed238cd383aa0110}, + {0x9ec95d1463e8a506, 0xf4363804324a40aa}, + {0xc67bb4597ce2ce48, 0xb143c6053edcd0d5}, + {0xf81aa16fdc1b81da, 0xdd94b7868e94050a}, + {0x9b10a4e5e9913128, 0xca7cf2b4191c8326}, + {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0}, + {0xf24a01a73cf2dccf, 0xbc633b39673c8cec}, + {0x976e41088617ca01, 0xd5be0503e085d813}, + {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18}, + {0xec9c459d51852ba2, 0xddf8e7d60ed1219e}, + {0x93e1ab8252f33b45, 0xcabb90e5c942b503}, + {0xb8da1662e7b00a17, 0x3d6a751f3b936243}, + {0xe7109bfba19c0c9d, 0x0cc512670a783ad4}, + {0x906a617d450187e2, 0x27fb2b80668b24c5}, + {0xb484f9dc9641e9da, 0xb1f9f660802dedf6}, + {0xe1a63853bbd26451, 0x5e7873f8a0396973}, + {0x8d07e33455637eb2, 0xdb0b487b6423e1e8}, + {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62}, + {0xdc5c5301c56b75f7, 0x7641a140cc7810fb}, + {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d}, + {0xac2820d9623bf429, 0x546345fa9fbdcd44}, + {0xd732290fbacaf133, 0xa97c177947ad4095}, + {0x867f59a9d4bed6c0, 0x49ed8eabcccc485d}, + {0xa81f301449ee8c70, 0x5c68f256bfff5a74}, + {0xd226fc195c6a2f8c, 0x73832eec6fff3111}, + {0x83585d8fd9c25db7, 0xc831fd53c5ff7eab}, + {0xa42e74f3d032f525, 0xba3e7ca8b77f5e55}, + {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb}, + {0x80444b5e7aa7cf85, 0x7980d163cf5b81b3}, + {0xa0555e361951c366, 0xd7e105bcc332621f}, + {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7}, + {0xfa856334878fc150, 0xb14f98f6f0feb951}, + {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3}, + {0xc3b8358109e84f07, 0x0a862f80ec4700c8}, + {0xf4a642e14c6262c8, 0xcd27bb612758c0fa}, + {0x98e7e9cccfbd7dbd, 0x8038d51cb897789c}, + {0xbf21e44003acdd2c, 0xe0470a63e6bd56c3}, + {0xeeea5d5004981478, 0x1858ccfce06cac74}, + {0x95527a5202df0ccb, 0x0f37801e0c43ebc8}, + {0xbaa718e68396cffd, 0xd30560258f54e6ba}, + {0xe950df20247c83fd, 0x47c6b82ef32a2069}, + {0x91d28b7416cdd27e, 0x4cdc331d57fa5441}, + {0xb6472e511c81471d, 0xe0133fe4adf8e952}, + {0xe3d8f9e563a198e5, 0x58180fddd97723a6}, + {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648}, + {0xb201833b35d63f73, 0x2cd2cc6551e513da}, + {0xde81e40a034bcf4f, 0xf8077f7ea65e58d1}, + {0x8b112e86420f6191, 0xfb04afaf27faf782}, + {0xadd57a27d29339f6, 0x79c5db9af1f9b563}, + {0xd94ad8b1c7380874, 0x18375281ae7822bc}, + {0x87cec76f1c830548, 0x8f2293910d0b15b5}, + {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb22}, + {0xd433179d9c8cb841, 0x5fa60692a46151eb}, + {0x849feec281d7f328, 0xdbc7c41ba6bcd333}, + {0xa5c7ea73224deff3, 0x12b9b522906c0800}, + {0xcf39e50feae16bef, 0xd768226b34870a00}, + {0x81842f29f2cce375, 0xe6a1158300d46640}, + {0xa1e53af46f801c53, 0x60495ae3c1097fd0}, + {0xca5e89b18b602368, 0x385bb19cb14bdfc4}, + {0xfcf62c1dee382c42, 0x46729e03dd9ed7b5}, + {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d1}, + {0xc5a05277621be293, 0xc7098b7305241885}, + { 0xf70867153aa2db38, + 0xb8cbee4fc66d1ea7 } +#else + {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, + {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, + {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, + {0x86a8d39ef77164bc, 0xae5dff9c02033198}, + {0xd98ddaee19068c76, 0x3badd624dd9b0958}, + {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, + {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, + {0xe55990879ddcaabd, 0xcc420a6a101d0516}, + {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, + {0x95a8637627989aad, 0xdde7001379a44aa9}, + {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, + {0xc350000000000000, 0x0000000000000000}, + {0x9dc5ada82b70b59d, 0xf020000000000000}, + {0xfee50b7025c36a08, 0x02f236d04753d5b4}, + {0xcde6fd5e09abcf26, 0xed4c0226b55e6f86}, + {0xa6539930bf6bff45, 0x84db8346b786151c}, + {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b2}, + {0xd910f7ff28069da4, 0x1b2ba1518094da04}, + {0xaf58416654a6babb, 0x387ac8d1970027b2}, + {0x8da471a9de737e24, 0x5ceaecfed289e5d2}, + {0xe4d5e82392a40515, 0x0fabaf3feaa5334a}, + {0xb8da1662e7b00a17, 0x3d6a751f3b936243}, + { 0x95527a5202df0ccb, + 0x0f37801e0c43ebc8 } +#endif + }; + +#if FMT_USE_FULL_CACHE_DRAGONBOX + return pow10_significands[k - float_info::min_k]; +#else + static constexpr const uint64_t powers_of_5_64[] = { + 0x0000000000000001, 0x0000000000000005, 0x0000000000000019, + 0x000000000000007d, 0x0000000000000271, 0x0000000000000c35, + 0x0000000000003d09, 0x000000000001312d, 0x000000000005f5e1, + 0x00000000001dcd65, 0x00000000009502f9, 0x0000000002e90edd, + 0x000000000e8d4a51, 0x0000000048c27395, 0x000000016bcc41e9, + 0x000000071afd498d, 0x0000002386f26fc1, 0x000000b1a2bc2ec5, + 0x000003782dace9d9, 0x00001158e460913d, 0x000056bc75e2d631, + 0x0001b1ae4d6e2ef5, 0x000878678326eac9, 0x002a5a058fc295ed, + 0x00d3c21bcecceda1, 0x0422ca8b0a00a425, 0x14adf4b7320334b9}; + + static constexpr const uint32_t pow10_recovery_errors[] = { + 0x50001400, 0x54044100, 0x54014555, 0x55954415, 0x54115555, 0x00000001, + 0x50000000, 0x00104000, 0x54010004, 0x05004001, 0x55555544, 0x41545555, + 0x54040551, 0x15445545, 0x51555514, 0x10000015, 0x00101100, 0x01100015, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04450514, 0x45414110, + 0x55555145, 0x50544050, 0x15040155, 0x11054140, 0x50111514, 0x11451454, + 0x00400541, 0x00000000, 0x55555450, 0x10056551, 0x10054011, 0x55551014, + 0x69514555, 0x05151109, 0x00155555}; + + static const int compression_ratio = 27; + + // Compute base index. + int cache_index = (k - float_info::min_k) / compression_ratio; + int kb = cache_index * compression_ratio + float_info::min_k; + int offset = k - kb; + + // Get base cache. + uint128_wrapper base_cache = pow10_significands[cache_index]; + if (offset == 0) return base_cache; + + // Compute the required amount of bit-shift. + int alpha = floor_log2_pow10(kb + offset) - floor_log2_pow10(kb) - offset; + FMT_ASSERT(alpha > 0 && alpha < 64, "shifting error detected"); + + // Try to recover the real cache. + uint64_t pow5 = powers_of_5_64[offset]; + uint128_wrapper recovered_cache = umul128(base_cache.high(), pow5); + uint128_wrapper middle_low = + umul128(base_cache.low() - (kb < 0 ? 1u : 0u), pow5); + + recovered_cache += middle_low.high(); + + uint64_t high_to_middle = recovered_cache.high() << (64 - alpha); + uint64_t middle_to_low = recovered_cache.low() << (64 - alpha); + + recovered_cache = + uint128_wrapper{(recovered_cache.low() >> alpha) | high_to_middle, + ((middle_low.low() >> alpha) | middle_to_low)}; + + if (kb < 0) recovered_cache += 1; + + // Get error. + int error_idx = (k - float_info::min_k) / 16; + uint32_t error = (pow10_recovery_errors[error_idx] >> + ((k - float_info::min_k) % 16) * 2) & + 0x3; + + // Add the error back. + FMT_ASSERT(recovered_cache.low() + error >= recovered_cache.low(), ""); + return {recovered_cache.high(), recovered_cache.low() + error}; +#endif + } + + static carrier_uint compute_mul(carrier_uint u, + const cache_entry_type& cache) FMT_NOEXCEPT { + return umul192_upper64(u, cache); + } + + static uint32_t compute_delta(cache_entry_type const& cache, + int beta_minus_1) FMT_NOEXCEPT { + return static_cast(cache.high() >> (64 - 1 - beta_minus_1)); + } + + static bool compute_mul_parity(carrier_uint two_f, + const cache_entry_type& cache, + int beta_minus_1) FMT_NOEXCEPT { + FMT_ASSERT(beta_minus_1 >= 1, ""); + FMT_ASSERT(beta_minus_1 < 64, ""); + + return ((umul192_middle64(two_f, cache) >> (64 - beta_minus_1)) & 1) != 0; + } + + static carrier_uint compute_left_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { + return (cache.high() - + (cache.high() >> (float_info::significand_bits + 2))) >> + (64 - float_info::significand_bits - 1 - beta_minus_1); + } + + static carrier_uint compute_right_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { + return (cache.high() + + (cache.high() >> (float_info::significand_bits + 1))) >> + (64 - float_info::significand_bits - 1 - beta_minus_1); + } + + static carrier_uint compute_round_up_for_shorter_interval_case( + const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { + return ((cache.high() >> + (64 - float_info::significand_bits - 2 - beta_minus_1)) + + 1) / + 2; + } +}; + +// Various integer checks +template +bool is_left_endpoint_integer_shorter_interval(int exponent) FMT_NOEXCEPT { + return exponent >= + float_info< + T>::case_shorter_interval_left_endpoint_lower_threshold && + exponent <= + float_info::case_shorter_interval_left_endpoint_upper_threshold; +} +template +bool is_endpoint_integer(typename float_info::carrier_uint two_f, + int exponent, int minus_k) FMT_NOEXCEPT { + if (exponent < float_info::case_fc_pm_half_lower_threshold) return false; + // For k >= 0. + if (exponent <= float_info::case_fc_pm_half_upper_threshold) return true; + // For k < 0. + if (exponent > float_info::divisibility_check_by_5_threshold) return false; + return divisible_by_power_of_5(two_f, minus_k); +} + +template +bool is_center_integer(typename float_info::carrier_uint two_f, int exponent, + int minus_k) FMT_NOEXCEPT { + // Exponent for 5 is negative. + if (exponent > float_info::divisibility_check_by_5_threshold) return false; + if (exponent > float_info::case_fc_upper_threshold) + return divisible_by_power_of_5(two_f, minus_k); + // Both exponents are nonnegative. + if (exponent >= float_info::case_fc_lower_threshold) return true; + // Exponent for 2 is negative. + return divisible_by_power_of_2(two_f, minus_k - exponent + 1); +} + +// Remove trailing zeros from n and return the number of zeros removed (float) +FMT_INLINE int remove_trailing_zeros(uint32_t& n) FMT_NOEXCEPT { +#ifdef FMT_BUILTIN_CTZ + int t = FMT_BUILTIN_CTZ(n); +#else + int t = ctz(n); +#endif + if (t > float_info::max_trailing_zeros) + t = float_info::max_trailing_zeros; + + const uint32_t mod_inv1 = 0xcccccccd; + const uint32_t max_quotient1 = 0x33333333; + const uint32_t mod_inv2 = 0xc28f5c29; + const uint32_t max_quotient2 = 0x0a3d70a3; + + int s = 0; + for (; s < t - 1; s += 2) { + if (n * mod_inv2 > max_quotient2) break; + n *= mod_inv2; + } + if (s < t && n * mod_inv1 <= max_quotient1) { + n *= mod_inv1; + ++s; + } + n >>= s; + return s; +} + +// Removes trailing zeros and returns the number of zeros removed (double) +FMT_INLINE int remove_trailing_zeros(uint64_t& n) FMT_NOEXCEPT { +#ifdef FMT_BUILTIN_CTZLL + int t = FMT_BUILTIN_CTZLL(n); +#else + int t = ctzll(n); +#endif + if (t > float_info::max_trailing_zeros) + t = float_info::max_trailing_zeros; + // Divide by 10^8 and reduce to 32-bits + // Since ret_value.significand <= (2^64 - 1) / 1000 < 10^17, + // both of the quotient and the r should fit in 32-bits + + const uint32_t mod_inv1 = 0xcccccccd; + const uint32_t max_quotient1 = 0x33333333; + const uint64_t mod_inv8 = 0xc767074b22e90e21; + const uint64_t max_quotient8 = 0x00002af31dc46118; + + // If the number is divisible by 1'0000'0000, work with the quotient + if (t >= 8) { + auto quotient_candidate = n * mod_inv8; + + if (quotient_candidate <= max_quotient8) { + auto quotient = static_cast(quotient_candidate >> 8); + + int s = 8; + for (; s < t; ++s) { + if (quotient * mod_inv1 > max_quotient1) break; + quotient *= mod_inv1; + } + quotient >>= (s - 8); + n = quotient; + return s; + } + } + + // Otherwise, work with the remainder + auto quotient = static_cast(n / 100000000); + auto remainder = static_cast(n - 100000000 * quotient); + + if (t == 0 || remainder * mod_inv1 > max_quotient1) { + return 0; + } + remainder *= mod_inv1; + + if (t == 1 || remainder * mod_inv1 > max_quotient1) { + n = (remainder >> 1) + quotient * 10000000ull; + return 1; + } + remainder *= mod_inv1; + + if (t == 2 || remainder * mod_inv1 > max_quotient1) { + n = (remainder >> 2) + quotient * 1000000ull; + return 2; + } + remainder *= mod_inv1; + + if (t == 3 || remainder * mod_inv1 > max_quotient1) { + n = (remainder >> 3) + quotient * 100000ull; + return 3; + } + remainder *= mod_inv1; + + if (t == 4 || remainder * mod_inv1 > max_quotient1) { + n = (remainder >> 4) + quotient * 10000ull; + return 4; + } + remainder *= mod_inv1; + + if (t == 5 || remainder * mod_inv1 > max_quotient1) { + n = (remainder >> 5) + quotient * 1000ull; + return 5; + } + remainder *= mod_inv1; + + if (t == 6 || remainder * mod_inv1 > max_quotient1) { + n = (remainder >> 6) + quotient * 100ull; + return 6; + } + remainder *= mod_inv1; + + n = (remainder >> 7) + quotient * 10ull; + return 7; +} + +// The main algorithm for shorter interval case +template +FMT_INLINE decimal_fp shorter_interval_case(int exponent) FMT_NOEXCEPT { + decimal_fp ret_value; + // Compute k and beta + const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent); + const int beta_minus_1 = exponent + floor_log2_pow10(-minus_k); + + // Compute xi and zi + using cache_entry_type = typename cache_accessor::cache_entry_type; + const cache_entry_type cache = cache_accessor::get_cached_power(-minus_k); + + auto xi = cache_accessor::compute_left_endpoint_for_shorter_interval_case( + cache, beta_minus_1); + auto zi = cache_accessor::compute_right_endpoint_for_shorter_interval_case( + cache, beta_minus_1); + + // If the left endpoint is not an integer, increase it + if (!is_left_endpoint_integer_shorter_interval(exponent)) ++xi; + + // Try bigger divisor + ret_value.significand = zi / 10; + + // If succeed, remove trailing zeros if necessary and return + if (ret_value.significand * 10 >= xi) { + ret_value.exponent = minus_k + 1; + ret_value.exponent += remove_trailing_zeros(ret_value.significand); + return ret_value; + } + + // Otherwise, compute the round-up of y + ret_value.significand = + cache_accessor::compute_round_up_for_shorter_interval_case( + cache, beta_minus_1); + ret_value.exponent = minus_k; + + // When tie occurs, choose one of them according to the rule + if (exponent >= float_info::shorter_interval_tie_lower_threshold && + exponent <= float_info::shorter_interval_tie_upper_threshold) { + ret_value.significand = ret_value.significand % 2 == 0 + ? ret_value.significand + : ret_value.significand - 1; + } else if (ret_value.significand < xi) { + ++ret_value.significand; + } + return ret_value; +} + +template decimal_fp to_decimal(T x) FMT_NOEXCEPT { + // Step 1: integer promotion & Schubfach multiplier calculation. + + using carrier_uint = typename float_info::carrier_uint; + using cache_entry_type = typename cache_accessor::cache_entry_type; + auto br = bit_cast(x); + + // Extract significand bits and exponent bits. + const carrier_uint significand_mask = + (static_cast(1) << float_info::significand_bits) - 1; + carrier_uint significand = (br & significand_mask); + int exponent = static_cast((br & exponent_mask()) >> + float_info::significand_bits); + + if (exponent != 0) { // Check if normal. + exponent += float_info::exponent_bias - float_info::significand_bits; + + // Shorter interval case; proceed like Schubfach. + if (significand == 0) return shorter_interval_case(exponent); + + significand |= + (static_cast(1) << float_info::significand_bits); + } else { + // Subnormal case; the interval is always regular. + if (significand == 0) return {0, 0}; + exponent = float_info::min_exponent - float_info::significand_bits; + } + + const bool include_left_endpoint = (significand % 2 == 0); + const bool include_right_endpoint = include_left_endpoint; + + // Compute k and beta. + const int minus_k = floor_log10_pow2(exponent) - float_info::kappa; + const cache_entry_type cache = cache_accessor::get_cached_power(-minus_k); + const int beta_minus_1 = exponent + floor_log2_pow10(-minus_k); + + // Compute zi and deltai + // 10^kappa <= deltai < 10^(kappa + 1) + const uint32_t deltai = cache_accessor::compute_delta(cache, beta_minus_1); + const carrier_uint two_fc = significand << 1; + const carrier_uint two_fr = two_fc | 1; + const carrier_uint zi = + cache_accessor::compute_mul(two_fr << beta_minus_1, cache); + + // Step 2: Try larger divisor; remove trailing zeros if necessary + + // Using an upper bound on zi, we might be able to optimize the division + // better than the compiler; we are computing zi / big_divisor here + decimal_fp ret_value; + ret_value.significand = divide_by_10_to_kappa_plus_1(zi); + uint32_t r = static_cast(zi - float_info::big_divisor * + ret_value.significand); + + if (r > deltai) { + goto small_divisor_case_label; + } else if (r < deltai) { + // Exclude the right endpoint if necessary + if (r == 0 && !include_right_endpoint && + is_endpoint_integer(two_fr, exponent, minus_k)) { + --ret_value.significand; + r = float_info::big_divisor; + goto small_divisor_case_label; + } + } else { + // r == deltai; compare fractional parts + // Check conditions in the order different from the paper + // to take advantage of short-circuiting + const carrier_uint two_fl = two_fc - 1; + if ((!include_left_endpoint || + !is_endpoint_integer(two_fl, exponent, minus_k)) && + !cache_accessor::compute_mul_parity(two_fl, cache, beta_minus_1)) { + goto small_divisor_case_label; + } + } + ret_value.exponent = minus_k + float_info::kappa + 1; + + // We may need to remove trailing zeros + ret_value.exponent += remove_trailing_zeros(ret_value.significand); + return ret_value; + + // Step 3: Find the significand with the smaller divisor + +small_divisor_case_label: + ret_value.significand *= 10; + ret_value.exponent = minus_k + float_info::kappa; + + const uint32_t mask = (1u << float_info::kappa) - 1; + auto dist = r - (deltai / 2) + (float_info::small_divisor / 2); + + // Is dist divisible by 2^kappa? + if ((dist & mask) == 0) { + const bool approx_y_parity = + ((dist ^ (float_info::small_divisor / 2)) & 1) != 0; + dist >>= float_info::kappa; + + // Is dist divisible by 5^kappa? + if (check_divisibility_and_divide_by_pow5::kappa>(dist)) { + ret_value.significand += dist; + + // Check z^(f) >= epsilon^(f) + // We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1, + // where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f) + // Since there are only 2 possibilities, we only need to care about the + // parity. Also, zi and r should have the same parity since the divisor + // is an even number + if (cache_accessor::compute_mul_parity(two_fc, cache, beta_minus_1) != + approx_y_parity) { + --ret_value.significand; + } else { + // If z^(f) >= epsilon^(f), we might have a tie + // when z^(f) == epsilon^(f), or equivalently, when y is an integer + if (is_center_integer(two_fc, exponent, minus_k)) { + ret_value.significand = ret_value.significand % 2 == 0 + ? ret_value.significand + : ret_value.significand - 1; + } + } + } + // Is dist not divisible by 5^kappa? + else { + ret_value.significand += dist; + } + } + // Is dist not divisible by 2^kappa? + else { + // Since we know dist is small, we might be able to optimize the division + // better than the compiler; we are computing dist / small_divisor here + ret_value.significand += + small_division_by_pow10::kappa>(dist); + } + return ret_value; +} +} // namespace dragonbox + +// Formats a floating-point number using a variation of the Fixed-Precision +// Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White: +// https://fmt.dev/papers/p372-steele.pdf. +FMT_CONSTEXPR20 inline void format_dragon(fp value, bool is_predecessor_closer, + int num_digits, buffer& buf, + int& exp10) { + bigint numerator; // 2 * R in (FPP)^2. + bigint denominator; // 2 * S in (FPP)^2. + // lower and upper are differences between value and corresponding boundaries. + bigint lower; // (M^- in (FPP)^2). + bigint upper_store; // upper's value if different from lower. + bigint* upper = nullptr; // (M^+ in (FPP)^2). + // Shift numerator and denominator by an extra bit or two (if lower boundary + // is closer) to make lower and upper integers. This eliminates multiplication + // by 2 during later computations. + int shift = is_predecessor_closer ? 2 : 1; + uint64_t significand = value.f << shift; + if (value.e >= 0) { + numerator.assign(significand); + numerator <<= value.e; + lower.assign(1); + lower <<= value.e; + if (shift != 1) { + upper_store.assign(1); + upper_store <<= value.e + 1; + upper = &upper_store; + } + denominator.assign_pow10(exp10); + denominator <<= shift; + } else if (exp10 < 0) { + numerator.assign_pow10(-exp10); + lower.assign(numerator); + if (shift != 1) { + upper_store.assign(numerator); + upper_store <<= 1; + upper = &upper_store; + } + numerator *= significand; + denominator.assign(1); + denominator <<= shift - value.e; + } else { + numerator.assign(significand); + denominator.assign_pow10(exp10); + denominator <<= shift - value.e; + lower.assign(1); + if (shift != 1) { + upper_store.assign(1ULL << 1); + upper = &upper_store; + } + } + // Invariant: value == (numerator / denominator) * pow(10, exp10). + if (num_digits < 0) { + // Generate the shortest representation. + if (!upper) upper = &lower; + bool even = (value.f & 1) == 0; + num_digits = 0; + char* data = buf.data(); + for (;;) { + int digit = numerator.divmod_assign(denominator); + bool low = compare(numerator, lower) - even < 0; // numerator <[=] lower. + // numerator + upper >[=] pow10: + bool high = add_compare(numerator, *upper, denominator) + even > 0; + data[num_digits++] = static_cast('0' + digit); + if (low || high) { + if (!low) { + ++data[num_digits - 1]; + } else if (high) { + int result = add_compare(numerator, numerator, denominator); + // Round half to even. + if (result > 0 || (result == 0 && (digit % 2) != 0)) + ++data[num_digits - 1]; + } + buf.try_resize(to_unsigned(num_digits)); + exp10 -= num_digits - 1; + return; + } + numerator *= 10; + lower *= 10; + if (upper != &lower) *upper *= 10; + } + } + // Generate the given number of digits. + exp10 -= num_digits - 1; + if (num_digits == 0) { + denominator *= 10; + auto digit = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0'; + buf.push_back(digit); + return; + } + buf.try_resize(to_unsigned(num_digits)); + for (int i = 0; i < num_digits - 1; ++i) { + int digit = numerator.divmod_assign(denominator); + buf[i] = static_cast('0' + digit); + numerator *= 10; + } + int digit = numerator.divmod_assign(denominator); + auto result = add_compare(numerator, numerator, denominator); + if (result > 0 || (result == 0 && (digit % 2) != 0)) { + if (digit == 9) { + const auto overflow = '0' + 10; + buf[num_digits - 1] = overflow; + // Propagate the carry. + for (int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) { + buf[i] = '0'; + ++buf[i - 1]; + } + if (buf[0] == overflow) { + buf[0] = '1'; + ++exp10; + } + return; + } + ++digit; + } + buf[num_digits - 1] = static_cast('0' + digit); +} + +template +FMT_HEADER_ONLY_CONSTEXPR20 int format_float(Float value, int precision, + float_specs specs, + buffer& buf) { + // float is passed as double to reduce the number of instantiations. + static_assert(!std::is_same::value, ""); + FMT_ASSERT(value >= 0, "value is negative"); + + const bool fixed = specs.format == float_format::fixed; + if (value <= 0) { // <= instead of == to silence a warning. + if (precision <= 0 || !fixed) { + buf.push_back('0'); + return 0; + } + buf.try_resize(to_unsigned(precision)); + fill_n(buf.data(), precision, '0'); + return -precision; + } + + if (specs.fallback) return snprintf_float(value, precision, specs, buf); + + if (!is_constant_evaluated() && precision < 0) { + // Use Dragonbox for the shortest format. + if (specs.binary32) { + auto dec = dragonbox::to_decimal(static_cast(value)); + write(buffer_appender(buf), dec.significand); + return dec.exponent; + } + auto dec = dragonbox::to_decimal(static_cast(value)); + write(buffer_appender(buf), dec.significand); + return dec.exponent; + } + + int exp = 0; + bool use_dragon = true; + if (is_fast_float()) { + // Use Grisu + Dragon4 for the given precision: + // https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf. + const int min_exp = -60; // alpha in Grisu. + int cached_exp10 = 0; // K in Grisu. + fp normalized = normalize(fp(value)); + const auto cached_pow = get_cached_power( + min_exp - (normalized.e + fp::num_significand_bits), cached_exp10); + normalized = normalized * cached_pow; + gen_digits_handler handler{buf.data(), 0, precision, -cached_exp10, fixed}; + if (grisu_gen_digits(normalized, 1, exp, handler) != digits::error && + !is_constant_evaluated()) { + exp += handler.exp10; + buf.try_resize(to_unsigned(handler.size)); + use_dragon = false; + } else { + exp += handler.size - cached_exp10 - 1; + precision = handler.precision; + } + } + if (use_dragon) { + auto f = fp(); + bool is_predecessor_closer = + specs.binary32 ? f.assign(static_cast(value)) : f.assign(value); + // Limit precision to the maximum possible number of significant digits in + // an IEEE754 double because we don't need to generate zeros. + const int max_double_digits = 767; + if (precision > max_double_digits) precision = max_double_digits; + format_dragon(f, is_predecessor_closer, precision, buf, exp); + } + if (!fixed && !specs.showpoint) { + // Remove trailing zeros. + auto num_digits = buf.size(); + while (num_digits > 0 && buf[num_digits - 1] == '0') { + --num_digits; + ++exp; + } + buf.try_resize(num_digits); + } + return exp; +} + +template +int snprintf_float(T value, int precision, float_specs specs, + buffer& buf) { + // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail. + FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer"); + static_assert(!std::is_same::value, ""); + + // Subtract 1 to account for the difference in precision since we use %e for + // both general and exponent format. + if (specs.format == float_format::general || + specs.format == float_format::exp) + precision = (precision >= 0 ? precision : 6) - 1; + + // Build the format string. + enum { max_format_size = 7 }; // The longest format is "%#.*Le". + char format[max_format_size]; + char* format_ptr = format; + *format_ptr++ = '%'; + if (specs.showpoint && specs.format == float_format::hex) *format_ptr++ = '#'; + if (precision >= 0) { + *format_ptr++ = '.'; + *format_ptr++ = '*'; + } + if (std::is_same()) *format_ptr++ = 'L'; + *format_ptr++ = specs.format != float_format::hex + ? (specs.format == float_format::fixed ? 'f' : 'e') + : (specs.upper ? 'A' : 'a'); + *format_ptr = '\0'; + + // Format using snprintf. + auto offset = buf.size(); + for (;;) { + auto begin = buf.data() + offset; + auto capacity = buf.capacity() - offset; +#ifdef FMT_FUZZ + if (precision > 100000) + throw std::runtime_error( + "fuzz mode - avoid large allocation inside snprintf"); +#endif + // Suppress the warning about a nonliteral format string. + // Cannot use auto because of a bug in MinGW (#1532). + int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF; + int result = precision >= 0 + ? snprintf_ptr(begin, capacity, format, precision, value) + : snprintf_ptr(begin, capacity, format, value); + if (result < 0) { + // The buffer will grow exponentially. + buf.try_reserve(buf.capacity() + 1); + continue; + } + auto size = to_unsigned(result); + // Size equal to capacity means that the last character was truncated. + if (size >= capacity) { + buf.try_reserve(size + offset + 1); // Add 1 for the terminating '\0'. + continue; + } + auto is_digit = [](char c) { return c >= '0' && c <= '9'; }; + if (specs.format == float_format::fixed) { + if (precision == 0) { + buf.try_resize(size); + return 0; + } + // Find and remove the decimal point. + auto end = begin + size, p = end; + do { + --p; + } while (is_digit(*p)); + int fraction_size = static_cast(end - p - 1); + std::memmove(p, p + 1, to_unsigned(fraction_size)); + buf.try_resize(size - 1); + return -fraction_size; + } + if (specs.format == float_format::hex) { + buf.try_resize(size + offset); + return 0; + } + // Find and parse the exponent. + auto end = begin + size, exp_pos = end; + do { + --exp_pos; + } while (*exp_pos != 'e'); + char sign = exp_pos[1]; + FMT_ASSERT(sign == '+' || sign == '-', ""); + int exp = 0; + auto p = exp_pos + 2; // Skip 'e' and sign. + do { + FMT_ASSERT(is_digit(*p), ""); + exp = exp * 10 + (*p++ - '0'); + } while (p != end); + if (sign == '-') exp = -exp; + int fraction_size = 0; + if (exp_pos != begin + 1) { + // Remove trailing zeros. + auto fraction_end = exp_pos - 1; + while (*fraction_end == '0') --fraction_end; + // Move the fractional part left to get rid of the decimal point. + fraction_size = static_cast(fraction_end - begin - 1); + std::memmove(begin + 1, begin + 2, to_unsigned(fraction_size)); + } + buf.try_resize(to_unsigned(fraction_size) + offset + 1); + return exp - fraction_size; + } +} +} // namespace detail + +template <> struct formatter { + FMT_CONSTEXPR format_parse_context::iterator parse( + format_parse_context& ctx) { + return ctx.begin(); + } + + format_context::iterator format(const detail::bigint& n, + format_context& ctx) { + auto out = ctx.out(); + bool first = true; + for (auto i = n.bigits_.size(); i > 0; --i) { + auto value = n.bigits_[i - 1u]; + if (first) { + out = format_to(out, FMT_STRING("{:x}"), value); + first = false; + continue; + } + out = format_to(out, FMT_STRING("{:08x}"), value); + } + if (n.exp_ > 0) + out = format_to(out, FMT_STRING("p{}"), + n.exp_ * detail::bigint::bigit_bits); + return out; + } +}; + +FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { + for_each_codepoint(s, [this](uint32_t cp, string_view) { + if (cp == invalid_code_point) FMT_THROW(std::runtime_error("invalid utf8")); + if (cp <= 0xFFFF) { + buffer_.push_back(static_cast(cp)); + } else { + cp -= 0x10000; + buffer_.push_back(static_cast(0xD800 + (cp >> 10))); + buffer_.push_back(static_cast(0xDC00 + (cp & 0x3FF))); + } + return true; + }); + buffer_.push_back(0); +} + +FMT_FUNC void format_system_error(detail::buffer& out, int error_code, + const char* message) FMT_NOEXCEPT { + FMT_TRY { + auto ec = std::error_code(error_code, std::generic_category()); + write(std::back_inserter(out), std::system_error(ec, message).what()); + return; + } + FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} + +FMT_FUNC void report_system_error(int error_code, + const char* message) FMT_NOEXCEPT { + report_error(format_system_error, error_code, message); +} + +// DEPRECATED! +// This function is defined here and not inline for ABI compatiblity. +FMT_FUNC void detail::error_handler::on_error(const char* message) { + throw_format_error(message); +} + +FMT_FUNC std::string vformat(string_view fmt, format_args args) { + // Don't optimize the "{}" case to keep the binary size small and because it + // can be better optimized in fmt::format anyway. + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + return to_string(buffer); +} + +#ifdef _WIN32 +namespace detail { +using dword = conditional_t; +extern "C" __declspec(dllimport) int __stdcall WriteConsoleW( // + void*, const void*, dword, dword*, void*); +} // namespace detail +#endif + +namespace detail { +FMT_FUNC void print(std::FILE* f, string_view text) { +#ifdef _WIN32 + auto fd = _fileno(f); + if (_isatty(fd)) { + detail::utf8_to_utf16 u16(string_view(text.data(), text.size())); + auto written = detail::dword(); + if (detail::WriteConsoleW(reinterpret_cast(_get_osfhandle(fd)), + u16.c_str(), static_cast(u16.size()), + &written, nullptr)) { + return; + } + // Fallback to fwrite on failure. It can happen if the output has been + // redirected to NUL. + } +#endif + detail::fwrite_fully(text.data(), 1, text.size(), f); +} +} // namespace detail + +FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) { + memory_buffer buffer; + detail::vformat_to(buffer, format_str, args); + detail::print(f, {buffer.data(), buffer.size()}); +} + +#ifdef _WIN32 +// Print assuming legacy (non-Unicode) encoding. +FMT_FUNC void detail::vprint_mojibake(std::FILE* f, string_view format_str, + format_args args) { + memory_buffer buffer; + detail::vformat_to(buffer, format_str, + basic_format_args>(args)); + fwrite_fully(buffer.data(), 1, buffer.size(), f); +} +#endif + +FMT_FUNC void vprint(string_view format_str, format_args args) { + vprint(stdout, format_str, args); +} + +FMT_END_NAMESPACE + +#endif // FMT_FORMAT_INL_H_ diff --git a/ctrtool/deps/libfmt/include/fmt/format.h b/ctrtool/deps/libfmt/include/fmt/format.h new file mode 100644 index 0000000..ee69651 --- /dev/null +++ b/ctrtool/deps/libfmt/include/fmt/format.h @@ -0,0 +1,3104 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - present, Victor Zverovich + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + --- Optional exception to the license --- + + As an exception, if, as a result of your compiling your source code, portions + of this Software are embedded into a machine-executable object form of such + source code, you may redistribute such embedded portions in such object form + without including the above copyright and permission notices. + */ + +#ifndef FMT_FORMAT_H_ +#define FMT_FORMAT_H_ + +#include // std::signbit +#include // uint32_t +#include // std::numeric_limits +#include // std::uninitialized_copy +#include // std::runtime_error +#include // std::system_error +#include // std::swap + +#ifdef __cpp_lib_bit_cast +# include // std::bitcast +#endif + +#include "core.h" + +#if FMT_GCC_VERSION +# define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) +#else +# define FMT_GCC_VISIBILITY_HIDDEN +#endif + +#ifdef __NVCC__ +# define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__) +#else +# define FMT_CUDA_VERSION 0 +#endif + +#ifdef __has_builtin +# define FMT_HAS_BUILTIN(x) __has_builtin(x) +#else +# define FMT_HAS_BUILTIN(x) 0 +#endif + +#if FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_NOINLINE __attribute__((noinline)) +#else +# define FMT_NOINLINE +#endif + +#if FMT_MSC_VER +# define FMT_MSC_DEFAULT = default +#else +# define FMT_MSC_DEFAULT +#endif + +#ifndef FMT_THROW +# if FMT_EXCEPTIONS +# if FMT_MSC_VER || FMT_NVCC +FMT_BEGIN_NAMESPACE +namespace detail { +template inline void do_throw(const Exception& x) { + // Silence unreachable code warnings in MSVC and NVCC because these + // are nearly impossible to fix in a generic code. + volatile bool b = true; + if (b) throw x; +} +} // namespace detail +FMT_END_NAMESPACE +# define FMT_THROW(x) detail::do_throw(x) +# else +# define FMT_THROW(x) throw x +# endif +# else +# define FMT_THROW(x) \ + do { \ + FMT_ASSERT(false, (x).what()); \ + } while (false) +# endif +#endif + +#if FMT_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif + +#ifndef FMT_MAYBE_UNUSED +# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) +# define FMT_MAYBE_UNUSED [[maybe_unused]] +# else +# define FMT_MAYBE_UNUSED +# endif +#endif + +// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers. +#if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC +# define FMT_DEPRECATED_ALIAS +#else +# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED +#endif + +#ifndef FMT_USE_USER_DEFINED_LITERALS +// EDG based compilers (Intel, NVIDIA, Elbrus, etc), GCC and MSVC support UDLs. +# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \ + FMT_MSC_VER >= 1900) && \ + (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= /* UDL feature */ 480) +# define FMT_USE_USER_DEFINED_LITERALS 1 +# else +# define FMT_USE_USER_DEFINED_LITERALS 0 +# endif +#endif + +// Defining FMT_REDUCE_INT_INSTANTIATIONS to 1, will reduce the number of +// integer formatter template instantiations to just one by only using the +// largest integer type. This results in a reduction in binary size but will +// cause a decrease in integer formatting performance. +#if !defined(FMT_REDUCE_INT_INSTANTIATIONS) +# define FMT_REDUCE_INT_INSTANTIATIONS 0 +#endif + +// __builtin_clz is broken in clang with Microsoft CodeGen: +// https://github.com/fmtlib/fmt/issues/519. +#if !FMT_MSC_VER +# if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +# endif +# if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +# endif +#endif + +// __builtin_ctz is broken in Intel Compiler Classic on Windows: +// https://github.com/fmtlib/fmt/issues/2510. +#ifndef __ICL +# if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) +# endif +# if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) +# endif +#endif + +#if FMT_MSC_VER +# include // _BitScanReverse[64], _BitScanForward[64], _umul128 +#endif + +// Some compilers masquerade as both MSVC and GCC-likes or otherwise support +// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the +// MSVC intrinsics if the clz and clzll builtins are not available. +#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(FMT_BUILTIN_CTZLL) +FMT_BEGIN_NAMESPACE +namespace detail { +// Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. +# if !defined(__clang__) +# pragma intrinsic(_BitScanForward) +# pragma intrinsic(_BitScanReverse) +# if defined(_WIN64) +# pragma intrinsic(_BitScanForward64) +# pragma intrinsic(_BitScanReverse64) +# endif +# endif + +inline auto clz(uint32_t x) -> int { + unsigned long r = 0; + _BitScanReverse(&r, x); + FMT_ASSERT(x != 0, ""); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. + FMT_MSC_WARNING(suppress : 6102) + return 31 ^ static_cast(r); +} +# define FMT_BUILTIN_CLZ(n) detail::clz(n) + +inline auto clzll(uint64_t x) -> int { + unsigned long r = 0; +# ifdef _WIN64 + _BitScanReverse64(&r, x); +# else + // Scan the high 32 bits. + if (_BitScanReverse(&r, static_cast(x >> 32))) return 63 ^ (r + 32); + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast(x)); +# endif + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. + return 63 ^ static_cast(r); +} +# define FMT_BUILTIN_CLZLL(n) detail::clzll(n) + +inline auto ctz(uint32_t x) -> int { + unsigned long r = 0; + _BitScanForward(&r, x); + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. + return static_cast(r); +} +# define FMT_BUILTIN_CTZ(n) detail::ctz(n) + +inline auto ctzll(uint64_t x) -> int { + unsigned long r = 0; + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. +# ifdef _WIN64 + _BitScanForward64(&r, x); +# else + // Scan the low 32 bits. + if (_BitScanForward(&r, static_cast(x))) return static_cast(r); + // Scan the high 32 bits. + _BitScanForward(&r, static_cast(x >> 32)); + r += 32; +# endif + return static_cast(r); +} +# define FMT_BUILTIN_CTZLL(n) detail::ctzll(n) +} // namespace detail +FMT_END_NAMESPACE +#endif + +#ifdef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY_CONSTEXPR20 FMT_CONSTEXPR20 +#else +# define FMT_HEADER_ONLY_CONSTEXPR20 +#endif + +FMT_BEGIN_NAMESPACE +namespace detail { + +template class formatbuf : public Streambuf { + private: + using char_type = typename Streambuf::char_type; + using streamsize = decltype(std::declval().sputn(nullptr, 0)); + using int_type = typename Streambuf::int_type; + using traits_type = typename Streambuf::traits_type; + + buffer& buffer_; + + public: + explicit formatbuf(buffer& buf) : buffer_(buf) {} + + protected: + // The put area is always empty. This makes the implementation simpler and has + // the advantage that the streambuf and the buffer are always in sync and + // sputc never writes into uninitialized memory. A disadvantage is that each + // call to sputc always results in a (virtual) call to overflow. There is no + // disadvantage here for sputn since this always results in a call to xsputn. + + auto overflow(int_type ch) -> int_type override { + if (!traits_type::eq_int_type(ch, traits_type::eof())) + buffer_.push_back(static_cast(ch)); + return ch; + } + + auto xsputn(const char_type* s, streamsize count) -> streamsize override { + buffer_.append(s, s + count); + return count; + } +}; + +// Implementation of std::bit_cast for pre-C++20. +template +FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To { + static_assert(sizeof(To) == sizeof(From), "size mismatch"); +#ifdef __cpp_lib_bit_cast + if (is_constant_evaluated()) return std::bit_cast(from); +#endif + auto to = To(); + std::memcpy(&to, &from, sizeof(to)); + return to; +} + +inline auto is_big_endian() -> bool { +#ifdef _WIN32 + return false; +#elif defined(__BIG_ENDIAN__) + return true; +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) + return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__; +#else + struct bytes { + char data[sizeof(int)]; + }; + return bit_cast(1).data[0] == 0; +#endif +} + +// A fallback implementation of uintptr_t for systems that lack it. +struct fallback_uintptr { + unsigned char value[sizeof(void*)]; + + fallback_uintptr() = default; + explicit fallback_uintptr(const void* p) { + *this = bit_cast(p); + if (const_check(is_big_endian())) { + for (size_t i = 0, j = sizeof(void*) - 1; i < j; ++i, --j) + std::swap(value[i], value[j]); + } + } +}; +#ifdef UINTPTR_MAX +using uintptr_t = ::uintptr_t; +inline auto to_uintptr(const void* p) -> uintptr_t { + return bit_cast(p); +} +#else +using uintptr_t = fallback_uintptr; +inline auto to_uintptr(const void* p) -> fallback_uintptr { + return fallback_uintptr(p); +} +#endif + +// Returns the largest possible value for type T. Same as +// std::numeric_limits::max() but shorter and not affected by the max macro. +template constexpr auto max_value() -> T { + return (std::numeric_limits::max)(); +} +template constexpr auto num_bits() -> int { + return std::numeric_limits::digits; +} +// std::numeric_limits::digits may return 0 for 128-bit ints. +template <> constexpr auto num_bits() -> int { return 128; } +template <> constexpr auto num_bits() -> int { return 128; } +template <> constexpr auto num_bits() -> int { + return static_cast(sizeof(void*) * + std::numeric_limits::digits); +} + +FMT_INLINE void assume(bool condition) { + (void)condition; +#if FMT_HAS_BUILTIN(__builtin_assume) + __builtin_assume(condition); +#endif +} + +// An approximation of iterator_t for pre-C++20 systems. +template +using iterator_t = decltype(std::begin(std::declval())); +template using sentinel_t = decltype(std::end(std::declval())); + +// A workaround for std::string not having mutable data() until C++17. +template +inline auto get_data(std::basic_string& s) -> Char* { + return &s[0]; +} +template +inline auto get_data(Container& c) -> typename Container::value_type* { + return c.data(); +} + +#if defined(_SECURE_SCL) && _SECURE_SCL +// Make a checked iterator to avoid MSVC warnings. +template using checked_ptr = stdext::checked_array_iterator; +template +constexpr auto make_checked(T* p, size_t size) -> checked_ptr { + return {p, size}; +} +#else +template using checked_ptr = T*; +template constexpr auto make_checked(T* p, size_t) -> T* { + return p; +} +#endif + +// Attempts to reserve space for n extra characters in the output range. +// Returns a pointer to the reserved range or a reference to it. +template ::value)> +#if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION +__attribute__((no_sanitize("undefined"))) +#endif +inline auto +reserve(std::back_insert_iterator it, size_t n) + -> checked_ptr { + Container& c = get_container(it); + size_t size = c.size(); + c.resize(size + n); + return make_checked(get_data(c) + size, n); +} + +template +inline auto reserve(buffer_appender it, size_t n) -> buffer_appender { + buffer& buf = get_container(it); + buf.try_reserve(buf.size() + n); + return it; +} + +template +constexpr auto reserve(Iterator& it, size_t) -> Iterator& { + return it; +} + +template +using reserve_iterator = + remove_reference_t(), 0))>; + +template +constexpr auto to_pointer(OutputIt, size_t) -> T* { + return nullptr; +} +template auto to_pointer(buffer_appender it, size_t n) -> T* { + buffer& buf = get_container(it); + auto size = buf.size(); + if (buf.capacity() < size + n) return nullptr; + buf.try_resize(size + n); + return buf.data() + size; +} + +template ::value)> +inline auto base_iterator(std::back_insert_iterator& it, + checked_ptr) + -> std::back_insert_iterator { + return it; +} + +template +constexpr auto base_iterator(Iterator, Iterator it) -> Iterator { + return it; +} + +// is spectacularly slow to compile in C++20 so use a simple fill_n +// instead (#1998). +template +FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T& value) + -> OutputIt { + for (Size i = 0; i < count; ++i) *out++ = value; + return out; +} +template +FMT_CONSTEXPR20 auto fill_n(T* out, Size count, char value) -> T* { + if (is_constant_evaluated()) { + return fill_n(out, count, value); + } + std::memset(out, value, to_unsigned(count)); + return out + count; +} + +#ifdef __cpp_char8_t +using char8_type = char8_t; +#else +enum char8_type : unsigned char {}; +#endif + +template +FMT_CONSTEXPR FMT_NOINLINE auto copy_str_noinline(InputIt begin, InputIt end, + OutputIt out) -> OutputIt { + return copy_str(begin, end, out); +} + +// A public domain branchless UTF-8 decoder by Christopher Wellons: +// https://github.com/skeeto/branchless-utf8 +/* Decode the next character, c, from s, reporting errors in e. + * + * Since this is a branchless decoder, four bytes will be read from the + * buffer regardless of the actual length of the next character. This + * means the buffer _must_ have at least three bytes of zero padding + * following the end of the data stream. + * + * Errors are reported in e, which will be non-zero if the parsed + * character was somehow invalid: invalid byte sequence, non-canonical + * encoding, or a surrogate half. + * + * The function returns a pointer to the next character. When an error + * occurs, this pointer will be a guess that depends on the particular + * error, but it will always advance at least one byte. + */ +FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e) + -> const char* { + constexpr const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07}; + constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536}; + constexpr const int shiftc[] = {0, 18, 12, 6, 0}; + constexpr const int shifte[] = {0, 6, 4, 2, 0}; + + int len = code_point_length(s); + const char* next = s + len; + + // Assume a four-byte character and load four bytes. Unused bits are + // shifted out. + *c = uint32_t(s[0] & masks[len]) << 18; + *c |= uint32_t(s[1] & 0x3f) << 12; + *c |= uint32_t(s[2] & 0x3f) << 6; + *c |= uint32_t(s[3] & 0x3f) << 0; + *c >>= shiftc[len]; + + // Accumulate the various error conditions. + using uchar = unsigned char; + *e = (*c < mins[len]) << 6; // non-canonical encoding + *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half? + *e |= (*c > 0x10FFFF) << 8; // out of range? + *e |= (uchar(s[1]) & 0xc0) >> 2; + *e |= (uchar(s[2]) & 0xc0) >> 4; + *e |= uchar(s[3]) >> 6; + *e ^= 0x2a; // top two bits of each tail byte correct? + *e >>= shifte[len]; + + return next; +} + +constexpr uint32_t invalid_code_point = ~uint32_t(); + +// Invokes f(cp, sv) for every code point cp in s with sv being the string view +// corresponding to the code point. cp is invalid_code_point on error. +template +FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) { + auto decode = [f](const char* buf_ptr, const char* ptr) { + auto cp = uint32_t(); + auto error = 0; + auto end = utf8_decode(buf_ptr, &cp, &error); + bool result = f(error ? invalid_code_point : cp, + string_view(ptr, to_unsigned(end - buf_ptr))); + return result ? end : nullptr; + }; + auto p = s.data(); + const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars. + if (s.size() >= block_size) { + for (auto end = p + s.size() - block_size + 1; p < end;) { + p = decode(p, p); + if (!p) return; + } + } + if (auto num_chars_left = s.data() + s.size() - p) { + char buf[2 * block_size - 1] = {}; + copy_str(p, p + num_chars_left, buf); + const char* buf_ptr = buf; + do { + auto end = decode(buf_ptr, p); + if (!end) return; + p += end - buf_ptr; + buf_ptr = end; + } while (buf_ptr - buf < num_chars_left); + } +} + +template +inline auto compute_width(basic_string_view s) -> size_t { + return s.size(); +} + +// Computes approximate display width of a UTF-8 string. +FMT_CONSTEXPR inline size_t compute_width(string_view s) { + size_t num_code_points = 0; + // It is not a lambda for compatibility with C++14. + struct count_code_points { + size_t* count; + FMT_CONSTEXPR auto operator()(uint32_t cp, string_view) const -> bool { + *count += detail::to_unsigned( + 1 + + (cp >= 0x1100 && + (cp <= 0x115f || // Hangul Jamo init. consonants + cp == 0x2329 || // LEFT-POINTING ANGLE BRACKET + cp == 0x232a || // RIGHT-POINTING ANGLE BRACKET + // CJK ... Yi except IDEOGRAPHIC HALF FILL SPACE: + (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) || + (cp >= 0xac00 && cp <= 0xd7a3) || // Hangul Syllables + (cp >= 0xf900 && cp <= 0xfaff) || // CJK Compatibility Ideographs + (cp >= 0xfe10 && cp <= 0xfe19) || // Vertical Forms + (cp >= 0xfe30 && cp <= 0xfe6f) || // CJK Compatibility Forms + (cp >= 0xff00 && cp <= 0xff60) || // Fullwidth Forms + (cp >= 0xffe0 && cp <= 0xffe6) || // Fullwidth Forms + (cp >= 0x20000 && cp <= 0x2fffd) || // CJK + (cp >= 0x30000 && cp <= 0x3fffd) || + // Miscellaneous Symbols and Pictographs + Emoticons: + (cp >= 0x1f300 && cp <= 0x1f64f) || + // Supplemental Symbols and Pictographs: + (cp >= 0x1f900 && cp <= 0x1f9ff)))); + return true; + } + }; + for_each_codepoint(s, count_code_points{&num_code_points}); + return num_code_points; +} + +inline auto compute_width(basic_string_view s) -> size_t { + return compute_width(basic_string_view( + reinterpret_cast(s.data()), s.size())); +} + +template +inline auto code_point_index(basic_string_view s, size_t n) -> size_t { + size_t size = s.size(); + return n < size ? n : size; +} + +// Calculates the index of the nth code point in a UTF-8 string. +inline auto code_point_index(basic_string_view s, size_t n) + -> size_t { + const char8_type* data = s.data(); + size_t num_code_points = 0; + for (size_t i = 0, size = s.size(); i != size; ++i) { + if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) return i; + } + return s.size(); +} + +template ::value> +struct is_fast_float : bool_constant::is_iec559 && + sizeof(T) <= sizeof(double)> {}; +template struct is_fast_float : std::false_type {}; + +#ifndef FMT_USE_FULL_CACHE_DRAGONBOX +# define FMT_USE_FULL_CACHE_DRAGONBOX 0 +#endif + +template +template +void buffer::append(const U* begin, const U* end) { + while (begin != end) { + auto count = to_unsigned(end - begin); + try_reserve(size_ + count); + auto free_cap = capacity_ - size_; + if (free_cap < count) count = free_cap; + std::uninitialized_copy_n(begin, count, make_checked(ptr_ + size_, count)); + size_ += count; + begin += count; + } +} + +template +struct is_locale : std::false_type {}; +template +struct is_locale> : std::true_type {}; +} // namespace detail + +FMT_MODULE_EXPORT_BEGIN + +// The number of characters to store in the basic_memory_buffer object itself +// to avoid dynamic memory allocation. +enum { inline_buffer_size = 500 }; + +/** + \rst + A dynamically growing memory buffer for trivially copyable/constructible types + with the first ``SIZE`` elements stored in the object itself. + + You can use the ``memory_buffer`` type alias for ``char`` instead. + + **Example**:: + + auto out = fmt::memory_buffer(); + format_to(std::back_inserter(out), "The answer is {}.", 42); + + This will append the following output to the ``out`` object: + + .. code-block:: none + + The answer is 42. + + The output can be converted to an ``std::string`` with ``to_string(out)``. + \endrst + */ +template > +class basic_memory_buffer final : public detail::buffer { + private: + T store_[SIZE]; + + // Don't inherit from Allocator avoid generating type_info for it. + Allocator alloc_; + + // Deallocate memory allocated by the buffer. + FMT_CONSTEXPR20 void deallocate() { + T* data = this->data(); + if (data != store_) alloc_.deallocate(data, this->capacity()); + } + + protected: + FMT_CONSTEXPR20 void grow(size_t size) override; + + public: + using value_type = T; + using const_reference = const T&; + + FMT_CONSTEXPR20 explicit basic_memory_buffer( + const Allocator& alloc = Allocator()) + : alloc_(alloc) { + this->set(store_, SIZE); + if (detail::is_constant_evaluated()) { + detail::fill_n(store_, SIZE, T{}); + } + } + FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); } + + private: + // Move data from other to this buffer. + FMT_CONSTEXPR20 void move(basic_memory_buffer& other) { + alloc_ = std::move(other.alloc_); + T* data = other.data(); + size_t size = other.size(), capacity = other.capacity(); + if (data == other.store_) { + this->set(store_, capacity); + if (detail::is_constant_evaluated()) { + detail::copy_str(other.store_, other.store_ + size, + detail::make_checked(store_, capacity)); + } else { + std::uninitialized_copy(other.store_, other.store_ + size, + detail::make_checked(store_, capacity)); + } + } else { + this->set(data, capacity); + // Set pointer to the inline array so that delete is not called + // when deallocating. + other.set(other.store_, 0); + } + this->resize(size); + } + + public: + /** + \rst + Constructs a :class:`fmt::basic_memory_buffer` object moving the content + of the other object to it. + \endrst + */ + FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other) + FMT_NOEXCEPT { + move(other); + } + + /** + \rst + Moves the content of the other ``basic_memory_buffer`` object to this one. + \endrst + */ + auto operator=(basic_memory_buffer&& other) FMT_NOEXCEPT + -> basic_memory_buffer& { + FMT_ASSERT(this != &other, ""); + deallocate(); + move(other); + return *this; + } + + // Returns a copy of the allocator associated with this buffer. + auto get_allocator() const -> Allocator { return alloc_; } + + /** + Resizes the buffer to contain *count* elements. If T is a POD type new + elements may not be initialized. + */ + FMT_CONSTEXPR20 void resize(size_t count) { this->try_resize(count); } + + /** Increases the buffer capacity to *new_capacity*. */ + void reserve(size_t new_capacity) { this->try_reserve(new_capacity); } + + // Directly append data into the buffer + using detail::buffer::append; + template + void append(const ContiguousRange& range) { + append(range.data(), range.data() + range.size()); + } +}; + +template +FMT_CONSTEXPR20 void basic_memory_buffer::grow( + size_t size) { +#ifdef FMT_FUZZ + if (size > 5000) throw std::runtime_error("fuzz mode - won't grow that much"); +#endif + const size_t max_size = std::allocator_traits::max_size(alloc_); + size_t old_capacity = this->capacity(); + size_t new_capacity = old_capacity + old_capacity / 2; + if (size > new_capacity) + new_capacity = size; + else if (new_capacity > max_size) + new_capacity = size > max_size ? size : max_size; + T* old_data = this->data(); + T* new_data = + std::allocator_traits::allocate(alloc_, new_capacity); + // The following code doesn't throw, so the raw pointer above doesn't leak. + std::uninitialized_copy(old_data, old_data + this->size(), + detail::make_checked(new_data, new_capacity)); + this->set(new_data, new_capacity); + // deallocate must not throw according to the standard, but even if it does, + // the buffer already uses the new storage and will deallocate it in + // destructor. + if (old_data != store_) alloc_.deallocate(old_data, old_capacity); +} + +using memory_buffer = basic_memory_buffer; + +template +struct is_contiguous> : std::true_type { +}; + +namespace detail { +FMT_API void print(std::FILE*, string_view); +} + +/** A formatting error such as invalid format string. */ +FMT_CLASS_API +class FMT_API format_error : public std::runtime_error { + public: + explicit format_error(const char* message) : std::runtime_error(message) {} + explicit format_error(const std::string& message) + : std::runtime_error(message) {} + format_error(const format_error&) = default; + format_error& operator=(const format_error&) = default; + format_error(format_error&&) = default; + format_error& operator=(format_error&&) = default; + ~format_error() FMT_NOEXCEPT override FMT_MSC_DEFAULT; +}; + +/** + \rst + Constructs a `~fmt::format_arg_store` object that contains references + to arguments and can be implicitly converted to `~fmt::format_args`. + If ``fmt`` is a compile-time string then `make_args_checked` checks + its validity at compile time. + \endrst + */ +template > +FMT_INLINE auto make_args_checked(const S& fmt, + const remove_reference_t&... args) + -> format_arg_store, remove_reference_t...> { + static_assert( + detail::count<( + std::is_base_of>::value && + std::is_reference::value)...>() == 0, + "passing views as lvalues is disallowed"); + detail::check_format_string(fmt); + return {args...}; +} + +// compile-time support +namespace detail_exported { +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +template struct fixed_string { + constexpr fixed_string(const Char (&str)[N]) { + detail::copy_str(static_cast(str), + str + N, data); + } + Char data[N]{}; +}; +#endif + +// Converts a compile-time string to basic_string_view. +template +constexpr auto compile_string_to_view(const Char (&s)[N]) + -> basic_string_view { + // Remove trailing NUL character if needed. Won't be present if this is used + // with a raw character array (i.e. not defined as a string). + return {s, N - (std::char_traits::to_int_type(s[N - 1]) == 0 ? 1 : 0)}; +} +template +constexpr auto compile_string_to_view(detail::std_string_view s) + -> basic_string_view { + return {s.data(), s.size()}; +} +} // namespace detail_exported + +FMT_BEGIN_DETAIL_NAMESPACE + +template struct is_integral : std::is_integral {}; +template <> struct is_integral : std::true_type {}; +template <> struct is_integral : std::true_type {}; + +template +using is_signed = + std::integral_constant::is_signed || + std::is_same::value>; + +// Returns true if value is negative, false otherwise. +// Same as `value < 0` but doesn't produce warnings if T is an unsigned type. +template ::value)> +FMT_CONSTEXPR auto is_negative(T value) -> bool { + return value < 0; +} +template ::value)> +FMT_CONSTEXPR auto is_negative(T) -> bool { + return false; +} + +template ::value)> +FMT_CONSTEXPR auto is_supported_floating_point(T) -> uint16_t { + return (std::is_same::value && FMT_USE_FLOAT) || + (std::is_same::value && FMT_USE_DOUBLE) || + (std::is_same::value && FMT_USE_LONG_DOUBLE); +} + +// Smallest of uint32_t, uint64_t, uint128_t that is large enough to +// represent all values of an integral type T. +template +using uint32_or_64_or_128_t = + conditional_t() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS, + uint32_t, + conditional_t() <= 64, uint64_t, uint128_t>>; +template +using uint64_or_128_t = conditional_t() <= 64, uint64_t, uint128_t>; + +#define FMT_POWERS_OF_10(factor) \ + factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \ + (factor)*1000000, (factor)*10000000, (factor)*100000000, \ + (factor)*1000000000 + +// Converts value in the range [0, 100) to a string. +constexpr const char* digits2(size_t value) { + // GCC generates slightly better code when value is pointer-size. + return &"0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"[value * 2]; +} + +// Sign is a template parameter to workaround a bug in gcc 4.8. +template constexpr Char sign(Sign s) { +#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604 + static_assert(std::is_same::value, ""); +#endif + return static_cast("\0-+ "[s]); +} + +template FMT_CONSTEXPR auto count_digits_fallback(T n) -> int { + int count = 1; + for (;;) { + // Integer division is slow so do it for a group of four digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + if (n < 10) return count; + if (n < 100) return count + 1; + if (n < 1000) return count + 2; + if (n < 10000) return count + 3; + n /= 10000u; + count += 4; + } +} +#if FMT_USE_INT128 +FMT_CONSTEXPR inline auto count_digits(uint128_t n) -> int { + return count_digits_fallback(n); +} +#endif + +#ifdef FMT_BUILTIN_CLZLL +// It is a separate function rather than a part of count_digits to workaround +// the lack of static constexpr in constexpr functions. +inline auto do_count_digits(uint64_t n) -> int { + // This has comparable performance to the version by Kendall Willets + // (https://github.com/fmtlib/format-benchmark/blob/master/digits10) + // but uses smaller tables. + // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). + static constexpr uint8_t bsr2log10[] = { + 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, + 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, + 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; + auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; + static constexpr const uint64_t zero_or_powers_of_10[] = { + 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL), + 10000000000000000000ULL}; + return t - (n < zero_or_powers_of_10[t]); +} +#endif + +// Returns the number of decimal digits in n. Leading zeros are not counted +// except for n == 0 in which case count_digits returns 1. +FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int { +#ifdef FMT_BUILTIN_CLZLL + if (!is_constant_evaluated()) { + return do_count_digits(n); + } +#endif + return count_digits_fallback(n); +} + +// Counts the number of digits in n. BITS = log2(radix). +template +FMT_CONSTEXPR auto count_digits(UInt n) -> int { +#ifdef FMT_BUILTIN_CLZ + if (num_bits() == 32) + return (FMT_BUILTIN_CLZ(static_cast(n) | 1) ^ 31) / BITS + 1; +#endif + // Lambda avoids unreachable code warnings from NVHPC. + return [](UInt m) { + int num_digits = 0; + do { + ++num_digits; + } while ((m >>= BITS) != 0); + return num_digits; + }(n); +} + +template <> auto count_digits<4>(detail::fallback_uintptr n) -> int; + +#ifdef FMT_BUILTIN_CLZ +// It is a separate function rather than a part of count_digits to workaround +// the lack of static constexpr in constexpr functions. +FMT_INLINE auto do_count_digits(uint32_t n) -> int { +// An optimization by Kendall Willets from https://bit.ly/3uOIQrB. +// This increments the upper 32 bits (log10(T) - 1) when >= T is added. +# define FMT_INC(T) (((sizeof(# T) - 1ull) << 32) - T) + static constexpr uint64_t table[] = { + FMT_INC(0), FMT_INC(0), FMT_INC(0), // 8 + FMT_INC(10), FMT_INC(10), FMT_INC(10), // 64 + FMT_INC(100), FMT_INC(100), FMT_INC(100), // 512 + FMT_INC(1000), FMT_INC(1000), FMT_INC(1000), // 4096 + FMT_INC(10000), FMT_INC(10000), FMT_INC(10000), // 32k + FMT_INC(100000), FMT_INC(100000), FMT_INC(100000), // 256k + FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000), // 2048k + FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000), // 16M + FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000), // 128M + FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000), // 1024M + FMT_INC(1000000000), FMT_INC(1000000000) // 4B + }; + auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31]; + return static_cast((n + inc) >> 32); +} +#endif + +// Optional version of count_digits for better performance on 32-bit platforms. +FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int { +#ifdef FMT_BUILTIN_CLZ + if (!is_constant_evaluated()) { + return do_count_digits(n); + } +#endif + return count_digits_fallback(n); +} + +template constexpr auto digits10() FMT_NOEXCEPT -> int { + return std::numeric_limits::digits10; +} +template <> constexpr auto digits10() FMT_NOEXCEPT -> int { + return 38; +} +template <> constexpr auto digits10() FMT_NOEXCEPT -> int { + return 38; +} + +template struct thousands_sep_result { + std::string grouping; + Char thousands_sep; +}; + +template +FMT_API auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result; +template +inline auto thousands_sep(locale_ref loc) -> thousands_sep_result { + auto result = thousands_sep_impl(loc); + return {result.grouping, Char(result.thousands_sep)}; +} +template <> +inline auto thousands_sep(locale_ref loc) -> thousands_sep_result { + return thousands_sep_impl(loc); +} + +template +FMT_API auto decimal_point_impl(locale_ref loc) -> Char; +template inline auto decimal_point(locale_ref loc) -> Char { + return Char(decimal_point_impl(loc)); +} +template <> inline auto decimal_point(locale_ref loc) -> wchar_t { + return decimal_point_impl(loc); +} + +// Compares two characters for equality. +template auto equal2(const Char* lhs, const char* rhs) -> bool { + return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]); +} +inline auto equal2(const char* lhs, const char* rhs) -> bool { + return memcmp(lhs, rhs, 2) == 0; +} + +// Copies two characters from src to dst. +template +FMT_CONSTEXPR20 FMT_INLINE void copy2(Char* dst, const char* src) { + if (!is_constant_evaluated() && sizeof(Char) == sizeof(char)) { + memcpy(dst, src, 2); + return; + } + *dst++ = static_cast(*src++); + *dst = static_cast(*src); +} + +template struct format_decimal_result { + Iterator begin; + Iterator end; +}; + +// Formats a decimal unsigned integer value writing into out pointing to a +// buffer of specified size. The caller must ensure that the buffer is large +// enough. +template +FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size) + -> format_decimal_result { + FMT_ASSERT(size >= count_digits(value), "invalid digit count"); + out += size; + Char* end = out; + while (value >= 100) { + // Integer division is slow so do it for a group of two digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + out -= 2; + copy2(out, digits2(static_cast(value % 100))); + value /= 100; + } + if (value < 10) { + *--out = static_cast('0' + value); + return {out, end}; + } + out -= 2; + copy2(out, digits2(static_cast(value))); + return {out, end}; +} + +template >::value)> +inline auto format_decimal(Iterator out, UInt value, int size) + -> format_decimal_result { + // Buffer is large enough to hold all digits (digits10 + 1). + Char buffer[digits10() + 1]; + auto end = format_decimal(buffer, value, size).end; + return {out, detail::copy_str_noinline(buffer, end, out)}; +} + +template +FMT_CONSTEXPR auto format_uint(Char* buffer, UInt value, int num_digits, + bool upper = false) -> Char* { + buffer += num_digits; + Char* end = buffer; + do { + const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; + unsigned digit = (value & ((1 << BASE_BITS) - 1)); + *--buffer = static_cast(BASE_BITS < 4 ? static_cast('0' + digit) + : digits[digit]); + } while ((value >>= BASE_BITS) != 0); + return end; +} + +template +auto format_uint(Char* buffer, detail::fallback_uintptr n, int num_digits, + bool = false) -> Char* { + auto char_digits = std::numeric_limits::digits / 4; + int start = (num_digits + char_digits - 1) / char_digits - 1; + if (int start_digits = num_digits % char_digits) { + unsigned value = n.value[start--]; + buffer = format_uint(buffer, value, start_digits); + } + for (; start >= 0; --start) { + unsigned value = n.value[start]; + buffer += char_digits; + auto p = buffer; + for (int i = 0; i < char_digits; ++i) { + unsigned digit = (value & ((1 << BASE_BITS) - 1)); + *--p = static_cast("0123456789abcdef"[digit]); + value >>= BASE_BITS; + } + } + return buffer; +} + +template +inline auto format_uint(It out, UInt value, int num_digits, bool upper = false) + -> It { + if (auto ptr = to_pointer(out, to_unsigned(num_digits))) { + format_uint(ptr, value, num_digits, upper); + return out; + } + // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1). + char buffer[num_bits() / BASE_BITS + 1]; + format_uint(buffer, value, num_digits, upper); + return detail::copy_str_noinline(buffer, buffer + num_digits, out); +} + +// A converter from UTF-8 to UTF-16. +class utf8_to_utf16 { + private: + basic_memory_buffer buffer_; + + public: + FMT_API explicit utf8_to_utf16(string_view s); + operator basic_string_view() const { return {&buffer_[0], size()}; } + auto size() const -> size_t { return buffer_.size() - 1; } + auto c_str() const -> const wchar_t* { return &buffer_[0]; } + auto str() const -> std::wstring { return {&buffer_[0], size()}; } +}; + +namespace dragonbox { + +// Type-specific information that Dragonbox uses. +template struct float_info; + +template <> struct float_info { + using carrier_uint = uint32_t; + static const int significand_bits = 23; + static const int exponent_bits = 8; + static const int min_exponent = -126; + static const int max_exponent = 127; + static const int exponent_bias = -127; + static const int decimal_digits = 9; + static const int kappa = 1; + static const int big_divisor = 100; + static const int small_divisor = 10; + static const int min_k = -31; + static const int max_k = 46; + static const int cache_bits = 64; + static const int divisibility_check_by_5_threshold = 39; + static const int case_fc_pm_half_lower_threshold = -1; + static const int case_fc_pm_half_upper_threshold = 6; + static const int case_fc_lower_threshold = -2; + static const int case_fc_upper_threshold = 6; + static const int case_shorter_interval_left_endpoint_lower_threshold = 2; + static const int case_shorter_interval_left_endpoint_upper_threshold = 3; + static const int shorter_interval_tie_lower_threshold = -35; + static const int shorter_interval_tie_upper_threshold = -35; + static const int max_trailing_zeros = 7; +}; + +template <> struct float_info { + using carrier_uint = uint64_t; + static const int significand_bits = 52; + static const int exponent_bits = 11; + static const int min_exponent = -1022; + static const int max_exponent = 1023; + static const int exponent_bias = -1023; + static const int decimal_digits = 17; + static const int kappa = 2; + static const int big_divisor = 1000; + static const int small_divisor = 100; + static const int min_k = -292; + static const int max_k = 326; + static const int cache_bits = 128; + static const int divisibility_check_by_5_threshold = 86; + static const int case_fc_pm_half_lower_threshold = -2; + static const int case_fc_pm_half_upper_threshold = 9; + static const int case_fc_lower_threshold = -4; + static const int case_fc_upper_threshold = 9; + static const int case_shorter_interval_left_endpoint_lower_threshold = 2; + static const int case_shorter_interval_left_endpoint_upper_threshold = 3; + static const int shorter_interval_tie_lower_threshold = -77; + static const int shorter_interval_tie_upper_threshold = -77; + static const int max_trailing_zeros = 16; +}; + +template struct decimal_fp { + using significand_type = typename float_info::carrier_uint; + significand_type significand; + int exponent; +}; + +template +FMT_API auto to_decimal(T x) FMT_NOEXCEPT -> decimal_fp; +} // namespace dragonbox + +template +constexpr auto exponent_mask() -> + typename dragonbox::float_info::carrier_uint { + using uint = typename dragonbox::float_info::carrier_uint; + return ((uint(1) << dragonbox::float_info::exponent_bits) - 1) + << dragonbox::float_info::significand_bits; +} + +// Writes the exponent exp in the form "[+-]d{2,3}" to buffer. +template +FMT_CONSTEXPR auto write_exponent(int exp, It it) -> It { + FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range"); + if (exp < 0) { + *it++ = static_cast('-'); + exp = -exp; + } else { + *it++ = static_cast('+'); + } + if (exp >= 100) { + const char* top = digits2(to_unsigned(exp / 100)); + if (exp >= 1000) *it++ = static_cast(top[0]); + *it++ = static_cast(top[1]); + exp %= 100; + } + const char* d = digits2(to_unsigned(exp)); + *it++ = static_cast(d[0]); + *it++ = static_cast(d[1]); + return it; +} + +template +FMT_HEADER_ONLY_CONSTEXPR20 auto format_float(T value, int precision, + float_specs specs, + buffer& buf) -> int; + +// Formats a floating-point number with snprintf. +template +auto snprintf_float(T value, int precision, float_specs specs, + buffer& buf) -> int; + +template constexpr auto promote_float(T value) -> T { + return value; +} +constexpr auto promote_float(float value) -> double { + return static_cast(value); +} + +template +FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, + const fill_t& fill) -> OutputIt { + auto fill_size = fill.size(); + if (fill_size == 1) return detail::fill_n(it, n, fill[0]); + auto data = fill.data(); + for (size_t i = 0; i < n; ++i) + it = copy_str(data, data + fill_size, it); + return it; +} + +// Writes the output of f, padded according to format specifications in specs. +// size: output size in code units. +// width: output display width in (terminal) column positions. +template +FMT_CONSTEXPR auto write_padded(OutputIt out, + const basic_format_specs& specs, + size_t size, size_t width, F&& f) -> OutputIt { + static_assert(align == align::left || align == align::right, ""); + unsigned spec_width = to_unsigned(specs.width); + size_t padding = spec_width > width ? spec_width - width : 0; + // Shifts are encoded as string literals because static constexpr is not + // supported in constexpr functions. + auto* shifts = align == align::left ? "\x1f\x1f\x00\x01" : "\x00\x1f\x00\x01"; + size_t left_padding = padding >> shifts[specs.align]; + size_t right_padding = padding - left_padding; + auto it = reserve(out, size + padding * specs.fill.size()); + if (left_padding != 0) it = fill(it, left_padding, specs.fill); + it = f(it); + if (right_padding != 0) it = fill(it, right_padding, specs.fill); + return base_iterator(out, it); +} + +template +constexpr auto write_padded(OutputIt out, const basic_format_specs& specs, + size_t size, F&& f) -> OutputIt { + return write_padded(out, specs, size, size, f); +} + +template +FMT_CONSTEXPR auto write_bytes(OutputIt out, string_view bytes, + const basic_format_specs& specs) + -> OutputIt { + return write_padded( + out, specs, bytes.size(), [bytes](reserve_iterator it) { + const char* data = bytes.data(); + return copy_str(data, data + bytes.size(), it); + }); +} + +template +auto write_ptr(OutputIt out, UIntPtr value, + const basic_format_specs* specs) -> OutputIt { + int num_digits = count_digits<4>(value); + auto size = to_unsigned(num_digits) + size_t(2); + auto write = [=](reserve_iterator it) { + *it++ = static_cast('0'); + *it++ = static_cast('x'); + return format_uint<4, Char>(it, value, num_digits); + }; + return specs ? write_padded(out, *specs, size, write) + : base_iterator(out, write(reserve(out, size))); +} + +template +FMT_CONSTEXPR auto write_char(OutputIt out, Char value, + const basic_format_specs& specs) + -> OutputIt { + return write_padded(out, specs, 1, [=](reserve_iterator it) { + *it++ = value; + return it; + }); +} +template +FMT_CONSTEXPR auto write(OutputIt out, Char value, + const basic_format_specs& specs, + locale_ref loc = {}) -> OutputIt { + return check_char_specs(specs) + ? write_char(out, value, specs) + : write(out, static_cast(value), specs, loc); +} + +// Data for write_int that doesn't depend on output iterator type. It is used to +// avoid template code bloat. +template struct write_int_data { + size_t size; + size_t padding; + + FMT_CONSTEXPR write_int_data(int num_digits, unsigned prefix, + const basic_format_specs& specs) + : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) { + if (specs.align == align::numeric) { + auto width = to_unsigned(specs.width); + if (width > size) { + padding = width - size; + size = width; + } + } else if (specs.precision > num_digits) { + size = (prefix >> 24) + to_unsigned(specs.precision); + padding = to_unsigned(specs.precision - num_digits); + } + } +}; + +// Writes an integer in the format +// +// where are written by write_digits(it). +// prefix contains chars in three lower bytes and the size in the fourth byte. +template +FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits, + unsigned prefix, + const basic_format_specs& specs, + W write_digits) -> OutputIt { + // Slightly faster check for specs.width == 0 && specs.precision == -1. + if ((specs.width | (specs.precision + 1)) == 0) { + auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24)); + if (prefix != 0) { + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); + } + return base_iterator(out, write_digits(it)); + } + auto data = write_int_data(num_digits, prefix, specs); + return write_padded( + out, specs, data.size, [=](reserve_iterator it) { + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); + it = detail::fill_n(it, data.padding, static_cast('0')); + return write_digits(it); + }); +} + +template class digit_grouping { + private: + thousands_sep_result sep_; + + struct next_state { + std::string::const_iterator group; + int pos; + }; + next_state initial_state() const { return {sep_.grouping.begin(), 0}; } + + // Returns the next digit group separator position. + int next(next_state& state) const { + if (!sep_.thousands_sep) return max_value(); + if (state.group == sep_.grouping.end()) + return state.pos += sep_.grouping.back(); + if (*state.group <= 0 || *state.group == max_value()) + return max_value(); + state.pos += *state.group++; + return state.pos; + } + + public: + explicit digit_grouping(locale_ref loc, bool localized = true) { + if (localized) + sep_ = thousands_sep(loc); + else + sep_.thousands_sep = Char(); + } + explicit digit_grouping(thousands_sep_result sep) : sep_(sep) {} + + Char separator() const { return sep_.thousands_sep; } + + int count_separators(int num_digits) const { + int count = 0; + auto state = initial_state(); + while (num_digits > next(state)) ++count; + return count; + } + + // Applies grouping to digits and write the output to out. + template + Out apply(Out out, basic_string_view digits) const { + auto num_digits = static_cast(digits.size()); + auto separators = basic_memory_buffer(); + separators.push_back(0); + auto state = initial_state(); + while (int i = next(state)) { + if (i >= num_digits) break; + separators.push_back(i); + } + for (int i = 0, sep_index = static_cast(separators.size() - 1); + i < num_digits; ++i) { + if (num_digits - i == separators[sep_index]) { + *out++ = separator(); + --sep_index; + } + *out++ = static_cast(digits[to_unsigned(i)]); + } + return out; + } +}; + +template +auto write_int_localized(OutputIt out, UInt value, unsigned prefix, + const basic_format_specs& specs, + const digit_grouping& grouping) -> OutputIt { + static_assert(std::is_same, UInt>::value, ""); + int num_digits = count_digits(value); + char digits[40]; + format_decimal(digits, value, num_digits); + unsigned size = to_unsigned((prefix != 0 ? 1 : 0) + num_digits + + grouping.count_separators(num_digits)); + return write_padded( + out, specs, size, size, [&](reserve_iterator it) { + if (prefix != 0) *it++ = static_cast(prefix); + return grouping.apply(it, string_view(digits, to_unsigned(num_digits))); + }); +} + +template +auto write_int_localized(OutputIt& out, UInt value, unsigned prefix, + const basic_format_specs& specs, locale_ref loc) + -> bool { + auto grouping = digit_grouping(loc); + out = write_int_localized(out, value, prefix, specs, grouping); + return true; +} + +FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) { + prefix |= prefix != 0 ? value << 8 : value; + prefix += (1u + (value > 0xff ? 1 : 0)) << 24; +} + +template struct write_int_arg { + UInt abs_value; + unsigned prefix; +}; + +template +FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign) + -> write_int_arg> { + auto prefix = 0u; + auto abs_value = static_cast>(value); + if (is_negative(value)) { + prefix = 0x01000000 | '-'; + abs_value = 0 - abs_value; + } else { + constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', + 0x1000000u | ' '}; + prefix = prefixes[sign]; + } + return {abs_value, prefix}; +} + +template +FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, + const basic_format_specs& specs, + locale_ref loc) -> OutputIt { + static_assert(std::is_same>::value, ""); + auto abs_value = arg.abs_value; + auto prefix = arg.prefix; + switch (specs.type) { + case presentation_type::none: + case presentation_type::dec: { + if (specs.localized && + write_int_localized(out, static_cast>(abs_value), + prefix, specs, loc)) { + return out; + } + auto num_digits = count_digits(abs_value); + return write_int( + out, num_digits, prefix, specs, [=](reserve_iterator it) { + return format_decimal(it, abs_value, num_digits).end; + }); + } + case presentation_type::hex_lower: + case presentation_type::hex_upper: { + bool upper = specs.type == presentation_type::hex_upper; + if (specs.alt) + prefix_append(prefix, unsigned(upper ? 'X' : 'x') << 8 | '0'); + int num_digits = count_digits<4>(abs_value); + return write_int( + out, num_digits, prefix, specs, [=](reserve_iterator it) { + return format_uint<4, Char>(it, abs_value, num_digits, upper); + }); + } + case presentation_type::bin_lower: + case presentation_type::bin_upper: { + bool upper = specs.type == presentation_type::bin_upper; + if (specs.alt) + prefix_append(prefix, unsigned(upper ? 'B' : 'b') << 8 | '0'); + int num_digits = count_digits<1>(abs_value); + return write_int(out, num_digits, prefix, specs, + [=](reserve_iterator it) { + return format_uint<1, Char>(it, abs_value, num_digits); + }); + } + case presentation_type::oct: { + int num_digits = count_digits<3>(abs_value); + // Octal prefix '0' is counted as a digit, so only add it if precision + // is not greater than the number of digits. + if (specs.alt && specs.precision <= num_digits && abs_value != 0) + prefix_append(prefix, '0'); + return write_int(out, num_digits, prefix, specs, + [=](reserve_iterator it) { + return format_uint<3, Char>(it, abs_value, num_digits); + }); + } + case presentation_type::chr: + return write_char(out, static_cast(abs_value), specs); + default: + throw_format_error("invalid type specifier"); + } + return out; +} +template +FMT_CONSTEXPR FMT_NOINLINE auto write_int_noinline( + OutputIt out, write_int_arg arg, const basic_format_specs& specs, + locale_ref loc) -> OutputIt { + return write_int(out, arg, specs, loc); +} +template ::value && + !std::is_same::value && + std::is_same>::value)> +FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, + const basic_format_specs& specs, + locale_ref loc) -> OutputIt { + return write_int_noinline(out, make_write_int_arg(value, specs.sign), specs, + loc); +} +// An inlined version of write used in format string compilation. +template ::value && + !std::is_same::value && + !std::is_same>::value)> +FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, + const basic_format_specs& specs, + locale_ref loc) -> OutputIt { + return write_int(out, make_write_int_arg(value, specs.sign), specs, loc); +} + +template +FMT_CONSTEXPR auto write(OutputIt out, basic_string_view s, + const basic_format_specs& specs) -> OutputIt { + auto data = s.data(); + auto size = s.size(); + if (specs.precision >= 0 && to_unsigned(specs.precision) < size) + size = code_point_index(s, to_unsigned(specs.precision)); + auto width = + specs.width != 0 ? compute_width(basic_string_view(data, size)) : 0; + return write_padded(out, specs, size, width, + [=](reserve_iterator it) { + return copy_str(data, data + size, it); + }); +} +template +FMT_CONSTEXPR auto write(OutputIt out, + basic_string_view> s, + const basic_format_specs& specs, locale_ref) + -> OutputIt { + check_string_type_spec(specs.type); + return write(out, s, specs); +} +template +FMT_CONSTEXPR auto write(OutputIt out, const Char* s, + const basic_format_specs& specs, locale_ref) + -> OutputIt { + return check_cstring_type_spec(specs.type) + ? write(out, basic_string_view(s), specs, {}) + : write_ptr(out, to_uintptr(s), &specs); +} + +template +FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isinf, + basic_format_specs specs, + const float_specs& fspecs) -> OutputIt { + auto str = + isinf ? (fspecs.upper ? "INF" : "inf") : (fspecs.upper ? "NAN" : "nan"); + constexpr size_t str_size = 3; + auto sign = fspecs.sign; + auto size = str_size + (sign ? 1 : 0); + // Replace '0'-padding with space for non-finite values. + const bool is_zero_fill = + specs.fill.size() == 1 && *specs.fill.data() == static_cast('0'); + if (is_zero_fill) specs.fill[0] = static_cast(' '); + return write_padded(out, specs, size, [=](reserve_iterator it) { + if (sign) *it++ = detail::sign(sign); + return copy_str(str, str + str_size, it); + }); +} + +// A decimal floating-point number significand * pow(10, exp). +struct big_decimal_fp { + const char* significand; + int significand_size; + int exponent; +}; + +constexpr auto get_significand_size(const big_decimal_fp& fp) -> int { + return fp.significand_size; +} +template +inline auto get_significand_size(const dragonbox::decimal_fp& fp) -> int { + return count_digits(fp.significand); +} + +template +constexpr auto write_significand(OutputIt out, const char* significand, + int significand_size) -> OutputIt { + return copy_str(significand, significand + significand_size, out); +} +template +inline auto write_significand(OutputIt out, UInt significand, + int significand_size) -> OutputIt { + return format_decimal(out, significand, significand_size).end; +} +template +FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, + int significand_size, int exponent, + const Grouping& grouping) -> OutputIt { + if (!grouping.separator()) { + out = write_significand(out, significand, significand_size); + return detail::fill_n(out, exponent, static_cast('0')); + } + auto buffer = memory_buffer(); + write_significand(appender(buffer), significand, significand_size); + detail::fill_n(appender(buffer), exponent, '0'); + return grouping.apply(out, string_view(buffer.data(), buffer.size())); +} + +template ::value)> +inline auto write_significand(Char* out, UInt significand, int significand_size, + int integral_size, Char decimal_point) -> Char* { + if (!decimal_point) + return format_decimal(out, significand, significand_size).end; + out += significand_size + 1; + Char* end = out; + int floating_size = significand_size - integral_size; + for (int i = floating_size / 2; i > 0; --i) { + out -= 2; + copy2(out, digits2(significand % 100)); + significand /= 100; + } + if (floating_size % 2 != 0) { + *--out = static_cast('0' + significand % 10); + significand /= 10; + } + *--out = decimal_point; + format_decimal(out - integral_size, significand, integral_size); + return end; +} + +template >::value)> +inline auto write_significand(OutputIt out, UInt significand, + int significand_size, int integral_size, + Char decimal_point) -> OutputIt { + // Buffer is large enough to hold digits (digits10 + 1) and a decimal point. + Char buffer[digits10() + 2]; + auto end = write_significand(buffer, significand, significand_size, + integral_size, decimal_point); + return detail::copy_str_noinline(buffer, end, out); +} + +template +FMT_CONSTEXPR auto write_significand(OutputIt out, const char* significand, + int significand_size, int integral_size, + Char decimal_point) -> OutputIt { + out = detail::copy_str_noinline(significand, + significand + integral_size, out); + if (!decimal_point) return out; + *out++ = decimal_point; + return detail::copy_str_noinline(significand + integral_size, + significand + significand_size, out); +} + +template +FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, + int significand_size, int integral_size, + Char decimal_point, + const Grouping& grouping) -> OutputIt { + if (!grouping.separator()) { + return write_significand(out, significand, significand_size, integral_size, + decimal_point); + } + auto buffer = basic_memory_buffer(); + write_significand(buffer_appender(buffer), significand, + significand_size, integral_size, decimal_point); + grouping.apply( + out, basic_string_view(buffer.data(), to_unsigned(integral_size))); + return detail::copy_str_noinline(buffer.data() + integral_size, + buffer.end(), out); +} + +template > +FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& fp, + const basic_format_specs& specs, + float_specs fspecs, locale_ref loc) + -> OutputIt { + auto significand = fp.significand; + int significand_size = get_significand_size(fp); + constexpr Char zero = static_cast('0'); + auto sign = fspecs.sign; + size_t size = to_unsigned(significand_size) + (sign ? 1 : 0); + using iterator = reserve_iterator; + + Char decimal_point = + fspecs.locale ? detail::decimal_point(loc) : static_cast('.'); + + int output_exp = fp.exponent + significand_size - 1; + auto use_exp_format = [=]() { + if (fspecs.format == float_format::exp) return true; + if (fspecs.format != float_format::general) return false; + // Use the fixed notation if the exponent is in [exp_lower, exp_upper), + // e.g. 0.0001 instead of 1e-04. Otherwise use the exponent notation. + const int exp_lower = -4, exp_upper = 16; + return output_exp < exp_lower || + output_exp >= (fspecs.precision > 0 ? fspecs.precision : exp_upper); + }; + if (use_exp_format()) { + int num_zeros = 0; + if (fspecs.showpoint) { + num_zeros = fspecs.precision - significand_size; + if (num_zeros < 0) num_zeros = 0; + size += to_unsigned(num_zeros); + } else if (significand_size == 1) { + decimal_point = Char(); + } + auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp; + int exp_digits = 2; + if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3; + + size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits); + char exp_char = fspecs.upper ? 'E' : 'e'; + auto write = [=](iterator it) { + if (sign) *it++ = detail::sign(sign); + // Insert a decimal point after the first digit and add an exponent. + it = write_significand(it, significand, significand_size, 1, + decimal_point); + if (num_zeros > 0) it = detail::fill_n(it, num_zeros, zero); + *it++ = static_cast(exp_char); + return write_exponent(output_exp, it); + }; + return specs.width > 0 ? write_padded(out, specs, size, write) + : base_iterator(out, write(reserve(out, size))); + } + + int exp = fp.exponent + significand_size; + if (fp.exponent >= 0) { + // 1234e5 -> 123400000[.0+] + size += to_unsigned(fp.exponent); + int num_zeros = fspecs.precision - exp; +#ifdef FMT_FUZZ + if (num_zeros > 5000) + throw std::runtime_error("fuzz mode - avoiding excessive cpu use"); +#endif + if (fspecs.showpoint) { + if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 1; + if (num_zeros > 0) size += to_unsigned(num_zeros) + 1; + } + auto grouping = Grouping(loc, fspecs.locale); + size += to_unsigned(grouping.count_separators(significand_size)); + return write_padded(out, specs, size, [&](iterator it) { + if (sign) *it++ = detail::sign(sign); + it = write_significand(it, significand, significand_size, + fp.exponent, grouping); + if (!fspecs.showpoint) return it; + *it++ = decimal_point; + return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; + }); + } else if (exp > 0) { + // 1234e-2 -> 12.34[0+] + int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0; + size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0); + auto grouping = Grouping(loc, fspecs.locale); + size += to_unsigned(grouping.count_separators(significand_size)); + return write_padded(out, specs, size, [&](iterator it) { + if (sign) *it++ = detail::sign(sign); + it = write_significand(it, significand, significand_size, exp, + decimal_point, grouping); + return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; + }); + } + // 1234e-6 -> 0.001234 + int num_zeros = -exp; + if (significand_size == 0 && fspecs.precision >= 0 && + fspecs.precision < num_zeros) { + num_zeros = fspecs.precision; + } + bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint; + size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros); + return write_padded(out, specs, size, [&](iterator it) { + if (sign) *it++ = detail::sign(sign); + *it++ = zero; + if (!pointy) return it; + *it++ = decimal_point; + it = detail::fill_n(it, num_zeros, zero); + return write_significand(it, significand, significand_size); + }); +} + +template class fallback_digit_grouping { + public: + constexpr fallback_digit_grouping(locale_ref, bool) {} + + constexpr Char separator() const { return Char(); } + + constexpr int count_separators(int) const { return 0; } + + template + constexpr Out apply(Out out, basic_string_view) const { + return out; + } +}; + +template +FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& fp, + const basic_format_specs& specs, + float_specs fspecs, locale_ref loc) + -> OutputIt { + if (is_constant_evaluated()) { + return do_write_float>(out, fp, specs, fspecs, + loc); + } else { + return do_write_float(out, fp, specs, fspecs, loc); + } +} + +template ::value)> +FMT_CONSTEXPR20 bool isinf(T value) { + if (is_constant_evaluated()) { +#if defined(__cpp_if_constexpr) + if constexpr (std::numeric_limits::is_iec559) { + auto bits = detail::bit_cast(static_cast(value)); + constexpr auto significand_bits = + dragonbox::float_info::significand_bits; + return (bits & exponent_mask()) && + !(bits & ((uint64_t(1) << significand_bits) - 1)); + } +#endif + } + return std::isinf(value); +} + +template ::value)> +FMT_CONSTEXPR20 bool isfinite(T value) { + if (is_constant_evaluated()) { +#if defined(__cpp_if_constexpr) + if constexpr (std::numeric_limits::is_iec559) { + auto bits = detail::bit_cast(static_cast(value)); + return (bits & exponent_mask()) != exponent_mask(); + } +#endif + } + return std::isfinite(value); +} + +template ::value)> +FMT_INLINE FMT_CONSTEXPR bool signbit(T value) { + if (is_constant_evaluated()) { +#ifdef __cpp_if_constexpr + if constexpr (std::numeric_limits::is_iec559) { + auto bits = detail::bit_cast(static_cast(value)); + return (bits & (uint64_t(1) << (num_bits() - 1))) != 0; + } +#endif + } + return std::signbit(value); +} + +template ::value)> +FMT_CONSTEXPR20 auto write(OutputIt out, T value, + basic_format_specs specs, locale_ref loc = {}) + -> OutputIt { + if (const_check(!is_supported_floating_point(value))) return out; + float_specs fspecs = parse_float_type_spec(specs); + fspecs.sign = specs.sign; + if (detail::signbit(value)) { // value < 0 is false for NaN so use signbit. + fspecs.sign = sign::minus; + value = -value; + } else if (fspecs.sign == sign::minus) { + fspecs.sign = sign::none; + } + + if (!detail::isfinite(value)) + return write_nonfinite(out, detail::isinf(value), specs, fspecs); + + if (specs.align == align::numeric && fspecs.sign) { + auto it = reserve(out, 1); + *it++ = detail::sign(fspecs.sign); + out = base_iterator(out, it); + fspecs.sign = sign::none; + if (specs.width != 0) --specs.width; + } + + memory_buffer buffer; + if (fspecs.format == float_format::hex) { + if (fspecs.sign) buffer.push_back(detail::sign(fspecs.sign)); + snprintf_float(promote_float(value), specs.precision, fspecs, buffer); + return write_bytes(out, {buffer.data(), buffer.size()}, + specs); + } + int precision = specs.precision >= 0 || specs.type == presentation_type::none + ? specs.precision + : 6; + if (fspecs.format == float_format::exp) { + if (precision == max_value()) + throw_format_error("number is too big"); + else + ++precision; + } + if (const_check(std::is_same())) fspecs.binary32 = true; + if (!is_fast_float()) fspecs.fallback = true; + int exp = format_float(promote_float(value), precision, fspecs, buffer); + fspecs.precision = precision; + auto fp = big_decimal_fp{buffer.data(), static_cast(buffer.size()), exp}; + return write_float(out, fp, specs, fspecs, loc); +} + +template ::value)> +FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt { + if (is_constant_evaluated()) { + return write(out, value, basic_format_specs()); + } + + if (const_check(!is_supported_floating_point(value))) return out; + + using floaty = conditional_t::value, double, T>; + using uint = typename dragonbox::float_info::carrier_uint; + auto bits = bit_cast(value); + + auto fspecs = float_specs(); + if (detail::signbit(value)) { + fspecs.sign = sign::minus; + value = -value; + } + + constexpr auto specs = basic_format_specs(); + uint mask = exponent_mask(); + if ((bits & mask) == mask) + return write_nonfinite(out, std::isinf(value), specs, fspecs); + + auto dec = dragonbox::to_decimal(static_cast(value)); + return write_float(out, dec, specs, fspecs, {}); +} + +template ::value && + !is_fast_float::value)> +inline auto write(OutputIt out, T value) -> OutputIt { + return write(out, value, basic_format_specs()); +} + +template +auto write(OutputIt out, monostate, basic_format_specs = {}, + locale_ref = {}) -> OutputIt { + FMT_ASSERT(false, ""); + return out; +} + +template +FMT_CONSTEXPR auto write(OutputIt out, basic_string_view value) + -> OutputIt { + auto it = reserve(out, value.size()); + it = copy_str_noinline(value.begin(), value.end(), it); + return base_iterator(out, it); +} + +template ::value)> +constexpr auto write(OutputIt out, const T& value) -> OutputIt { + return write(out, to_string_view(value)); +} + +template ::value && + !std::is_same::value && + !std::is_same::value)> +FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { + auto abs_value = static_cast>(value); + bool negative = is_negative(value); + // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer. + if (negative) abs_value = ~abs_value + 1; + int num_digits = count_digits(abs_value); + auto size = (negative ? 1 : 0) + static_cast(num_digits); + auto it = reserve(out, size); + if (auto ptr = to_pointer(it, size)) { + if (negative) *ptr++ = static_cast('-'); + format_decimal(ptr, abs_value, num_digits); + return out; + } + if (negative) *it++ = static_cast('-'); + it = format_decimal(it, abs_value, num_digits).end; + return base_iterator(out, it); +} + +// FMT_ENABLE_IF() condition separated to workaround an MSVC bug. +template < + typename Char, typename OutputIt, typename T, + bool check = + std::is_enum::value && !std::is_same::value && + mapped_type_constant>::value != + type::custom_type, + FMT_ENABLE_IF(check)> +FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { + return write( + out, static_cast::type>(value)); +} + +template ::value)> +FMT_CONSTEXPR auto write(OutputIt out, T value, + const basic_format_specs& specs = {}, + locale_ref = {}) -> OutputIt { + return specs.type != presentation_type::none && + specs.type != presentation_type::string + ? write(out, value ? 1 : 0, specs, {}) + : write_bytes(out, value ? "true" : "false", specs); +} + +template +FMT_CONSTEXPR auto write(OutputIt out, Char value) -> OutputIt { + auto it = reserve(out, 1); + *it++ = value; + return base_iterator(out, it); +} + +template +FMT_CONSTEXPR_CHAR_TRAITS auto write(OutputIt out, const Char* value) + -> OutputIt { + if (!value) { + throw_format_error("string pointer is null"); + } else { + out = write(out, basic_string_view(value)); + } + return out; +} + +template ::value)> +auto write(OutputIt out, const T* value, + const basic_format_specs& specs = {}, locale_ref = {}) + -> OutputIt { + check_pointer_type_spec(specs.type, error_handler()); + return write_ptr(out, to_uintptr(value), &specs); +} + +// A write overload that handles implicit conversions. +template > +FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> enable_if_t< + std::is_class::value && !is_string::value && + !std::is_same::value && + !std::is_same().map(value))>::value, + OutputIt> { + return write(out, arg_mapper().map(value)); +} + +template > +FMT_CONSTEXPR auto write(OutputIt out, const T& value) + -> enable_if_t::value == type::custom_type, + OutputIt> { + using formatter_type = + conditional_t::value, + typename Context::template formatter_type, + fallback_formatter>; + auto ctx = Context(out, {}, {}); + return formatter_type().format(value, ctx); +} + +// An argument visitor that formats the argument and writes it via the output +// iterator. It's a class and not a generic lambda for compatibility with C++11. +template struct default_arg_formatter { + using iterator = buffer_appender; + using context = buffer_context; + + iterator out; + basic_format_args args; + locale_ref loc; + + template auto operator()(T value) -> iterator { + return write(out, value); + } + auto operator()(typename basic_format_arg::handle h) -> iterator { + basic_format_parse_context parse_ctx({}); + context format_ctx(out, args, loc); + h.format(parse_ctx, format_ctx); + return format_ctx.out(); + } +}; + +template struct arg_formatter { + using iterator = buffer_appender; + using context = buffer_context; + + iterator out; + const basic_format_specs& specs; + locale_ref locale; + + template + FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator { + return detail::write(out, value, specs, locale); + } + auto operator()(typename basic_format_arg::handle) -> iterator { + // User-defined types are handled separately because they require access + // to the parse context. + return out; + } +}; + +template struct custom_formatter { + basic_format_parse_context& parse_ctx; + buffer_context& ctx; + + void operator()( + typename basic_format_arg>::handle h) const { + h.format(parse_ctx, ctx); + } + template void operator()(T) const {} +}; + +template +using is_integer = + bool_constant::value && !std::is_same::value && + !std::is_same::value && + !std::is_same::value>; + +template class width_checker { + public: + explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {} + + template ::value)> + FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { + if (is_negative(value)) handler_.on_error("negative width"); + return static_cast(value); + } + + template ::value)> + FMT_CONSTEXPR auto operator()(T) -> unsigned long long { + handler_.on_error("width is not integer"); + return 0; + } + + private: + ErrorHandler& handler_; +}; + +template class precision_checker { + public: + explicit FMT_CONSTEXPR precision_checker(ErrorHandler& eh) : handler_(eh) {} + + template ::value)> + FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { + if (is_negative(value)) handler_.on_error("negative precision"); + return static_cast(value); + } + + template ::value)> + FMT_CONSTEXPR auto operator()(T) -> unsigned long long { + handler_.on_error("precision is not integer"); + return 0; + } + + private: + ErrorHandler& handler_; +}; + +template