Initial commit

This commit is contained in:
Hector Martin
2016-11-23 14:35:12 +09:00
commit 5b1c4f85b6
296 changed files with 39925 additions and 0 deletions

10
channel/channelapp/.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
stub.bin
*.dol
*.elf
.*.swp
dist
build
i18n/merge
i18n/*.gen
*.map

230
channel/channelapp/Makefile Normal file
View File

@@ -0,0 +1,230 @@
#pngcrush -rem iTXt -rem tEXt -d out *.png
PREFIX = $(DEVKITPPC)/bin/powerpc-eabi-
CC = $(PREFIX)gcc
AS = $(PREFIX)as
OBJCOPY = $(PREFIX)objcopy
ELF2DOL =$(DEVKITPPC)/bin/elf2dol
GDB = $(PREFIX)gdb
BIN2S = $(DEVKITPPC)/bin/bin2s
TARGET_STUB = stub
TARGET_APP = channelapp
TARGET_CHAN = channelapp-channel
WIIPAX = ../../wiipax/client/wiipax
BASE_ADDR = 0x81330000
DIR_STUB = stub
DIR_SRC = source
DIR_DATA = data
DIR_DATA_CRYPT = $(DIR_DATA)/crypt
DIR_I18N = i18n
DIR_BUILD = build
DIR_BUILD_CHAN = $(DIR_BUILD)/channel
DIR_INCLUDES = $(DIR_BUILD) \
$(DEVKITPRO)/libogc/include \
$(DEVKITPRO)/3rd/include \
$(DEVKITPRO)/3rd/include/freetype2
DIR_LIBS = \
$(DEVKITPRO)/libogc/lib/wii \
$(DEVKITPRO)/3rd/lib
LIBS = fat wiiuse bte mxml png15 z ogc m db freetype
MACHDEP = -g -DGEKKO -mrvl -mcpu=750 -meabi -mhard-float
CFLAGS = $(MACHDEP) -Os -Wall -DBASE_ADDR=$(BASE_ADDR) $(DIR_INCLUDES:%=-I%)
# using -Os for the stub makes it dependent on libgcc
CFLAGS_STUB = $(MACHDEP) -O2 -Wall -DBASE_ADDR=$(BASE_ADDR) $(DIR_INCLUDES:%=-I%)
ASFLAGS = -D_LANGUAGE_ASSEMBLY -DHW_RVL
LDFLAGS_STUB = $(MACHDEP) -Wl,--section-start,.init=0x80001800 -nostartfiles -nodefaultlibs
LDFLAGS_APP = $(MACHDEP) -specs=newrvl.spec -Wl,--section-start,.init=$(BASE_ADDR) \
$(DIR_LIBS:%=-L%) $(LIBS:%=-l%) -Wl,-Map,channelapp.map
LDFLAGS_CHAN = $(MACHDEP) -specs=newrvl.spec -Wl,--section-start,.init=$(BASE_ADDR) -Wl,-e,_stub_start $(DIR_LIBS:%=-L%) $(LIBS:%=-l%) -Wl,-Map,channelapp_chan.map
FILES_STUB = $(wildcard $(DIR_STUB)/*.S) $(wildcard $(DIR_STUB)/*.c)
FILES_STUB_OBJx = $(FILES_STUB:$(DIR_STUB)/%.S=$(DIR_BUILD)/%.o)
FILES_STUB_OBJ = $(FILES_STUB_OBJx:$(DIR_STUB)/%.c=$(DIR_BUILD)/%.o)
BANNER_BIN = banner/banner.bin
BANNER_OBJ = $(DIR_BUILD)/banner_bin.o
FILES_TTF = $(wildcard $(DIR_DATA)/*.ttf)
FILES_TTF_OBJ = $(FILES_TTF:$(DIR_DATA)/%.ttf=$(DIR_BUILD)/%_ttf.o)
FILES_PNG = $(wildcard $(DIR_DATA)/*.png)
FILES_PNG_OBJ = $(FILES_PNG:$(DIR_DATA)/%.png=$(DIR_BUILD)/%_png.o)
POTPL = $(DIR_I18N)/template.pot
POTPL_MRG = $(DIR_I18N)/template.merge.pot
FILES_PO = $(wildcard $(DIR_I18N)/*.po)
FILES_PO_ENC = $(FILES_PO:$(DIR_I18N)/%.po=$(DIR_BUILD)/%.enc.po)
FILES_MO = $(FILES_PO_ENC:$(DIR_BUILD)/%.enc.po=$(DIR_BUILD)/%.mo)
FILES_MO_OBJ = $(FILES_MO:$(DIR_BUILD)/%.mo=$(DIR_BUILD)/%_mo.o)
ENCODING = utf-8
FILES_PO_MRG = $(FILES_PO:$(DIR_I18N)/%.po=$(DIR_I18N)/merge/%.po)
FILES_SRC = $(wildcard $(DIR_SRC)/*.c)
FILES_SRC_OBJ = $(FILES_SRC:$(DIR_SRC)/%.c=$(DIR_BUILD)/%.o) \
$(DIR_BUILD)/$(TARGET_STUB)_bin.o $(BANNER_OBJ) \
$(FILES_PNG_OBJ) $(FILES_MO_OBJ) $(FILES_TTF_OBJ)
FILES_CHAN = $(DIR_CHAN)/nandloader.S
FILES_CHAN_OBJ = $(DIR_BUILD)/nandloader.o $(FILES_SRC_OBJ)
.PHONY: all channel world clean upload gdb debug
all:
@[ -d $(DIR_BUILD) ] || mkdir $(DIR_BUILD)
@$(MAKE) --no-print-directory data
@$(MAKE) --no-print-directory $(TARGET_APP).elf
channel:
@$(MAKE) --no-print-directory all
@$(MAKE) --no-print-directory $(TARGET_CHAN).dol
world:
@$(MAKE) --no-print-directory all
@$(MAKE) --no-print-directory $(TARGET_CHAN).dol
data: $(BANNER_OBJ) $(FILES_PNG_OBJ) $(FILES_MO_OBJ) \
$(FILES_PNG_INT_OBJ) $(FILES_INT_OBJ) \
$(FILES_TTF_OBJ)
%.bin: %.elf
@echo $(@F)
@$(OBJCOPY) -O binary $< $@
%.dol: %.elf $(ELF2DOL)
@echo $(@F)
@$(ELF2DOL) $< $@
$(TARGET_STUB).elf: $(FILES_STUB_OBJ)
@echo $(@F)
@$(CC) $(FILES_STUB_OBJ) $(LDFLAGS_STUB) -o $@
$(TARGET_APP)_nopax.elf: $(FILES_SRC_OBJ) newrvl.ld
@echo $(@F)
@$(CC) $(FILES_SRC_OBJ) $(LDFLAGS_APP) -o $@
$(TARGET_APP).elf: $(TARGET_APP)_nopax.elf
@$(WIIPAX) -s devkitfail $< $@
$(TARGET_CHAN).elf: $(TARGET_APP)_nopax.elf
@echo $(@F)
@$(WIIPAX) -s dkfailchannel $< $@
$(DIR_BUILD)/$(TARGET_STUB)_bin.o: $(TARGET_STUB).bin
@echo $(@F)
@$(BIN2S) -a 32 $< | $(AS) -o $@
$(BANNER_BIN):
@$(MAKE) -C banner
$(BANNER_OBJ): $(BANNER_BIN)
@echo $(@F)
@$(BIN2S) -a 32 $< | $(AS) -o $@
@echo "extern const u8 $(<F:%.bin=%_bin)[];" > $(@:%.o=%.h)
@echo "extern const u8 $(<F:%.bin=%_bin)_end;" >> $(@:%.o=%.h)
@echo "extern const u32 $(<F:%.bin=%_bin)_size;" >> $(@:%.o=%.h)
$(DIR_BUILD)/%_png.o: $(DIR_DATA)/%.png
@echo $(@F)
@$(BIN2S) -a 32 $< | $(AS) -o $@
@echo "extern const u8 $(<F:%.png=%_png)[];" > $(@:%.o=%.h)
@echo "extern const u8 $(<F:%.png=%_png)_end;" >> $(@:%.o=%.h)
@echo "extern const u32 $(<F:%.png=%_png)_size;" >> $(@:%.o=%.h)
$(DIR_BUILD)/%_ttf.o: $(DIR_DATA)/%.ttf
@echo $(@F)
@$(BIN2S) -a 32 $< | $(AS) -o $@
@echo "extern const u8 $(<F:%.ttf=%_ttf)[];" > $(@:%.o=%.h)
@echo "extern const u8 $(<F:%.ttf=%_ttf)_end;" >> $(@:%.o=%.h)
@echo "extern const u32 $(<F:%.ttf=%_ttf)_size;" >> $(@:%.o=%.h)
$(DIR_BUILD)/%_mo.o: $(DIR_BUILD)/%.mo
@echo $(@F)
@$(BIN2S) -a 32 $< | $(AS) -o $@
@echo "extern const u8 $(<F:%.mo=%_mo)[];" > $(@:%.o=%.h)
@echo "extern const u8 $(<F:%.mo=%_mo)_end;" >> $(@:%.o=%.h)
@echo "extern const u32 $(<F:%.mo=%_mo)_size;" >> $(@:%.o=%.h)
$(DIR_BUILD)/%.o: $(DIR_INT)/%
@echo $(@F)
@$(BIN2S) -a 32 $< | $(AS) -o $@
@echo "extern const u8 $(subst .,_,$(<F))[];" > $(@:%.o=%.h)
@echo "extern const u8 $(subst .,_,$(<F))_end;" >> $(@:%.o=%.h)
@echo "extern const u32 $(subst .,_,$(<F))_size;" >> $(@:%.o=%.h)
$(DIR_BUILD)/%.mo: $(DIR_BUILD)/%.enc.po
@echo $(@F)
@msgfmt --no-hash -o $@ $<
$(DIR_BUILD)/%.enc.po: $(DIR_I18N)/%.po
@echo $(@F)
@msgconv -t $(ENCODING) -o $@ $<
$(DIR_BUILD)/%.o: $(DIR_STUB)/%.c
@echo $(@F)
@$(CC) $(CFLAGS_STUB) -MMD -MP -MF $(@:%.o=%.d) -c $< -o $@
$(DIR_BUILD)/%.o: $(DIR_STUB)/%.S
@echo $(@F)
@$(CC) $(ASFLAGS) -c $< -o $@
$(DIR_BUILD)/%.o: $(DIR_SRC)/%.c
@echo $(@F)
@$(CC) $(CFLAGS) -MMD -MP -MF $(@:%.o=%.d) -c $< -o $@
-include $(FILES_SRC_OBJ:%.o=%.d)
clean:
rm -rf $(DIR_BUILD) \
*.elf *.dol *.bin *.map i18n/merge/* $(POTPL).gen
@$(MAKE) -C banner clean
wiiload:
@$(MAKE) --no-print-directory all
@$(DEVKITPPC)/bin/wiiload $(TARGET_APP).elf
upload: wiiload
$(POTPL).gen: source/*.c
@echo "GETTEXT $(POTPL).gen"
@xgettext --from-code=UTF-8 -C -o $(POTPL).gen --keyword=_ source/*.c
@sed -i.bak s/CHARSET/UTF-8/g $(POTPL).gen
$(POTPL): $(POTPL).gen
@echo "MERGE $(POTPL_MRG)"
@msgmerge $(POTPL) $(POTPL).gen > $(POTPL_MRG)
@mv -v $(POTPL_MRG) $(POTPL)
@rm $(POTPL).gen.bak
genmsgs: $(POTPL)
msgmerge: $(POTPL) $(FILES_PO_MRG)
movemerge:
@mv -v i18n/merge/* i18n
msgupdate: msgmerge movemerge msgstats
%.postats: %.po
@echo -n "$<: "
@msgfmt --statistics -o /dev/null $<
msgstats: $(FILES_PO:%.po=%.postats)
msgmergestats: msgmerge $(FILES_PO_MRG:%.po=%.postats)
$(DIR_I18N)/merge/%.po : $(DIR_I18N)/%.po $(POTPL)
@[ ! -d $(DIR_I18N)/merge ] && mkdir -p $(DIR_I18N)/merge || true
@echo "MERGE $(@F)"
@msgmerge -o $@ $(@:$(DIR_I18N)/merge/%.po=$(DIR_I18N)/%.po) $(POTPL)
gdb:
$(GDB) -n $(TARGET_APP)_nopax.elf
debug:
$(GDB) -n $(TARGET_APP)_nopax.elf -x gdb.txt

3
channel/channelapp/banner/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
twintig
banner.bin

View File

@@ -0,0 +1,11 @@
all: banner.bin
banner.bin: twintig title banner.ppm icon.ppm
@$(CURDIR)/twintig
twintig: twintig.c
@gcc -g -O2 -Wall $< -o $@
clean:
rm -f twintig banner.bin

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -0,0 +1,103 @@
// Copyright 2007,2008 Segher Boessenkool <segher@kernel.crashing.org>
// Licensed under the terms of the GNU GPL, version 2
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define ERROR(s) do { fprintf(stderr, s "\n"); exit(1); } while (0)
// basic data types
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
void wbe16(u8 *p, u16 x) {
p[0] = x >> 8;
p[1] = x;
}
void wbe32(u8 *p, u32 x) {
wbe16(p, x >> 16);
wbe16(p + 2, x);
}
static int read_image(u8 *data, u32 w, u32 h, const char *name) {
FILE *fp;
u32 x, y;
u32 ww, hh;
fp = fopen(name, "rb");
if (!fp)
return -1;
if (fscanf(fp, "P6 %d %d 255\n", &ww, &hh) != 2)
ERROR("bad ppm");
if (ww != w || hh != h)
ERROR("wrong size ppm");
for (y = 0; y < h; y++)
for (x = 0; x < w; x++) {
u8 pix[3];
u16 raw;
u32 x0, x1, y0, y1, off;
x0 = x & 3;
x1 = x >> 2;
y0 = y & 3;
y1 = y >> 2;
off = x0 + 4 * y0 + 16 * x1 + 4 * w * y1;
if (fread(pix, 3, 1, fp) != 1)
ERROR("read");
raw = (pix[0] & 0xf8) << 7;
raw |= (pix[1] & 0xf8) << 2;
raw |= (pix[2] & 0xf8) >> 3;
raw |= 0x8000;
wbe16(data + 2*off, raw);
}
fclose(fp);
return 0;
}
int main(int argc, char **argv) {
FILE *in, *fp;
u8 header[0x72a0];
fp = fopen("banner.bin", "wb+");
if (!fp)
ERROR("open banner.bin");
memset(header, 0, sizeof header);
memcpy(header, "WIBN", 4);
header[9] = 2; // wtf
in = fopen("title", "rb");
if (!in)
ERROR("open title");
if (fread(header + 0x20, 0x80, 1, in) != 1)
ERROR("read title");
fclose(in);
if(read_image(header + 0xa0, 192, 64, "banner.ppm"))
ERROR("open banner.ppm");
if(read_image(header + 0x60a0, 48, 48, "icon.ppm"))
ERROR("open icon.ppm");
if (fwrite(header, 0x72a0, 1, fp) != 1)
ERROR("write header");
fclose(fp);
return 0;
}

143
channel/channelapp/config.h Normal file
View File

@@ -0,0 +1,143 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
#define CHANNEL_VERSION_DATE 201611230000llu
#define CHANNEL_VERSION_STR "1.1.3"
//#define DEBUG_APP
//#define DEBUG_STUB
#define ENABLE_WIDESCREEN
#define ENABLE_SCREENSHOTS
//#define ENABLE_UPDATES
//#define FORCE_LANG CONF_LANG_JAPANESE
#ifdef DEBUG_APP
void gprintf_enable(int enable);
int gprintf(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
void hexdump(const void *d, int len);
void memstats(int reset);
#define CHKBUFACC(access, ptr, len) \
do { \
if ((access < ptr) || (access >= ptr + len)) \
gprintf("WARNING: buffer access out of range: %s:%d\n", __FILE__, __LINE__); \
} while (0)
#else
#define gprintf(...)
#define hexdump(...)
#define memstats(...)
#define gprintf_enable(...)
#define CHKBUFACC(...)
#endif
#define UPDATE_URL "http://example.com/update.sxml"
#define UPDATE_PUBLIC_KEY \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
#define USBGECKO_CHANNEL 1
#define STUB_MAGIC 0x4c4f41444b544858ull
#define STUB_ADDR_MAGIC ((u64 *) 0x80002f00)
#define STUB_ADDR_TITLE ((u64 *) 0x80002f08)
#define BOOTMII_IOS 254
#define TITLEID_BOOTMII (0x0000000100000000LL | BOOTMII_IOS)
#define PREFERRED IOS_GetPreferredVersion()
#define UNCHANGED IOS_GetVersion()
#define MY_TITLEID 0x000100014f484243ull
#define STUB_LOAD_IOS_VERSION UNCHANGED
#define APPS_IOS_VERSION PREFERRED
#define VIEW_Z_ORIGIN -420
#define GFX_ORIGIN_STACK_SIZE 16
// peak bubbles
#define MAX_BUBBLE_COUNT 20
// minimum bubbles
#define MIN_BUBBLE_COUNT 4
// cycle time in minutes
#define BUBBLE_TIME_CYCLE (60*24)
// time (in minutes, inside cycle) of minimum bubbles
#define BUBBLE_MIN_TIME (60*4)
// time (in minutes) offset from BUBBLE_MIN_TIME of maximum bubbles
#define BUBBLE_MAX_OFFSET (60*12)
// bubble size
#define BUBBLE_SIZE_MIN 0.4
#define BUBBLE_SIZE_MAX 1.0
// bubble pop radius modifier
#define BUBBLE_POP_RADIUS 0.8
// bubble pop generates this many bubbles
#define BUBBLE_POP_MAX 10
#define BUBBLE_POP_MIN 5
// bubble pop sub-bubble size
#define BUBBLE_POP_SIZE_MIN 0.2
#define BUBBLE_POP_SIZE_MAX 0.4
// bubble pop spread out range
#define BUBBLE_POP_SPREAD_X 40
#define BUBBLE_POP_SPREAD_Y 30
#define IRAND(max) ((int) ((float) (max) * (rand () / (RAND_MAX + 1.0))))
#define FRAND(max) ((max) * (rand () / (RAND_MAX + 1.0)))
#define WIDGET_DISABLED_COLOR 0xFFFFFF54
#define DIALOG_MASK_COLOR 0x101010a0
#define TEX_LAYER_WIDGETS 2
#define TEX_LAYER_DIALOGS 30
#define TEX_LAYER_CURSOR 80
#define APP_ENTRY_ICON_X 8
#define APP_ENTRY_ICON_Y 8
#define GRID_APP_ENTRY_ICON_X 8
#define GRID_APP_ENTRY_ICON_Y 8
#define APP_ENTRY_ICON_WIDTH 128
#define APP_ENTRY_ICON_HEIGHT 48
#define APP_ENTRY_TEXT1_X 156
#define APP_ENTRY_TEXT1_Y 8
#define APP_ENTRY_TEXT2_X 156
#define APP_ENTRY_TEXT2_Y 54
#define MAX_ENTRIES 1024
#define TCP_CONNECT_TIMEOUT 5000
#define TCP_BLOCK_SIZE (16 * 1024)
#define TCP_BLOCK_RECV_TIMEOUT 10000
#define TCP_BLOCK_SEND_TIMEOUT 4000
#define WIILOAD_MIN_VERSION 0x0005
#define ARGS_MAX_LEN 1024
#define LD_TCP_PORT 4299
#define LD_THREAD_STACKSIZE (1024 * 8)
#define LD_THREAD_PRIO 48
#define LD_TIMEOUT 3000
#define LD_MIN_ADDR 0x80003400
#define LD_MAX_ADDR (BASE_ADDR - 1 - ARGS_MAX_LEN)
#define LD_MAX_SIZE (LD_MAX_ADDR - LD_MIN_ADDR)
#define LD_ARGS_ADDR (LD_MAX_ADDR + 1)
#define HTTP_THREAD_STACKSIZE (1024 * 8)
#define HTTP_THREAD_PRIO 48
#define HTTP_TIMEOUT 30000
#define MANAGE_THREAD_STACKSIZE (1024 * 16)
#define MANAGE_THREAD_PRIO 48
#define APPENTRY_THREAD_STACKSIZE (1024 * 16)
#define APPENTRY_THREAD_PRIO 62
#define UPDATE_THREAD_STACKSIZE (1024 * 8)
#define UPDATE_THREAD_PRIO 58
#define FORCE_INLINE __attribute__((always_inline))
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -0,0 +1,4 @@
target remote /dev/ttyUSB0
info threads
bt

View File

@@ -0,0 +1,257 @@
# translation of template.pot to Dutch
# Dutch translations for PACKAGE package.
# Copyright (C) 2008 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# blasty
msgid ""
msgstr ""
"Project-Id-Version: nederlands\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-22 21:29+0900\n"
"PO-Revision-Date: 2008-05-21 01:17+0200\n"
"Last-Translator: ChronoX\n"
"Language-Team: Dutch\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: KBabel 1.11.4\n"
#: source/dialogs.c:53
msgid "no description available"
msgstr "Geen omschrijving beschikbaar"
#: source/dialogs.c:55
msgid "Information"
msgstr "Informatie"
#: source/dialogs.c:56
msgid "Confirmation"
msgstr "Bevestiging"
#: source/dialogs.c:57
msgid "Warning"
msgstr "Waarschuwing"
#: source/dialogs.c:58
msgid "Error"
msgstr "Error"
#: source/dialogs.c:59
msgid "Ok"
msgstr "OK"
#: source/dialogs.c:60
msgid "Cancel"
msgstr "Annuleren"
#: source/dialogs.c:61
msgid "Yes"
msgstr "Ja"
#: source/dialogs.c:62
msgid "No"
msgstr "Nee"
#: source/dialogs.c:63
msgid "Delete"
msgstr "Verwijder"
#: source/dialogs.c:64
msgid "Load"
msgstr "Start"
#: source/dialogs.c:65 source/m_main.c:95
msgid "Back"
msgstr "Terug"
#: source/dialogs.c:66
msgid "Options"
msgstr "Opties"
#: source/dialogs.c:67
msgid "Device:"
msgstr "Apparaat:"
#: source/dialogs.c:68
msgid "Internal SD Slot"
msgstr "Intern SD Slot"
#: source/dialogs.c:69
msgid "USB device"
msgstr "USB apparaat"
#: source/dialogs.c:70
msgid "SDGecko Slot A"
msgstr "SDGecko Slot A"
#: source/dialogs.c:71
msgid "SDGecko Slot B"
msgstr "SDGecko Slot B"
#: source/dialogs.c:72
msgid "Sort applications by:"
msgstr "Sorteer applicaties op:"
#: source/dialogs.c:73
msgid "Name"
msgstr "Naam"
#: source/dialogs.c:74
msgid "Date"
msgstr "Datum"
#: source/dialogs.c:110
msgid "<YourLanguageHere> translation by <YourNickNameHere>"
msgstr "Nederlandse vertaling door bLAStY en ChronoX"
#: source/dialogs.c:115
msgid "Theme:"
msgstr "Thema:"
#: source/dialogs.c:125
#, c-format
msgid "Version: %s"
msgstr "Versie: %s"
#: source/dialogs.c:126
#, c-format
msgid "Author: %s"
msgstr "Auteur: %s"
#: source/loader.c:716
msgid "Error while reading the application from the SD card"
msgstr ""
"Er is een fout opgetreden tijdens het lezen van de applicatie van de SD kaart"
#: source/loader.c:717
msgid "Error while receiving the application"
msgstr "Er is een fout opgetreden tijdens het ontvangen van de applicatie"
#: source/loader.c:718
msgid "Error uncompressing the received data"
msgstr "Error tijdens het uitpakken van de ontvangen data"
#: source/loader.c:719
msgid "This is not a valid Wii application"
msgstr "Dit is geen geldige Wii applicatie"
#: source/loader.c:720
msgid "This is not a usable ZIP file"
msgstr "Dit is geen bruikbaar ZIP bestand"
#: source/loader.c:721
msgid "Not enough memory"
msgstr "Niet genoeg geheugen"
#: source/loader.c:763
#, c-format
msgid "Loading %s"
msgstr "Bezig met laden van %s"
#: source/loader.c:772
#, c-format
msgid "Receiving over USBGecko"
msgstr "Ontvangen via USBGecko"
#: source/loader.c:782
#, c-format
msgid "Receiving from %s"
msgstr "Laden via %s"
#: source/loader.c:968
#, c-format
msgid ""
"Extract the received ZIP file?\n"
"%s of free space are required."
msgstr ""
"Pak het ontvangen ZIP bestand uit?\n"
"%s aan vrije ruimte is vereist."
#: source/loader.c:969
#, c-format
msgid "WARNING: Files in '%s' will be overwritten"
msgstr "WAARSCHUWING: Bestanden in '%s' zullen worden overschreven"
#: source/loader.c:970
msgid "Error while extracting the ZIP file"
msgstr "Er is een fout opgetreden tijdens het uitpakken van de ZIP filee"
#: source/main.c:250
msgid "Do you really want to delete this application?"
msgstr "Wil je echt deze applicatie verwijderen?"
#: source/main.c:251
#, c-format
msgid "Error deleting '%s'"
msgstr "Kon '%s' niet verwijderen"
#: source/manage.c:518
msgid "Extracting"
msgstr "Uitpakken"
#: source/m_main.c:80
msgid "Network not initialized"
msgstr "Netwerk niet geïnitialiseerd"
#: source/m_main.c:81
#, c-format
msgid "Your Wii's IP is %u.%u.%u.%u"
msgstr "IP adres: %u.%u.%u.%u"
#: source/m_main.c:97
msgid "About"
msgstr "Info"
#: source/m_main.c:102
msgid "Launch BootMii"
msgstr "BootMii starten"
#: source/m_main.c:106
msgid "Exit to System Menu"
msgstr "Terug naar System Menu"
#: source/m_main.c:109
msgid "Shutdown"
msgstr "Afsluiten"
#: source/update.c:232
#, c-format
msgid ""
"An update to the Homebrew Channel (version %s, replacing the installed "
"version %s) is available for installation, do you want to update now?\n"
"\n"
"Release notes:\n"
"\n"
"%s"
msgstr ""
"Een update voor het Homebrew Kanaal (%s zal de huidige %s vervangen) is "
"beschikbaar, wil je nu updaten?\n"
"\n"
"Release notes:\n"
"\n"
"%s"
#: source/update.c:262
#, c-format
msgid "Downloading Update (%u kB)"
msgstr "Update wordt gedownload (%u kB)"
#: source/update.c:304
msgid "Download failed"
msgstr "Downloaden mislukt"
#: source/widgets.c:16
msgid "<no description>"
msgstr "<geen omschrijving>"
#~ msgid "Version: <unknown>"
#~ msgstr "Versie: <onbekend>"
#~ msgid "Coder: <unknown>"
#~ msgstr "Auteur: <onbekend>"
#~ msgid "Deleting"
#~ msgstr "Verijwderen"

View File

@@ -0,0 +1,261 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-22 21:29+0900\n"
"PO-Revision-Date: 2008-05-23 08:52+0100\n"
"Last-Translator: Bruno C. <Chandler>\n"
"Language-Team: LANGUAGE\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: source/dialogs.c:53
msgid "no description available"
msgstr "aucune description disponible"
# This and the following strings are dialog box "title bars"
#: source/dialogs.c:55
msgid "Information"
msgstr "Information"
#: source/dialogs.c:56
msgid "Confirmation"
msgstr "Confirmation"
#: source/dialogs.c:57
msgid "Warning"
msgstr "Avertissement"
#: source/dialogs.c:58
msgid "Error"
msgstr "Erreur"
# button text
#: source/dialogs.c:59
msgid "Ok"
msgstr "Ok"
# button text
#: source/dialogs.c:60
msgid "Cancel"
msgstr "Annuler"
# button text
#: source/dialogs.c:61
msgid "Yes"
msgstr "Oui"
# button text
#: source/dialogs.c:62
msgid "No"
msgstr "Non"
#: source/dialogs.c:63
msgid "Delete"
msgstr "Supprimer"
# button text
#: source/dialogs.c:64
msgid "Load"
msgstr "Charger"
# button text
#: source/dialogs.c:65 source/m_main.c:95
msgid "Back"
msgstr "Retour"
#: source/dialogs.c:66
msgid "Options"
msgstr "Options"
#: source/dialogs.c:67
msgid "Device:"
msgstr "Dispositif:"
#: source/dialogs.c:68
msgid "Internal SD Slot"
msgstr "Lecteur de carte SD"
#: source/dialogs.c:69
msgid "USB device"
msgstr "Dispositif USB"
#: source/dialogs.c:70
msgid "SDGecko Slot A"
msgstr "Lecteur SDGecko A"
#: source/dialogs.c:71
msgid "SDGecko Slot B"
msgstr "Lecteur SDGecko B"
#: source/dialogs.c:72
msgid "Sort applications by:"
msgstr "Trier les applications par:"
#: source/dialogs.c:73
msgid "Name"
msgstr "Nom"
#: source/dialogs.c:74
msgid "Date"
msgstr "Date"
#: source/dialogs.c:110
msgid "<YourLanguageHere> translation by <YourNickNameHere>"
msgstr "Traduction française par Chandler et Strangerke"
#: source/dialogs.c:115
msgid "Theme:"
msgstr "Thème:"
#: source/dialogs.c:125
#, c-format
msgid "Version: %s"
msgstr "Version : %s"
#: source/dialogs.c:126
#, c-format
msgid "Author: %s"
msgstr "Auteur : %s"
#: source/loader.c:716
msgid "Error while reading the application from the SD card"
msgstr "Erreur de lecture de l'application à partir de la carte SD"
#: source/loader.c:717
msgid "Error while receiving the application"
msgstr "Erreur lors de la réception de l'application"
#: source/loader.c:718
msgid "Error uncompressing the received data"
msgstr "Erreur de décompression des données reçues"
#: source/loader.c:719
msgid "This is not a valid Wii application"
msgstr "Application Wii non valide"
#: source/loader.c:720
msgid "This is not a usable ZIP file"
msgstr "Ce fichier ZIP est inutilisable"
#: source/loader.c:721
msgid "Not enough memory"
msgstr "Mémoire insuffisante"
#: source/loader.c:763
#, c-format
msgid "Loading %s"
msgstr "Chargement de %s"
#: source/loader.c:772
#, c-format
msgid "Receiving over USBGecko"
msgstr "Réception sur USBGecko"
#: source/loader.c:782
#, c-format
msgid "Receiving from %s"
msgstr "Réception à partir de %s"
#: source/loader.c:968
#, c-format
msgid ""
"Extract the received ZIP file?\n"
"%s of free space are required."
msgstr ""
"Decompression du fichier ZIP reçu?\n"
"Un espace libre de %s est nécessaire."
#: source/loader.c:969
#, c-format
msgid "WARNING: Files in '%s' will be overwritten"
msgstr "ATTENTION: Les fichiers dans '%s' seront écrasés"
#: source/loader.c:970
msgid "Error while extracting the ZIP file"
msgstr "Erreur de décompression du fichier ZIP"
#: source/main.c:250
msgid "Do you really want to delete this application?"
msgstr "Voulez-vous vraiment supprimer cette application?"
#: source/main.c:251
#, c-format
msgid "Error deleting '%s'"
msgstr "Errur lors de la suppression de '%s'"
#: source/manage.c:518
msgid "Extracting"
msgstr "Extraction en cours"
#: source/m_main.c:80
msgid "Network not initialized"
msgstr "Réseau non initialisé"
#: source/m_main.c:81
#, c-format
msgid "Your Wii's IP is %u.%u.%u.%u"
msgstr "L'IP de votre Wii est %u.%u.%u.%u"
# button text
#: source/m_main.c:97
msgid "About"
msgstr "À propos de"
#: source/m_main.c:102
msgid "Launch BootMii"
msgstr "Lancer BootMii"
#: source/m_main.c:106
msgid "Exit to System Menu"
msgstr "Retour au menu système"
#: source/m_main.c:109
msgid "Shutdown"
msgstr "Arrêt"
#: source/update.c:232
#, c-format
msgid ""
"An update to the Homebrew Channel (version %s, replacing the installed "
"version %s) is available for installation, do you want to update now?\n"
"\n"
"Release notes:\n"
"\n"
"%s"
msgstr ""
"Une mise à jour de la chaine Homebrew (version %s, remplaçant la version "
"installée %s) est disponible. Voulez-vous faire la mise à jour maintenant ?\n"
"\n"
"Notes de version :\n"
"\n"
"%s"
#: source/update.c:262
#, c-format
msgid "Downloading Update (%u kB)"
msgstr "Téléchargement... (%u Ko)"
#: source/update.c:304
msgid "Download failed"
msgstr "Échec du téléchargement"
#: source/widgets.c:16
msgid "<no description>"
msgstr "<aucune description>"
#~ msgid "Version: <unknown>"
#~ msgstr "Version : <inconnue>"
#~ msgid "Coder: <unknown>"
#~ msgstr "Auteur : <inconnu>"
#~ msgid "Deleting"
#~ msgstr "Suppression en cours"

View File

@@ -0,0 +1,256 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-22 21:29+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: NICKNAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: source/dialogs.c:53
msgid "no description available"
msgstr "keine Beschreibung"
#: source/dialogs.c:55
msgid "Information"
msgstr "Information"
#: source/dialogs.c:56
msgid "Confirmation"
msgstr "Bestätigen"
#: source/dialogs.c:57
msgid "Warning"
msgstr "Achtung"
#: source/dialogs.c:58
msgid "Error"
msgstr "Fehler"
#: source/dialogs.c:59
msgid "Ok"
msgstr "OK"
#: source/dialogs.c:60
msgid "Cancel"
msgstr "Abbrechen"
#: source/dialogs.c:61
msgid "Yes"
msgstr "Ja"
#: source/dialogs.c:62
msgid "No"
msgstr "Nein"
#: source/dialogs.c:63
msgid "Delete"
msgstr "Löschen"
# button text
#: source/dialogs.c:64
msgid "Load"
msgstr "Laden"
# button text
#: source/dialogs.c:65 source/m_main.c:95
msgid "Back"
msgstr "Zurück"
#: source/dialogs.c:66
msgid "Options"
msgstr "Einstellungen"
#: source/dialogs.c:67
msgid "Device:"
msgstr "Quelle:"
#: source/dialogs.c:68
msgid "Internal SD Slot"
msgstr "Interner SD Slot"
#: source/dialogs.c:69
msgid "USB device"
msgstr "USB-Laufwerk"
#: source/dialogs.c:70
msgid "SDGecko Slot A"
msgstr "SDGecko Slot A"
#: source/dialogs.c:71
msgid "SDGecko Slot B"
msgstr "SDGecko Slot B"
#: source/dialogs.c:72
msgid "Sort applications by:"
msgstr "Anwendungen sortieren nach:"
#: source/dialogs.c:73
msgid "Name"
msgstr "Name"
#: source/dialogs.c:74
msgid "Date"
msgstr "Datum"
#: source/dialogs.c:110
msgid "<YourLanguageHere> translation by <YourNickNameHere>"
msgstr "Deutsche Übersetzung: Elena Vectoradvenberg"
#: source/dialogs.c:115
msgid "Theme:"
msgstr "Thema:"
#: source/dialogs.c:125
#, c-format
msgid "Version: %s"
msgstr "Version: %s"
#: source/dialogs.c:126
#, c-format
msgid "Author: %s"
msgstr "Autor: %s"
#: source/loader.c:716
msgid "Error while reading the application from the SD card"
msgstr "Fehler beim Lesen der Anwendung von der SD-Karte"
#: source/loader.c:717
msgid "Error while receiving the application"
msgstr "Fehler beim Empfang der Anwendung"
#: source/loader.c:718
msgid "Error uncompressing the received data"
msgstr "Fehler beim Entpacken der empfangenen Daten"
#: source/loader.c:719
msgid "This is not a valid Wii application"
msgstr "Das ist keine gültige Wii-Anwendung"
#: source/loader.c:720
msgid "This is not a usable ZIP file"
msgstr "Dies ist keine gültige ZIP-Datei"
#: source/loader.c:721
msgid "Not enough memory"
msgstr "Nicht genug Speicher"
#: source/loader.c:763
#, c-format
msgid "Loading %s"
msgstr "Lade %s"
#: source/loader.c:772
#, c-format
msgid "Receiving over USBGecko"
msgstr "Empfange über USBGecko"
#: source/loader.c:782
#, c-format
msgid "Receiving from %s"
msgstr "Empfange von %s"
#: source/loader.c:968
#, c-format
msgid ""
"Extract the received ZIP file?\n"
"%s of free space are required."
msgstr ""
"Entpacken der empfangenen ZIP-Datei?\n"
"%s bytes freier Speicherplatz werden benötigt."
#: source/loader.c:969
#, c-format
msgid "WARNING: Files in '%s' will be overwritten"
msgstr "ACHTUNG: Dateien in '%s' werden überschrieben"
#: source/loader.c:970
msgid "Error while extracting the ZIP file"
msgstr "Fehler beim Empfang der Anwendung"
#: source/main.c:250
msgid "Do you really want to delete this application?"
msgstr "Soll die Anwendung wirklich gelöscht werden?"
#: source/main.c:251
#, c-format
msgid "Error deleting '%s'"
msgstr "Fehler beim Löschen von '%s'"
#: source/manage.c:518
msgid "Extracting"
msgstr "Entpacke"
#: source/m_main.c:80
msgid "Network not initialized"
msgstr "Netzwerk nicht initialisiert"
#: source/m_main.c:81
#, c-format
msgid "Your Wii's IP is %u.%u.%u.%u"
msgstr "Die IP deiner Wii ist %u.%u.%u.%u"
# button text
#: source/m_main.c:97
msgid "About"
msgstr "Info"
#: source/m_main.c:102
msgid "Launch BootMii"
msgstr "BootMii starten"
#: source/m_main.c:106
msgid "Exit to System Menu"
msgstr "Beenden, zum Systemmenü"
#: source/m_main.c:109
msgid "Shutdown"
msgstr "Herunterfahren"
#: source/update.c:232
#, c-format
msgid ""
"An update to the Homebrew Channel (version %s, replacing the installed "
"version %s) is available for installation, do you want to update now?\n"
"\n"
"Release notes:\n"
"\n"
"%s"
msgstr ""
"Ein Update für den Homebrew Channel ist verfügbar (Version %s, ersetzt die "
"aktuelle Version %s). Soll jetzt aktualisiert werden?\n"
"\n"
"Versionsinfo:\n"
"\n"
"%s"
#: source/update.c:262
#, c-format
msgid "Downloading Update (%u kB)"
msgstr "Lade Update (%u KB)"
#: source/update.c:304
msgid "Download failed"
msgstr "Download fehlgeschlagen"
#: source/widgets.c:16
msgid "<no description>"
msgstr "<keine Beschreibung>"
#~ msgid "Version: <unknown>"
#~ msgstr "Version: <unbekannt>"
#~ msgid "Coder: <unknown>"
#~ msgstr "Coder: <unbekannt>"
#~ msgid "Deleting"
#~ msgstr "Lösche"

View File

@@ -0,0 +1,267 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-22 21:29+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: NICKNAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: source/dialogs.c:53
msgid "no description available"
msgstr "nessuna descrizione disponibile"
# This and the following strings are dialog box "title bars"
#: source/dialogs.c:55
msgid "Information"
msgstr "Informazioni"
#: source/dialogs.c:56
msgid "Confirmation"
msgstr "Conferma"
#: source/dialogs.c:57
msgid "Warning"
msgstr "Avvertenza"
#: source/dialogs.c:58
msgid "Error"
msgstr "Errore"
# button text
#: source/dialogs.c:59
msgid "Ok"
msgstr "Ok"
# button text
#: source/dialogs.c:60
msgid "Cancel"
msgstr "Annulla"
# button text
#: source/dialogs.c:61
msgid "Yes"
msgstr "Sì"
# button text
#: source/dialogs.c:62
msgid "No"
msgstr "No"
#: source/dialogs.c:63
msgid "Delete"
msgstr "Elimina"
# button text
#: source/dialogs.c:64
msgid "Load"
msgstr "Carica"
# button text
#: source/dialogs.c:65 source/m_main.c:95
msgid "Back"
msgstr "Indietro"
#: source/dialogs.c:66
msgid "Options"
msgstr "Opzioni"
#: source/dialogs.c:67
msgid "Device:"
msgstr "Periferica:"
#: source/dialogs.c:68
msgid "Internal SD Slot"
msgstr "Slot SD Interno"
#: source/dialogs.c:69
msgid "USB device"
msgstr "Pendrive USB"
#: source/dialogs.c:70
msgid "SDGecko Slot A"
msgstr "SDGecko Slot A"
#: source/dialogs.c:71
msgid "SDGecko Slot B"
msgstr "SDGecko Slot B"
#: source/dialogs.c:72
msgid "Sort applications by:"
msgstr "Ordina applicazioni per:"
#: source/dialogs.c:73
msgid "Name"
msgstr "Nome"
#: source/dialogs.c:74
msgid "Date"
msgstr "Data"
#: source/dialogs.c:110
msgid "<YourLanguageHere> translation by <YourNickNameHere>"
msgstr ""
"Traduzione italiana di EnricoBr\n"
"Aggiornata da The Lemon Man"
#: source/dialogs.c:115
msgid "Theme:"
msgstr "Tema:"
#: source/dialogs.c:125
#, c-format
msgid "Version: %s"
msgstr "Versione: %s"
#: source/dialogs.c:126
#, c-format
msgid "Author: %s"
msgstr "Autore: %s"
#: source/loader.c:716
msgid "Error while reading the application from the SD card"
msgstr "Errore durante la lettura dell'applicazione dalla scheda SD"
#: source/loader.c:717
msgid "Error while receiving the application"
msgstr "Errore durante la ricezione dell'applicazione"
#: source/loader.c:718
msgid "Error uncompressing the received data"
msgstr "Errore durante la decompressione dei dati ricevuti"
#: source/loader.c:719
msgid "This is not a valid Wii application"
msgstr "Non è un'applicazione Wii valida"
#: source/loader.c:720
msgid "This is not a usable ZIP file"
msgstr "Questo non è un file ZIP utilizzabile"
#: source/loader.c:721
msgid "Not enough memory"
msgstr "Memoria insufficiente"
#: source/loader.c:763
#, c-format
msgid "Loading %s"
msgstr "Caricamento di %s"
#: source/loader.c:772
#, c-format
msgid "Receiving over USBGecko"
msgstr "Ricezione su USBGecko"
#: source/loader.c:782
#, c-format
msgid "Receiving from %s"
msgstr "Ricezione da %s"
#: source/loader.c:968
#, c-format
msgid ""
"Extract the received ZIP file?\n"
"%s of free space are required."
msgstr ""
"Estrarre il file ZIP ricevuto?\n"
"Sono richiesti %s di spazio libero."
#: source/loader.c:969
#, c-format
msgid "WARNING: Files in '%s' will be overwritten"
msgstr "ATTENZIONE: I file in '%s' verranno sovrascritti"
#: source/loader.c:970
msgid "Error while extracting the ZIP file"
msgstr "Errore durante l'estrazione del file ZIP"
#: source/main.c:250
msgid "Do you really want to delete this application?"
msgstr "Sei sicuro di voler cancellare questa domanda?"
#: source/main.c:251
#, c-format
msgid "Error deleting '%s'"
msgstr "Errore durante l' eliminazione di '%s'"
#: source/manage.c:518
msgid "Extracting"
msgstr "Estraendo"
#: source/m_main.c:80
msgid "Network not initialized"
msgstr "Rete non inizializzata"
#: source/m_main.c:81
#, c-format
msgid "Your Wii's IP is %u.%u.%u.%u"
msgstr "L'indirizzo IP del Wii è %u.%u.%u.%u"
# button text
#: source/m_main.c:97
msgid "About"
msgstr "Informazioni"
#: source/m_main.c:102
msgid "Launch BootMii"
msgstr "Lanciare BootMii"
#: source/m_main.c:106
msgid "Exit to System Menu"
msgstr "Ritorna al Menu di Sistema"
#: source/m_main.c:109
msgid "Shutdown"
msgstr "Spegni"
#: source/update.c:232
#, c-format
msgid ""
"An update to the Homebrew Channel (version %s, replacing the installed "
"version %s) is available for installation, do you want to update now?\n"
"\n"
"Release notes:\n"
"\n"
"%s"
msgstr ""
"È disponibile per l'installazione un aggiornamento di Homebrew Channel "
"(versione %s, in sostituzione della versione %s installata); vuoi eseguire "
"adesso l'aggiornamento?\n"
"\n"
"Note sulla versione:\n"
"\n"
"%s"
#: source/update.c:262
#, c-format
msgid "Downloading Update (%u kB)"
msgstr "Download (%u kB)"
#: source/update.c:304
msgid "Download failed"
msgstr "Download non riuscito"
#: source/widgets.c:16
msgid "<no description>"
msgstr "<nessuna descrizione>"
#~ msgid "Version: <unknown>"
#~ msgstr "Versione: <unknown>"
#~ msgid "Coder: <unknown>"
#~ msgstr "Sviluppatore: <unknown>"
#~ msgid "Deleting"
#~ msgstr "Eliminando"
#~ msgid "Do you really want to exit to the boring, boring System Menu?\n"
#~ msgstr "Confermi di voler uscire al noiosissimo menu di sistema?\n"

View File

@@ -0,0 +1,253 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: homebrew_channel\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-22 21:29+0900\n"
"PO-Revision-Date: 2011-01-10 05:53+0200\n"
"Last-Translator: Jan Ekstrom <jeebjp@gmail.com>\n"
"Language-Team: \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: source/dialogs.c:53
msgid "no description available"
msgstr "詳細情報はありません "
# This and the following strings are dialog box "title bars"
#: source/dialogs.c:55
msgid "Information"
msgstr "報告"
#: source/dialogs.c:56
msgid "Confirmation"
msgstr "確認"
#: source/dialogs.c:57
msgid "Warning"
msgstr "警告"
#: source/dialogs.c:58
msgid "Error"
msgstr "エラー"
# button text
#: source/dialogs.c:59
msgid "Ok"
msgstr "Ok"
# button text
#: source/dialogs.c:60
msgid "Cancel"
msgstr "キャンセル"
# button text
#: source/dialogs.c:61
msgid "Yes"
msgstr "はい"
# button text
#: source/dialogs.c:62
msgid "No"
msgstr "いいえ"
#: source/dialogs.c:63
msgid "Delete"
msgstr "削除"
# button text
#: source/dialogs.c:64
msgid "Load"
msgstr "起動"
# button text
#: source/dialogs.c:65 source/m_main.c:95
msgid "Back"
msgstr "戻る"
#: source/dialogs.c:66
msgid "Options"
msgstr "オプション"
#: source/dialogs.c:67
msgid "Device:"
msgstr "デバイス:"
#: source/dialogs.c:68
msgid "Internal SD Slot"
msgstr "内部SDスロット"
#: source/dialogs.c:69
msgid "USB device"
msgstr "USBデバイス"
#: source/dialogs.c:70
msgid "SDGecko Slot A"
msgstr "SDGeckoのスロットA"
#: source/dialogs.c:71
msgid "SDGecko Slot B"
msgstr "SDGeckoのスロットB"
#: source/dialogs.c:72
msgid "Sort applications by:"
msgstr "アプリケーションの並べ替え順序 "
#: source/dialogs.c:73
msgid "Name"
msgstr "名前"
#: source/dialogs.c:74
msgid "Date"
msgstr "日付"
#: source/dialogs.c:110
msgid "<YourLanguageHere> translation by <YourNickNameHere>"
msgstr "日本語、JEEB氏による翻訳"
#: source/dialogs.c:115
msgid "Theme:"
msgstr "テーマ:"
#: source/dialogs.c:125
#, c-format
msgid "Version: %s"
msgstr "バージョン: %s"
#: source/dialogs.c:126
#, c-format
msgid "Author: %s"
msgstr "作者: %s"
#: source/loader.c:716
msgid "Error while reading the application from the SD card"
msgstr "アプリケーションをSDカードから読み込んでいる最中エラーが発生しました。"
#: source/loader.c:717
msgid "Error while receiving the application"
msgstr "アプリケーションを受信している最中エラーが発生しました。"
#: source/loader.c:718
msgid "Error uncompressing the received data"
msgstr "受信されたデータを解凍中エラーが発生しました。"
#: source/loader.c:719
msgid "This is not a valid Wii application"
msgstr "これは妥当なWiiアプリケーションではありません。"
#: source/loader.c:720
msgid "This is not a usable ZIP file"
msgstr "これは妥当なZIPファイルではありません。"
#: source/loader.c:721
msgid "Not enough memory"
msgstr "メモリーが足りません。"
#: source/loader.c:763
#, c-format
msgid "Loading %s"
msgstr "%sをロード中。"
#: source/loader.c:772
#, c-format
msgid "Receiving over USBGecko"
msgstr "USBGecko経由で受信中。"
#: source/loader.c:782
#, c-format
msgid "Receiving from %s"
msgstr "%sから受信中。"
#: source/loader.c:968
#, c-format
msgid ""
"Extract the received ZIP file?\n"
"%s of free space are required."
msgstr ""
"受信されたZIPファイルを解凍しますか。\n"
"%sの空き領域が必要になります。"
#: source/loader.c:969
#, c-format
msgid "WARNING: Files in '%s' will be overwritten"
msgstr "警告: 「%s」の中のファイルはすべて上書きされます。"
#: source/loader.c:970
msgid "Error while extracting the ZIP file"
msgstr "ZIPファイルを解凍中エラーが発生しました。"
#: source/main.c:250
msgid "Do you really want to delete this application?"
msgstr "本当にこのアプリケーションを削除しますか。"
#: source/main.c:251
#, c-format
msgid "Error deleting '%s'"
msgstr "「%s」を削除中にエラーが発生しました。"
#: source/manage.c:518
msgid "Extracting"
msgstr "解凍中"
#: source/m_main.c:80
msgid "Network not initialized"
msgstr "ネットワークが初期化されていません。"
#: source/m_main.c:81
#, c-format
msgid "Your Wii's IP is %u.%u.%u.%u"
msgstr "このWiiのIPアドレスは %u.%u.%u.%u"
# button text
#: source/m_main.c:97
msgid "About"
msgstr "このアプリケーションについて"
#: source/m_main.c:102
msgid "Launch BootMii"
msgstr "BootMiiを起動"
#: source/m_main.c:106
msgid "Exit to System Menu"
msgstr "システムメニューへ戻る"
#: source/m_main.c:109
msgid "Shutdown"
msgstr "シャットダウン"
# note: a non-breaking space is used in "Homebrew Channel" here.
#: source/update.c:232
#, c-format
msgid ""
"An update to the Homebrew Channel (version %s, replacing the installed "
"version %s) is available for installation, do you want to update now?\n"
"\n"
"Release notes:\n"
"\n"
"%s"
msgstr ""
"Homebrew Channelに利用可能な更新があります。 (バージョン%s、現在のバージョ"
"ン%sを置換 今すぐ更新しますか。\n"
"\n"
"リリース ノート :\n"
"\n"
"%s"
#: source/update.c:262
#, c-format
msgid "Downloading Update (%u kB)"
msgstr "更新をダウンロード中 (%u kB)"
#: source/update.c:304
msgid "Download failed"
msgstr "ダウンロードが失敗しました。"
#: source/widgets.c:16
msgid "<no description>"
msgstr "<詳細情報はありません >"

View File

@@ -0,0 +1,258 @@
# translation of template.pot to Spanish
# Spanish translations for PACKAGE package.
# Copyright (C) 2008 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# marcan <marcan@marcansoft.com>, 2008.
msgid ""
msgstr ""
"Project-Id-Version: spanish\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-22 21:29+0900\n"
"PO-Revision-Date: 2008-05-21 01:17+0200\n"
"Last-Translator: marcan <marcan@marcansoft.com>\n"
"Language-Team: Spanish\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: KBabel 1.11.4\n"
#: source/dialogs.c:53
msgid "no description available"
msgstr "descripción no disponible"
#: source/dialogs.c:55
msgid "Information"
msgstr "Información"
#: source/dialogs.c:56
msgid "Confirmation"
msgstr "Confirmación"
#: source/dialogs.c:57
msgid "Warning"
msgstr "Advertencia"
#: source/dialogs.c:58
msgid "Error"
msgstr "Error"
#: source/dialogs.c:59
msgid "Ok"
msgstr "Aceptar"
#: source/dialogs.c:60
msgid "Cancel"
msgstr "Cancelar"
#: source/dialogs.c:61
msgid "Yes"
msgstr "Sí"
#: source/dialogs.c:62
msgid "No"
msgstr "No"
#: source/dialogs.c:63
msgid "Delete"
msgstr "Eliminar"
# button text
#: source/dialogs.c:64
msgid "Load"
msgstr "Cargar"
# button text
#: source/dialogs.c:65 source/m_main.c:95
msgid "Back"
msgstr "Atrás"
#: source/dialogs.c:66
msgid "Options"
msgstr "Opciones"
#: source/dialogs.c:67
msgid "Device:"
msgstr "Dispositivo:"
#: source/dialogs.c:68
msgid "Internal SD Slot"
msgstr "Ranura SD Interna"
#: source/dialogs.c:69
msgid "USB device"
msgstr "Dispositivo USB"
#: source/dialogs.c:70
msgid "SDGecko Slot A"
msgstr "SDGecko en Slot A"
#: source/dialogs.c:71
msgid "SDGecko Slot B"
msgstr "SDGecko en Slot B"
#: source/dialogs.c:72
msgid "Sort applications by:"
msgstr "Ordenar aplicaciones por:"
#: source/dialogs.c:73
msgid "Name"
msgstr "Nombre"
#: source/dialogs.c:74
msgid "Date"
msgstr "Fecha"
#: source/dialogs.c:110
msgid "<YourLanguageHere> translation by <YourNickNameHere>"
msgstr "Traducción al español - marcan"
#: source/dialogs.c:115
msgid "Theme:"
msgstr "Tema:"
#: source/dialogs.c:125
#, c-format
msgid "Version: %s"
msgstr "Versión: %s"
#: source/dialogs.c:126
#, c-format
msgid "Author: %s"
msgstr "Autor: %s"
#: source/loader.c:716
msgid "Error while reading the application from the SD card"
msgstr "Error al leer la aplicación desde la tarjeta SD"
#: source/loader.c:717
msgid "Error while receiving the application"
msgstr "Error al recibir la aplicación"
#: source/loader.c:718
msgid "Error uncompressing the received data"
msgstr "Error al descomprimir los datos recibidos"
#: source/loader.c:719
msgid "This is not a valid Wii application"
msgstr "Esta no es una aplicación de Wii válida"
#: source/loader.c:720
msgid "This is not a usable ZIP file"
msgstr "Este archivo ZIP no se puede utilizar"
#: source/loader.c:721
msgid "Not enough memory"
msgstr "Memoria insuficiente"
#: source/loader.c:763
#, c-format
msgid "Loading %s"
msgstr "Cargando %s"
#: source/loader.c:772
#, c-format
msgid "Receiving over USBGecko"
msgstr "Recibiendo por USBGecko"
#: source/loader.c:782
#, c-format
msgid "Receiving from %s"
msgstr "Recibiendo desde %s"
#: source/loader.c:968
#, c-format
msgid ""
"Extract the received ZIP file?\n"
"%s of free space are required."
msgstr ""
"¿Desea extraer el archivo ZIP recibido?\n"
"Se requiren %s de espacio libre."
#: source/loader.c:969
#, c-format
msgid "WARNING: Files in '%s' will be overwritten"
msgstr "AVISO: Se reemplazarán archivos en '%s'"
#: source/loader.c:970
msgid "Error while extracting the ZIP file"
msgstr "Error al extraer el archivo ZIP"
#: source/main.c:250
msgid "Do you really want to delete this application?"
msgstr "¿Estás seguro de que quieres eliminar esta aplicación?"
#: source/main.c:251
#, c-format
msgid "Error deleting '%s'"
msgstr "Error al eliminar '%s'"
#: source/manage.c:518
msgid "Extracting"
msgstr "Extrayendo"
#: source/m_main.c:80
msgid "Network not initialized"
msgstr "La red no se ha inicializado"
#: source/m_main.c:81
#, c-format
msgid "Your Wii's IP is %u.%u.%u.%u"
msgstr "La IP de tu Wii es %u.%u.%u.%u"
#: source/m_main.c:97
msgid "About"
msgstr "Acerca de"
#: source/m_main.c:102
msgid "Launch BootMii"
msgstr "Lanzar BootMii"
#: source/m_main.c:106
msgid "Exit to System Menu"
msgstr "Salir al menú del sistema"
#: source/m_main.c:109
msgid "Shutdown"
msgstr "Apagar"
#: source/update.c:232
#, c-format
msgid ""
"An update to the Homebrew Channel (version %s, replacing the installed "
"version %s) is available for installation, do you want to update now?\n"
"\n"
"Release notes:\n"
"\n"
"%s"
msgstr ""
"Está disponible la versión %s del Canal Homebrew, que sustituye a la versión "
"instalada (%s). ¿Quieres actualizar ahora?\n"
"\n"
"Notas sobre la versión:\n"
"\n"
"%s"
#: source/update.c:262
#, c-format
msgid "Downloading Update (%u kB)"
msgstr "Descargando (%u kB)"
#: source/update.c:304
msgid "Download failed"
msgstr "Error al descargar"
#: source/widgets.c:16
msgid "<no description>"
msgstr "<sin descripción>"
#~ msgid "Version: <unknown>"
#~ msgstr "Versión: <desconocida>"
#~ msgid "Coder: <unknown>"
#~ msgstr "Autor: <desconocido>"
#~ msgid "Deleting"
#~ msgstr "Eliminando"

View File

@@ -0,0 +1,244 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-22 21:29+0900\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: NICKNAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: source/dialogs.c:53
msgid "no description available"
msgstr ""
# This and the following strings are dialog box "title bars"
#: source/dialogs.c:55
msgid "Information"
msgstr ""
#: source/dialogs.c:56
msgid "Confirmation"
msgstr ""
#: source/dialogs.c:57
msgid "Warning"
msgstr ""
#: source/dialogs.c:58
msgid "Error"
msgstr ""
# button text
#: source/dialogs.c:59
msgid "Ok"
msgstr ""
# button text
#: source/dialogs.c:60
msgid "Cancel"
msgstr ""
# button text
#: source/dialogs.c:61
msgid "Yes"
msgstr ""
# button text
#: source/dialogs.c:62
msgid "No"
msgstr ""
#: source/dialogs.c:63
msgid "Delete"
msgstr ""
# button text
#: source/dialogs.c:64
msgid "Load"
msgstr ""
# button text
#: source/dialogs.c:65 source/m_main.c:95
msgid "Back"
msgstr ""
#: source/dialogs.c:66
msgid "Options"
msgstr ""
#: source/dialogs.c:67
msgid "Device:"
msgstr ""
#: source/dialogs.c:68
msgid "Internal SD Slot"
msgstr ""
#: source/dialogs.c:69
msgid "USB device"
msgstr ""
#: source/dialogs.c:70
msgid "SDGecko Slot A"
msgstr ""
#: source/dialogs.c:71
msgid "SDGecko Slot B"
msgstr ""
#: source/dialogs.c:72
msgid "Sort applications by:"
msgstr ""
#: source/dialogs.c:73
msgid "Name"
msgstr ""
#: source/dialogs.c:74
msgid "Date"
msgstr ""
#: source/dialogs.c:110
msgid "<YourLanguageHere> translation by <YourNickNameHere>"
msgstr ""
#: source/dialogs.c:115
msgid "Theme:"
msgstr ""
#: source/dialogs.c:125
#, c-format
msgid "Version: %s"
msgstr ""
#: source/dialogs.c:126
#, c-format
msgid "Author: %s"
msgstr ""
#: source/loader.c:716
msgid "Error while reading the application from the SD card"
msgstr ""
#: source/loader.c:717
msgid "Error while receiving the application"
msgstr ""
#: source/loader.c:718
msgid "Error uncompressing the received data"
msgstr ""
#: source/loader.c:719
msgid "This is not a valid Wii application"
msgstr ""
#: source/loader.c:720
msgid "This is not a usable ZIP file"
msgstr ""
#: source/loader.c:721
msgid "Not enough memory"
msgstr ""
#: source/loader.c:763
#, c-format
msgid "Loading %s"
msgstr ""
#: source/loader.c:772
#, c-format
msgid "Receiving over USBGecko"
msgstr ""
#: source/loader.c:782
#, c-format
msgid "Receiving from %s"
msgstr ""
#: source/loader.c:968
#, c-format
msgid ""
"Extract the received ZIP file?\n"
"%s of free space are required."
msgstr ""
#: source/loader.c:969
#, c-format
msgid "WARNING: Files in '%s' will be overwritten"
msgstr ""
#: source/loader.c:970
msgid "Error while extracting the ZIP file"
msgstr ""
#: source/main.c:250
msgid "Do you really want to delete this application?"
msgstr ""
#: source/main.c:251
#, c-format
msgid "Error deleting '%s'"
msgstr ""
#: source/manage.c:518
msgid "Extracting"
msgstr ""
#: source/m_main.c:80
msgid "Network not initialized"
msgstr ""
#: source/m_main.c:81
#, c-format
msgid "Your Wii's IP is %u.%u.%u.%u"
msgstr ""
# button text
#: source/m_main.c:97
msgid "About"
msgstr ""
#: source/m_main.c:102
msgid "Launch BootMii"
msgstr ""
#: source/m_main.c:106
msgid "Exit to System Menu"
msgstr ""
#: source/m_main.c:109
msgid "Shutdown"
msgstr ""
#: source/update.c:232
#, c-format
msgid ""
"An update to the Homebrew Channel (version %s, replacing the installed "
"version %s) is available for installation, do you want to update now?\n"
"\n"
"Release notes:\n"
"\n"
"%s"
msgstr ""
#: source/update.c:262
#, c-format
msgid "Downloading Update (%u kB)"
msgstr ""
#: source/update.c:304
msgid "Download failed"
msgstr ""
#: source/widgets.c:16
msgid "<no description>"
msgstr ""

View File

@@ -0,0 +1,306 @@
/*
* Linkscript for GC, automatically sets up DOL structures,
* generate ELF file and use objdump, or generate binary
* directly.
*
* PSUL doesn't seem to handle separate text and data sections correctly,
* that is why the text and data sections are merged in the header.
*
* If you want to experiment, it should be quite obvious how to
* change the header to list the data separately.
*/
OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc");
OUTPUT_ARCH(powerpc:common);
EXTERN(_start);
ENTRY(_start);
PHDRS
{
stub PT_LOAD FLAGS(5);
text PT_LOAD FLAGS(5);
data PT_LOAD FLAGS(6);
}
SECTIONS
{
/* stub is loaded at physical address 0x00003400 (though both 0x80003400 and 0x00003400 are equivalent for IOS) */
/* This can also be used to load an arbitrary standalone stub at an arbitrary address in memory, for any purpose */
/* Use -Wl,--section-start,.stub=0xADDRESS to change */
. = 0x00003400;
.stub :
{
KEEP(*(.stub))
} :stub = 0
/* default base address */
/* use -Wl,--section-start,.init=0xADDRESS to change */
. = 0x80004000;
/* Program */
.init :
{
KEEP (*crt0.o(*.init))
KEEP (*(.init))
} :text = 0
.plt : { *(.plt) }
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
.rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
.rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
.rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
.rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
.rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
.rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
.rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
.rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rela.got1 : { *(.rela.got1) }
.rela.got2 : { *(.rela.got2) }
.rel.sdata : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
.rela.sdata : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
.rel.sbss : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
.rela.sbss : { *(.rela.sbss .rela.sbss.* .rel.gnu.linkonce.sb.*) }
.rel.sdata2 : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
.rela.sdata2 : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
.rel.sbss2 : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
.rela.sbss2 : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
.rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.text :
{
*(.text)
*(.text.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t.*)
. = ALIGN(32); /* REQUIRED. LD is flaky without it. */
} = 0
.fini :
{
KEEP (*(.fini))
. = ALIGN(32); /* REQUIRED. LD is flaky without it. */
} = 0
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*) } :data
.rodata1 : {
*(.rodata1)
. = ALIGN(32);
} :data
.sdata2 : { *(.sdata2) *(.sdata2.*) *(.gnu.linkonce.s2.*) }
.sbss2 : { *(.sbss2) *(.sbss2.*) *(.gnu.linkonce.sb2.*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
the linker would then create the section even if it turns out to
be empty, which isn't pretty. */
. = ALIGN(32 / 8);
PROVIDE (__preinit_array_start = .);
.preinit_array : { *(.preinit_array) }
PROVIDE (__preinit_array_end = .);
PROVIDE (__init_array_start = .);
.init_array : { *(.init_array) }
PROVIDE (__init_array_end = .);
PROVIDE (__fini_array_start = .);
.fini_array : { *(.fini_array) }
PROVIDE (__fini_array_end = .);
.data :
{
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
. = ALIGN(32); /* REQUIRED. LD is flaky without it. */
}
.data1 : { *(.data1) }
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.eh_frame : { KEEP (*(.eh_frame)) }
.gcc_except_table : { *(.gcc_except_table) }
.fixup : { *(.fixup) }
.got1 : { *(.got1) }
.got2 : { *(.got2) }
.dynamic : { *(.dynamic) }
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
/* We don't want to include the .ctor section from
from the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
. = ALIGN(32); /* REQUIRED. LD is flaky without it. */
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
. = ALIGN(32); /* REQUIRED. LD is flaky without it. */
}
.jcr : { KEEP (*(.jcr)) }
.got : { *(.got.plt) *(.got) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata :
{
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(32); /* REQUIRED. LD is flaky without it. */
}
_edata = .;
PROVIDE (edata = .);
.sbss :
{
__sbss_start = .;
PROVIDE (__sbss_start = .);
PROVIDE (___sbss_start = .);
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
PROVIDE (__sbss_end = .);
PROVIDE (___sbss_end = .);
. = ALIGN(32); /* REQUIRED. LD is flaky without it. */
__sbss_end = .;
}
.bss :
{
__bss_start = .;
PROVIDE (__bss_start = .);
*(.dynbss)
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections. */
. = ALIGN(32);
PROVIDE (__bss_end = .);
__bss_end = .;
}
_end = .;
PROVIDE(end = .);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* These must appear regardless of . */
}
__isIPL = 0;
__stack_addr = (__bss_start + SIZEOF(.bss) + 0x20000 + 7) & (-8);
__stack_end = (__bss_start + SIZEOF(.bss));
__intrstack_addr = (__stack_addr + 0x4000);
__intrstack_end = (__stack_addr);
__Arena1Lo = (__intrstack_addr + 31) & (-32);
__Arena1Hi = (0x817FEFF0);
__Arena2Lo = (0x90002000);
__Arena2Hi = (0x933E0000);
__gxregs = (__Arena1Hi + 31) & (-32);
__ipcbufferLo = (0x933e0000);
__ipcbufferHi = (0x93400000);
/* for backward compatibility with old crt0 */
PROVIDE (__stack = (0x817FEFF0));
PROVIDE(__isIPL = __isIPL);
PROVIDE(__stack_addr = __stack_addr);
PROVIDE(__stack_end = __stack_end);
PROVIDE(__intrstack_addr = __intrstack_addr);
PROVIDE(__intrstack_end = __intrstack_end);
PROVIDE(__Arena1Lo = __Arena1Lo);
PROVIDE(__Arena1Hi = __Arena1Hi);
PROVIDE(__Arena2Lo = __Arena2Lo);
PROVIDE(__Arena2Hi = __Arena2Hi);
PROVIDE(__ipcbufferLo = __ipcbufferLo);
PROVIDE(__ipcbufferHi = __ipcbufferHi);
PROVIDE(__gxregs = __gxregs);

View File

@@ -0,0 +1,2 @@
*link_start_rvl:
-T newrvl.ld%s

View File

@@ -0,0 +1,713 @@
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/dir.h>
#include <ogcsys.h>
#include <ogc/cond.h>
#include <sdcard/gcsd.h>
#include <sdcard/wiisd_io.h>
#include <ogc/usbstorage.h>
#include <fat.h>
#include "../config.h"
#include "tex.h"
#include "panic.h"
#include "appentry.h"
typedef struct {
const char *name;
const DISC_INTERFACE *device;
bool last_status;
} device_t;
static app_entry *entries_all[MAX_ENTRIES];
static u32 entry_count_all = 0;
app_entry *entries[MAX_ENTRIES];
u32 entry_count = 0;
const char *app_path = "/apps";
const char *app_fn_boot_elf = "boot.elf";
const char *app_fn_boot_dol = "boot.dol";
const char *app_fn_theme = "theme.zip";
const char *app_fn_meta = "meta.xml";
const char *app_fn_icon = "icon.png";
static device_t devices[DEVICE_COUNT] = {
{ "sd", &__io_wiisd, false },
{ "usb", &__io_usbstorage, false },
{ "carda", &__io_gcsda, false },
{ "cardb", &__io_gcsdb, false }
};
static int device_active = -1;
static int device_prefered = -1;
static app_filter current_filter = APP_FILTER_ALL;
static app_sort current_sort = APP_SORT_NAME;
static bool cmp_descending = false;
static bool cmp_release_date = false;
static int cmp_app_entry (const void *p1, const void *p2) {
const app_entry *a1;
const app_entry *a2;
if (cmp_descending) {
a1 = *((const app_entry **) p2);
a2 = *((const app_entry **) p1);
} else {
a1 = *((const app_entry **) p1);
a2 = *((const app_entry **) p2);
}
if (!a1->meta && !a2->meta)
return stricmp (a1->dirname, a2->dirname);
if (!a1->meta && a2->meta)
return 1;
if (a1->meta && !a2->meta)
return -1;
if (cmp_release_date) {
if (!a1->meta->release_date && !a2->meta->release_date)
return 0;
if (!a1->meta->release_date && a2->meta->release_date)
return -1;
if (a1->meta->release_date && !a2->meta->release_date)
return 1;
if (a1->meta->release_date > a2->meta->release_date)
return 1;
return -1;
}
if (!a1->meta->name && !a2->meta->name)
return stricmp (a1->dirname, a2->dirname);
if (!a1->meta->name && a2->meta->name)
return 1;
if (a1->meta->name && !a2->meta->name)
return -1;
return stricmp (a1->meta->name, a2->meta->name);
}
static void app_entry_filter(app_filter filter) {
u32 i;
for (i = 0; i < MAX_ENTRIES; ++i)
entries[i] = NULL;
entry_count = 0;
for (i = 0; i < MAX_ENTRIES; ++i) {
if (!entries_all[i])
continue;
switch (filter) {
case APP_FILTER_ICONSONLY:
if (!entries_all[i]->icon)
continue;
break;
case APP_FILTER_DATEONLY:
if (!entries_all[i]->meta) //|| !entries_all[i]->meta->release_date)
continue;
break;
default:
break;
}
entries[entry_count] = entries_all[i];
entry_count++;
}
current_filter = filter;
if (entry_count)
qsort(entries, entry_count, sizeof(app_entry *), cmp_app_entry);
}
app_sort app_entry_get_sort(void) {
return current_sort;
}
void app_entry_set_sort(app_sort sort) {
switch (sort) {
case APP_SORT_DATE:
cmp_descending = true;
cmp_release_date = true;
current_filter = APP_FILTER_DATEONLY;
current_sort = APP_SORT_DATE;
break;
default:
cmp_descending = false;
cmp_release_date = false;
current_filter = APP_FILTER_ALL;
current_sort = APP_SORT_NAME;
break;
}
if (settings.sort_order != current_sort)
settings.sort_order = current_sort;
}
static app_entry *app_entry_load_single (const char *dirname) {
app_entry *entry;
app_entry_type type;
char tmp[MAXPATHLEN + 32];
struct stat st;
type = AET_BOOT_ELF;
sprintf(tmp, "%s/%s/%s", app_path, dirname, app_fn_boot_elf);
if (stat(tmp, &st)) {
type = AET_BOOT_DOL;
sprintf(tmp, "%s/%s/%s", app_path, dirname, app_fn_boot_dol);
if (stat(tmp, &st)) {
type = AET_THEME;
sprintf(tmp, "%s/%s/%s", app_path, dirname, app_fn_theme);
if (stat(tmp, &st))
return NULL;
if (st.st_size > MAX_THEME_ZIP_SIZE)
return NULL;
}
}
if (!st.st_size || st.st_size > LD_MAX_SIZE)
return NULL;
entry = (app_entry *) pmalloc(sizeof(app_entry));
entry->type = type;
entry->size = st.st_size;
entry->dirname = pstrdup(dirname);
entry->icon = NULL;
entry->meta = NULL;
sprintf(tmp, "%s/%s/%s", app_path, dirname, app_fn_meta);
if (stat(tmp, &st) == 0)
entry->meta = meta_parse(tmp);
sprintf(tmp, "%s/%s/%s", app_path, dirname, app_fn_icon);
if (stat(tmp, &st) == 0)
entry->icon = tex_from_png_file(tmp, &st, APP_ENTRY_ICON_WIDTH,
APP_ENTRY_ICON_HEIGHT);
return entry;
}
void app_entries_free(void) {
u32 i;
for (i = 0; i < MAX_ENTRIES; ++i) {
entries[i] = NULL;
if (!entries_all[i])
continue;
free (entries_all[i]->dirname);
tex_free (entries_all[i]->icon);
meta_free (entries_all[i]->meta);
free(entries_all[i]);
entries_all[i] = NULL;
}
entry_count_all = 0;
entry_count = 0;
}
static void app_entry_load_all (void) {
app_entry *entry;
DIR *d;
struct dirent *de;
app_entries_free ();
d = opendir(app_path);
if (!d)
return;
while ((de = readdir(d))) {
// ignore dotfiles / dotdirs
if (de->d_name[0] == '\0' || de->d_name[0] == '.')
continue;
// All apps have their own dir
if (de->d_type != DT_DIR)
continue;
entry = app_entry_load_single(de->d_name);
if (!entry)
continue;
entries_all[entry_count_all] = entry;
entry_count_all++;
if (entry_count_all >= MAX_ENTRIES)
break;
}
closedir(d);
app_entry_filter(current_filter);
}
bool app_entry_remove(app_entry *app) {
u32 i;
bool res = false;
for (i = 0; i < MAX_ENTRIES; ++i)
if (entries_all[i] == app) {
free(entries_all[i]->dirname);
tex_free(entries_all[i]->icon);
meta_free(entries_all[i]->meta);
free(entries_all[i]);
entries_all[i] = NULL;
entry_count_all--;
res = true;
break;
}
if (res)
app_entry_filter(current_filter);
return res;
}
app_entry *app_entry_add(const char *dirname) {
app_entry *entry = NULL;
u32 i;
bool filter = false;
gprintf("adding entry '%s'\n", dirname);
for (i = 0; i < MAX_ENTRIES; ++i) {
if (entries_all[i]) {
if (!strcasecmp(entries_all[i]->dirname, dirname)) {
gprintf("removing old entry '%s'\n", entries_all[i]->dirname);
free(entries_all[i]->dirname);
tex_free(entries_all[i]->icon);
meta_free(entries_all[i]->meta);
free(entries_all[i]);
entries_all[i] = NULL;
entry_count_all--;
filter = true;
break;
}
}
}
if (entry_count_all >= MAX_ENTRIES)
goto exit;
entry = app_entry_load_single(dirname);
if (!entry)
goto exit;
for (i = 0; i < MAX_ENTRIES; ++i)
if (!entries_all[i]) {
entries_all[i] = entry;
entry_count_all++;
filter = true;
break;
}
exit:
if (filter)
app_entry_filter(current_filter);
return entry;
}
static bool _mount(int index) {
devices[index].last_status = fatMountSimple(devices[index].name,
devices[index].device);
if (!devices[index].last_status) {
devices[index].device->shutdown();
return false;
}
return true;
}
typedef enum {
AE_CMD_IDLE = 0,
AE_CMD_EXIT,
AE_CMD_SCAN,
AE_CMD_POLLSTATUS
} ae_cmd;
typedef struct {
bool running;
ae_cmd cmd;
ae_action action;
bool status[DEVICE_COUNT];
bool umount;
int mount;
bool loading;
mutex_t cmutex;
cond_t cond;
} ae_args;
static lwp_t ae_thread;
static u8 ae_stack[APPENTRY_THREAD_STACKSIZE] ATTRIBUTE_ALIGN (32);
static ae_args ta_ae;
static void *ae_func (void *arg) {
ae_args *ta = (ae_args *) arg;
int i;
char cwd[16];
ta->running = true;
for (i = 0; i < DEVICE_COUNT; ++i)
ta_ae.status[i] = false;
LWP_MutexLock (ta->cmutex);
while (true) {
ta->cmd = AE_CMD_IDLE;
LWP_CondWait(ta->cond, ta->cmutex);
if (ta->cmd == AE_CMD_EXIT)
break;
switch (ta->cmd) {
case AE_CMD_SCAN:
if (device_active >= 0) {
if (!ta->umount && devices[device_active].device->isInserted())
continue;
gprintf("device lost: %s\n", devices[device_active].name);
ta->umount = false;
fatUnmount(devices[device_active].name);
devices[device_active].device->shutdown();
devices[device_active].last_status = false;
device_active = -1;
ta->action = AE_ACT_REMOVE;
continue;
}
if (ta->mount >= 0) {
if (_mount(ta->mount))
device_active = ta->mount;
ta->mount = -1;
}
if ((device_active < 0) && (device_prefered >= 0)) {
if (_mount(device_prefered))
device_active = device_prefered;
}
if (device_active < 0) {
for (i = 0; i < DEVICE_COUNT; ++i)
if (_mount(i)) {
device_active = i;
break;
}
}
if (device_active >= 0) {
gprintf("device mounted: %s\n", devices[device_active].name);
ta->loading = true;
strcpy(cwd, devices[device_active].name);
strcat(cwd, ":/");
gprintf("chdir to '%s'\n", cwd);
if (chdir(cwd))
gprintf("chdir failed: %d\n", errno);
app_entry_load_all();
ta->loading = false;
ta->action = AE_ACT_ADD;
}
continue;
case AE_CMD_POLLSTATUS:
for (i = 0; i < DEVICE_COUNT; ++i) {
if (i == device_active) {
ta->status[i] = devices[i].last_status =
devices[i].device->isInserted();
if (!ta->umount && !devices[i].last_status)
ta->umount = true;
continue;
}
if (devices[i].last_status) {
if (!devices[i].device->isInserted()) {
ta->status[i] = devices[i].last_status = false;
devices[i].device->shutdown();
}
continue;
}
if (!devices[i].device->startup()) {
ta->status[i] = devices[i].last_status = false;
continue;
}
ta->status[i] = devices[i].last_status =
devices[i].device->isInserted();
if (!devices[i].last_status)
devices[i].device->shutdown();
}
continue;
default:
break;
}
}
LWP_MutexUnlock (ta->cmutex);
gprintf("app entry thread done\n");
ta->running = false;
return NULL;
}
void app_entry_init(void) {
s32 res;
memset(&entries_all, 0, sizeof(app_entry *) * MAX_ENTRIES);
memset(&entries, 0, sizeof(app_entry *) * MAX_ENTRIES);
gprintf("starting app entry thread\n");
ta_ae.cmd = AE_CMD_IDLE;
ta_ae.action = AE_ACT_NONE;
ta_ae.umount = false;
ta_ae.mount = -1;
ta_ae.loading = false;
res = LWP_MutexInit (&ta_ae.cmutex, false);
if (res) {
gprintf ("error creating cmutex: %ld\n", res);
return;
}
res = LWP_CondInit (&ta_ae.cond);
if (res) {
gprintf ("error creating cond: %ld\n", res);
return;
}
memset(&ae_stack, 0, APPENTRY_THREAD_STACKSIZE);
res = LWP_CreateThread(&ae_thread, ae_func, &ta_ae, ae_stack,
APPENTRY_THREAD_STACKSIZE, APPENTRY_THREAD_PRIO);
if (res) {
gprintf("error creating thread: %ld\n", res);
}
}
void app_entry_deinit (void) {
u8 i;
if (ta_ae.running) {
gprintf ("stopping app entry thread\n");
for (i = 0; i < 25; ++i) {
if (LWP_MutexTryLock (ta_ae.cmutex) == 0) {
break;
}
usleep (20 * 1000);
}
if (i < 25) {
gprintf ("sending app entry thread the exit cmd\n");
ta_ae.cmd = AE_CMD_EXIT;
LWP_SetThreadPriority (ae_thread, LWP_PRIO_HIGHEST);
LWP_CondBroadcast (ta_ae.cond);
LWP_MutexUnlock (ta_ae.cmutex);
LWP_JoinThread(ae_thread, NULL);
LWP_CondDestroy (ta_ae.cond);
LWP_MutexDestroy (ta_ae.cmutex);
app_entries_free ();
} else {
gprintf("app entry thread didn't shutdown gracefully!\n");
}
if (device_active >= 0) {
fatUnmount(devices[device_active].name);
devices[device_active].device->shutdown();
}
USB_Deinitialize();
}
}
void app_entry_scan(void) {
if (!ta_ae.running)
return;
if (LWP_MutexTryLock(ta_ae.cmutex) != 0)
return;
ta_ae.cmd = AE_CMD_SCAN;
LWP_CondBroadcast(ta_ae.cond);
LWP_MutexUnlock(ta_ae.cmutex);
}
ae_action app_entry_action(void) {
ae_action res;
if (!ta_ae.running)
return AE_ACT_NONE;
if (LWP_MutexTryLock(ta_ae.cmutex) != 0)
return AE_ACT_NONE;
res = ta_ae.action;
ta_ae.action = AE_ACT_NONE;
LWP_MutexUnlock(ta_ae.cmutex);
return res;
}
void app_entry_poll_status(bool reset) {
if (!ta_ae.running)
return;
if (LWP_MutexTryLock(ta_ae.cmutex) != 0)
return;
ta_ae.cmd = AE_CMD_POLLSTATUS;
LWP_CondBroadcast(ta_ae.cond);
LWP_MutexUnlock(ta_ae.cmutex);
}
int app_entry_get_status(bool *status) {
u8 i;
if (status)
for (i = 0; i < DEVICE_COUNT; ++i)
status[i] = ta_ae.status[i];
return device_active;
}
void app_entry_set_prefered(int device) {
if (device < 0) {
device_prefered = -1;
return;
}
if (device > DEVICE_COUNT - 1) {
device_prefered = -1;
return;
}
device_prefered = device;
if (settings.device != device_prefered)
settings.device = device_prefered;
}
void app_entry_set_device(int device) {
if (device < 0)
return;
if (device > DEVICE_COUNT - 1)
return;
ta_ae.umount = true;
ta_ae.mount = device;
}
bool app_entry_get_path(char *buf) {
if (device_active < 0)
return false;
strcpy(buf, devices[device_active].name);
return true;
}
bool app_entry_get_filename(char *buf, app_entry *app) {
if (device_active < 0)
return false;
sprintf(buf, "%s:%s/%s/", devices[device_active].name,
app_path, app->dirname);
switch(app->type) {
case AET_BOOT_ELF:
strcat(buf, app_fn_boot_elf);
return true;
case AET_BOOT_DOL:
strcat(buf, app_fn_boot_dol);
return true;
case AET_THEME:
strcat(buf, app_fn_theme);
return true;
}
return false;
}
app_entry *app_entry_find(char *dirname) {
u32 i;
for (i = 0; i < entry_count; ++i)
if (!strcasecmp(entries[i]->dirname, dirname))
return entries[i];
return NULL;
}
bool app_entry_is_loading(void) {
if (!ta_ae.running)
return false;
return ta_ae.loading;
}

View File

@@ -0,0 +1,80 @@
#ifndef _APPENTRY_H_
#define _APPENTRY_H_
#include <gctypes.h>
#include "gfx.h"
#include "xml.h"
#define DEVICE_COUNT 4
#define MAX_THEME_ZIP_SIZE (20 * 1024 * 1024)
typedef enum {
AET_BOOT_ELF = 0,
AET_BOOT_DOL,
AET_THEME
} app_entry_type;
typedef struct {
app_entry_type type;
u32 size;
char *dirname;
gfx_entity *icon;
meta_info *meta;
} app_entry;
typedef enum {
AE_ACT_NONE = 0,
AE_ACT_REMOVE,
AE_ACT_ADD
} ae_action;
typedef enum {
APP_FILTER_ALL = 0,
APP_FILTER_ICONSONLY,
APP_FILTER_DATEONLY
} app_filter;
typedef enum {
APP_SORT_NAME = 0,
APP_SORT_DATE
} app_sort;
extern const char *app_path;
extern const char *app_fn_boot_elf;
extern const char *app_fn_boot_dol;
extern const char *app_fn_theme;
extern const char *app_fn_meta;
extern const char *app_fn_icon;
extern app_entry *entries[MAX_ENTRIES];
extern u32 entry_count;
void app_entry_init (void);
void app_entry_deinit (void);
void app_entries_free(void);
void app_entry_scan(void);
ae_action app_entry_action(void);
void app_entry_poll_status(bool reset);
int app_entry_get_status(bool *status);
void app_entry_set_prefered(int device);
void app_entry_set_device(int device);
bool app_entry_get_path(char *buf);
bool app_entry_get_filename(char *buf, app_entry *app);
app_entry *app_entry_find(char *dirname);
app_sort app_entry_get_sort(void);
void app_entry_set_sort(app_sort sort);
app_entry *app_entry_add(const char *dirname);
bool app_entry_remove(app_entry *app);
bool app_entry_is_loading(void);
#endif

View File

@@ -0,0 +1,340 @@
// this file was taken from libogc, see http://www.devkitpro.org/
#ifndef __ASM_H__
#define __ASM_H__
#ifdef _LANGUAGE_ASSEMBLY
/* Condition Register Bit Fields */
#define cr0 0
#define cr1 1
#define cr2 2
#define cr3 3
#define cr4 4
#define cr5 5
#define cr6 6
#define cr7 7
/* General Purpose Registers (GPRs) */
#define r0 0
#define r1 1
#define sp 1
#define r2 2
#define toc 2
#define r3 3
#define r4 4
#define r5 5
#define r6 6
#define r7 7
#define r8 8
#define r9 9
#define r10 10
#define r11 11
#define r12 12
#define r13 13
#define r14 14
#define r15 15
#define r16 16
#define r17 17
#define r18 18
#define r19 19
#define r20 20
#define r21 21
#define r22 22
#define r23 23
#define r24 24
#define r25 25
#define r26 26
#define r27 27
#define r28 28
#define r29 29
#define r30 30
#define r31 31
/* Floating Point Registers (FPRs) */
#define fr0 0
#define fr1 1
#define fr2 2
#define fr3 3
#define fr4 4
#define fr5 5
#define fr6 6
#define fr7 7
#define fr8 8
#define fr9 9
#define fr10 10
#define fr11 11
#define fr12 12
#define fr13 13
#define fr14 14
#define fr15 15
#define fr16 16
#define fr17 17
#define fr18 18
#define fr19 19
#define fr20 20
#define fr21 21
#define fr22 22
#define fr23 23
#define fr24 24
#define fr25 25
#define fr26 26
#define fr27 27
#define fr28 28
#define fr29 29
#define fr30 30
#define fr31 31
#define vr0 0
#define vr1 1
#define vr2 2
#define vr3 3
#define vr4 4
#define vr5 5
#define vr6 6
#define vr7 7
#define vr8 8
#define vr9 9
#define vr10 10
#define vr11 11
#define vr12 12
#define vr13 13
#define vr14 14
#define vr15 15
#define vr16 16
#define vr17 17
#define vr18 18
#define vr19 19
#define vr20 20
#define vr21 21
#define vr22 22
#define vr23 23
#define vr24 24
#define vr25 25
#define vr26 26
#define vr27 27
#define vr28 28
#define vr29 29
#define vr30 30
#define vr31 31
#endif //_LANGUAGE_ASSEMBLY
#define SPRG0 272
#define SPRG1 273
#define SPRG2 274
#define SPRG3 275
#define PMC1 953
#define PMC2 954
#define PMC3 957
#define PMC4 958
#define MMCR0 952
#define MMCR1 956
#define LINK_REGISTER_CALLEE_UPDATE_ROOM 4
#define EXCEPTION_NUMBER 8
#define SRR0_OFFSET 12
#define SRR1_OFFSET 16
#define GPR0_OFFSET 20
#define GPR1_OFFSET 24
#define GPR2_OFFSET 28
#define GPR3_OFFSET 32
#define GPR4_OFFSET 36
#define GPR5_OFFSET 40
#define GPR6_OFFSET 44
#define GPR7_OFFSET 48
#define GPR8_OFFSET 52
#define GPR9_OFFSET 56
#define GPR10_OFFSET 60
#define GPR11_OFFSET 64
#define GPR12_OFFSET 68
#define GPR13_OFFSET 72
#define GPR14_OFFSET 76
#define GPR15_OFFSET 80
#define GPR16_OFFSET 84
#define GPR17_OFFSET 88
#define GPR18_OFFSET 92
#define GPR19_OFFSET 96
#define GPR20_OFFSET 100
#define GPR21_OFFSET 104
#define GPR22_OFFSET 108
#define GPR23_OFFSET 112
#define GPR24_OFFSET 116
#define GPR25_OFFSET 120
#define GPR26_OFFSET 124
#define GPR27_OFFSET 128
#define GPR28_OFFSET 132
#define GPR29_OFFSET 136
#define GPR30_OFFSET 140
#define GPR31_OFFSET 144
#define GQR0_OFFSET 148
#define GQR1_OFFSET 152
#define GQR2_OFFSET 156
#define GQR3_OFFSET 160
#define GQR4_OFFSET 164
#define GQR5_OFFSET 168
#define GQR6_OFFSET 172
#define GQR7_OFFSET 176
#define CR_OFFSET 180
#define LR_OFFSET 184
#define CTR_OFFSET 188
#define XER_OFFSET 192
#define MSR_OFFSET 196
#define DAR_OFFSET 200
#define STATE_OFFSET 204
#define MODE_OFFSET 206
#define FPR0_OFFSET 208
#define FPR1_OFFSET 216
#define FPR2_OFFSET 224
#define FPR3_OFFSET 232
#define FPR4_OFFSET 240
#define FPR5_OFFSET 248
#define FPR6_OFFSET 256
#define FPR7_OFFSET 264
#define FPR8_OFFSET 272
#define FPR9_OFFSET 280
#define FPR10_OFFSET 288
#define FPR11_OFFSET 296
#define FPR12_OFFSET 304
#define FPR13_OFFSET 312
#define FPR14_OFFSET 320
#define FPR15_OFFSET 328
#define FPR16_OFFSET 336
#define FPR17_OFFSET 344
#define FPR18_OFFSET 352
#define FPR19_OFFSET 360
#define FPR20_OFFSET 368
#define FPR21_OFFSET 376
#define FPR22_OFFSET 384
#define FPR23_OFFSET 392
#define FPR24_OFFSET 400
#define FPR25_OFFSET 408
#define FPR26_OFFSET 416
#define FPR27_OFFSET 424
#define FPR28_OFFSET 432
#define FPR29_OFFSET 440
#define FPR30_OFFSET 448
#define FPR31_OFFSET 456
#define FPSCR_OFFSET 464
#define PSR0_OFFSET 472
#define PSR1_OFFSET 480
#define PSR2_OFFSET 488
#define PSR3_OFFSET 496
#define PSR4_OFFSET 504
#define PSR5_OFFSET 512
#define PSR6_OFFSET 520
#define PSR7_OFFSET 528
#define PSR8_OFFSET 536
#define PSR9_OFFSET 544
#define PSR10_OFFSET 552
#define PSR11_OFFSET 560
#define PSR12_OFFSET 568
#define PSR13_OFFSET 576
#define PSR14_OFFSET 584
#define PSR15_OFFSET 592
#define PSR16_OFFSET 600
#define PSR17_OFFSET 608
#define PSR18_OFFSET 616
#define PSR19_OFFSET 624
#define PSR20_OFFSET 632
#define PSR21_OFFSET 640
#define PSR22_OFFSET 648
#define PSR23_OFFSET 656
#define PSR24_OFFSET 664
#define PSR25_OFFSET 672
#define PSR26_OFFSET 680
#define PSR27_OFFSET 688
#define PSR28_OFFSET 696
#define PSR29_OFFSET 704
#define PSR30_OFFSET 712
#define PSR31_OFFSET 720
/*
* maintain the EABI requested 8 bytes aligment
* As SVR4 ABI requires 16, make it 16 (as some
* exception may need more registers to be processed...)
*/
#define EXCEPTION_FRAME_END 728
#define IBAT0U 528
#define IBAT0L 529
#define IBAT1U 530
#define IBAT1L 531
#define IBAT2U 532
#define IBAT2L 533
#define IBAT3U 534
#define IBAT3L 535
#define IBAT4U 560
#define IBAT4L 561
#define IBAT5U 562
#define IBAT5L 563
#define IBAT6U 564
#define IBAT6L 565
#define IBAT7U 566
#define IBAT7L 567
#define DBAT0U 536
#define DBAT0L 537
#define DBAT1U 538
#define DBAT1L 538
#define DBAT2U 540
#define DBAT2L 541
#define DBAT3U 542
#define DBAT3L 543
#define DBAT4U 568
#define DBAT4L 569
#define DBAT5U 570
#define DBAT5L 571
#define DBAT6U 572
#define DBAT6L 573
#define DBAT7U 574
#define DBAT7L 575
#define HID0 1008
#define HID1 1009
#define HID2 920
#define HID4 1011
#define GQR0 912
#define GQR1 913
#define GQR2 914
#define GQR3 915
#define GQR4 916
#define GQR5 917
#define GQR6 918
#define GQR7 919
#define L2CR 1017
#define WPAR 921
#define DMAU 922
#define DMAL 923
#define MSR_RI 0x00000002
#define MSR_DR 0x00000010
#define MSR_IR 0x00000020
#define MSR_IP 0x00000040
#define MSR_SE 0x00000400
#define MSR_ME 0x00001000
#define MSR_FP 0x00002000
#define MSR_POW 0x00004000
#define MSR_EE 0x00008000
#define PPC_ALIGNMENT 8
#define PPC_CACHE_ALIGNMENT 32
#endif //__ASM_H__

View File

@@ -0,0 +1,84 @@
#include <ogcsys.h>
#include <ogc/machine/processor.h>
#include "../config.h"
#include "debug.h"
#include "panic.h"
#include "blob.h"
#define MAX_BLOBS 8
#define BLOB_MINSLACK (512*1024)
typedef struct {
void *the_blob;
size_t blob_size;
void *old_arena2hi;
} blob_t;
blob_t blobs[MAX_BLOBS];
int num_blobs = 0;
// supports only stack-type allocs (free last alloced)
void *blob_alloc(size_t size)
{
u32 level;
u32 addr;
void *old_arena2hi;
_CPU_ISR_Disable(level);
if (num_blobs >= MAX_BLOBS) {
_CPU_ISR_Restore(level);
gprintf("too many blobs\n");
panic();
}
old_arena2hi = SYS_GetArena2Hi();
addr = (((u32)old_arena2hi) - size) & (~0x1f);
if (addr < (BLOB_MINSLACK + (u32)SYS_GetArena2Lo())) {
_CPU_ISR_Restore(level);
return NULL;
}
blobs[num_blobs].old_arena2hi = old_arena2hi;
blobs[num_blobs].the_blob = (void*)addr;
blobs[num_blobs].blob_size = size;
num_blobs++;
SYS_SetArena2Hi((void*)addr);
_CPU_ISR_Restore(level);
gprintf("allocated blob size %d at 0x%08lx\n", size, addr);
return (void*)addr;
}
void blob_free(void *p)
{
u32 level;
if (!p)
return;
_CPU_ISR_Disable(level);
if (num_blobs == 0) {
_CPU_ISR_Restore(level);
gprintf("blob_free with no blobs\n");
panic();
}
num_blobs--;
if (p != blobs[num_blobs].the_blob) {
_CPU_ISR_Restore(level);
gprintf("mismatched blob_free (%p != %p)\n", p, blobs[num_blobs].the_blob);
panic();
}
if (SYS_GetArena2Hi() != p) {
_CPU_ISR_Restore(level);
gprintf("someone else used MEM2 (%p != %p)\n", p, SYS_GetArena2Hi());
panic();
}
SYS_SetArena2Hi(blobs[num_blobs].old_arena2hi);
_CPU_ISR_Restore(level);
gprintf("freed blob size %d at %p\n", blobs[num_blobs].blob_size, p);
}

View File

@@ -0,0 +1,9 @@
#ifndef _BLOB_H_
#define _BLOB_H_
#include <sys/types.h>
void *blob_alloc(size_t size);
void blob_free(void *p);
#endif

View File

@@ -0,0 +1,330 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <ogcsys.h>
#include <ogc/lwp_watchdog.h>
#include "../config.h"
#include "theme.h"
#include "view.h"
#include "controls.h"
#include "i18n.h"
#include "browser.h"
#define AE_OFFSET 4
#define TRANS_STEPS 20
#define MAX_COLUMNS 4
#define ROWS 5
static bool first_set = true;
static u16 top_offset = 0;
static view *v_browser = NULL;
static int columns_current = 1;
static int columns_new = 1;
static bool inited_widgets = false;
view * browser_init(void) {
v_browser = view_new (AE_OFFSET + (MAX_COLUMNS * ROWS * 2), NULL,
0, 0, 0, 0);
browser_theme_reinit();
return v_browser;
}
void browser_deinit(void) {
view_free(v_browser);
inited_widgets = false;
v_browser = NULL;
}
void browser_theme_reinit(void) {
int i;
if (inited_widgets)
for (i = 0; i < v_browser->widget_count; ++i)
widget_free(&v_browser->widgets[i]);
widget_image (&v_browser->widgets[0], 24, 192, 0,
theme_gfx[THEME_ARROW_LEFT], NULL, true,
theme_gfx[THEME_ARROW_LEFT_FOCUS]);
widget_image (&v_browser->widgets[1],
view_width - 24 - theme_gfx[THEME_ARROW_RIGHT]->w, 192, 0,
theme_gfx[THEME_ARROW_RIGHT], NULL, true,
theme_gfx[THEME_ARROW_RIGHT_FOCUS]);
widget_image (&v_browser->widgets[2],
view_width - 32 - theme_gfx[THEME_GECKO_ACTIVE]->w -
theme_gfx[THEME_LAN_ACTIVE]->w, 412, 0,
theme_gfx[THEME_GECKO_ACTIVE], theme_gfx[THEME_GECKO],
false, NULL);
widget_image (&v_browser->widgets[3],
view_width - 32 - theme_gfx[THEME_GECKO_ACTIVE]->w, 412, 0,
theme_gfx[THEME_LAN_ACTIVE], theme_gfx[THEME_LAN],
false, NULL);
widget_set_flag (&v_browser->widgets[2], WF_ENABLED, false);
widget_set_flag (&v_browser->widgets[3], WF_ENABLED, false);
widget_set_flag (&v_browser->widgets[0], WF_VISIBLE, false);
widget_set_flag (&v_browser->widgets[1], WF_VISIBLE, false);
inited_widgets = true;
}
static void browser_set_top_offset(const app_entry *app) {
u32 i;
if (!app || (entry_count < 1)) {
top_offset = 0;
return;
}
for (i = 0; i < entry_count; ++i)
if (entries[i] == app) {
top_offset = i;
break;
}
top_offset /= columns_new * ROWS;
top_offset *= columns_new * ROWS;
if (top_offset > entry_count - 1)
top_offset -= columns_new * ROWS;
}
void browser_gen_view(browser_action action, const app_entry *app) {
bool less, more;
app_entry *entry;
s8 focus;
u32 i, j;
u16 y;
u8 o1, o2;
s16 xal, xar, x1, x2;
float xm;
float vala = 0;
float val1[MAX_COLUMNS * ROWS];
float val2[MAX_COLUMNS * ROWS];
float stepa = M_TWOPI / TRANS_STEPS;
float step = M_PI / (TRANS_STEPS - 6);
s16 s;
float f1, f2;
switch (action) {
case BA_REMOVE:
break;
case BA_ADD:
case BA_REFRESH:
browser_set_top_offset(app);
break;
case BA_NEXT:
if (entry_count <= top_offset + (columns_new * ROWS))
return;
top_offset += columns_current * ROWS;
break;
case BA_PREV:
if (top_offset < 1)
return;
if (top_offset < columns_current * ROWS)
return;
top_offset -= columns_current * ROWS;
break;
}
if (action == BA_REMOVE) {
less = false;
more = false;
} else {
less = top_offset > 0;
more = entry_count > top_offset + (columns_new * ROWS);
}
memset(val1, 0, sizeof(float) * MAX_COLUMNS * ROWS);
memset(val2, 0, sizeof(float) * MAX_COLUMNS * ROWS);
if (first_set) {
o1 = AE_OFFSET;
o2 = AE_OFFSET + (MAX_COLUMNS * ROWS);
} else {
o1 = AE_OFFSET + (MAX_COLUMNS * ROWS);
o2 = AE_OFFSET;
}
first_set = !first_set;
focus = o2;
xal = v_browser->widgets[0].coords.x;
xar = v_browser->widgets[1].coords.x;
if (columns_current == 1)
x1 = (view_width - theme_gfx[THEME_APP_ENTRY]->w) / 2;
else
x1 = (view_width - (theme_gfx[THEME_GRID_APP_ENTRY]->w *
columns_current)) / 2;
if (columns_new == 1)
x2 = (view_width - theme_gfx[THEME_APP_ENTRY]->w) / 2;
else
x2 = (view_width - (theme_gfx[THEME_GRID_APP_ENTRY]->w *
columns_new)) / 2;
if (action == BA_PREV) {
xm = view_width / 2;
x2 = -view_width + x2;
} else {
xm = -view_width / 2;
x2 = view_width + x2;
}
y = 64;
for (i = 0; i < (MAX_COLUMNS * ROWS); ++i)
widget_free(&v_browser->widgets[o2 + i]);
if (action != BA_REMOVE)
for (i = 0; i < (columns_new * ROWS); ++i) {
if (entry_count > top_offset + i) {
entry = entries[top_offset + i];
if (entry && (entry == app))
focus += i;
if (columns_new == 1)
widget_app_entry(&v_browser->widgets[o2 + i],
x2, y, 0, entry);
else
widget_grid_app_entry(&v_browser->widgets[o2 + i],
x2 + ((i % columns_new) *
theme_gfx[THEME_GRID_APP_ENTRY]->w),
y, 0, entry);
}
if (((i+1) % columns_new) == 0)
y += theme_gfx[THEME_APP_ENTRY]->h;
}
for (i = 0; i < TRANS_STEPS; ++i) {
vala += stepa;
s = roundf (156.0 * (cosf (vala) - 1));
// adjust L/R button positions
v_browser->widgets[0].coords.x = xal + s;
v_browser->widgets[1].coords.x = xar - s;
for (j = 0; j < MAX_COLUMNS * ROWS; ++j) {
if ((i > j / columns_current) &&
(i < TRANS_STEPS - (ROWS - j / columns_current)))
val1[j] += step;
if ((i > j / columns_new) &&
(i < TRANS_STEPS - (ROWS - j / columns_new)))
val2[j] += step;
f1 = roundf (xm * (cosf (val1[j]) - 1));
f2 = roundf (xm * (cosf (val2[j]) - 1));
v_browser->widgets[o1 + j].coords.x = x1 - f1 +
((j % columns_current) * theme_gfx[THEME_GRID_APP_ENTRY]->w);
v_browser->widgets[o2 + j].coords.x = x2 - f2 +
((j % columns_new) * theme_gfx[THEME_GRID_APP_ENTRY]->w);
}
view_plot (v_browser, 0, NULL, NULL, NULL);
if (i == TRANS_STEPS / 2) {
widget_set_flag (&v_browser->widgets[0], WF_VISIBLE, true);
widget_set_flag (&v_browser->widgets[1], WF_VISIBLE, true);
widget_set_flag (&v_browser->widgets[0], WF_VISIBLE, less);
widget_set_flag (&v_browser->widgets[1], WF_VISIBLE, more);
view_set_focus (v_browser, focus);
}
}
for (i = 0; i < (MAX_COLUMNS * ROWS); ++i)
widget_free(&v_browser->widgets[o1 + i]);
columns_current = columns_new;
if (action == BA_REMOVE)
top_offset = 0;
}
void browser_set_focus(u32 bd) {
if (columns_current == 1) {
if (bd & PADS_UP) {
view_set_focus_prev(v_browser);
return;
}
if (bd & PADS_DOWN) {
view_set_focus_next(v_browser);
return;
}
return;
} else {
if (bd & PADS_LEFT) {
view_set_focus_prev(v_browser);
return;
}
if (bd & PADS_RIGHT) {
view_set_focus_next(v_browser);
return;
}
if (bd & PADS_UP) {
view_move_focus(v_browser, -columns_current);
return;
}
if (bd & PADS_DOWN) {
view_move_focus(v_browser, columns_current);
return;
}
return;
}
}
app_entry *browser_sel(void) {
if ((entry_count < 1) || (v_browser->focus < AE_OFFSET))
return NULL;
u32 i;
if (first_set)
i = top_offset + v_browser->focus - AE_OFFSET;
else
i = top_offset + v_browser->focus - (MAX_COLUMNS * ROWS) - AE_OFFSET;
return entries[i];
}
void browser_switch_mode(void) {
const app_entry *app = browser_sel();
int mode = 0;
if (columns_current == 1) {
if (widescreen)
columns_new = 4;
else
columns_new = 3;
mode = 1;
} else {
columns_new = 1;
}
if (v_browser)
browser_gen_view(BA_REFRESH, app);
if (settings.browse_mode != mode)
settings.browse_mode = mode;
}

View File

@@ -0,0 +1,26 @@
#ifndef _BROWSER_H_
#define _BROWSER_H_
#include <gctypes.h>
#include "view.h"
typedef enum {
BA_ADD = 0,
BA_REMOVE,
BA_REFRESH,
BA_NEXT,
BA_PREV
} browser_action;
view * browser_init(void);
void browser_deinit(void);
void browser_theme_reinit(void);
void browser_gen_view(browser_action action, const app_entry *app);
void browser_set_focus(u32 bd);
app_entry *browser_sel(void);
void browser_switch_mode(void);
#endif

View File

@@ -0,0 +1,233 @@
#include <stdlib.h>
#include <math.h>
#include "../config.h"
#include "gfx.h"
#include "theme.h"
#include "bubbles.h"
#include <ogc/lwp_watchdog.h>
#define BUBBLE_DELTA (MAX_BUBBLE_COUNT-MIN_BUBBLE_COUNT)
typedef struct {
float x;
float py;
float speed;
float xm;
float val;
float step;
int popped;
int popcnt;
int tex;
} bubble;
static gfx_entity *tex_bubbles[3];
static gfx_queue_entry entries_bubbles[MAX_BUBBLE_COUNT];
static gfx_queue_entry entries_sub_bubbles[MAX_BUBBLE_COUNT][BUBBLE_POP_MAX];
static bubble bubbles[MAX_BUBBLE_COUNT];
static bubble sub_bubbles[MAX_BUBBLE_COUNT][BUBBLE_POP_MAX];
static int bubble_count = -1;
static void bubble_rand(int i) {
int tex;
tex = IRAND (3);
bubbles[i].x = IRAND (view_width);
bubbles[i].py = view_height + IRAND (200);
bubbles[i].speed = 1.2 + FRAND (4 - tex);
bubbles[i].xm = 3.0 + (IRAND ((tex + 1)) * bubbles[i].speed);
bubbles[i].val = 0;
bubbles[i].step = M_TWOPI / (64 + FRAND (64.0));
bubbles[i].popped = 0;
bubbles[i].popcnt = 0;
bubbles[i].tex = tex;
gfx_qe_entity(&entries_bubbles[i], tex_bubbles[tex], bubbles[i].x,
bubbles[i].py, -2, COL_DEFAULT);
entries_bubbles[i].entity.scale = BUBBLE_SIZE_MIN +
FRAND (BUBBLE_SIZE_MAX - BUBBLE_SIZE_MIN);
entries_bubbles[i].entity.rad = FRAND (M_PI_4);
}
static void bubble_update_count(void) {
static int div = 0;
s32 minute;
static int new_count;
int t;
// time() might be expensive due to RTC reading
// so slow it down a bit
if ((div++ >= 600) || (bubble_count < 0)) {
div = 0;
t = time(NULL);
minute = (t / 60 - BUBBLE_MIN_TIME) % BUBBLE_TIME_CYCLE;
if (minute <= BUBBLE_MAX_OFFSET)
new_count = (BUBBLE_DELTA * minute / BUBBLE_MAX_OFFSET) +
MIN_BUBBLE_COUNT;
else
new_count = (BUBBLE_DELTA * (BUBBLE_TIME_CYCLE - minute) /
(BUBBLE_TIME_CYCLE - BUBBLE_MAX_OFFSET)) +
MIN_BUBBLE_COUNT;
if (new_count < MIN_BUBBLE_COUNT) // should never happen
new_count = MIN_BUBBLE_COUNT;
if (new_count > MAX_BUBBLE_COUNT) // should never happen
new_count = MAX_BUBBLE_COUNT;
}
if (((div % 6) == 0) || (bubble_count < 0)) {
if (bubble_count < 0)
bubble_count = 0;
if (bubble_count < new_count) {
while (bubble_count < new_count)
bubble_rand(bubble_count++);
} else if (bubble_count > new_count)
bubble_count--;
}
}
static void bubble_pop(int i) {
int j;
bubbles[i].popped = 1;
bubbles[i].popcnt = IRAND(BUBBLE_POP_MAX - BUBBLE_POP_MIN) + BUBBLE_POP_MIN;
entries_bubbles[i].entity.color = 0x00000000;
for (j = 0; j < bubbles[i].popcnt; j++) {
int tex;
float sa;
float dx,dy;
sa = FRAND(M_TWOPI);
dx = sin(sa) * FRAND(BUBBLE_POP_SPREAD_X);
dy = (cos(sa) - 1.5) * FRAND(BUBBLE_POP_SPREAD_Y);
tex = bubbles[i].tex;
sub_bubbles[i][j].x = bubbles[i].x + dx;
sub_bubbles[i][j].py = entries_bubbles[i].entity.coords.y + dy;
sub_bubbles[i][j].speed = bubbles[i].speed - 0.5 + FRAND (4 - tex);
sub_bubbles[i][j].xm = bubbles[i].xm * (0.8 + FRAND(1.0));
sub_bubbles[i][j].val = bubbles[i].val;
sub_bubbles[i][j].step = bubbles[i].step * (0.8 + FRAND(0.4));
sub_bubbles[i][j].popped = 0;
sub_bubbles[i][j].popcnt = 0;
gfx_qe_entity (&entries_sub_bubbles[i][j], tex_bubbles[tex],
sub_bubbles[i][j].x, sub_bubbles[i][j].py,
-2, COL_DEFAULT);
entries_sub_bubbles[i][j].entity.scale = (BUBBLE_POP_SIZE_MIN +
FRAND (BUBBLE_POP_SIZE_MAX - BUBBLE_POP_SIZE_MIN)) *
entries_bubbles[i].entity.scale;
entries_sub_bubbles[i][j].entity.rad = entries_bubbles[i].entity.rad;
}
}
void bubbles_init(void) {
srand (gettime ());
bubbles_theme_reinit();
bubble_update_count();
}
void bubbles_deinit(void) {
}
void bubbles_theme_reinit(void) {
tex_bubbles[0] = theme_gfx[THEME_BUBBLE1];
tex_bubbles[1] = theme_gfx[THEME_BUBBLE2];
tex_bubbles[2] = theme_gfx[THEME_BUBBLE3];
bubble_count = -1;
bubble_update_count();
}
void bubble_update(bool wm, s32 x, s32 y) {
int i, j, deadcnt;
gfx_coordinates *coords;
f32 radius;
bubble_update_count();
for (i = 0; i < bubble_count; ++i) {
coords = &entries_bubbles[i].entity.coords;
radius = entries_bubbles[i].entity.scale *
entries_bubbles[i].entity.entity->w / 2 * BUBBLE_POP_RADIUS;
if (!bubbles[i].popped && wm) {
float cx = coords->x + entries_bubbles[i].entity.entity->w/2;
float cy = coords->y - entries_bubbles[i].entity.entity->h/2;
if ((abs(x - cx) < radius) && (abs(y - cy) < radius))
bubble_pop(i);
}
if (bubbles[i].popped) {
deadcnt = 0;
for (j = 0; j < bubbles[i].popcnt; j++) {
coords = &entries_sub_bubbles[i][j].entity.coords;
radius = entries_sub_bubbles[i][j].entity.scale *
entries_sub_bubbles[i][j].entity.entity->w / 2 *
BUBBLE_POP_RADIUS;
if (!sub_bubbles[i][j].popped && wm) {
float cx = coords->x + entries_bubbles[i].entity.entity->w/2;
float cy = coords->y - entries_bubbles[i].entity.entity->h/2;
if ((abs(x - cx) < radius) && (abs(y - cy) < radius)) {
entries_sub_bubbles[i][j].entity.color = 0x00000000;
sub_bubbles[i][j].popped = 1;
}
}
sub_bubbles[i][j].py -= sub_bubbles[i][j].speed;
coords->y = sub_bubbles[i][j].py;
if ((coords->y < -100) || sub_bubbles[i][j].popped) {
deadcnt++;
continue;
}
coords->x = sub_bubbles[i][j].x + roundf (sub_bubbles[i][j].xm *
sinf (sub_bubbles[i][j].val));
sub_bubbles[i][j].val += sub_bubbles[i][j].step;
}
if(deadcnt >= bubbles[i].popcnt) {
bubble_rand(i);
continue;
}
gfx_frame_push (entries_sub_bubbles[i], bubbles[i].popcnt);
} else {
bubbles[i].py -= bubbles[i].speed;
coords->y = bubbles[i].py;
if (coords->y < -100) {
bubble_rand(i);
continue;
}
coords->x = bubbles[i].x + roundf (bubbles[i].xm *
sinf (bubbles[i].val));
bubbles[i].val += bubbles[i].step;
}
}
gfx_frame_push(entries_bubbles, bubble_count);
}
void bubble_popall(void) {
int i;
for (i = 0; i < bubble_count; ++i)
if (!bubbles[i].popped)
bubble_pop(i);
}

View File

@@ -0,0 +1,15 @@
#ifndef _BUBBLES_H_
#define _BUBBLES_H_
#include <gctypes.h>
void bubbles_init(void);
void bubbles_deinit(void);
void bubbles_theme_reinit(void);
void bubble_update(bool wm, s32 x, s32 y);
void bubble_popall(void);
#endif

View File

@@ -0,0 +1,240 @@
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <ogcsys.h>
#include <ogc/lwp_watchdog.h>
#include "../config.h"
#include "controls.h"
#include "gfx.h"
static s32 pointer_owner = -1;
WPADData *wpads[WPAD_MAX_WIIMOTES];
static int rumbling = 0;
void controls_init (void) {
int i;
i = WPAD_Init ();
if(i < 0) {
gprintf("WPAD_Init failed: %d\n",i);
return;
}
for(i=0;i<WPAD_MAX_WIIMOTES;i++) {
WPAD_SetDataFormat (i, WPAD_FMT_BTNS_ACC_IR);
WPAD_SetVRes (i, view_width + 128, view_height + 128);
}
WPAD_SetIdleTimeout (120);
}
void controls_deinit (void) {
WPAD_Shutdown ();
}
static u32 wpad_button_transform(WPADData *wd, u32 btns) {
btns &= ~PADW_BUTTON_NET_INIT;
btns &= ~PADW_BUTTON_SCREENSHOT;
switch(wd->exp.type) {
case WPAD_EXP_NUNCHUK:
if(btns & WPAD_NUNCHUK_BUTTON_Z)
btns |= PADW_BUTTON_NET_INIT;
if(btns & WPAD_NUNCHUK_BUTTON_C)
btns |= PADW_BUTTON_SCREENSHOT;
break;
case WPAD_EXP_CLASSIC:
if(btns & WPAD_CLASSIC_BUTTON_LEFT)
btns |= WPAD_BUTTON_LEFT;
if(btns & WPAD_CLASSIC_BUTTON_RIGHT)
btns |= WPAD_BUTTON_RIGHT;
if(btns & WPAD_CLASSIC_BUTTON_UP)
btns |= WPAD_BUTTON_UP;
if(btns & WPAD_CLASSIC_BUTTON_DOWN)
btns |= WPAD_BUTTON_DOWN;
if(btns & WPAD_CLASSIC_BUTTON_A)
btns |= WPAD_BUTTON_A;
if(btns & WPAD_CLASSIC_BUTTON_B)
btns |= WPAD_BUTTON_B;
if(btns & WPAD_CLASSIC_BUTTON_X)
btns |= WPAD_BUTTON_1;
if(btns & WPAD_CLASSIC_BUTTON_Y)
btns |= WPAD_BUTTON_2;
if((btns & WPAD_CLASSIC_BUTTON_FULL_L) || (btns & WPAD_CLASSIC_BUTTON_MINUS))
btns |= WPAD_BUTTON_MINUS;
if((btns & WPAD_CLASSIC_BUTTON_FULL_R) || (btns & WPAD_CLASSIC_BUTTON_PLUS))
btns |= WPAD_BUTTON_PLUS;
if(btns & WPAD_CLASSIC_BUTTON_HOME)
btns |= WPAD_BUTTON_HOME;
if(btns & WPAD_CLASSIC_BUTTON_ZR)
btns |= PADW_BUTTON_NET_INIT;
if(btns & WPAD_CLASSIC_BUTTON_ZL)
btns |= PADW_BUTTON_SCREENSHOT;
break;
case WPAD_EXP_GUITARHERO3:
if(btns & WPAD_GUITAR_HERO_3_BUTTON_STRUM_UP)
btns |= WPAD_BUTTON_UP;
if(btns & WPAD_GUITAR_HERO_3_BUTTON_STRUM_DOWN)
btns |= WPAD_BUTTON_DOWN;
if(btns & WPAD_GUITAR_HERO_3_BUTTON_GREEN)
btns |= WPAD_BUTTON_A;
if(btns & WPAD_GUITAR_HERO_3_BUTTON_RED)
btns |= WPAD_BUTTON_B;
if(btns & WPAD_GUITAR_HERO_3_BUTTON_PLUS)
btns |= WPAD_BUTTON_PLUS;
if(btns & WPAD_GUITAR_HERO_3_BUTTON_MINUS)
btns |= WPAD_BUTTON_MINUS;
if(btns & WPAD_GUITAR_HERO_3_BUTTON_YELLOW)
btns |= WPAD_BUTTON_LEFT;
if(btns & WPAD_GUITAR_HERO_3_BUTTON_BLUE)
btns |= WPAD_BUTTON_RIGHT;
if(btns & WPAD_GUITAR_HERO_3_BUTTON_ORANGE)
btns |= WPAD_BUTTON_1;
break;
}
return (btns&0xffff) << 16;
}
void controls_scan (u32 *down, u32 *held, u32 *up) {
u32 bd, bh, bu;
int i;
s32 last_owner;
PAD_ScanPads ();
bd = PAD_ButtonsDown (0);
bh = PAD_ButtonsHeld (0);
bu = PAD_ButtonsUp (0);
WPAD_ScanPads ();
for(i=0;i<WPAD_MAX_WIIMOTES;i++)
if(WPAD_Probe (i, NULL) == WPAD_ERR_NONE) {
wpads[i] = WPAD_Data(i);
} else {
wpads[i] = NULL;
}
last_owner = pointer_owner;
// kill pointer owner if it stops pointing
if((pointer_owner >= 0) && (!wpads[pointer_owner] || !wpads[pointer_owner]->ir.valid)) {
pointer_owner = -1;
}
// find a new pointer owner if necessary
if(pointer_owner < 0) {
for(i=0;i<WPAD_MAX_WIIMOTES;i++) {
if(wpads[i] && wpads[i]->ir.valid) {
pointer_owner = i;
break;
}
}
}
// pointer owner owns buttons
if(pointer_owner >= 0) {
bd |= wpad_button_transform(wpads[pointer_owner], wpads[pointer_owner]->btns_d);
bh |= wpad_button_transform(wpads[pointer_owner], wpads[pointer_owner]->btns_h);
bu |= wpad_button_transform(wpads[pointer_owner], wpads[pointer_owner]->btns_u);
} else {
// otherwise just mix all buttons together
for(i=0;i<WPAD_MAX_WIIMOTES;i++) {
if(wpads[i]) {
bd |= wpad_button_transform(wpads[i], wpads[i]->btns_d);
bh |= wpad_button_transform(wpads[i], wpads[i]->btns_h);
bu |= wpad_button_transform(wpads[i], wpads[i]->btns_u);
}
}
}
if(last_owner >= 0 && last_owner != pointer_owner && rumbling) {
WPAD_Rumble (last_owner, 0);
if(pointer_owner >= 0)
WPAD_Rumble(pointer_owner, 1);
}
if (down)
*down = bd;
if (held)
*held = bh;
if (up)
*up = bu;
}
bool controls_ir (s32 *x, s32 *y, f32 *roll) {
if (pointer_owner >= 0 && wpads[pointer_owner] && wpads[pointer_owner]->ir.valid) {
*x = wpads[pointer_owner]->ir.x - 64;
*y = wpads[pointer_owner]->ir.y - 64;
if(roll)
*roll = -wpads[pointer_owner]->ir.angle / 180.0 * M_PI;
return true;
} else {
return false;
}
}
void controls_rumble(int rumble) {
if(pointer_owner >= 0)
WPAD_Rumble(pointer_owner, rumble);
rumbling = rumble;
}
static s32 wpad_sticky(int chan) {
s32 sy = 0;
if(wpads[chan]) {
switch(wpads[chan]->exp.type) {
case WPAD_EXP_NUNCHUK:
sy = wpads[chan]->exp.nunchuk.js.pos.y - wpads[chan]->exp.nunchuk.js.center.y;
break;
case WPAD_EXP_CLASSIC:
sy = (wpads[chan]->exp.classic.ljs.pos.y - wpads[chan]->exp.classic.ljs.center.y) * 4;
break;
case WPAD_EXP_GUITARHERO3:
sy = (wpads[chan]->exp.gh3.js.pos.y - wpads[chan]->exp.gh3.js.center.y) * 4;
break;
}
}
return sy;
}
#define DEADZONE 10
s32 deadzone(s32 v) {
if(v > DEADZONE)
return v - DEADZONE;
if(v < -DEADZONE)
return v + DEADZONE;
return 0;
}
s32 controls_sticky(void) {
s32 sy;
int i;
sy = deadzone(PAD_StickY(0));
if(pointer_owner >= 0) {
sy += deadzone(wpad_sticky(pointer_owner));
} else {
for(i=0;i<WPAD_MAX_WIIMOTES;i++) {
sy += deadzone(wpad_sticky(i));
}
}
return sy;
}
void controls_set_ir_threshold(int on) {
int i;
for(i=0;i<WPAD_MAX_WIIMOTES;i++) {
if(on)
WPAD_SetIdleThresholds(i, WPAD_THRESH_DEFAULT_BUTTONS, 10, WPAD_THRESH_DEFAULT_ACCEL, WPAD_THRESH_DEFAULT_JOYSTICK, WPAD_THRESH_DEFAULT_BALANCEBOARD, WPAD_THRESH_DEFAULT_MOTION_PLUS);
else
WPAD_SetIdleThresholds(i, WPAD_THRESH_DEFAULT_BUTTONS, WPAD_THRESH_DEFAULT_IR, WPAD_THRESH_DEFAULT_ACCEL, WPAD_THRESH_DEFAULT_JOYSTICK, WPAD_THRESH_DEFAULT_BALANCEBOARD, WPAD_THRESH_DEFAULT_MOTION_PLUS);
}
}

View File

@@ -0,0 +1,36 @@
#ifndef _CONTROLS_H_
#define _CONTROLS_H_
#include <gctypes.h>
#include <wiiuse/wpad.h>
// fake wiimote buttons for mapping extension buttons
#define PADW_BUTTON_NET_INIT 0x2000
#define PADW_BUTTON_SCREENSHOT 0x4000
#define PADS_A (PAD_BUTTON_A | (WPAD_BUTTON_A << 16))
#define PADS_B (PAD_BUTTON_B | (WPAD_BUTTON_B << 16))
#define PADS_MINUS (PAD_TRIGGER_L | (WPAD_BUTTON_MINUS << 16))
#define PADS_PLUS (PAD_TRIGGER_R | (WPAD_BUTTON_PLUS << 16))
#define PADS_1 (PAD_BUTTON_X | (WPAD_BUTTON_1 << 16))
#define PADS_2 (PAD_BUTTON_Y | (WPAD_BUTTON_2 << 16))
#define PADS_HOME (PAD_BUTTON_START | (WPAD_BUTTON_HOME << 16))
#define PADS_UP (PAD_BUTTON_UP | (WPAD_BUTTON_UP << 16))
#define PADS_DOWN (PAD_BUTTON_DOWN | (WPAD_BUTTON_DOWN << 16))
#define PADS_LEFT (PAD_BUTTON_LEFT | (WPAD_BUTTON_LEFT << 16))
#define PADS_RIGHT (PAD_BUTTON_RIGHT | (WPAD_BUTTON_RIGHT << 16))
#define PADS_DPAD (PADS_UP | PADS_DOWN | PADS_LEFT | PADS_RIGHT)
#define PADS_NET_INIT (PAD_TRIGGER_Z | (PADW_BUTTON_NET_INIT << 16))
#define PADS_SCREENSHOT (PADW_BUTTON_SCREENSHOT << 16)
void controls_init (void);
void controls_deinit (void);
void controls_scan (u32 *down, u32 *held, u32 *up);
bool controls_ir (s32 *x, s32 *y, f32 *roll);
void controls_rumble(int rumble);
s32 controls_sticky(void);
void controls_set_ir_threshold(int on);
#endif

View File

@@ -0,0 +1,55 @@
#include "../config.h"
#include <gctypes.h>
#include "cursor_drag_png.h"
#include "cursor_drag_shade_png.h"
#include "cursor_pic_png.h"
#include "cursor_shade_png.h"
#include "cursors.h"
static cursor cursors[CUR_MAX];
void cursors_init (void) {
cursors[CUR_STD].tex[0] = tex_from_png (cursor_shade_png,
cursor_shade_png_size, 96,96);
cursors[CUR_STD].tex[1] = tex_from_png (cursor_pic_png, cursor_pic_png_size,
96, 96);
cursors[CUR_STD].hotspot_x = cursors[CUR_STD].tex[1]->w / 2;
cursors[CUR_STD].hotspot_y = cursors[CUR_STD].tex[1]->h / 2;
cursors[CUR_DRAG].tex[0] = tex_from_png (cursor_drag_shade_png,
cursor_drag_shade_png_size,
96, 96);
cursors[CUR_DRAG].tex[1] = tex_from_png (cursor_drag_png,
cursor_drag_png_size, 96, 96);
cursors[CUR_DRAG].hotspot_x = cursors[CUR_DRAG].tex[1]->w / 2;
cursors[CUR_DRAG].hotspot_y = cursors[CUR_DRAG].tex[1]->h / 2;
}
void cursors_deinit (void) {
u8 i;
for (i = 0; i < CUR_MAX; ++i) {
tex_free (cursors[i].tex[0]);
tex_free (cursors[i].tex[1]);
}
}
void cursors_queue (gfx_queue_entry *queue, cursor_type type, s16 x, s16 y,
f32 roll) {
gfx_qe_entity (&queue[0], cursors[type].tex[0],
x - cursors[type].hotspot_x + 2,
y - cursors[type].hotspot_y + 4, TEX_LAYER_CURSOR,
COL_DEFAULT);
gfx_qe_entity (&queue[1], cursors[type].tex[1],
x - cursors[type].hotspot_x,
y - cursors[type].hotspot_y, TEX_LAYER_CURSOR + 1,
COL_DEFAULT);
queue[0].entity.rad = roll;
queue[1].entity.rad = roll;
}

View File

@@ -0,0 +1,28 @@
#ifndef _CURSORS_H_
#define _CURSORS_H_
#include <gctypes.h>
#include "gfx.h"
#include "tex.h"
typedef enum {
CUR_STD = 0,
CUR_DRAG,
CUR_MAX
} cursor_type;
typedef struct {
gfx_entity *tex[2];
s16 hotspot_x, hotspot_y;
} cursor;
void cursors_init (void);
void cursors_deinit (void);
void cursors_queue (gfx_queue_entry *queue, cursor_type type, s16 x, s16 y,
f32 roll);
#endif

View File

@@ -0,0 +1,88 @@
#include <stdio.h>
#include <stdarg.h>
#include <ogcsys.h>
#include <ogc/machine/processor.h>
#include "../config.h"
#ifdef DEBUG_APP
//#define DEBUG_MEMSTATS
static int gprintf_enabled = 1;
void gprintf_enable(int enable) {
gprintf_enabled = enable;
}
int gprintf(const char *format, ...)
{
va_list ap;
u32 level;
int ret;
if (!gprintf_enabled)
return 0;
level = IRQ_Disable();
va_start(ap, format);
ret = vprintf(format, ap);
va_end(ap);
IRQ_Restore(level);
return ret;
}
/********* you know you love it **********/
static char ascii(char s) {
if(s < 0x20) return '.';
if(s > 0x7E) return '.';
return s;
}
void hexdump(const void *d, int len) {
u8 *data;
int i, off;
data = (u8*)d;
for (off=0; off<len; off += 16) {
gprintf("%08x ",off);
for(i=0; i<16; i++)
if((i+off)>=len) gprintf(" ");
else gprintf("%02x ",data[off+i]);
gprintf(" ");
for(i=0; i<16; i++)
if((i+off)>=len) gprintf(" ");
else gprintf("%c",ascii(data[off+i]));
gprintf("\n");
}
}
/********* you know you love it **********/
#ifndef UINT_MAX
#define UINT_MAX ((u32)((s32)-1))
#endif
void memstats(int reset) {
#ifdef DEBUG_MEMSTATS
static u32 min_free = UINT_MAX;
static u32 temp_free;
static u32 level;
if (reset)
min_free = UINT_MAX;
_CPU_ISR_Disable(level);
temp_free = (u32) SYS_GetArena2Hi() - (u32) SYS_GetArena2Lo();
_CPU_ISR_Restore(level);
if (temp_free < min_free) {
min_free = temp_free;
gprintf("MEM2 free: %8u\n", min_free);
}
#endif
}
#endif

View File

@@ -0,0 +1,623 @@
#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <math.h>
#include <ogcsys.h>
#include "../config.h"
#include "controls.h"
#include "theme.h"
#include "font.h"
#include "widgets.h"
#include "view.h"
#include "xml.h"
#include "panic.h"
#include "dialogs.h"
#include "i18n.h"
#define TRANS_STEPS 15
static const char *app_entry_desc_default;
static const char *caption_info;
static const char *caption_confirm;
static const char *caption_warning;
static const char *caption_error;
static const char *caption_ok;
static const char *caption_cancel;
static const char *caption_yes;
static const char *caption_no;
static const char *caption_delete;
static const char *caption_load;
static const char *caption_back;
static const char *caption_options;
static const char *caption_device;
static const char *caption_device_names[DEVICE_COUNT];
static const char *caption_sort_by;
static const char *caption_sort_name;
static const char *caption_sort_date;
static const char *l_version;
static const char *l_coder;
static const char *string_about_pre;
static const char *string_about_post;
static const char *string_about_trans;
static const char *string_about_theme;
static char *string_about_gen;
void dialogs_theme_reinit (void) {
app_entry_desc_default = _("no description available");
caption_info = _("Information");
caption_confirm = _("Confirmation");
caption_warning = _("Warning");
caption_error = _("Error");
caption_ok = _("Ok");
caption_cancel = _("Cancel");
caption_yes = _("Yes");
caption_no = _("No");
caption_delete = _("Delete");
caption_load = _("Load");
caption_back = _("Back");
caption_options = _("Options");
caption_device = _("Device:");
caption_device_names[0] = _("Internal SD Slot");
caption_device_names[1] = _("USB device");
caption_device_names[2] = _("SDGecko Slot A");
caption_device_names[3] = _("SDGecko Slot B");
caption_sort_by = _("Sort applications by:");
caption_sort_name = _("Name");
caption_sort_date = _("Date");
string_about_pre =
"Credits\n\n"
"The Homebrew Channel was made possible by the following people:\n\n"
"dhewg (EWRONGCHAN) - application code, geckoloader code\n"
"blasty (ESTONED) - application code\n"
"marcan (EFAILURE) - reload stub, banner, installer, packaging\n"
"bushing (EWANTPONY) - socket code, loader code\n"
"segher (EBUGFOUND) - nandloader stub code\n"
"souLLy (ENOTHERE) - banner graphics\n"
"drmr (EMORECOWBELL) - banner audio, channel graphics\n"
"mha (E404) - update server and hosting";
string_about_post =
"Powered by devkitPPC and libogc, by shagkur, WinterMute, "
"and everyone else who contributed\n\n"
"Thanks to all the beta testers\n\n"
"Kind regards to the following people too:\n\n"
"sepp256 - dropped some good GX hints\n"
"chishm, svpe, rodries, hermes - libfat port\n"
"alien - some graphics\n"
"jodi - the lulz\n\n"
"And last but not least, thanks to the authors of the following libraries:\n\n"
"wiiuse - para's Wiimote library, now integrated with libogc\n"
"libpng - the official PNG library\n"
"Mini-XML - small and efficient XML parsing library\n"
"FreeType - the free TrueType/OpenType font renderer\n";
string_about_trans = _("<YourLanguageHere> translation by <YourNickNameHere>");
if (!i18n_have_mo())
string_about_trans = "";
string_about_theme = _("Theme:");
if (string_about_gen)
free(string_about_gen);
string_about_gen = pmalloc(strlen(string_about_pre) +
strlen(string_about_post) +
strlen(string_about_trans) +
strlen(string_about_theme) + 128);
l_version = _("Version: %s");
l_coder = _("Author: %s");
}
void dialogs_init (void) {
string_about_gen = NULL;
dialogs_theme_reinit();
}
void dialogs_deinit (void) {
free(string_about_gen);
}
void dialog_fade (view *v, bool fade_in) {
float val;
float step;
s16 y;
float yf;
u32 c;
u8 stepa;
u8 i;
if (fade_in) {
val = 0;
step = M_PI / (2 * TRANS_STEPS);
y = v->coords.y + view_height;
c = DIALOG_MASK_COLOR & 0xffffff00;
stepa = (DIALOG_MASK_COLOR & 0xff) / TRANS_STEPS;
} else {
val = M_PI;
step = M_PI / (2 * TRANS_STEPS);
y = v->coords.y;
c = DIALOG_MASK_COLOR;
stepa = -(DIALOG_MASK_COLOR & 0xff) / TRANS_STEPS;
}
yf = view_height;
for (i = 0; i < TRANS_STEPS; ++i) {
v->coords.y = y - roundf (yf * sinf (val));
val += step;
c += stepa;
view_plot (v, c, NULL, NULL, NULL);
}
}
view * dialog_app (const app_entry *entry, const view *sub_view) {
view *v;
u16 x, gap;
char *name;
char coder[64];
char version[64];
const char *desc;
u16 ym, hm, yb;
if (entry->meta && entry->meta->name)
name = entry->meta->name;
else
name = entry->dirname;
if (entry->meta && entry->meta->coder)
snprintf (coder, sizeof (coder), l_coder, entry->meta->coder);
else
*coder = 0;
if (entry->meta && entry->meta->version)
snprintf (version, sizeof (version), l_version, entry->meta->version);
else
*version = 0;
if (entry->meta && entry->meta->long_description)
desc = entry->meta->long_description;
else
desc = app_entry_desc_default;
v = view_new (11, sub_view, (view_width - theme_gfx[THEME_DIALOG]->w) / 2,
44, TEX_LAYER_DIALOGS, PADS_B);
widget_image(&v->widgets[0], 0, 0, 0, theme_gfx[THEME_DIALOG],
NULL, false, NULL);
widget_label (&v->widgets[1], 32, 16, 1, name,
theme_gfx[THEME_DIALOG]->w - 64, FA_CENTERED, FA_ASCENDER,
FONT_DLGTITLE);
if (entry->icon)
widget_image(&v->widgets[2], 32, 48, 1, entry->icon, NULL, false, NULL);
widget_label (&v->widgets[3], 48 + APP_ENTRY_ICON_WIDTH, 72, 1, version,
theme_gfx[THEME_DIALOG]->w - 72 - APP_ENTRY_ICON_WIDTH,
FA_LEFT, FA_DESCENDER, FONT_LABEL);
widget_label (&v->widgets[4], 48 + APP_ENTRY_ICON_WIDTH, 72, 1, coder,
theme_gfx[THEME_DIALOG]->w - 72 - APP_ENTRY_ICON_WIDTH,
FA_LEFT, FA_ASCENDER, FONT_LABEL);
yb = theme_gfx[THEME_DIALOG]->h - theme_gfx[THEME_BUTTON_TINY]->h - 16;
ym = 48 + APP_ENTRY_ICON_HEIGHT + 8;
hm = yb - ym - 8;
widget_memo_deco (&v->widgets[5], 32, ym, 1,
theme_gfx[THEME_DIALOG]->w - 64, hm, desc, FA_LEFT);
gap = (theme_gfx[THEME_DIALOG]->w -
theme_gfx[THEME_BUTTON_TINY]->w * 3) / 4;
x = gap;
widget_button (&v->widgets[8], x, yb, 1, BTN_TINY, caption_delete);
x += gap + theme_gfx[THEME_BUTTON_TINY]->w;
widget_button (&v->widgets[9], x, yb, 1, BTN_TINY, caption_load);
x += gap + theme_gfx[THEME_BUTTON_TINY]->w;
widget_button (&v->widgets[10], x, yb, 1, BTN_TINY, caption_back);
view_set_focus (v, 10);
return v;
}
view * dialog_progress (const view *sub_view, const char *caption, u32 max) {
view *v;
v = view_new (1, sub_view, (view_width - theme_gfx[THEME_PROGRESS]->w) / 2,
(view_height - theme_gfx[THEME_PROGRESS]->h) / 2,
TEX_LAYER_DIALOGS, 0);
widget_progress (&v->widgets[0], 0, 0, 0, caption, max);
widget_set_progress (&v->widgets[0], 0);
return v;
}
void dialog_set_progress (const view *v, u32 progress) {
widget_set_progress (&v->widgets[0], progress);
}
view * dialog_about (const view *sub_view) {
view *v;
u16 ym, hm, yb, hmn;
u8 l, hf;
strcpy(string_about_gen, string_about_pre);
if (string_about_trans && strlen(string_about_trans)) {
strcat(string_about_gen, "\n\n");
strcat(string_about_gen, string_about_trans);
}
if (theme.description && strlen(theme.description)) {
strcat(string_about_gen, "\n\n");
strcat(string_about_gen, string_about_theme);
strcat(string_about_gen, " ");
strcat(string_about_gen, theme.description);
}
strcat(string_about_gen, "\n\n");
strcat(string_about_gen, string_about_post);
v = view_new (3, sub_view, (view_width - theme_gfx[THEME_DIALOG]->w) / 2,
44, TEX_LAYER_DIALOGS, 0);
widget_image (&v->widgets[0], 0, 0, 0, theme_gfx[THEME_DIALOG],
NULL, false, NULL);
widget_image (&v->widgets[1], (theme_gfx[THEME_DIALOG]->w -
theme_gfx[THEME_ABOUT]->w) / 2, 16, 1,
theme_gfx[THEME_ABOUT], NULL, false, NULL);
yb = theme_gfx[THEME_DIALOG]->h - 16;
ym = 16 + theme_gfx[THEME_ABOUT]->h + 8;
hm = yb - ym - 8;
hf = font_get_y_spacing(FONT_MEMO);
l = hm / hf;
hmn = l * hf;
if (hmn < hm) {
ym += (hm - hmn) / 2;
hm = hmn;
}
widget_memo (&v->widgets[2], 32, ym, 1, theme_gfx[THEME_DIALOG]->w - 64,
hm, string_about_gen, FA_CENTERED);
v->widgets[2].cur = CUR_STD;
return v;
}
static view *dialog_message(const view *sub_view, dialog_message_type type,
dialog_message_buttons buttons, const char *text,
u8 focus) {
view *v;
u8 c;
u16 x, gap;
const char *caption = NULL, *b1 = NULL, *b2 = NULL;
u16 ym, hm, yb;
u8 hf;
gfx_entity *icon = NULL;
c = 6;
switch (buttons) {
case DLGB_OK:
c++;
break;
case DLGB_OKCANCEL:
case DLGB_YESNO:
c += 2;
break;
}
v = view_new (c, sub_view, (view_width - theme_gfx[THEME_DIALOG]->w) / 2,
44, TEX_LAYER_DIALOGS, PADS_B);
widget_image (&v->widgets[0], 0, 0, 0, theme_gfx[THEME_DIALOG],
NULL, false, NULL);
switch (type) {
case DLGMT_INFO:
caption = caption_info;
icon = theme_gfx[THEME_DLG_INFO];
break;
case DLGMT_CONFIRM:
caption = caption_confirm;
icon = theme_gfx[THEME_DLG_CONFIRM];
break;
case DLGMT_WARNING:
caption = caption_warning;
icon = theme_gfx[THEME_DLG_WARNING];
break;
case DLGMT_ERROR:
caption = caption_error;
icon = theme_gfx[THEME_DLG_ERROR];
break;
}
widget_image (&v->widgets[1], 128, 24, 0, icon, NULL, false, NULL);
widget_label (&v->widgets[2], 32, 32, 1, caption,
theme_gfx[THEME_DIALOG]->w - 64, FA_CENTERED, FA_ASCENDER,
FONT_DLGTITLE);
hf = font_get_height (FONT_DLGTITLE);
yb = theme_gfx[THEME_DIALOG]->h - theme_gfx[THEME_BUTTON_SMALL]->h - 32;
ym = 32 + hf + 8;
hm = yb - ym - 8;
widget_memo_deco (&v->widgets[3], 32, ym, 1,
theme_gfx[THEME_DIALOG]->w - 64, hm, text, FA_CENTERED);
switch (buttons) {
case DLGB_OK:
b1 = caption_ok;
b2 = NULL;
break;
case DLGB_OKCANCEL:
b1 = caption_ok;
b2 = caption_cancel;
break;
case DLGB_YESNO:
b1 = caption_yes;
b2 = caption_no;
break;
}
if (b2) {
gap = (theme_gfx[THEME_DIALOG]->w -
theme_gfx[THEME_BUTTON_SMALL]->w * 2) / 3;
x = gap;
widget_button (&v->widgets[6], x, yb, 1, BTN_SMALL, b1);
x += gap + theme_gfx[THEME_BUTTON_SMALL]->w;
widget_button (&v->widgets[7], x, yb, 1, BTN_SMALL, b2);
} else {
gap = (theme_gfx[THEME_DIALOG]->w -
theme_gfx[THEME_BUTTON_SMALL]->w) / 2;
x = gap;
widget_button (&v->widgets[6], x, yb, 1, BTN_SMALL, b1);
}
view_set_focus (v, 6 + focus);
return v;
}
s8 show_message (const view *sub_view, dialog_message_type type,
dialog_message_buttons buttons, const char *text, u8 focus) {
view *v;
u8 fhw;
u32 bd;
s8 res;
s16 mm;
v = dialog_message (sub_view, type, buttons, text, focus);
dialog_fade (v, true);
fhw = font_get_y_spacing(FONT_MEMO);
while (true) {
view_plot (v, DIALOG_MASK_COLOR, &bd, NULL, NULL);
if (bd & PADS_LEFT)
view_set_focus_prev (v);
if (bd & PADS_RIGHT)
view_set_focus_next (v);
mm = 0;
if (bd & PADS_UP)
mm += fhw;
if (bd & PADS_DOWN)
mm -= fhw;
mm += controls_sticky() / 8;
if (v->drag && (v->drag_widget == 4))
mm += -v->drag_y / 32;
widget_scroll_memo_deco (&v->widgets[3], mm);
if ((bd & PADS_A) && (v->focus != -1))
break;
}
res = v->focus - 6;
dialog_fade (v, false);
view_free (v);
return res;
}
#define DLG_DEV_FIRST 4
dialog_options_result show_options_dialog(const view *sub_view) {
u32 frame = 0;
view *v;
dialog_options_result ret;
int device;
app_sort sort;
bool status[DEVICE_COUNT];
u32 i, bd;
app_entry_poll_status(true);
v = view_new (12, sub_view, (view_width - theme_gfx[THEME_DIALOG]->w) / 2,
44, TEX_LAYER_DIALOGS, PADS_B);
widget_image (&v->widgets[0], 0, 0, 0, theme_gfx[THEME_DIALOG],
NULL, false, NULL);
widget_label (&v->widgets[1], 32, 16, 1, caption_options,
theme_gfx[THEME_DIALOG]->w - 64, FA_CENTERED, FA_ASCENDER, FONT_DLGTITLE);
widget_label (&v->widgets[2], 32, 60, 1, caption_device,
theme_gfx[THEME_DIALOG]->w - 64, FA_LEFT, FA_DESCENDER, FONT_LABEL);
widget_label (&v->widgets[3], 32, 212, 1, caption_sort_by,
theme_gfx[THEME_DIALOG]->w - 64, FA_LEFT, FA_DESCENDER, FONT_LABEL);
widget_button (&v->widgets[4], 52, 64, 1, BTN_SMALL, NULL);
widget_button (&v->widgets[5], 268, 64, 1, BTN_SMALL, NULL);
widget_button (&v->widgets[6], 52, 128, 1, BTN_SMALL, NULL);
widget_button (&v->widgets[7], 268, 128, 1, BTN_SMALL, NULL);
widget_button (&v->widgets[8], 52, 216, 1, BTN_SMALL, NULL);
widget_button (&v->widgets[9], 268, 216, 1, BTN_SMALL, NULL);
widget_button (&v->widgets[10], 32,
theme_gfx[THEME_DIALOG]->h -
theme_gfx[THEME_BUTTON_SMALL]->h - 16 , 1, BTN_SMALL,
caption_ok);
widget_button (&v->widgets[11], theme_gfx[THEME_DIALOG]->w -
theme_gfx[THEME_BUTTON_SMALL]->w - 32,
theme_gfx[THEME_DIALOG]->h -
theme_gfx[THEME_BUTTON_SMALL]->h - 16 , 1, BTN_SMALL,
caption_back);
device = app_entry_get_status(status);
sort = app_entry_get_sort();
ret.confirmed = false;
ret.device = device;
ret.sort = sort;
for (i = 0; i < DEVICE_COUNT; ++i) {
if (i == device)
widget_button_set_caption(&v->widgets[DLG_DEV_FIRST + i],
FONT_BUTTON,
caption_device_names[i]);
else
widget_button_set_caption(&v->widgets[DLG_DEV_FIRST + i],
FONT_BUTTON_DESEL,
caption_device_names[i]);
widget_set_flag (&v->widgets[DLG_DEV_FIRST + i], WF_ENABLED, status[i]);
}
if (ret.sort == APP_SORT_DATE) {
widget_button_set_caption(&v->widgets[8],
FONT_BUTTON_DESEL,
caption_sort_name);
widget_button_set_caption(&v->widgets[9],
FONT_BUTTON,
caption_sort_date);
} else {
widget_button_set_caption(&v->widgets[8],
FONT_BUTTON,
caption_sort_name);
widget_button_set_caption(&v->widgets[9],
FONT_BUTTON_DESEL,
caption_sort_date);
}
view_set_focus (v, 11);
dialog_fade (v, true);
while (true) {
app_entry_get_status(status);
for (i = 0; i < DEVICE_COUNT; ++i)
widget_set_flag (&v->widgets[DLG_DEV_FIRST + i], WF_ENABLED,
status[i]);
view_plot (v, DIALOG_MASK_COLOR, &bd, NULL, NULL);
frame++;
if (bd & PADS_LEFT)
view_set_focus_prev (v);
if (bd & PADS_RIGHT)
view_set_focus_next (v);
if (bd & PADS_UP)
if (v->focus == view_move_focus(v, -2))
view_move_focus(v, -4);
if (bd & PADS_DOWN)
if (v->focus == view_move_focus(v, 2))
view_move_focus(v, 4);
if (bd & (PADS_B | PADS_1))
break;
if ((bd & PADS_A) && (v->focus != -1)) {
if ((v->focus >= DLG_DEV_FIRST) &&
(v->focus < DLG_DEV_FIRST + DEVICE_COUNT)) {
widget_button_set_caption(&v->widgets[DLG_DEV_FIRST + ret.device],
FONT_BUTTON_DESEL,
caption_device_names[ret.device]);
ret.device = v->focus - DLG_DEV_FIRST;
widget_button_set_caption(&v->widgets[DLG_DEV_FIRST + ret.device],
FONT_BUTTON,
caption_device_names[ret.device]);
} else if (v->focus == 8) {
ret.sort = APP_SORT_NAME;
widget_button_set_caption(&v->widgets[8],
FONT_BUTTON,
caption_sort_name);
widget_button_set_caption(&v->widgets[9],
FONT_BUTTON_DESEL,
caption_sort_date);
} else if (v->focus == 9) {
ret.sort = APP_SORT_DATE;
widget_button_set_caption(&v->widgets[8],
FONT_BUTTON_DESEL,
caption_sort_name);
widget_button_set_caption(&v->widgets[9],
FONT_BUTTON,
caption_sort_date);
} else if ((v->focus == 10) || (v->focus == 11)) {
break;
}
}
if ((frame % 30) == 0)
app_entry_poll_status(false);
}
if ((bd & PADS_A) && (v->focus == 10))
ret.confirmed = true;
dialog_fade (v, false);
view_free (v);
return ret;
}

View File

@@ -0,0 +1,46 @@
#ifndef _DIALOGS_H_
#define _DIALOGS_H_
#include <gctypes.h>
#include "gfx.h"
#include "view.h"
typedef enum {
DLGMT_INFO = 0,
DLGMT_CONFIRM,
DLGMT_WARNING,
DLGMT_ERROR
} dialog_message_type;
typedef enum {
DLGB_OK,
DLGB_OKCANCEL,
DLGB_YESNO
} dialog_message_buttons;
typedef struct {
bool confirmed;
int device;
app_sort sort;
} dialog_options_result;
extern u16 width_dialog, height_dialog;
void dialogs_init (void);
void dialogs_theme_reinit (void);
void dialogs_deinit (void);
void dialog_fade (view *v, bool fade_in);
view * dialog_app (const app_entry *entry, const view *sub_view);
view * dialog_progress (const view *sub_view, const char *caption, u32 max);
void dialog_set_progress (const view *v, u32 progress);
view * dialog_about (const view *sub_view);
s8 show_message (const view *sub_view, dialog_message_type type,
dialog_message_buttons buttons, const char *text, u8 focus);
dialog_options_result show_options_dialog(const view *sub_view);
#endif

View File

@@ -0,0 +1,79 @@
#include <stdlib.h>
#include <string.h>
#include <ogcsys.h>
#include <gccore.h>
#include "../config.h"
static u32 inbuf[8] __attribute__((aligned(0x20)));
static u32 outbuf[8] __attribute__((aligned(0x20)));
static s32 _dvd_fd = -1;
static const char _dvd_path[] __attribute__((aligned(0x20))) = "/dev/di";
typedef enum {
WDVD_OPEN = 0,
WDVD_STOP,
WDVD_CLOSE,
WDVD_DONE
} wiidvd_state;
static wiidvd_state _state;
static s32 __WiiDVD_Callback(s32 result, void *userdata)
{
s32 res = -1;
switch (_state) {
case WDVD_OPEN:
_dvd_fd = result;
if (_dvd_fd < 0)
return 0;
memset(inbuf, 0, 0x20);
inbuf[0x00] = 0xe3000000;
inbuf[0x01] = 0;
inbuf[0x02] = 0;
_state = WDVD_STOP;
res = IOS_IoctlAsync( _dvd_fd, 0xe3, inbuf, 0x20, outbuf, 0x20,
__WiiDVD_Callback, NULL);
break;
case WDVD_STOP:
_state = WDVD_CLOSE;
res = IOS_CloseAsync(_dvd_fd, __WiiDVD_Callback, NULL);
break;
case WDVD_CLOSE:
_dvd_fd = -1;
_state = WDVD_DONE;
res = 0;
break;
default:
break;
}
return res;
}
s32 WiiDVD_StopMotorAsync(void) {
_state = WDVD_OPEN;
gprintf("starting DVD motor stop callback chain\n");
return IOS_OpenAsync(_dvd_path, 0, __WiiDVD_Callback, NULL);
}
void WiiDVD_ShutDown(void) {
s32 fd = _dvd_fd;
if (fd > 0) {
_dvd_fd = -1;
_state = WDVD_DONE;
IOS_Close(fd);
gprintf("killed DVD motor stop callback chain\n");
}
}

View File

@@ -0,0 +1,10 @@
#ifndef _DVD_H_
#define _DVD_H_
#include <gctypes.h>
s32 WiiDVD_StopMotorAsync(void);
void WiiDVD_ShutDown(void);
#endif

View File

@@ -0,0 +1,413 @@
// Copyright 2007-2009 Segher Boessenkool <segher@kernel.crashing.org>
// Licensed under the terms of the GNU GPL, version 2
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
#include <string.h>
#include <ogcsys.h>
#include "sha1.h"
#include "ecdsa.h"
#include "../config.h"
#ifdef ENABLE_UPDATES
// order of the addition group of points
static u8 ec_N[30] =
"\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x13\xe9\x74\xe7\x2f\x8a\x69\x22\x03\x1d\x26\x03\xcf\xe0\xd7";
// base point
static u8 ec_G[60] =
"\x00\xfa\xc9\xdf\xcb\xac\x83\x13\xbb\x21\x39\xf1\xbb\x75\x5f"
"\xef\x65\xbc\x39\x1f\x8b\x36\xf8\xf8\xeb\x73\x71\xfd\x55\x8b"
"\x01\x00\x6a\x08\xa4\x19\x03\x35\x06\x78\xe5\x85\x28\xbe\xbf"
"\x8a\x0b\xef\xf8\x67\xa7\xca\x36\x71\x6f\x7e\x01\xf8\x10\x52";
static const u8 square[16] =
"\x00\x01\x04\x05\x10\x11\x14\x15\x40\x41\x44\x45\x50\x51\x54\x55";
static void bn_zero(u8 *d, u32 n)
{
memset(d, 0, n);
}
static void bn_copy(u8 *d, const u8 *a, u32 n)
{
memcpy(d, a, n);
}
static int bn_compare(const u8 *a, const u8 *b, u32 n)
{
u32 i;
for (i = 0; i < n; i++) {
if (a[i] < b[i])
return -1;
if (a[i] > b[i])
return 1;
}
return 0;
}
static void bn_sub_modulus(u8 *a, const u8 *N, u32 n)
{
u32 i;
u32 dig;
u8 c;
c = 0;
for (i = n - 1; i < n; i--) {
dig = N[i] + c;
c = (a[i] < dig);
a[i] -= dig;
}
}
static void bn_add(u8 *d, const u8 *a, const u8 *b, const u8 *N, u32 n)
{
u32 i;
u32 dig;
u8 c;
c = 0;
for (i = n - 1; i < n; i--) {
dig = a[i] + b[i] + c;
c = (dig >= 0x100);
d[i] = dig;
}
if (c)
bn_sub_modulus(d, N, n);
if (bn_compare(d, N, n) >= 0)
bn_sub_modulus(d, N, n);
}
static void bn_mul(u8 *d, const u8 *a, const u8 *b, const u8 *N, u32 n)
{
u32 i;
u8 mask;
bn_zero(d, n);
for (i = 0; i < n; i++)
for (mask = 0x80; mask != 0; mask >>= 1) {
bn_add(d, d, d, N, n);
if ((a[i] & mask) != 0)
bn_add(d, d, b, N, n);
}
}
static void bn_exp(u8 *d, const u8 *a, const u8 *N, u32 n, const u8 *e, u32 en)
{
u8 t[512];
u32 i;
u8 mask;
bn_zero(d, n);
d[n-1] = 1;
for (i = 0; i < en; i++)
for (mask = 0x80; mask != 0; mask >>= 1) {
bn_mul(t, d, d, N, n);
if ((e[i] & mask) != 0)
bn_mul(d, t, a, N, n);
else
bn_copy(d, t, n);
}
}
// only for prime N -- stupid but lazy, see if I care
static void bn_inv(u8 *d, const u8 *a, const u8 *N, u32 n)
{
u8 t[512], s[512];
bn_copy(t, N, n);
bn_zero(s, n);
s[n-1] = 2;
bn_sub_modulus(t, s, n);
bn_exp(d, a, N, n, t, n);
}
static void elt_copy(u8 *d, const u8 *a)
{
memcpy(d, a, 30);
}
static void elt_zero(u8 *d)
{
memset(d, 0, 30);
}
static int elt_is_zero(const u8 *d)
{
u32 i;
for (i = 0; i < 30; i++)
if (d[i] != 0)
return 0;
return 1;
}
static void elt_add(u8 *d, u8 *a, const u8 *b)
{
u32 i;
for (i = 0; i < 30; i++)
d[i] = a[i] ^ b[i];
}
static void elt_mul_x(u8 *d, u8 *a)
{
u8 carry, x, y;
u32 i;
carry = a[0] & 1;
x = 0;
for (i = 0; i < 29; i++) {
y = a[i + 1];
d[i] = x ^ (y >> 7);
x = y << 1;
}
d[29] = x ^ carry;
d[20] ^= carry << 2;
}
static void elt_mul(u8 *d, u8 *a, u8 *b)
{
u32 i, n;
u8 mask;
elt_zero(d);
i = 0;
mask = 1;
for (n = 0; n < 233; n++) {
elt_mul_x(d, d);
if ((a[i] & mask) != 0)
elt_add(d, d, b);
mask >>= 1;
if (mask == 0) {
mask = 0x80;
i++;
}
}
}
static void elt_square_to_wide(u8 *d, u8 *a)
{
u32 i;
for (i = 0; i < 30; i++) {
d[2*i] = square[a[i] >> 4];
d[2*i + 1] = square[a[i] & 15];
}
}
static void wide_reduce(u8 *d)
{
u32 i;
u8 x;
for (i = 0; i < 30; i++) {
x = d[i];
d[i + 19] ^= x >> 7;
d[i + 20] ^= x << 1;
d[i + 29] ^= x >> 1;
d[i + 30] ^= x << 7;
}
x = d[30] & ~1;
d[49] ^= x >> 7;
d[50] ^= x << 1;
d[59] ^= x >> 1;
d[30] &= 1;
}
static void elt_square(u8 *d, u8 *a)
{
u8 wide[60];
elt_square_to_wide(wide, a);
wide_reduce(wide);
elt_copy(d, wide + 30);
}
static void itoh_tsujii(u8 *d, u8 *a, u8 *b, u32 j)
{
u8 t[30];
elt_copy(t, a);
while (j--) {
elt_square(d, t);
elt_copy(t, d);
}
elt_mul(d, t, b);
}
static void elt_inv(u8 *d, u8 *a)
{
u8 t[30];
u8 s[30];
itoh_tsujii(t, a, a, 1);
itoh_tsujii(s, t, a, 1);
itoh_tsujii(t, s, s, 3);
itoh_tsujii(s, t, a, 1);
itoh_tsujii(t, s, s, 7);
itoh_tsujii(s, t, t, 14);
itoh_tsujii(t, s, a, 1);
itoh_tsujii(s, t, t, 29);
itoh_tsujii(t, s, s, 58);
itoh_tsujii(s, t, t, 116);
elt_square(d, s);
}
static int point_is_zero(const u8 *p)
{
return elt_is_zero(p) && elt_is_zero(p + 30);
}
static void point_double(u8 *r, u8 *p)
{
u8 s[30], t[30];
u8 *px, *py, *rx, *ry;
px = p;
py = p + 30;
rx = r;
ry = r + 30;
if (elt_is_zero(px)) {
elt_zero(rx);
elt_zero(ry);
return;
}
elt_inv(t, px);
elt_mul(s, py, t);
elt_add(s, s, px);
elt_square(t, px);
elt_square(rx, s);
elt_add(rx, rx, s);
rx[29] ^= 1;
elt_mul(ry, s, rx);
elt_add(ry, ry, rx);
elt_add(ry, ry, t);
}
static void point_add(u8 *r, u8 *p, const u8 *q)
{
u8 s[30], t[30], u[30];
u8 *px, *py, *rx, *ry;
const u8 *qx, *qy;
px = p;
py = p + 30;
qx = q;
qy = q + 30;
rx = r;
ry = r + 30;
if (point_is_zero(p)) {
elt_copy(rx, qx);
elt_copy(ry, qy);
return;
}
if (point_is_zero(q)) {
elt_copy(rx, px);
elt_copy(ry, py);
return;
}
elt_add(u, px, qx);
if (elt_is_zero(u)) {
elt_add(u, py, qy);
if (elt_is_zero(u))
point_double(r, p);
else {
elt_zero(rx);
elt_zero(ry);
}
return;
}
elt_inv(t, u);
elt_add(u, py, qy);
elt_mul(s, t, u);
elt_square(t, s);
elt_add(t, t, s);
elt_add(t, t, qx);
t[29] ^= 1;
elt_mul(u, s, t);
elt_add(s, u, py);
elt_add(rx, t, px);
elt_add(ry, s, rx);
}
static void point_mul(u8 *d, u8 *a, const u8 *b) // a is bignum
{
u32 i;
u8 mask;
elt_zero(d);
elt_zero(d + 30);
for (i = 0; i < 30; i++)
for (mask = 0x80; mask != 0; mask >>= 1) {
point_double(d, d);
if ((a[i] & mask) != 0)
point_add(d, d, b);
}
}
int check_ecdsa(const u8 *Q, u8 *R, u8 *S, u8 *hash)
{
u8 Sinv[30];
u8 e[30];
u8 w1[30], w2[30];
u8 r1[60], r2[60];
bn_inv(Sinv, S, ec_N, 30);
elt_zero(e);
memcpy(e + 10, hash, 20);
bn_mul(w1, e, Sinv, ec_N, 30);
bn_mul(w2, R, Sinv, ec_N, 30);
point_mul(r1, w1, ec_G);
point_mul(r2, w2, Q);
point_add(r1, r1, r2);
if (bn_compare(r1, ec_N, 30) >= 0)
bn_sub_modulus(r1, ec_N, 30);
return (bn_compare(r1, R, 30) == 0);
}
#endif

View File

@@ -0,0 +1,8 @@
#ifndef _ECDSA_H_
#define _ECDSA_H_
#include <ogcsys.h>
int check_ecdsa(const u8 *Q, u8 *R, u8 *S, u8 *hash);
#endif

View File

@@ -0,0 +1,594 @@
/*
* Copyright (c) 1995, 1996, 2001, 2002
* Erik Theisen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This is the ELF ABI header file
* formerly known as "elf_abi.h".
*/
#ifndef _ELF_ABI_H
#define _ELF_ABI_H
#include <gctypes.h>
/*
* This version doesn't work for 64-bit ABIs - Erik.
*/
/*
* These typedefs need to be handled better.
*/
typedef u32 Elf32_Addr; /* Unsigned program address */
typedef u32 Elf32_Off; /* Unsigned file offset */
typedef s32 Elf32_Sword; /* Signed large integer */
typedef u32 Elf32_Word; /* Unsigned large integer */
typedef u16 Elf32_Half; /* Unsigned medium integer */
/* e_ident[] identification indexes */
#define EI_MAG0 0 /* file ID */
#define EI_MAG1 1 /* file ID */
#define EI_MAG2 2 /* file ID */
#define EI_MAG3 3 /* file ID */
#define EI_CLASS 4 /* file class */
#define EI_DATA 5 /* data encoding */
#define EI_VERSION 6 /* ELF header version */
#define EI_OSABI 7 /* OS/ABI specific ELF extensions */
#define EI_ABIVERSION 8 /* ABI target version */
#define EI_PAD 9 /* start of pad bytes */
#define EI_NIDENT 16 /* Size of e_ident[] */
/* e_ident[] magic number */
#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */
#define ELFMAG1 'E' /* e_ident[EI_MAG1] */
#define ELFMAG2 'L' /* e_ident[EI_MAG2] */
#define ELFMAG3 'F' /* e_ident[EI_MAG3] */
#define ELFMAG "\177ELF" /* magic */
#define SELFMAG 4 /* size of magic */
/* e_ident[] file class */
#define ELFCLASSNONE 0 /* invalid */
#define ELFCLASS32 1 /* 32-bit objs */
#define ELFCLASS64 2 /* 64-bit objs */
#define ELFCLASSNUM 3 /* number of classes */
/* e_ident[] data encoding */
#define ELFDATANONE 0 /* invalid */
#define ELFDATA2LSB 1 /* Little-Endian */
#define ELFDATA2MSB 2 /* Big-Endian */
#define ELFDATANUM 3 /* number of data encode defines */
/* e_ident[] OS/ABI specific ELF extensions */
#define ELFOSABI_NONE 0 /* No extension specified */
#define ELFOSABI_HPUX 1 /* Hewlett-Packard HP-UX */
#define ELFOSABI_NETBSD 2 /* NetBSD */
#define ELFOSABI_LINUX 3 /* Linux */
#define ELFOSABI_SOLARIS 6 /* Sun Solaris */
#define ELFOSABI_AIX 7 /* AIX */
#define ELFOSABI_IRIX 8 /* IRIX */
#define ELFOSABI_FREEBSD 9 /* FreeBSD */
#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX */
#define ELFOSABI_MODESTO 11 /* Novell Modesto */
#define ELFOSABI_OPENBSD 12 /* OpenBSD */
/* 64-255 Architecture-specific value range */
/* e_ident[] ABI Version */
#define ELFABIVERSION 0
/* e_ident */
#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
(ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
(ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
(ehdr).e_ident[EI_MAG3] == ELFMAG3)
/* ELF Header */
typedef struct elfhdr{
unsigned char e_ident[EI_NIDENT]; /* ELF Identification */
Elf32_Half e_type; /* object file type */
Elf32_Half e_machine; /* machine */
Elf32_Word e_version; /* object file version */
Elf32_Addr e_entry; /* virtual entry point */
Elf32_Off e_phoff; /* program header table offset */
Elf32_Off e_shoff; /* section header table offset */
Elf32_Word e_flags; /* processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size */
Elf32_Half e_phentsize; /* program header entry size */
Elf32_Half e_phnum; /* number of program header entries */
Elf32_Half e_shentsize; /* section header entry size */
Elf32_Half e_shnum; /* number of section header entries */
Elf32_Half e_shstrndx; /* section header table's "section
header string table" entry offset */
} Elf32_Ehdr;
/* e_type */
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* relocatable file */
#define ET_EXEC 2 /* executable file */
#define ET_DYN 3 /* shared object file */
#define ET_CORE 4 /* core file */
#define ET_NUM 5 /* number of types */
#define ET_LOOS 0xfe00 /* reserved range for operating */
#define ET_HIOS 0xfeff /* system specific e_type */
#define ET_LOPROC 0xff00 /* reserved range for processor */
#define ET_HIPROC 0xffff /* specific e_type */
/* e_machine */
#define EM_NONE 0 /* No Machine */
#define EM_M32 1 /* AT&T WE 32100 */
#define EM_SPARC 2 /* SPARC */
#define EM_386 3 /* Intel 80386 */
#define EM_68K 4 /* Motorola 68000 */
#define EM_88K 5 /* Motorola 88000 */
#if 0
#define EM_486 6 /* RESERVED - was Intel 80486 */
#endif
#define EM_860 7 /* Intel 80860 */
#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */
#define EM_S370 9 /* IBM System/370 Processor */
#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */
#if 0
#define EM_SPARC64 11 /* RESERVED - was SPARC v9
64-bit unoffical */
#endif
/* RESERVED 11-14 for future use */
#define EM_PARISC 15 /* HPPA */
/* RESERVED 16 for future use */
#define EM_VPP500 17 /* Fujitsu VPP500 */
#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */
#define EM_960 19 /* Intel 80960 */
#define EM_PPC 20 /* PowerPC */
#define EM_PPC64 21 /* 64-bit PowerPC */
#define EM_S390 22 /* IBM System/390 Processor */
/* RESERVED 23-35 for future use */
#define EM_V800 36 /* NEC V800 */
#define EM_FR20 37 /* Fujitsu FR20 */
#define EM_RH32 38 /* TRW RH-32 */
#define EM_RCE 39 /* Motorola RCE */
#define EM_ARM 40 /* Advanced Risc Machines ARM */
#define EM_ALPHA 41 /* Digital Alpha */
#define EM_SH 42 /* Hitachi SH */
#define EM_SPARCV9 43 /* SPARC Version 9 */
#define EM_TRICORE 44 /* Siemens TriCore embedded processor */
#define EM_ARC 45 /* Argonaut RISC Core */
#define EM_H8_300 46 /* Hitachi H8/300 */
#define EM_H8_300H 47 /* Hitachi H8/300H */
#define EM_H8S 48 /* Hitachi H8S */
#define EM_H8_500 49 /* Hitachi H8/500 */
#define EM_IA_64 50 /* Intel Merced */
#define EM_MIPS_X 51 /* Stanford MIPS-X */
#define EM_COLDFIRE 52 /* Motorola Coldfire */
#define EM_68HC12 53 /* Motorola M68HC12 */
#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/
#define EM_PCP 55 /* Siemens PCP */
#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
#define EM_NDR1 57 /* Denso NDR1 microprocessor */
#define EM_STARCORE 58 /* Motorola Start*Core processor */
#define EM_ME16 59 /* Toyota ME16 processor */
#define EM_ST100 60 /* STMicroelectronic ST100 processor */
#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/
#define EM_X86_64 62 /* AMD x86-64 */
#define EM_PDSP 63 /* Sony DSP Processor */
/* RESERVED 64,65 for future use */
#define EM_FX66 66 /* Siemens FX66 microcontroller */
#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */
#define EM_SVX 73 /* Silicon Graphics SVx */
#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */
#define EM_VAX 75 /* Digital VAX */
#define EM_CHRIS 76 /* Axis Communications embedded proc. */
#define EM_JAVELIN 77 /* Infineon Technologies emb. proc. */
#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */
#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */
#define EM_MMIX 80 /* Donald Knuth's edu 64-bit proc. */
#define EM_HUANY 81 /* Harvard University mach-indep objs */
#define EM_PRISM 82 /* SiTera Prism */
#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */
#define EM_FR30 84 /* Fujitsu FR30 */
#define EM_D10V 85 /* Mitsubishi DV10V */
#define EM_D30V 86 /* Mitsubishi DV30V */
#define EM_V850 87 /* NEC v850 */
#define EM_M32R 88 /* Mitsubishi M32R */
#define EM_MN10300 89 /* Matsushita MN10200 */
#define EM_MN10200 90 /* Matsushita MN10200 */
#define EM_PJ 91 /* picoJava */
#define EM_NUM 92 /* number of machine types */
/* Version */
#define EV_NONE 0 /* Invalid */
#define EV_CURRENT 1 /* Current */
#define EV_NUM 2 /* number of versions */
/* Section Header */
typedef struct {
Elf32_Word sh_name; /* name - index into section header
string table section */
Elf32_Word sh_type; /* type */
Elf32_Word sh_flags; /* flags */
Elf32_Addr sh_addr; /* address */
Elf32_Off sh_offset; /* file offset */
Elf32_Word sh_size; /* section size */
Elf32_Word sh_link; /* section header table index link */
Elf32_Word sh_info; /* extra information */
Elf32_Word sh_addralign; /* address alignment */
Elf32_Word sh_entsize; /* section entry size */
} Elf32_Shdr;
/* Special Section Indexes */
#define SHN_UNDEF 0 /* undefined */
#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */
#define SHN_LOPROC 0xff00 /* reserved range for processor */
#define SHN_HIPROC 0xff1f /* specific section indexes */
#define SHN_LOOS 0xff20 /* reserved range for operating */
#define SHN_HIOS 0xff3f /* specific semantics */
#define SHN_ABS 0xfff1 /* absolute value */
#define SHN_COMMON 0xfff2 /* common symbol */
#define SHN_XINDEX 0xffff /* Index is an extra table */
#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */
/* sh_type */
#define SHT_NULL 0 /* inactive */
#define SHT_PROGBITS 1 /* program defined information */
#define SHT_SYMTAB 2 /* symbol table section */
#define SHT_STRTAB 3 /* string table section */
#define SHT_RELA 4 /* relocation section with addends*/
#define SHT_HASH 5 /* symbol hash table section */
#define SHT_DYNAMIC 6 /* dynamic section */
#define SHT_NOTE 7 /* note section */
#define SHT_NOBITS 8 /* no space section */
#define SHT_REL 9 /* relation section without addends */
#define SHT_SHLIB 10 /* reserved - purpose unknown */
#define SHT_DYNSYM 11 /* dynamic symbol table section */
#define SHT_INIT_ARRAY 14 /* Array of constructors */
#define SHT_FINI_ARRAY 15 /* Array of destructors */
#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
#define SHT_GROUP 17 /* Section group */
#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
#define SHT_NUM 19 /* number of section types */
#define SHT_LOOS 0x60000000 /* Start OS-specific */
#define SHT_HIOS 0x6fffffff /* End OS-specific */
#define SHT_LOPROC 0x70000000 /* reserved range for processor */
#define SHT_HIPROC 0x7fffffff /* specific section header types */
#define SHT_LOUSER 0x80000000 /* reserved range for application */
#define SHT_HIUSER 0xffffffff /* specific indexes */
/* Section names */
#define ELF_BSS ".bss" /* uninitialized data */
#define ELF_COMMENT ".comment" /* version control information */
#define ELF_DATA ".data" /* initialized data */
#define ELF_DATA1 ".data1" /* initialized data */
#define ELF_DEBUG ".debug" /* debug */
#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */
#define ELF_DYNSTR ".dynstr" /* dynamic string table */
#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */
#define ELF_FINI ".fini" /* termination code */
#define ELF_FINI_ARRAY ".fini_array" /* Array of destructors */
#define ELF_GOT ".got" /* global offset table */
#define ELF_HASH ".hash" /* symbol hash table */
#define ELF_INIT ".init" /* initialization code */
#define ELF_INIT_ARRAY ".init_array" /* Array of constuctors */
#define ELF_INTERP ".interp" /* Pathname of program interpreter */
#define ELF_LINE ".line" /* Symbolic line numnber information */
#define ELF_NOTE ".note" /* Contains note section */
#define ELF_PLT ".plt" /* Procedure linkage table */
#define ELF_PREINIT_ARRAY ".preinit_array" /* Array of pre-constructors */
#define ELF_REL_DATA ".rel.data" /* relocation data */
#define ELF_REL_FINI ".rel.fini" /* relocation termination code */
#define ELF_REL_INIT ".rel.init" /* relocation initialization code */
#define ELF_REL_DYN ".rel.dyn" /* relocaltion dynamic link info */
#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */
#define ELF_REL_TEXT ".rel.text" /* relocation code */
#define ELF_RODATA ".rodata" /* read-only data */
#define ELF_RODATA1 ".rodata1" /* read-only data */
#define ELF_SHSTRTAB ".shstrtab" /* section header string table */
#define ELF_STRTAB ".strtab" /* string table */
#define ELF_SYMTAB ".symtab" /* symbol table */
#define ELF_SYMTAB_SHNDX ".symtab_shndx"/* symbol table section index */
#define ELF_TBSS ".tbss" /* thread local uninit data */
#define ELF_TDATA ".tdata" /* thread local init data */
#define ELF_TDATA1 ".tdata1" /* thread local init data */
#define ELF_TEXT ".text" /* code */
/* Section Attribute Flags - sh_flags */
#define SHF_WRITE 0x1 /* Writable */
#define SHF_ALLOC 0x2 /* occupies memory */
#define SHF_EXECINSTR 0x4 /* executable */
#define SHF_MERGE 0x10 /* Might be merged */
#define SHF_STRINGS 0x20 /* Contains NULL terminated strings */
#define SHF_INFO_LINK 0x40 /* sh_info contains SHT index */
#define SHF_LINK_ORDER 0x80 /* Preserve order after combining*/
#define SHF_OS_NONCONFORMING 0x100 /* Non-standard OS specific handling */
#define SHF_GROUP 0x200 /* Member of section group */
#define SHF_TLS 0x400 /* Thread local storage */
#define SHF_MASKOS 0x0ff00000 /* OS specific */
#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor */
/* specific section attributes */
/* Section Group Flags */
#define GRP_COMDAT 0x1 /* COMDAT group */
#define GRP_MASKOS 0x0ff00000 /* Mask OS specific flags */
#define GRP_MASKPROC 0xf0000000 /* Mask processor specific flags */
/* Symbol Table Entry */
typedef struct elf32_sym {
Elf32_Word st_name; /* name - index into string table */
Elf32_Addr st_value; /* symbol value */
Elf32_Word st_size; /* symbol size */
unsigned char st_info; /* type and binding */
unsigned char st_other; /* 0 - no defined meaning */
Elf32_Half st_shndx; /* section header index */
} Elf32_Sym;
/* Symbol table index */
#define STN_UNDEF 0 /* undefined */
/* Extract symbol info - st_info */
#define ELF32_ST_BIND(x) ((x) >> 4)
#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf)
#define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf))
#define ELF32_ST_VISIBILITY(x) ((x) & 0x3)
/* Symbol Binding - ELF32_ST_BIND - st_info */
#define STB_LOCAL 0 /* Local symbol */
#define STB_GLOBAL 1 /* Global symbol */
#define STB_WEAK 2 /* like global - lower precedence */
#define STB_NUM 3 /* number of symbol bindings */
#define STB_LOOS 10 /* reserved range for operating */
#define STB_HIOS 12 /* system specific symbol bindings */
#define STB_LOPROC 13 /* reserved range for processor */
#define STB_HIPROC 15 /* specific symbol bindings */
/* Symbol type - ELF32_ST_TYPE - st_info */
#define STT_NOTYPE 0 /* not specified */
#define STT_OBJECT 1 /* data object */
#define STT_FUNC 2 /* function */
#define STT_SECTION 3 /* section */
#define STT_FILE 4 /* file */
#define STT_NUM 5 /* number of symbol types */
#define STT_TLS 6 /* Thread local storage symbol */
#define STT_LOOS 10 /* reserved range for operating */
#define STT_HIOS 12 /* system specific symbol types */
#define STT_LOPROC 13 /* reserved range for processor */
#define STT_HIPROC 15 /* specific symbol types */
/* Symbol visibility - ELF32_ST_VISIBILITY - st_other */
#define STV_DEFAULT 0 /* Normal visibility rules */
#define STV_INTERNAL 1 /* Processor specific hidden class */
#define STV_HIDDEN 2 /* Symbol unavailable in other mods */
#define STV_PROTECTED 3 /* Not preemptible, not exported */
/* Relocation entry with implicit addend */
typedef struct
{
Elf32_Addr r_offset; /* offset of relocation */
Elf32_Word r_info; /* symbol table index and type */
} Elf32_Rel;
/* Relocation entry with explicit addend */
typedef struct
{
Elf32_Addr r_offset; /* offset of relocation */
Elf32_Word r_info; /* symbol table index and type */
Elf32_Sword r_addend;
} Elf32_Rela;
/* Extract relocation info - r_info */
#define ELF32_R_SYM(i) ((i) >> 8)
#define ELF32_R_TYPE(i) ((unsigned char) (i))
#define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t))
/* Program Header */
typedef struct {
Elf32_Word p_type; /* segment type */
Elf32_Off p_offset; /* segment offset */
Elf32_Addr p_vaddr; /* virtual address of segment */
Elf32_Addr p_paddr; /* physical address - ignored? */
Elf32_Word p_filesz; /* number of bytes in file for seg. */
Elf32_Word p_memsz; /* number of bytes in mem. for seg. */
Elf32_Word p_flags; /* flags */
Elf32_Word p_align; /* memory alignment */
} Elf32_Phdr;
/* Segment types - p_type */
#define PT_NULL 0 /* unused */
#define PT_LOAD 1 /* loadable segment */
#define PT_DYNAMIC 2 /* dynamic linking section */
#define PT_INTERP 3 /* the RTLD */
#define PT_NOTE 4 /* auxiliary information */
#define PT_SHLIB 5 /* reserved - purpose undefined */
#define PT_PHDR 6 /* program header */
#define PT_TLS 7 /* Thread local storage template */
#define PT_NUM 8 /* Number of segment types */
#define PT_LOOS 0x60000000 /* reserved range for operating */
#define PT_HIOS 0x6fffffff /* system specific segment types */
#define PT_LOPROC 0x70000000 /* reserved range for processor */
#define PT_HIPROC 0x7fffffff /* specific segment types */
/* Segment flags - p_flags */
#define PF_X 0x1 /* Executable */
#define PF_W 0x2 /* Writable */
#define PF_R 0x4 /* Readable */
#define PF_MASKOS 0x0ff00000 /* OS specific segment flags */
#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */
/* specific segment flags */
/* Dynamic structure */
typedef struct
{
Elf32_Sword d_tag; /* controls meaning of d_val */
union
{
Elf32_Word d_val; /* Multiple meanings - see d_tag */
Elf32_Addr d_ptr; /* program virtual address */
} d_un;
} Elf32_Dyn;
extern Elf32_Dyn _DYNAMIC[];
/* Dynamic Array Tags - d_tag */
#define DT_NULL 0 /* marks end of _DYNAMIC array */
#define DT_NEEDED 1 /* string table offset of needed lib */
#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */
#define DT_PLTGOT 3 /* address PLT/GOT */
#define DT_HASH 4 /* address of symbol hash table */
#define DT_STRTAB 5 /* address of string table */
#define DT_SYMTAB 6 /* address of symbol table */
#define DT_RELA 7 /* address of relocation table */
#define DT_RELASZ 8 /* size of relocation table */
#define DT_RELAENT 9 /* size of relocation entry */
#define DT_STRSZ 10 /* size of string table */
#define DT_SYMENT 11 /* size of symbol table entry */
#define DT_INIT 12 /* address of initialization func. */
#define DT_FINI 13 /* address of termination function */
#define DT_SONAME 14 /* string table offset of shared obj */
#define DT_RPATH 15 /* string table offset of library
search path */
#define DT_SYMBOLIC 16 /* start sym search in shared obj. */
#define DT_REL 17 /* address of rel. tbl. w addends */
#define DT_RELSZ 18 /* size of DT_REL relocation table */
#define DT_RELENT 19 /* size of DT_REL relocation entry */
#define DT_PLTREL 20 /* PLT referenced relocation entry */
#define DT_DEBUG 21 /* bugger */
#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */
#define DT_JMPREL 23 /* add. of PLT's relocation entries */
#define DT_BIND_NOW 24 /* Process relocations of object */
#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */
#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */
#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */
#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */
#define DT_RUNPATH 29 /* Library search path */
#define DT_FLAGS 30 /* Flags for the object being loaded */
#define DT_ENCODING 32 /* Start of encoded range */
#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/
#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */
#define DT_NUM 34 /* Number used. */
#define DT_LOOS 0x60000000 /* reserved range for OS */
#define DT_HIOS 0x6fffffff /* specific dynamic array tags */
#define DT_LOPROC 0x70000000 /* reserved range for processor */
#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */
/* Dynamic Tag Flags - d_un.d_val */
#define DF_ORIGIN 0x01 /* Object may use DF_ORIGIN */
#define DF_SYMBOLIC 0x02 /* Symbol resolutions starts here */
#define DF_TEXTREL 0x04 /* Object contains text relocations */
#define DF_BIND_NOW 0x08 /* No lazy binding for this object */
#define DF_STATIC_TLS 0x10 /* Static thread local storage */
/* Standard ELF hashing function */
unsigned long elf_hash(const unsigned char *name);
#define ELF_TARG_VER 1 /* The ver for which this code is intended */
/*
* XXX - PowerPC defines really don't belong in here,
* but we'll put them in for simplicity.
*/
/* Values for Elf32/64_Ehdr.e_flags. */
#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */
/* Cygnus local bits below */
#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/
#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib
flag */
/* PowerPC relocations defined by the ABIs */
#define R_PPC_NONE 0
#define R_PPC_ADDR32 1 /* 32bit absolute address */
#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */
#define R_PPC_ADDR16 3 /* 16bit absolute address */
#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */
#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */
#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */
#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */
#define R_PPC_ADDR14_BRTAKEN 8
#define R_PPC_ADDR14_BRNTAKEN 9
#define R_PPC_REL24 10 /* PC relative 26 bit */
#define R_PPC_REL14 11 /* PC relative 16 bit */
#define R_PPC_REL14_BRTAKEN 12
#define R_PPC_REL14_BRNTAKEN 13
#define R_PPC_GOT16 14
#define R_PPC_GOT16_LO 15
#define R_PPC_GOT16_HI 16
#define R_PPC_GOT16_HA 17
#define R_PPC_PLTREL24 18
#define R_PPC_COPY 19
#define R_PPC_GLOB_DAT 20
#define R_PPC_JMP_SLOT 21
#define R_PPC_RELATIVE 22
#define R_PPC_LOCAL24PC 23
#define R_PPC_UADDR32 24
#define R_PPC_UADDR16 25
#define R_PPC_REL32 26
#define R_PPC_PLT32 27
#define R_PPC_PLTREL32 28
#define R_PPC_PLT16_LO 29
#define R_PPC_PLT16_HI 30
#define R_PPC_PLT16_HA 31
#define R_PPC_SDAREL16 32
#define R_PPC_SECTOFF 33
#define R_PPC_SECTOFF_LO 34
#define R_PPC_SECTOFF_HI 35
#define R_PPC_SECTOFF_HA 36
/* Keep this the last entry. */
#define R_PPC_NUM 37
/* The remaining relocs are from the Embedded ELF ABI, and are not
in the SVR4 ELF ABI. */
#define R_PPC_EMB_NADDR32 101
#define R_PPC_EMB_NADDR16 102
#define R_PPC_EMB_NADDR16_LO 103
#define R_PPC_EMB_NADDR16_HI 104
#define R_PPC_EMB_NADDR16_HA 105
#define R_PPC_EMB_SDAI16 106
#define R_PPC_EMB_SDA2I16 107
#define R_PPC_EMB_SDA2REL 108
#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */
#define R_PPC_EMB_MRKREF 110
#define R_PPC_EMB_RELSEC16 111
#define R_PPC_EMB_RELST_LO 112
#define R_PPC_EMB_RELST_HI 113
#define R_PPC_EMB_RELST_HA 114
#define R_PPC_EMB_BIT_FLD 115
#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */
/* Diab tool relocations. */
#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */
#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */
#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */
#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */
#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */
#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */
/* This is a phony reloc to handle any old fashioned TOC16 references
that may still be in object files. */
#define R_PPC_TOC16 255
#endif /* _ELF_H */

View File

@@ -0,0 +1,774 @@
#include <string.h>
#include <ogcsys.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include "../config.h"
#include "panic.h"
#include "theme.h"
#include "font.h"
#include "droid_ttf.h"
#include "droidbold_ttf.h"
#define ROUNDUP4B(x) ((x + 4 - 1) & ~(4 - 1))
#define X_RATIO (widescreen?WIDESCREEN_RATIO:1.0)
//#define FONT_CHECKER
FT_Library library;
typedef struct {
int codepoint;
int next_idx;
int glyph_index;
int valid;
gfx_entity *texture;
int x, y;
int w, h;
FT_Pos dx, dy;
} font_glyph;
typedef struct {
const void *data;
u32 data_len;
FT_Face face;
int max_glyphs;
int num_glyphs;
int em_w, em_h;
int em_height;
int ascender;
int descender;
int height;
font_glyph *glyphs;
} font_face;
static font_face *fonts[FONT_MAX];
typedef struct {
int size;
const void *data;
const u32 *data_len; // bin2s stupidity
} font_default;
const font_default default_fonts[FONT_MAX] =
{
[FONT_LABEL] = { 16, droidbold_ttf, &droidbold_ttf_size},
[FONT_DLGTITLE] = { 20, droidbold_ttf, &droidbold_ttf_size},
[FONT_MEMO] = { 16, droid_ttf, &droid_ttf_size},
[FONT_APPNAME] = { 20, droidbold_ttf, &droidbold_ttf_size},
[FONT_APPDESC] = { 16, droidbold_ttf, &droidbold_ttf_size},
[FONT_BUTTON] = { 20, droidbold_ttf, &droidbold_ttf_size},
[FONT_BUTTON_DESEL] = { 20, droid_ttf, &droid_ttf_size},
};
#define GLYPH_CACHE_ROOT 64
#define GLYPH_CACHE_INIT 32
#define GLYPH_CACHE_GROW 32
font_glyph *font_get_char(font_id id, int codepoint);
#if 0
static const char *utf8(u32 codepoint)
{
static char buf[5];
if (codepoint < 0x80) {
buf[0] = codepoint;
buf[1] = 0;
} else if (codepoint < 0x800) {
buf[0] = 0xC0 | (codepoint>>6);
buf[1] = 0x80 | (codepoint&0x3F);
buf[2] = 0;
} else if (codepoint < 0x10000) {
buf[0] = 0xE0 | (codepoint>>12);
buf[1] = 0x80 | ((codepoint>>6)&0x3F);
buf[2] = 0x80 | (codepoint&0x3F);
buf[3] = 0;
} else if (codepoint < 0x110000) {
buf[0] = 0xF0 | (codepoint>>18);
buf[1] = 0x80 | ((codepoint>>12)&0x3F);
buf[2] = 0x80 | ((codepoint>>6)&0x3F);
buf[3] = 0x80 | (codepoint&0x3F);
buf[4] = 0;
} else {
buf[0] = '?';
buf[1] = 0;
}
return buf;
}
#endif
int font_load(font_id id, bool use_theme)
{
int ret;
int i;
const void *data;
u32 data_len;
int em;
font_face *font;
if (fonts[id])
return 0;
gprintf("Loading font ID %d\n", id);
data = default_fonts[id].data;
data_len = *default_fonts[id].data_len;
em = default_fonts[id].size;
if (use_theme && theme_fonts[id].data) {
data = theme_fonts[id].data;
data_len = theme_fonts[id].data_len;
}
if (use_theme && theme_fonts[id].size)
em = theme_fonts[id].size;
// maybe we can reuse the entire font, look for other fonts
for (i=0; i<FONT_MAX; i++) {
if (fonts[i] && fonts[i]->data == data && fonts[i]->em_h == em) {
gprintf("Cloned font object from font ID %d\n", i);
fonts[id] = fonts[i];
return 0;
}
}
font = pmalloc(sizeof(*font));
memset(font, 0, sizeof(*font));
font->data = data;
font->data_len = data_len;
font->em_h = font->em_w = em;
font->face = NULL;
// maybe we can reuse the FT_Font object, look for other fonts
for (i=0; i<FONT_MAX; i++) {
if (fonts[i] && fonts[i]->data == font->data) {
gprintf("Reused FreeType font subobject from font ID %d\n", i);
font->face = fonts[i]->face;
break;
}
}
if (!font->face) {
ret = FT_New_Memory_Face(library, font->data, font->data_len, 0, &font->face);
if (ret != 0) {
gprintf("Failed to load font\n");
// try to fall back
if (use_theme && theme_fonts[id].data) {
free(font);
theme_fonts[id].data = NULL;
return font_load(id, false);
}
return ret;
} else {
gprintf("Loaded font at %p\n", font->data);
}
}
gprintf("Font contains %ld faces\n", font->face->num_faces);
gprintf("Face contains %ld glyphs\n", font->face->num_glyphs);
if (widescreen)
font->em_w = (int)(font->em_w / WIDESCREEN_RATIO + 0.5);
ret = FT_Set_Pixel_Sizes(font->face, font->em_w, font->em_h);
if (ret) {
gprintf("FT_Set_Pixel_Sizes failed: %d\n", ret);
free(font);
return ret;
}
if (!FT_HAS_KERNING(font->face))
gprintf("Font has no usable kerning data\n");
else
gprintf("Font has kerning data\n");
font->max_glyphs = GLYPH_CACHE_ROOT+GLYPH_CACHE_INIT;
font->num_glyphs = GLYPH_CACHE_ROOT; //base "hashtable" set
font->glyphs = pmalloc(sizeof(font_glyph) * font->max_glyphs);
memset(font->glyphs, 0, sizeof(font_glyph) * font->max_glyphs);
for(i=0; i<font->max_glyphs; i++) {
font->glyphs[i].codepoint = -1;
font->glyphs[i].next_idx = -1;
}
fonts[id] = font;
font_glyph *glyph = font_get_char(id, 'M');
font->em_height = glyph->h; // height of capital M
font->ascender = (font->face->size->metrics.ascender+32)>>6;
font->descender = (font->face->size->metrics.descender+32)>>6;
font->height = (font->face->size->metrics.height+32)>>6;
gprintf("Ascender is %d\n", font->ascender);
gprintf("Descender is %d\n", font->descender);
gprintf("Height is %d\n", font->height);
gprintf("Font ID %d loaded\n", id);
return 0;
}
font_glyph *font_get_char(font_id id, int codepoint)
{
int ret;
font_glyph *glyph;
font_load(id,1);
font_face *font = fonts[id];
glyph = &font->glyphs[codepoint&(GLYPH_CACHE_ROOT-1)];
if (glyph->codepoint != -1) {
while(1) {
if (glyph->codepoint == codepoint) {
//gprintf("FONT: Glyph %d (%s) is cached\n", codepoint, utf8(codepoint));
return glyph;
}
if (glyph->next_idx == -1) {
glyph->next_idx = font->num_glyphs;
if (font->num_glyphs == font->max_glyphs) {
font->glyphs = prealloc(font->glyphs, sizeof(font_glyph) * (font->max_glyphs + GLYPH_CACHE_GROW));
memset(&font->glyphs[font->max_glyphs], 0, GLYPH_CACHE_GROW*sizeof(font_glyph));
font->max_glyphs += GLYPH_CACHE_GROW;
gprintf("FONT: expanded glyph cache size to %d\n", font->max_glyphs);
}
glyph = &font->glyphs[font->num_glyphs];
font->num_glyphs++;
break;
}
glyph = &font->glyphs[glyph->next_idx];
}
}
memset(glyph, 0, sizeof(*glyph));
glyph->codepoint = codepoint;
glyph->next_idx = -1;
glyph->valid = 0;
glyph->texture = pmalloc(sizeof(*glyph->texture));
glyph->dx = 0;
glyph->dy = 0;
FT_GlyphSlot slot = font->face->glyph;
FT_UInt glyph_index;
ret = FT_Set_Pixel_Sizes(font->face, font->em_w, font->em_h);
if (ret)
return glyph;
glyph_index = FT_Get_Char_Index(font->face, codepoint);
ret = FT_Load_Glyph(font->face, glyph_index, FT_LOAD_DEFAULT);
if (ret)
return glyph;
ret = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
if (ret)
return glyph;
glyph->dx = slot->advance.x;
glyph->dy = slot->advance.y;
glyph->glyph_index = glyph_index;
int cw = slot->bitmap.width;
int ch = slot->bitmap.rows;
glyph->w = cw;
glyph->h = ch;
if (!cw || !ch)
return glyph;
int tw = (cw+7)/8;
int th = (ch+3)/4;
int tpitch = tw * 32;
u8 *pix = pmemalign(32, tw*th*32);
memset(pix, 0, tw*th*32);
int x,y;
u8 *p = slot->bitmap.buffer;
for(y=0; y<ch; y++) {
u8 *lp = p;
int ty = y/4;
int py = y%4;
u8 *lpix = pix + ty*tpitch + py*8;
for(x=0; x<cw; x++) {
int tx = x/8;
int px = x%8;
#ifndef FONT_CHECKER
lpix[32*tx + px] = *lp++;
#else
if ((x+y)&1)
lpix[32*tx + px] = 0xff;
else
lpix[32*tx + px] = 0;
#endif
}
p += slot->bitmap.pitch;
}
gfx_gen_tex (glyph->texture, 8*tw, 4*th, pix, GFXT_A8);
glyph->x = slot->bitmap_left;
glyph->y = slot->bitmap_top;
glyph->valid = 1;
//gprintf("FONT: Rendered and cached glyph %d (%s) at pos %d size %dx%d\n", codepoint, utf8(codepoint), glyph-font->glyphs, cw, ch);
//gprintf("Free MEM1: %ld MEM2: %ld\n", SYS_GetArena1Size(), SYS_GetArena2Size());
return glyph;
}
void font_kern(font_id id, int left, int right, FT_Pos *dx, FT_Pos *dy)
{
FT_Vector delta;
if (!FT_HAS_KERNING(fonts[id]->face)) {
return;
}
if (FT_Get_Kerning(fonts[id]->face, left, right, FT_KERNING_UNFITTED, &delta))
return;
//gprintf("Kern font %d for glyphs %d,%d is %ld,%ld\n", id, left, right, delta.x, delta.y);
*dx += delta.x;
*dy += delta.y;
}
void font_init(void)
{
int ret;
memset(fonts, 0, sizeof(fonts));
ret = FT_Init_FreeType(&library);
if (ret != 0) {
gprintf("FreeType init failed (%d)\n", ret);
return;
}
gprintf("FreeType initialized\n");
}
void font_clear (void) {
int id,id2;
for (id=0; id<FONT_MAX; id++) {
int g;
if (!fonts[id])
continue;
// kill all clones first
for (id2=0; id2<FONT_MAX; id2++) {
if (id2 != id && fonts[id2] && fonts[id2] == fonts[id])
fonts[id2] = NULL;
}
for (g=0; g<fonts[id]->num_glyphs; g++) {
if (fonts[id]->glyphs[g].texture)
free(fonts[id]->glyphs[g].texture);
fonts[id]->glyphs[g].texture = NULL;
}
free(fonts[id]->glyphs);
fonts[id]->glyphs = NULL;
if (fonts[id]->face) {
FT_Face face = fonts[id]->face;
FT_Done_Face(face);
// other fonts can share this face object, so nuke all
for (id2=0; id2<FONT_MAX; id2++) {
if (fonts[id2] && fonts[id2]->face == face)
fonts[id2]->face = NULL;
}
}
free(fonts[id]);
fonts[id] = NULL;
}
}
void font_deinit (void) {
font_clear();
FT_Done_FreeType(library);
}
static u32 utf8_get_char(const char **s)
{
const char *c = *s;
u32 mbc = '?';
if (!c[0])
return 0;
if (c[0] <= 0x7f) {
mbc = c[0];
c++;
} else if (c[0] >= 0xc0 && c[0] <= 0xdf) {
if ((c[1]&0xc0) != 0x80) {
c++;
if (c[0])
c++;
} else {
mbc = (c[1]&0x3f) | ((c[0]&0x1f)<<6);
c+=2;
}
} else if (c[0] >= 0xe0 && c[0] <= 0xef) {
if (((c[1]&0xc0) != 0x80) || ((c[2]&0xc0) != 0x80)) {
c++;
if (c[0])
c++;
if (c[0])
c++;
} else {
mbc = (c[2]&0x3f) | ((c[1]&0x3f)<<6) | ((c[0]&0x1f)<<12);
c+=3;
}
} else if (c[0] >= 0xf0 && c[0] <= 0xf7) {
if (((c[1]&0xc0) != 0x80) || ((c[2]&0xc0) != 0x80) || ((c[3]&0xc0) != 0x80)) {
c++;
if (c[0])
c++;
if (c[0])
c++;
if (c[0])
c++;
} else {
mbc = (c[3]&0x3f) | ((c[2]&0x3f)<<6) | ((c[1]&0x3f)<<12) | ((c[0]&0x1f)<<18);
c+=4;
}
} else {
c++;
}
*s = c;
return mbc;
}
int font_get_ascender(font_id id) {
font_load(id,1);
return fonts[id]->ascender;
}
int font_get_height(font_id id) {
font_load(id,1);
return fonts[id]->ascender - fonts[id]->descender;
}
int font_get_em_height(font_id id) {
font_load(id,1);
return fonts[id]->em_height;
}
int font_get_y_spacing(font_id id) {
font_load(id,1);
return fonts[id]->height;
}
int font_get_min_y(font_id id) {
font_load(id,1);
return -fonts[id]->descender;
}
u16 font_get_string_width (font_id id, const char *s, int count) {
int i = 0;
u32 mbc;
int cx = 0;
int cy = 0;
FT_Pos cdx = 0, cdy = 0;
u32 previous = 0;
font_load(id,1);
while((mbc = utf8_get_char(&s))) {
if (mbc == '\n') {
if (*s)
mbc = ' ';
else
continue;
}
if (mbc == '\r')
continue;
font_glyph *glyph = font_get_char(id, mbc);
if (previous)
font_kern(id, previous, glyph->glyph_index, &cdx, &cdy);
cx += (cdx+32) >> 6;
cy += (cdy+32) >> 6;
cdx = glyph->dx;
cdy = glyph->dy;
previous = glyph->glyph_index;
i++;
if (i == count)
break;
}
cx += (cdx+32) >> 6;
cy += (cdy+32) >> 6;
return cx;
}
int font_get_char_count (font_id id, const char *s, u16 max_width) {
//u16 res = 0;
int i = 0;
u32 mbc;
int cx = 0;
int cy = 0;
FT_Pos cdx = 0, cdy = 0;
u32 previous = 0;
max_width /= X_RATIO;
font_load(id,1);
while((mbc = utf8_get_char(&s))) {
if (mbc == '\n') {
if (*s)
mbc = ' ';
else
continue;
}
if (mbc == '\r')
continue;
font_glyph *glyph = font_get_char(id, mbc);
if (previous)
font_kern(id, previous, glyph->glyph_index, &cdx, &cdy);
cx += (cdx+32) >> 6;
cy += (cdy+32) >> 6;
if (max_width && (cx >= max_width))
return i;
cdx = glyph->dx;
cdy = glyph->dy;
previous = glyph->glyph_index;
i++;
}
return i;
}
int font_wrap_string (char ***lines, font_id id, const char *s,
u16 max_width) {
const char *p = s;
char **res = NULL;
int line = 0;
int start = 0;
int end = 0;
int ls = -1;
bool lb;
int cx = 0;
int cy = 0;
int i = 0;
u32 mbc;
FT_Pos cdx = 0, cdy = 0;
u32 previous = 0;
max_width /= X_RATIO;
font_load(id,1);
while (true) {
i = p - s;
mbc = utf8_get_char(&p);
lb = false;
if (mbc == ' ')
ls = p - s;
if ((mbc == '\n') || mbc == 0) {
lb = true;
end = i;
i = p - s;
} else if (mbc == '\r') {
continue;
} else {
font_glyph *glyph = font_get_char(id, mbc);
if (previous)
font_kern(id, previous, glyph->glyph_index, &cdx, &cdy);
cx += (cdx+32) >> 6;
cy += (cdy+32) >> 6;
int w = (glyph->dx+32) >> 6;
if ((glyph->w + glyph->x) > w)
w = glyph->w + glyph->x;
if ((cx + w) >= max_width) {
lb = true;
if (ls <= start) {
if (i == start)
i++;
end = i;
p = &s[i];
} else {
end = ls;
i = ls;
p = &s[i];
}
}
cdx = glyph->dx;
cdy = glyph->dy;
previous = glyph->glyph_index;
}
if (lb) {
res = prealloc (res, (line + 1) * sizeof (char **));
if (end <= start)
res[line] = NULL;
else {
res[line] = strndup (&s[start], end - start);
}
line++;
start = i;
cx = 0;
cy = 0;
cdx = 0;
cdy = 0;
previous = 0;
}
if (mbc == 0)
break;
}
*lines = res;
return line;
}
void font_free_lines (char **lines, u32 count) {
int i;
for (i = 0; i < count; ++i)
free (lines[i]);
free (lines);
}
void font_plot_string (gfx_queue_entry *entries, int count, font_id id,
const char *s, u16 x, u16 y, u16 layer, u16 width,
font_xalign xalign, font_yalign yalign) {
int cx;
int cy;
if (!count)
return;
cx = x;
cy = y;
cx /= X_RATIO;
switch (xalign) {
case FA_LEFT:
break;
case FA_CENTERED:
cx += (width/X_RATIO - font_get_string_width (id, s, count)) / 2;
break;
case FA_RIGHT:
cx += width/X_RATIO - font_get_string_width (id, s, count);
break;
}
switch (yalign) {
case FA_ASCENDER:
cy += fonts[id]->ascender;
break;
case FA_EM_TOP:
cy += fonts[id]->em_height;
break;
case FA_EM_CENTERED:
cy += fonts[id]->em_height/2;
break;
case FA_BASELINE:
break;
case FA_DESCENDER:
cy += fonts[id]->descender;
break;
}
FT_Pos cdx = 0, cdy = 0;
u32 previous = 0;
int first = 1;
u32 mbc;
while ((mbc = utf8_get_char(&s))) {
if (mbc == '\n') {
if (*s)
mbc = ' ';
else
break;
}
if (mbc == '\r')
continue;
font_glyph *glyph = font_get_char(id, mbc);
if (previous)
font_kern(id, previous, glyph->glyph_index, &cdx, &cdy);
cx += (cdx+32) >> 6;
cy += (cdy+32) >> 6;
if (!glyph->valid) {
entries->type = GFXQ_NULL;
goto next_glyph;
}
// fudgity fudge, helps make text left-align slightly better/nicer,
// especially with differing fonts.
// do this only for chars with glyph->x > 0. Those with glyph->x < 0
// are usually kerned together and look better a bit to the left anyway.
if(xalign == FA_LEFT && first && glyph->x > 0)
cx -= glyph->x;
gfx_qe_entity (entries, glyph->texture,
((float)(cx + glyph->x)) * X_RATIO,
cy - glyph->y,
layer, theme_fonts[id].color);
//gprintf("Render %d (%s) at %d %d -> %d %d size %d %d\n", mbc, utf8(mbc), cx, cy, cx + glyph->x, cy - glyph->y + fonts[id]->height, glyph->texture->w, glyph->texture->h);
first = 0;
next_glyph:
count--;
entries++;
if (!count)
break;
cdx = glyph->dx;
cdy = glyph->dy;
previous = glyph->glyph_index;
}
if (count) {
gprintf("BUG: %d queue entries empty, padding with NULLs\n", count);
while (count--) {
entries->type = GFXQ_NULL;
// this superfluous statement carefully chosen for optimal crashiness
entries++->entity.coords.z = 0;
}
}
}

View File

@@ -0,0 +1,54 @@
#ifndef _FONT_H_
#define _FONT_H_
#include <gctypes.h>
#include "gfx.h"
typedef enum {
FONT_LABEL = 0,
FONT_DLGTITLE,
FONT_MEMO,
FONT_APPNAME,
FONT_APPDESC,
FONT_BUTTON,
FONT_BUTTON_DESEL,
FONT_MAX
} font_id;
typedef enum {
FA_LEFT = 0,
FA_CENTERED,
FA_RIGHT
} font_xalign;
typedef enum {
FA_ASCENDER = 0,
FA_EM_TOP,
FA_EM_CENTERED,
FA_BASELINE,
FA_DESCENDER,
} font_yalign;
void font_init (void);
void font_clear (void);
void font_deinit (void);
int font_get_height (font_id id);
int font_get_em_height (font_id id);
int font_get_ascender (font_id id);
int font_get_y_spacing (font_id id);
int font_get_min_y(font_id id);
int font_get_char_count (font_id id, const char *s, u16 max_width);
int font_wrap_string (char ***lines, font_id id, const char *s, u16 max_width);
void font_free_lines (char **lines, u32 count);
void font_plot_string (gfx_queue_entry *entries, int count, font_id id,
const char *s, u16 x, u16 y, u16 layer, u16 width,
font_xalign xalign, font_yalign yalign);
#endif

View File

@@ -0,0 +1,539 @@
#include <malloc.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <stdio.h>
#include <gccore.h>
#include <ogc/machine/processor.h>
#include <ogc/lwp_watchdog.h>
#include <ogc/conf.h>
#include "../config.h"
#include "gfx.h"
#include "panic.h"
#include "title.h"
#define DEFAULT_FIFO_SIZE (256 * 1024)
#define CLIPPING_X (view_width / 2 + 64)
#define CLIPPING_Y (view_height / 2 + 64)
#define FONT_NEAREST_NEIGHBOR
static u32 *xfb;
static GXRModeObj *vmode;
static float px_width, px_height;
static u8 *gp_fifo;
static Mtx view;
static u8 origin_stack_size;
static const gfx_coordinates *origin_stack[GFX_ORIGIN_STACK_SIZE];
static gfx_coordinates origin_current;
static u32 *efb_buffer = NULL;
u16 view_width = 0;
u16 view_height = 0;
bool widescreen = false;
void gfx_init_video (void) {
u8 i;
VIDEO_Init ();
vmode = VIDEO_GetPreferredMode (NULL);
#ifdef ENABLE_WIDESCREEN
if (CONF_GetAspectRatio() == CONF_ASPECT_16_9) {
gprintf("aspect: 16:9\n");
view_width = 852; // 16:9
view_height = 480;
vmode->viWidth = 672;
widescreen = true;
if (is_vwii()) {
// poke DMCU to turn off pillarboxing
write32(0xd8006a0, 0x30000004);
mask32(0xd8006a8, 0, 2);
}
} else {
#endif
gprintf("aspect: 4:3\n");
view_width = 640;
view_height = 480;
vmode->viWidth = 672;
if (is_vwii()) {
// poke DMCU to turn on pillarboxing
write32(0xd8006a0, 0x10000002);
mask32(0xd8006a8, 0, 2);
}
#ifdef ENABLE_WIDESCREEN
}
#endif
if (vmode == &TVPal576IntDfScale || vmode == &TVPal576ProgScale) {
vmode->viXOrigin = (VI_MAX_WIDTH_PAL - vmode->viWidth) / 2;
vmode->viYOrigin = (VI_MAX_HEIGHT_PAL - vmode->viHeight) / 2;
} else {
vmode->viXOrigin = (VI_MAX_WIDTH_NTSC - vmode->viWidth) / 2;
vmode->viYOrigin = (VI_MAX_HEIGHT_NTSC - vmode->viHeight) / 2;
}
px_width = vmode->fbWidth / (float) view_width;
px_height = vmode->efbHeight / (float) view_height;
VIDEO_SetBlack (TRUE);
VIDEO_Configure (vmode);
VIDEO_Flush ();
VIDEO_WaitVSync();
xfb = (u32 *) SYS_AllocateFramebuffer (vmode);
DCInvalidateRange(xfb, VIDEO_GetFrameBufferSize(vmode));
xfb = MEM_K0_TO_K1 (xfb);
VIDEO_ClearFrameBuffer (vmode, xfb, COLOR_BLACK);
VIDEO_SetNextFramebuffer (xfb);
VIDEO_SetBlack (TRUE);
VIDEO_Flush ();
gp_fifo = (u8 *) pmemalign (32, DEFAULT_FIFO_SIZE);
for (i = 0; i < 4; ++i)
VIDEO_WaitVSync();
}
void gfx_init () {
Mtx44 p;
GX_AbortFrame ();
GXColor gxbackground = { 0, 0, 0, 0xff };
memset (gp_fifo, 0, DEFAULT_FIFO_SIZE);
GX_Init (gp_fifo, DEFAULT_FIFO_SIZE);
GX_SetCopyClear (gxbackground, 0x00ffffff);
// GX voodoo - properly comment me some day
// the 0.05 fudge factors for some reason help align textures on the pixel grid
// it's still not perfect though
GX_SetViewport (0, 0, vmode->fbWidth+0.05, vmode->efbHeight+0.05, 0, 1);
GX_SetDispCopyYScale ((f32) vmode->xfbHeight / (f32) vmode->efbHeight);
GX_SetScissor (0, 0, vmode->fbWidth, vmode->efbHeight);
GX_SetDispCopySrc (0, 0, vmode->fbWidth, vmode->efbHeight);
GX_SetDispCopyDst (vmode->fbWidth, vmode->xfbHeight);
GX_SetCopyFilter (vmode->aa, vmode->sample_pattern, GX_TRUE,
vmode->vfilter);
GX_SetFieldMode (vmode->field_rendering,
((vmode->viHeight == 2 * vmode->xfbHeight) ?
GX_ENABLE : GX_DISABLE));
GX_SetPixelFmt (GX_PF_RGB8_Z24, GX_ZC_LINEAR);
GX_SetCullMode (GX_CULL_NONE);
GX_SetDispCopyGamma (GX_GM_1_0);
guOrtho(p, view_height / 2, -(view_height / 2),
-(view_width / 2), view_width / 2, 100, 1000);
GX_LoadProjectionMtx (p, GX_ORTHOGRAPHIC);
GX_ClearVtxDesc ();
GX_SetVtxDesc (GX_VA_POS, GX_DIRECT);
GX_SetVtxDesc (GX_VA_CLR0, GX_DIRECT);
GX_SetVtxDesc (GX_VA_TEX0, GX_DIRECT);
GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
memset (&view, 0, sizeof (Mtx));
guMtxIdentity(view);
GX_Flush ();
GX_DrawDone ();
GX_SetColorUpdate (GX_TRUE);
GX_CopyDisp (xfb, GX_TRUE);
GX_Flush ();
GX_DrawDone ();
GX_CopyDisp (xfb, GX_TRUE);
GX_Flush ();
GX_DrawDone ();
VIDEO_SetBlack (FALSE);
VIDEO_Flush ();
}
void gfx_deinit (void) {
u8 i;
GX_AbortFrame ();
VIDEO_SetBlack (TRUE);
VIDEO_Flush();
for (i = 0; i < 4; ++i)
VIDEO_WaitVSync();
}
void gfx_get_efb_size(u16 *x, u16*y) {
*x = vmode->fbWidth;
*y = vmode->efbHeight;
}
void gfx_set_efb_buffer(u32 *buffer) {
efb_buffer = buffer;
}
// entity generators
void gfx_gen_gradient (gfx_entity *entity, u16 w, u16 h,
u32 c1, u32 c2, u32 c3, u32 c4) {
entity->type = GFXE_GRADIENT;
entity->w = w;
entity->h = h;
entity->gradient.c1 = c1;
entity->gradient.c2 = c2;
entity->gradient.c3 = c3;
entity->gradient.c4 = c4;
}
void gfx_gen_tex (gfx_entity *entity, u16 w, u16 h, u8 *pixels, gfx_tex_type type) {
entity->type = GFXE_TEXTURE;
entity->w = w;
entity->h = h;
entity->texture.pixels = pixels;
entity->texture.type = type;
switch(type) {
case GFXT_RGBA8:
DCFlushRange (pixels, w * h * 4);
GX_InitTexObj (&entity->texture.obj, pixels, w, h, GX_TF_RGBA8, GX_CLAMP,
GX_CLAMP, GX_FALSE);
break;
case GFXT_A8:
DCFlushRange (pixels, w * h);
GX_InitTexObj (&entity->texture.obj, pixels, w, h, GX_TF_I8, GX_CLAMP,
GX_CLAMP, GX_FALSE);
#ifdef FONT_NEAREST_NEIGHBOR
GX_InitTexObjFilterMode(&entity->texture.obj, GX_NEAR, GX_NEAR);
#endif
break;
}
}
// queue entry generators
void gfx_qe_origin_push (gfx_queue_entry *entry, gfx_coordinates *coords) {
entry->type = GFXQ_ORIGIN;
entry->origin.coords = coords;
}
void gfx_qe_origin_pop (gfx_queue_entry *entry) {
entry->type = GFXQ_ORIGIN;
entry->origin.coords = NULL;
}
void gfx_qe_scissor_reset (gfx_queue_entry *entry) {
entry->type = GFXQ_SCISSOR;
entry->scissor.x = 0;
entry->scissor.y = 0;
entry->scissor.z = 0;
entry->scissor.w = 0;
entry->scissor.h = 0;
}
void gfx_qe_scissor (gfx_queue_entry *entry, u16 x, u16 y, u16 z, u16 w, u16 h) {
entry->type = GFXQ_SCISSOR;
entry->scissor.x = x;
entry->scissor.y = y;
entry->scissor.z = z;
entry->scissor.w = w;
entry->scissor.h = h;
}
void gfx_qe_entity (gfx_queue_entry *entry, gfx_entity *entity, f32 x, f32 y,
s16 layer, u32 color) {
entry->type = GFXQ_ENTITY;
entry->entity.coords.x = x;
entry->entity.coords.y = y + entity->h;
entry->entity.coords.z = layer;
entry->entity.scale = 1.0f;
entry->entity.rad = 0.0f;
entry->entity.entity = entity;
entry->entity.color = color;
}
// helper functions
static void get_origin (s16 *x, s16 *y, s16 *z, u8 m) {
u8 i;
*x = -view_width / 2;
*y = view_height / 2;
*z = VIEW_Z_ORIGIN;
for (i = 0; i < origin_stack_size - m; ++i) {
*x += origin_stack[i]->x;
*y -= origin_stack[i]->y;
*z += origin_stack[i]->z;
}
}
static void set_scissor (const gfx_queue_entry *entry) {
s16 x, y, z, w, h;
if (entry->scissor.w != 0 && entry->scissor.h != 0) {
// TODO 1ast parm hardcoded for memo
get_origin (&x, &y, &z, 1);
x = roundf ((float) (x + view_width / 2 + entry->scissor.x) * px_width);
y = roundf ((float) (-y + view_height / 2 + entry->scissor.y) *
px_height);
w = roundf ((float) entry->scissor.w * px_width);
h = roundf ((float) entry->scissor.h * px_height);
GX_SetScissor (x, y, w, h);
} else {
GX_SetScissor (0, 0, vmode->fbWidth, vmode->efbHeight);
}
}
static void plot_vert_c (f32 x, f32 y, f32 z, u32 c) {
GX_Position3f32 (x, y, z);
GX_Color1u32 (c);
GX_TexCoord2f32 (0.0f, 0.0f);
}
static void plot_gradient (const gfx_queue_entry *entry, Mtx v) {
Mtx m, m2;
Mtx mv;
f32 xf, yf, zf, wf, hf;
xf = origin_current.x + entry->entity.coords.x;
yf = origin_current.y - entry->entity.coords.y;
zf = origin_current.z + entry->entity.coords.z;
wf = entry->entity.entity->w;
hf = entry->entity.entity->h;
guMtxIdentity(m);
guMtxTransApply(m, m, -wf/2, -hf/2, 0);
if (entry->entity.scale != 1.0f) {
guMtxScale(m2, entry->entity.scale, entry->entity.scale, 0.0);
guMtxConcat(m2, m, m);
}
if (entry->entity.rad != 0.0f) {
guMtxRotRad(m2, 'z', entry->entity.rad);
guMtxConcat(m2, m, m);
}
guMtxTransApply(m, m, wf/2+xf, hf/2+yf, zf);
guMtxConcat(v, m, mv);
GX_LoadPosMtxImm (mv, GX_PNMTX0);
GX_Begin (GX_QUADS, GX_VTXFMT0, 4);
plot_vert_c (0, hf, 0, entry->entity.entity->gradient.c1);
plot_vert_c (wf, hf, 0, entry->entity.entity->gradient.c2);
plot_vert_c (wf, 0, 0, entry->entity.entity->gradient.c3);
plot_vert_c (0, 0, 0, entry->entity.entity->gradient.c4);
GX_End ();
}
static void plot_vert (f32 x, f32 y, f32 z, f32 s, f32 t, u32 c) {
GX_Position3f32 (x, y, z);
GX_Color1u32 (c);
GX_TexCoord2f32 (s, t);
}
static void plot_texture (const gfx_queue_entry *entry, Mtx v) {
Mtx m, m2;
Mtx mv;
f32 xf, yf, zf, wf, hf;
yf = origin_current.y - entry->entity.coords.y;
zf = origin_current.z + entry->entity.coords.z;
hf = entry->entity.entity->h;
if (widescreen && entry->entity.entity->texture.type == GFXT_A8) {
// align origin to pixel grid
xf = (int)(origin_current.x / WIDESCREEN_RATIO);
xf = xf*WIDESCREEN_RATIO + entry->entity.coords.x;
// width is specified in physical pixels
wf = entry->entity.entity->w * WIDESCREEN_RATIO;
} else {
xf = origin_current.x + entry->entity.coords.x;
wf = entry->entity.entity->w;
}
if (yf > CLIPPING_Y)
return;
if ((yf + hf) < -CLIPPING_Y)
return;
if (xf > CLIPPING_X)
return;
if ((xf + wf) < -CLIPPING_X)
return;
GX_LoadTexObj (&entry->entity.entity->texture.obj, GX_TEXMAP0);
guMtxIdentity(m);
guMtxTransApply(m, m, -wf/2, -hf/2, 0);
if (entry->entity.scale != 1.0f) {
guMtxScale(m2, entry->entity.scale, entry->entity.scale, 0.0);
guMtxConcat(m2, m, m);
}
if (entry->entity.rad != 0.0f) {
guMtxRotRad(m2, 'z', entry->entity.rad);
guMtxConcat(m2, m, m);
}
guMtxTransApply(m, m, wf/2+xf, hf/2+yf, zf);
guMtxConcat(v, m, mv);
switch (entry->entity.entity->texture.type) {
case GFXT_RGBA8:
GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE);
break;
case GFXT_A8:
GX_SetNumTevStages(1);
GX_SetTevColorIn(GX_TEVSTAGE0,GX_CC_ZERO,GX_CC_ZERO,GX_CC_ZERO,GX_CC_RASC);
GX_SetTevAlphaIn(GX_TEVSTAGE0,GX_CA_ZERO,GX_CA_TEXA,GX_CA_RASA,GX_CA_ZERO);
GX_SetTevColorOp(GX_TEVSTAGE0,GX_TEV_ADD,GX_TB_ZERO,GX_CS_SCALE_1,GX_TRUE,GX_TEVPREV);
GX_SetTevAlphaOp(GX_TEVSTAGE0,GX_TEV_ADD,GX_TB_ZERO,GX_CS_SCALE_1,GX_TRUE,GX_TEVPREV);
break;
}
GX_LoadPosMtxImm (mv, GX_PNMTX0);
GX_Begin (GX_QUADS, GX_VTXFMT0, 4);
plot_vert (0, hf, 0, 0.0, 0.0, entry->entity.color);
plot_vert (wf, hf, 0, 1.0, 0.0, entry->entity.color);
plot_vert (wf, 0, 0, 1.0, 1.0, entry->entity.color);
plot_vert (0, 0, 0, 0.0, 1.0, entry->entity.color);
GX_End ();
}
// higher level frame functions
void gfx_frame_start (void) {
origin_stack_size = 0;
origin_current.x = -view_width / 2;
origin_current.y = view_height / 2;
origin_current.z = VIEW_Z_ORIGIN;
GX_InvVtxCache ();
GX_InvalidateTexAll ();
GX_SetNumChans (1);
GX_SetNumTexGens (1);
GX_SetTexCoordGen (GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE);
GX_SetTevOrder (GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
GX_SetBlendMode (GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA,
GX_LO_NOOP);
}
void gfx_frame_push (const gfx_queue_entry *entries, int count) {
while (count--) {
switch (entries->type) {
case GFXQ_ORIGIN:
if (entries->origin.coords) {
origin_current.x += entries->origin.coords->x;
origin_current.y -= entries->origin.coords->y;
origin_current.z += entries->origin.coords->z;
origin_stack[origin_stack_size] = entries->origin.coords;
origin_stack_size++;
} else {
if (origin_stack_size > 0) {
origin_current.x -= origin_stack[origin_stack_size - 1]->x;
origin_current.y += origin_stack[origin_stack_size - 1]->y;
origin_current.z -= origin_stack[origin_stack_size - 1]->z;
origin_stack_size--;
} else {
origin_current.x += -view_width / 2;
origin_current.y -= view_height / 2;
origin_current.z += view_height / 2;
}
}
break;
case GFXQ_SCISSOR:
set_scissor (entries);
break;
case GFXQ_ENTITY:
switch (entries->entity.entity->type) {
case GFXE_GRADIENT:
GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR);
plot_gradient (entries, view);
break;
case GFXE_TEXTURE:
plot_texture (entries, view);
break;
}
case GFXQ_NULL:
break;
default:
gprintf("Unknown queue entry type 0x%x\n", entries->type);
break;
}
entries++;
}
}
void gfx_frame_end (void) {
GX_DrawDone ();
#ifdef ENABLE_SCREENSHOTS
if (efb_buffer) {
u16 x, y;
GXColor c;
u32 val;
u32 *p = efb_buffer;
for (y = 0; y < vmode->efbHeight; ++y) {
for (x = 0; x < vmode->fbWidth; ++x) {
GX_PeekARGB(x, y, &c);
val = ((u32) c.a) << 24;
val |= ((u32) c.r) << 16;
val |= ((u32) c.g) << 8;
val |= c.b;
*p++ = val;
}
}
efb_buffer = NULL;
}
#endif
GX_SetZMode (GX_TRUE, GX_LEQUAL, GX_TRUE);
GX_SetColorUpdate (GX_TRUE);
VIDEO_WaitVSync ();
GX_CopyDisp (xfb, GX_TRUE);
GX_Flush ();
}

View File

@@ -0,0 +1,96 @@
#ifndef _GFX_H_
#define _GFX_H_
#include <ogc/gx.h>
#define COL_DEFAULT 0xFFFFFFFF
#define WIDESCREEN_RATIO (852.0/640.0)
typedef struct {
f32 x, y, z;
} gfx_coordinates;
typedef enum {
GFXT_RGBA8,
GFXT_A8
} gfx_tex_type;
typedef enum {
GFXE_GRADIENT,
GFXE_TEXTURE
} gfx_entity_type;
typedef struct {
gfx_entity_type type;
u16 w, h;
union {
struct {
u32 c1, c2, c3, c4;
} gradient;
struct {
u8 *pixels;
gfx_tex_type type;
GXTexObj obj;
} texture;
};
} gfx_entity;
typedef enum {
GFXQ_NULL = -1,
GFXQ_ORIGIN,
GFXQ_SCISSOR,
GFXQ_ENTITY
} gfx_queue_type;
typedef struct {
gfx_queue_type type;
union {
struct {
gfx_coordinates *coords;
} origin;
struct {
u16 x, y, z, w, h;
} scissor;
struct {
gfx_coordinates coords;
f32 scale;
f32 rad;
gfx_entity *entity;
u32 color;
} entity;
};
} gfx_queue_entry;
extern bool widescreen;
extern u16 view_height, view_width;
void gfx_init_video (void);
void gfx_init (void);
void gfx_deinit (void);
void gfx_get_efb_size(u16 *x, u16 *y);
void gfx_set_efb_buffer(u32 *buffer);
void gfx_gen_gradient (gfx_entity *entity, u16 w, u16 h,
u32 c1, u32 c2, u32 c3, u32 c4);
void gfx_gen_tex (gfx_entity *entity, u16 w, u16 h, u8 *pixels, gfx_tex_type type);
void gfx_qe_origin_push (gfx_queue_entry *entry, gfx_coordinates *coords);
void gfx_qe_origin_pop (gfx_queue_entry *entry);
void gfx_qe_scissor_reset (gfx_queue_entry *entry);
void gfx_qe_scissor (gfx_queue_entry *entry, u16 x, u16 y, u16 z, u16 w, u16 h);
void gfx_qe_entity (gfx_queue_entry *entry, gfx_entity *entity, f32 x, f32 y,
s16 layer, u32 color);
void gfx_frame_start (void);
void gfx_frame_push (const gfx_queue_entry *entries, int count);
void gfx_frame_end (void);
#endif

View File

@@ -0,0 +1,67 @@
/* File ggets.c - goodgets is a safe alternative to gets */
/* By C.B. Falconer. Public domain 2002-06-22 */
/* attribution appreciated. */
/* Revised 2002-06-26 New prototype.
2002-06-27 Incomplete final lines
2006-06-14 Simplified, using getc, not fgets
2006-06-15 Fixed memory leak at EOF
*/
/* fggets and ggets [which is fggets(ln, stdin)] set *ln to
a buffer filled with the next complete line from the text
stream f. The storage has been allocated within fggets,
and is normally reduced to be an exact fit. The trailing
\n has been removed, so the resultant line is ready for
dumping with puts. The buffer will be as large as is
required to hold the complete line.
Note: this means a final file line without a \n terminator
has an effective \n appended, as EOF occurs within the read.
If no error occurs fggets returns 0. If an EOF occurs on
the input file, EOF is returned. For memory allocation
errors some positive value is returned. In this case *ln
may point to a partial line. For other errors memory is
freed and *ln is set to NULL.
Freeing of assigned storage is the callers responsibility
*/
#include <stdio.h>
#include <stdlib.h>
#include "panic.h"
#include "ggets.h"
#define INITSIZE 112 /* power of 2 minus 16, helps malloc */
#define DELTASIZE (INITSIZE + 16)
enum {OK = 0, NOMEM};
int fggets(char* *ln, FILE *f)
{
int cursize, ch, ix;
char *buffer;
*ln = NULL; /* default */
buffer = pmalloc(INITSIZE);
cursize = INITSIZE;
ix = 0;
while ((EOF != (ch = getc(f))) && ('\n' != ch)) {
if (ix >= (cursize - 1)) { /* extend buffer */
cursize += DELTASIZE;
buffer = prealloc(buffer, (size_t)cursize);
}
buffer[ix++] = ch;
}
if ((EOF == ch) && (0 == ix)) {
free(buffer);
return EOF;
}
buffer[ix] = '\0';
*ln = prealloc(buffer, (size_t)ix + 1);
return OK;
} /* fggets */
/* End of ggets.c */

View File

@@ -0,0 +1,45 @@
/* File ggets.h - goodgets is a safe alternative to gets */
/* By C.B. Falconer. Public domain 2002-06-22 */
/* attribution appreciated. */
/* Revised 2002-06-26 New prototype.
2002-06-27 Incomplete final lines
*/
/* fggets and ggets [which is fggets(ln, stdin)] set *ln to
a buffer filled with the next complete line from the text
stream f. The storage has been allocated within fggets,
and is normally reduced to be an exact fit. The trailing
\n has been removed, so the resultant line is ready for
dumping with puts. The buffer will be as large as is
required to hold the complete line.
Note: this means a final file line without a \n terminator
has an effective \n appended, as EOF occurs within the read.
If no error occurs fggets returns 0. If an EOF occurs on
the input file, EOF is returned. For memory allocation
errors some positive value is returned. In this case *ln
may point to a partial line. For other errors memory is
freed and *ln is set to NULL.
Freeing of assigned storage is the callers responsibility
*/
#ifndef ggets_h_
# define ggets_h_
# ifdef __cplusplus
extern "C" {
# endif
int fggets(char* *ln, FILE *f);
#define ggets(ln) fggets(ln, stdin)
# ifdef __cplusplus
}
# endif
#endif
/* END ggets.h */

View File

@@ -0,0 +1,455 @@
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <ogcsys.h>
#include <network.h>
#include <ogc/machine/processor.h>
#include <ogc/lwp_watchdog.h>
#include <ogc/cond.h>
#include "../config.h"
#ifdef ENABLE_UPDATES
#include "tcp.h"
#include "panic.h"
#include "http.h"
extern u32 ms_id;
extern u32 ng_id;
typedef enum {
HTTPCMD_IDLE = 0,
HTTPCMD_EXIT,
HTTPCMD_FETCH
} http_cmd;
typedef struct {
bool running;
bool done;
http_cmd cmd;
char *host;
u16 port;
char *path;
u32 max_size;
u16 sysmenu_version;
char *region;
char *area;
mutex_t mutex;
mutex_t cmutex;
cond_t cond;
http_state state;
http_res res;
u32 http_status;
u32 content_length;
u32 progress;
u8 *data;
} http_arg;
static lwp_t http_thread;
static u8 http_stack[HTTP_THREAD_STACKSIZE] ATTRIBUTE_ALIGN (32);
static http_arg ta_http;
static u16 get_tmd_version(u64 title) {
STACK_ALIGN(u8, tmdbuf, 1024, 32);
u32 tmd_view_size = 0;
s32 res;
res = ES_GetTMDViewSize(title, &tmd_view_size);
if (res < 0)
return 0;
if (tmd_view_size > 1024)
return 0;
res = ES_GetTMDView(title, tmdbuf, tmd_view_size);
if (res < 0)
return 0;
return (tmdbuf[88] << 8) | tmdbuf[89];
}
static bool http_split_url (char **host, char **path, const char *url) {
const char *p;
char *c;
if (strncasecmp (url, "http://", 7))
return false;
p = url + 7;
c = strchr (p, '/');
if (c[0] == 0)
return false;
*host = strndup (p, c - p);
*path = pstrdup (c);
return true;
}
static void * http_func (void *arg) {
http_arg *ta = (http_arg *) arg;
int s;
char *request, *r;
int linecount;
char *line;
bool b;
s64 t;
ta->running = true;
LWP_MutexLock (ta->cmutex);
LWP_MutexLock (ta_http.mutex);
ta->state = HTTPS_IDLE;
ta->done = true;
LWP_MutexUnlock (ta_http.mutex);
while (true) {
while (ta->cmd == HTTPCMD_IDLE)
LWP_CondWait(ta->cond, ta->cmutex);
if (ta->cmd == HTTPCMD_EXIT)
break;
ta->cmd = HTTPCMD_IDLE;
s = tcp_connect (ta->host, ta->port);
LWP_MutexLock (ta_http.mutex);
if (s < 0) {
ta->state = HTTPS_IDLE;
ta->done = true;
ta->res = HTTPR_ERR_CONNECT;
LWP_MutexUnlock (ta_http.mutex);
continue;
}
ta->state = HTTPS_REQUESTING;
LWP_MutexUnlock (ta_http.mutex);
request = (char *) pmalloc (2048);
r = request;
r += sprintf (r, "GET %s HTTP/1.1\r\n", ta->path);
r += sprintf (r, "Host: %s\r\n", ta->host);
r += sprintf (r, "Cache-Control: no-cache\r\n");
r += sprintf (r, "User-Agent: TheHomebrewChannel/%s Wii/%08lx"
" (%lu; %u; %s-%s)\r\n", CHANNEL_VERSION_STR,
ng_id, ms_id, ta->sysmenu_version, ta->region,
ta->area);
strcat (r, "\r\n");
b = tcp_write (s, (u8 *) request, strlen (request), NULL, NULL);
free (request);
if (!b) {
LWP_MutexLock (ta_http.mutex);
ta->state = HTTPS_IDLE;
ta->done = true;
ta->res = HTTPR_ERR_REQUEST;
LWP_MutexUnlock (ta_http.mutex);
net_close (s);
continue;
}
linecount = 0;
t = gettime ();
while (true) {
line = tcp_readln (s, 0xff, t, HTTP_TIMEOUT);
if (!line) {
LWP_MutexLock (ta_http.mutex);
ta->http_status = 404;
ta->res = HTTPR_ERR_REQUEST;
break;
}
if (strlen (line) < 1) {
free (line);
LWP_MutexLock (ta_http.mutex);
break;
}
sscanf (line, "HTTP/1.%*u %lu", &ta->http_status);
sscanf (line, "Content-Length: %lu", &ta->content_length);
free (line);
linecount++;
if (linecount == 32) {
LWP_MutexLock (ta_http.mutex);
ta->http_status = 404;
ta->res = HTTPR_ERR_REQUEST;
break;
}
}
if (ta->content_length < 1)
ta->http_status = 404;
if (ta->http_status != 200) {
ta->res = HTTPR_ERR_STATUS;
ta->state = HTTPS_IDLE;
ta->done = true;
LWP_MutexUnlock (ta_http.mutex);
net_close (s);
continue;
}
if (ta->content_length > ta->max_size) {
ta->res = HTTPR_ERR_TOOBIG;
ta->state = HTTPS_IDLE;
ta->done = true;
LWP_MutexUnlock (ta_http.mutex);
net_close (s);
continue;
}
ta->state = HTTPS_RECEIVING;
// safety, for char[] parsing
ta->data = (u8 *) pmalloc (ta->content_length + 1);
LWP_MutexUnlock (ta_http.mutex);
b = tcp_read (s, ta->data, ta->content_length, &ta->mutex,
&ta->progress);
if (!b) {
LWP_MutexLock (ta_http.mutex);
free (ta->data);
ta->data = NULL;
ta->res = HTTPR_ERR_RECEIVE;
ta->state = HTTPS_IDLE;
ta->done = true;
LWP_MutexUnlock (ta_http.mutex);
net_close (s);
continue;
}
gprintf("done with download\n");
LWP_MutexLock (ta_http.mutex);
ta->data[ta->content_length] = 0;
ta->res = HTTPR_OK;
ta->state = HTTPS_IDLE;
ta->done = true;
LWP_MutexUnlock (ta_http.mutex);
net_close (s);
}
LWP_MutexUnlock (ta->cmutex);
gprintf("http thread done\n");
ta->running = false;
return NULL;
}
void http_init (void) {
s32 res;
gprintf ("starting http thread\n");
memset (&ta_http, 0, sizeof (http_arg));
ta_http.sysmenu_version = get_tmd_version(0x0000000100000002ll);
switch (CONF_GetRegion()) {
case CONF_REGION_JP:
ta_http.region = pstrdup("JP");
break;
case CONF_REGION_US:
ta_http.region = pstrdup("US");
break;
case CONF_REGION_EU:
ta_http.region = pstrdup("EU");
break;
case CONF_REGION_KR:
ta_http.region = pstrdup("KR");
break;
case CONF_REGION_CN:
ta_http.region = pstrdup("CN");
break;
default:
ta_http.region = pstrdup("UNK");
break;
}
switch (CONF_GetArea()) {
case CONF_AREA_JPN:
ta_http.area = pstrdup("JPN");
break;
case CONF_AREA_USA:
ta_http.area = pstrdup("USA");
break;
case CONF_AREA_EUR:
ta_http.area = pstrdup("EUR");
break;
case CONF_AREA_AUS:
ta_http.area = pstrdup("AUS");
break;
case CONF_AREA_BRA:
ta_http.area = pstrdup("BRA");
break;
case CONF_AREA_TWN:
ta_http.area = pstrdup("TWN");
break;
case CONF_AREA_ROC:
ta_http.area = pstrdup("ROC");
break;
case CONF_AREA_KOR:
ta_http.area = pstrdup("KOR");
break;
case CONF_AREA_HKG:
ta_http.area = pstrdup("HKG");
break;
case CONF_AREA_ASI:
ta_http.area = pstrdup("ASI");
break;
case CONF_AREA_LTN:
ta_http.area = pstrdup("LTN");
break;
case CONF_AREA_SAF:
ta_http.area = pstrdup("SAF");
break;
case CONF_AREA_CHN:
ta_http.area = pstrdup("CHN");
break;
default:
ta_http.area = pstrdup("UNK");
break;
}
res = LWP_MutexInit (&ta_http.mutex, false);
if (res) {
gprintf ("error creating mutex: %ld\n", res);
return;
}
res = LWP_MutexInit (&ta_http.cmutex, false);
if (res) {
gprintf ("error creating cmutex: %ld\n", res);
return;
}
res = LWP_CondInit (&ta_http.cond);
if (res) {
gprintf ("error creating cond: %ld\n", res);
return;
}
memset (&http_stack, 0, HTTP_THREAD_STACKSIZE);
res = LWP_CreateThread (&http_thread, http_func, &ta_http, http_stack,
HTTP_THREAD_STACKSIZE, HTTP_THREAD_PRIO);
gprintf("created http thread\n");
if (res) {
gprintf ("error creating thread: %ld\n", res);
}
}
void http_deinit (void) {
int i;
if (ta_http.running) {
gprintf ("stopping http thread\n");
for (i = 0; i < 25; ++i) {
if (LWP_MutexTryLock (ta_http.cmutex) == 0) {
break;
}
usleep (20 * 1000);
}
if (i < 25) {
gprintf ("sending http entry thread the exit cmd\n");
ta_http.cmd = HTTPCMD_EXIT;
LWP_SetThreadPriority (http_thread, LWP_PRIO_HIGHEST);
LWP_CondBroadcast (ta_http.cond);
LWP_MutexUnlock (ta_http.cmutex);
LWP_JoinThread(http_thread, NULL);
LWP_CondDestroy (ta_http.cond);
LWP_MutexDestroy (ta_http.cmutex);
LWP_MutexDestroy (ta_http.mutex);
free(ta_http.region);
free(ta_http.area);
return;
}
gprintf("http thread didn't shutdown gracefully!\n");
}
return;
}
bool http_ready (void) {
return ta_http.running && ta_http.done;
}
bool http_request (const char *url, u32 max_size) {
if (!http_ready () || !http_split_url (&ta_http.host, &ta_http.path, url))
return false;
LWP_MutexLock (ta_http.cmutex);
ta_http.done = false;
ta_http.cmd = HTTPCMD_FETCH;
ta_http.port = 80;
ta_http.max_size = max_size;
LWP_CondBroadcast (ta_http.cond);
LWP_MutexUnlock (ta_http.cmutex);
return true;
}
bool http_get_state (http_state *state, u32 *content_length, u32 *progress) {
if (!ta_http.running)
return false;
LWP_MutexLock (ta_http.mutex);
*state = ta_http.state;
*content_length = ta_http.content_length;
*progress = ta_http.progress;
LWP_MutexUnlock (ta_http.mutex);
return true;
}
bool http_get_result (http_res *res, u32 *http_status, u8 **content,
u32 *length) {
if (!http_ready())
return false;
*res = ta_http.res;
*http_status = ta_http.http_status;
if (ta_http.res == HTTPR_OK) {
*content = ta_http.data;
*length = ta_http.content_length;
} else {
*content = NULL;
*length = 0;
}
free (ta_http.host);
ta_http.host = NULL;
free (ta_http.path);
ta_http.path = NULL;
return true;
}
#endif

View File

@@ -0,0 +1,33 @@
#ifndef _HTTP_H_
#define _HTTP_H_
#include <gctypes.h>
typedef enum {
HTTPS_IDLE = 0,
HTTPS_CONNECTING,
HTTPS_REQUESTING,
HTTPS_RECEIVING
} http_state;
typedef enum {
HTTPR_OK,
HTTPR_ERR_CONNECT,
HTTPR_ERR_REQUEST,
HTTPR_ERR_STATUS,
HTTPR_ERR_TOOBIG,
HTTPR_ERR_RECEIVE
} http_res;
void http_init (void);
void http_deinit (void);
bool http_ready (void);
bool http_request (const char *url, u32 max_size);
bool http_get_state (http_state *state, u32 *content_length, u32 *progress);
bool http_get_result (http_res *res, u32 *http_status, u8 **content,
u32 *length);
#endif

View File

@@ -0,0 +1,86 @@
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <gctypes.h>
#include "../config.h"
struct mo_entry {
u32 length;
u32 offset;
} __attribute__((packed));
struct mo_hdr {
u32 magic;
u32 revision;
u32 count;
struct mo_entry *source;
struct mo_entry *target;
u32 hash_size;
void *hashes;
} __attribute__((packed));
static struct mo_hdr mo;
static int mo_inited = false;
static const char *mo_data = NULL;
#define MAGIC_SWAB 0xde120495
#define MAGIC 0x950412de
#define SWAB16(x) ((((x)>>8)&0xFF) | (((x)&0xFF)<<8))
#define SWAB32(x) ((SWAB16((x)&0xFFFF)<<16)|(SWAB16(((x)>>16)&0xFFFF)))
#define ENDIAN(x) ((mo.magic == MAGIC_SWAB) ? SWAB32(x) : (x))
void i18n_set_mo(const void *mo_file) {
mo_inited = true;
if(!mo_file) {
mo_data = NULL;
gprintf("i18n: unset mo file\n");
return;
}
memcpy(&mo, mo_file, sizeof(struct mo_hdr));
if(mo.magic == MAGIC_SWAB) {
mo.revision = SWAB32(mo.revision);
mo.count = SWAB32(mo.count);
mo.source = (struct mo_entry*)SWAB32((u32)mo.source);
mo.target = (struct mo_entry*)SWAB32((u32)mo.target);
mo.hash_size = SWAB32(mo.hash_size);
mo.hashes = (void*)SWAB32((u32)mo.magic);
} else if(mo.magic != MAGIC) {
gprintf("i18n: bad mo file magic 0x%08lx\n",mo.magic);
return;
}
if(mo.revision != 0)
gprintf("i18n: bad mo file revision 0x%08lx\n",mo.revision);
mo_data = (char*)mo_file;
mo.source = (struct mo_entry*)(mo_data + (u32)mo.source);
gprintf("i18n: configured mo file at %p\n",mo_data);
mo.target = (struct mo_entry*)(mo_data + (u32)mo.target);
}
const char *i18n(char *english_string) {
int i;
if(!mo_inited)
gprintf("i18n: warning: attempted to translate '%s' before init\n", english_string);
if(!mo_data)
return english_string;
for(i = 0; i < mo.count; i++) {
if(!strcmp(english_string, &mo_data[ENDIAN(mo.source[i].offset)]))
return &mo_data[ENDIAN(mo.target[i].offset)];
}
gprintf("i18n: could not find string for %s\n", english_string);
return english_string;
}
u32 i18n_have_mo(void) {
return mo_data ? 1 : 0;
}

View File

@@ -0,0 +1,13 @@
#ifndef _I18N_H_
#define _I18N_H_
#include <gctypes.h>
#define _(x) i18n(x)
void i18n_set_mo(const void *mo_file);
const char *i18n(char *english_string);
u32 i18n_have_mo(void);
#endif

View File

@@ -0,0 +1,129 @@
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <gccore.h>
#include "../config.h"
#include "blob.h"
#include "panic.h"
#include "isfs.h"
#define ROUNDUP32B(x) ((x + 32 - 1) & ~(32 - 1))
static fstats __st ATTRIBUTE_ALIGN(32);
s32 isfs_get(const char *path, u8 **buf, u32 expected, u32 maxsize, bool use_blob) {
s32 ret;
s32 fd;
u8 *__buf;
gprintf("reading %s (expecting %lu bytes)\n", path, expected);
ret = ISFS_Open(path, ISFS_OPEN_READ);
if (ret < 0) {
gprintf("ISFS_Open failed (%ld)\n", ret);
return ret;
}
fd = ret;
ret = ISFS_GetFileStats(fd, &__st);
if (ret < 0) {
gprintf("ISFS_GetFileStats failed (%ld)\n", ret);
return ret;
}
DCInvalidateRange(&__st, sizeof(__st));
if ((__st.file_length == 0) ||
(maxsize && (__st.file_length > maxsize)) ||
(expected && (__st.file_length != expected))) {
gprintf("invalid size: %lu\n", __st.file_length);
ISFS_Close(fd);
return -1;
}
if (use_blob) {
__buf = blob_alloc(ROUNDUP32B(__st.file_length + 1));
if (!__buf)
panic();
} else {
__buf = pmemalign(32, ROUNDUP32B(__st.file_length + 1));
}
gprintf("reading %lu bytes\n", __st.file_length);
ret = ISFS_Read(fd, __buf, __st.file_length);
if (ret < 0) {
gprintf("ISFS_Read failed (%ld)\n", ret);
free(__buf);
ISFS_Close(fd);
return ret;
}
DCInvalidateRange(__buf, __st.file_length + 1);
__buf[__st.file_length] = 0;
if (ret != __st.file_length) {
gprintf("ISFS_Read short read (%ld)\n", ret);
free(__buf);
ISFS_Close(fd);
return -1;
}
ret = ISFS_Close(fd);
if (ret < 0) {
gprintf("ISFS_Close failed (%ld)\n", ret);
free(__buf);
return ret;
}
*buf = __buf;
return __st.file_length;
}
s32 isfs_put(const char *path, const void *buf, u32 len) {
s32 fd, ret;
ISFS_Delete(path);
gprintf("writing %s (%lu bytes)\n", path, len);
ret = ISFS_CreateFile(path, 0, 3, 3, 0);
if (ret < 0) {
gprintf("ISFS_CreateFile failed (%ld)\n", ret);
return ret;
}
ret = ISFS_Open(path, 3);
if (ret < 0) {
gprintf("ISFS_Open failed (%ld)\n", ret);
ISFS_Delete(path);
return ret;
}
fd = ret;
DCFlushRange((void *) buf, len);
ret = ISFS_Write(fd, buf, len);
if (ret < 0) {
gprintf("ISFS_Write failed (%ld)\n", ret);
ISFS_Close(fd);
ISFS_Delete(path);
return ret;
}
if (ret != len) {
gprintf("ISFS_Write short write (%ld)\n", ret);
ISFS_Close(fd);
ISFS_Delete(path);
return -1;
}
ret = ISFS_Close(fd);
if (ret < 0) {
gprintf("ISFS_Close failed (%ld)\n", ret);
ISFS_Delete(path);
return ret;
}
return 0;
}

View File

@@ -0,0 +1,9 @@
#ifndef ___ISFS_H__
#define ___ISFS_H__
#include <gctypes.h>
s32 isfs_get(const char *path, u8 **buf, u32 expected, u32 maxsize, bool use_blob);
s32 isfs_put(const char *path, const void *buf, u32 len);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
#ifndef _LOADER_H_
#define _LOADER_H_
#include <unistd.h>
#include <gctypes.h>
#include "loader_reloc.h"
#include "appentry.h"
#include "view.h"
typedef enum {
LT_UNKNOWN = 0,
LT_EXECUTABLE,
LT_ZIP_APP,
LT_ZIP_THEME
} loader_type;
typedef struct {
loader_type type;
u8 *data;
u32 data_len;
char args[ARGS_MAX_LEN];
u32 args_len;
char dirname[MAXPATHLEN];
u32 bytes;
} loader_result;
void loader_init (void);
void loader_deinit (void);
void loader_tcp_init (void);
void loader_signal_threads (void);
bool loader_gecko_initialized (void);
bool loader_tcp_initializing (void);
bool loader_tcp_initialized (void);
bool loader_handshaked (void);
void loader_load(loader_result *result, view *sub_view, app_entry *entry);
bool loader_load_executable(entry_point *ep, loader_result *result,
view *sub_view);
bool loader_handle_zip_app(loader_result *result, view *sub_view);
#endif

View File

@@ -0,0 +1,283 @@
#include <stdio.h>
#include <string.h>
#include <ogcsys.h>
#include <ogc/machine/processor.h>
#include "../config.h"
#include "loader.h"
#include "elf_abi.h"
#include "asm.h"
extern void __exception_closeall ();
typedef struct _dolheader {
u32 text_pos[7];
u32 data_pos[11];
u32 text_start[7];
u32 data_start[11];
u32 text_size[7];
u32 data_size[11];
u32 bss_start;
u32 bss_size;
u32 entry_point;
} dolheader;
static void patch_crt0 (entry_point *ep) {
u8 *p = (u8 *) *ep;
if (p[0x20] == 0x41) {
gprintf ("patching crt0\n");
p[0x20] = 0x40;
DCFlushRange ((void *) &p[0x20], 1);
}
}
static void set_argv (entry_point *ep, const char *args, u16 arg_len) {
u32 *p = (u32 *) *ep;
struct __argv *argv;
char *cmdline;
if (p[1] != ARGV_MAGIC) {
gprintf ("application does not support argv\n");
return;
}
gprintf ("setting argv\n");
argv = (struct __argv *) &p[2];
cmdline = (char *) LD_ARGS_ADDR;
memcpy (cmdline, args, arg_len);
#ifdef DEBUG_APP
size_t i;
gprintf ("cmdline='");
for (i = 0; i < arg_len; ++i)
if (cmdline[i] == 0)
gprintf ("\\0");
else
gprintf ("%c", cmdline[i]);
gprintf ("'\n");
#endif
argv->argvMagic = ARGV_MAGIC;
argv->commandLine = cmdline;
argv->length = arg_len;
DCFlushRange (&p[2], 4);
DCFlushRange ((void *) LD_ARGS_ADDR, arg_len);
}
static bool reloc_dol (entry_point *ep, const u8 *addr, u32 size,
bool check_overlap) {
u32 i;
dolheader *dolfile;
dolfile = (dolheader *) addr;
for (i = 0; i < 7; i++) {
if (!dolfile->text_size[i])
continue;
gprintf ("loading text section %lu @ 0x%08lx (0x%08lx bytes)\n", i,
dolfile->text_start[i], dolfile->text_size[i]);
if (dolfile->text_pos[i] + dolfile->text_size[i] > size)
return false;
if (check_overlap && ((dolfile->text_start[i] < LD_MIN_ADDR) ||
((dolfile->text_start[i] + dolfile->text_size[i] >
LD_MAX_ADDR))))
return false;
memmove ((void *) dolfile->text_start[i], addr + dolfile->text_pos[i],
dolfile->text_size[i]);
DCFlushRange ((void *) dolfile->text_start[i], dolfile->text_size[i]);
ICInvalidateRange ((void *) dolfile->text_start[i],
dolfile->text_size[i]);
}
for(i = 0; i < 11; i++) {
if (!dolfile->data_size[i])
continue;
gprintf ("loading data section %lu @ 0x%08lx (0x%08lx bytes)\n", i,
dolfile->data_start[i], dolfile->data_size[i]);
if (dolfile->data_pos[i] + dolfile->data_size[i] > size)
return false;
if (check_overlap && ((dolfile->data_start[i] < LD_MIN_ADDR) ||
(dolfile->data_start[i] + dolfile->data_size[i] > LD_MAX_ADDR)))
return false;
memmove ((void*) dolfile->data_start[i], addr + dolfile->data_pos[i],
dolfile->data_size[i]);
DCFlushRange ((void *) dolfile->data_start[i], dolfile->data_size[i]);
}
*ep = (entry_point) dolfile->entry_point;
return true;
}
static s8 is_valid_elf (const u8 *addr, u32 size) {
Elf32_Ehdr *ehdr; /* Elf header structure pointer */
ehdr = (Elf32_Ehdr *) addr;
if (!IS_ELF (*ehdr))
return 0;
if (ehdr->e_ident[EI_CLASS] != ELFCLASS32)
return -1;
if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
return -1;
if (ehdr->e_ident[EI_VERSION] != EV_CURRENT)
return -1;
if (ehdr->e_type != ET_EXEC)
return -1;
if (ehdr->e_machine != EM_PPC)
return -1;
return 1;
}
static bool reloc_elf (entry_point *ep, const u8 *addr, u32 size,
bool check_overlap) {
Elf32_Ehdr *ehdr;
Elf32_Phdr *phdrs;
u8 *image;
int i;
ehdr = (Elf32_Ehdr *) addr;
if(ehdr->e_phoff == 0 || ehdr->e_phnum == 0) {
gprintf("ELF has no phdrs\n");
return false;
}
if(ehdr->e_phentsize != sizeof(Elf32_Phdr)) {
gprintf("Invalid ELF phdr size\n");
return false;
}
phdrs = (Elf32_Phdr*)(addr + ehdr->e_phoff);
for(i=0;i<ehdr->e_phnum;i++) {
if(phdrs[i].p_type != PT_LOAD) {
gprintf("skip PHDR %d of type %ld\n", i, phdrs[i].p_type);
} else {
phdrs[i].p_paddr &= 0x3FFFFFFF;
phdrs[i].p_paddr |= 0x80000000;
gprintf ("PHDR %d 0x%08lx [0x%lx] -> 0x%08lx [0x%lx] <", i,
phdrs[i].p_offset, phdrs[i].p_filesz,
phdrs[i].p_paddr, phdrs[i].p_memsz);
if(phdrs[i].p_flags & PF_R)
gprintf("R");
if(phdrs[i].p_flags & PF_W)
gprintf("W");
if(phdrs[i].p_flags & PF_X)
gprintf("X");
gprintf(">\n");
if(phdrs[i].p_filesz > phdrs[i].p_memsz) {
gprintf ("-> file size > mem size\n");
return false;
}
if(phdrs[i].p_filesz) {
if (check_overlap && ((phdrs[i].p_paddr < LD_MIN_ADDR) ||
(phdrs[i].p_paddr + phdrs[i].p_filesz) > LD_MAX_ADDR)) {
gprintf ("-> failed overlap check\n");
return false;
}
gprintf ("-> load 0x%lx\n", phdrs[i].p_filesz);
image = (u8 *) (addr + phdrs[i].p_offset);
memmove ((void *) phdrs[i].p_paddr, (const void *) image,
phdrs[i].p_filesz);
DCFlushRange ((void *) phdrs[i].p_paddr, phdrs[i].p_memsz);
if(phdrs[i].p_flags & PF_X)
ICInvalidateRange ((void *) phdrs[i].p_paddr, phdrs[i].p_memsz);
} else {
gprintf ("-> skip\n");
}
}
}
*ep = (entry_point) ((ehdr->e_entry & 0x3FFFFFFF) | 0x80000000);
return true;
}
bool loader_reloc (entry_point *ep, const u8 *addr, u32 size, const char *args,
u16 arg_len, bool check_overlap) {
s8 res;
bool b;
res = is_valid_elf (addr, size);
if (res < 0)
return false;
if (res == 1)
b = reloc_elf (ep, addr, size, check_overlap);
else
b = reloc_dol (ep, addr, size, check_overlap);
if (b) {
patch_crt0 (ep);
if (args && arg_len)
set_argv (ep, args, arg_len);
}
return b;
}
static const u32 exec_stub[] = {
0x7c6903a6, // mtctr r3
0x3d208133, // lis r9, 0x8133
0x3d408180, // lis r10, 0x8180
0x90090000, // 1: stw r0, 0(r9)
0x39290004, // addi r9, r9, 4
0x7c295000, // cmpd r9, r10
0x4180fff4, // blt 1b
0x4e800420 // bctr
};
void loader_exec (entry_point ep) {
gprintf ("shutting down services and vectoring...\n");
SYS_ResetSystem (SYS_SHUTDOWN, 0, 0);
__exception_closeall ();
// these pokes make ninty SDK dols work, I'm told
*(vu32*)0x800000F8 = 0x0E7BE2C0; // Bus Clock Speed
*(vu32*)0x800000FC = 0x2B73A840; // CPU Clock Speed
void *target = (void *)((int)(SYS_GetArena2Hi() - sizeof exec_stub) & ~31);
void (*f_exec_stub) (int) = target;
memcpy(target, exec_stub, sizeof exec_stub);
DCFlushRange(target, sizeof exec_stub);
ICInvalidateRange(target, sizeof exec_stub);
f_exec_stub((u32)ep);
gprintf ("this cant be good\n");
}

View File

@@ -0,0 +1,13 @@
#ifndef _LOADER_RELOC_H_
#define _LOADER_RELOC_H_
#include <gctypes.h>
typedef void (*entry_point) (void);
bool loader_reloc (entry_point *ep, const u8 *addr, u32 size, const char *args,
u16 arg_len, bool check_overlap);
void loader_exec (entry_point ep);
#endif

View File

@@ -0,0 +1,141 @@
#include <stdio.h>
#include <malloc.h>
#include <ogcsys.h>
#include <network.h>
#include "../config.h"
#include "theme.h"
#include "view.h"
#include "loader.h"
#include "i18n.h"
#include "panic.h"
#include "m_main.h"
static view *v_m_main;
static const char *text_no_ip;
static const char *text_has_ip;
static bool bootmii_ios = false;
static bool bootmii_is_installed(u64 title_id) {
u32 tmd_view_size;
u8 *tmdbuf;
bool ret;
if (ES_GetTMDViewSize(title_id, &tmd_view_size) < 0)
return false;
if (tmd_view_size < 90)
return false;
if (tmd_view_size > 1024)
return false;
tmdbuf = pmemalign(32, 1024);
if (ES_GetTMDView(title_id, tmdbuf, tmd_view_size) < 0) {
free(tmdbuf);
return false;
}
if (tmdbuf[50] == 'B' && tmdbuf[51] == 'M')
ret = true;
else
ret = false;
free(tmdbuf);
return ret;
}
static bool inited_widgets = false;
view * m_main_init (void) {
bootmii_ios = bootmii_is_installed(TITLEID_BOOTMII);
v_m_main = view_new (8, NULL, 0, 0, 0, 0);
m_main_theme_reinit();
m_main_update();
view_set_focus(v_m_main, 0);
return v_m_main;
}
void m_main_deinit(void) {
view_free (v_m_main);
inited_widgets = false;
v_m_main = NULL;
}
void m_main_theme_reinit(void) {
u16 x, y, yadd;
int i;
char buffer[20];
text_no_ip = _("Network not initialized");
text_has_ip = _("Your Wii's IP is %u.%u.%u.%u");
if (inited_widgets)
for (i = 0; i < v_m_main->widget_count; ++i)
widget_free(&v_m_main->widgets[i]);
if (bootmii_ios)
yadd = 16;
else
yadd = 32;
x = (view_width - theme_gfx[THEME_BUTTON]->w) / 2;
y = 80;
widget_button (&v_m_main->widgets[0], x, y, 0, BTN_NORMAL, _("Back"));
y += theme_gfx[THEME_BUTTON]->h + yadd;
widget_button (&v_m_main->widgets[1], x, y, 0, BTN_NORMAL, _("About"));
y += theme_gfx[THEME_BUTTON]->h + yadd;
if (bootmii_ios) {
widget_button (&v_m_main->widgets[2], x, y, 0, BTN_NORMAL,
_("Launch BootMii"));
y += theme_gfx[THEME_BUTTON]->h + yadd;
}
widget_button (&v_m_main->widgets[3], x, y, 0, BTN_NORMAL, _("Exit to System Menu"));
y += theme_gfx[THEME_BUTTON]->h + yadd;
widget_button (&v_m_main->widgets[4], x, y, 0, BTN_NORMAL, _("Shutdown"));
widget_label (&v_m_main->widgets[5], view_width / 3 * 2 - 16, 32, 0,
CHANNEL_VERSION_STR, view_width / 3 - 32, FA_RIGHT,
FA_ASCENDER, FONT_LABEL);
sprintf(buffer, "IOS%ld v%ld.%ld", IOS_GetVersion(), IOS_GetRevisionMajor(),
IOS_GetRevisionMinor());
widget_label (&v_m_main->widgets[6], view_width / 3 * 2 - 16,
32 + font_get_y_spacing(FONT_LABEL), 0, buffer,
view_width / 3 - 32, FA_RIGHT, FA_ASCENDER, FONT_LABEL);
inited_widgets = true;
}
void m_main_update (void) {
u32 ip;
char buffer[64];
if (loader_tcp_initialized ()) {
ip = net_gethostip ();
sprintf (buffer, text_has_ip, (ip >> 24) & 0xff, (ip >> 16) & 0xff,
(ip >> 8) & 0xff, ip & 0xff);
widget_label (&v_m_main->widgets[7], 48, 32, 0, buffer,
view_width / 3 * 2 - 32, FA_LEFT, FA_ASCENDER, FONT_LABEL);
} else {
widget_label (&v_m_main->widgets[7], 48, 32, 0, text_no_ip,
view_width / 3 * 2 - 32, FA_LEFT, FA_ASCENDER, FONT_LABEL);
}
}

View File

@@ -0,0 +1,15 @@
#ifndef _M_MAIN_H_
#define _M_MAIN_H_
#include <gctypes.h>
#include "view.h"
view * m_main_init (void);
void m_main_deinit (void);
void m_main_theme_reinit (void);
void m_main_update (void);
#endif

View File

@@ -0,0 +1,825 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <locale.h>
#include <ctype.h>
#include <ogcsys.h>
#include <ogc/machine/processor.h>
#include <ogc/conf.h>
#include <debug.h>
#include "../config.h"
#include "controls.h"
#include "appentry.h"
#include "playtime.h"
#include "gfx.h"
#include "tex.h"
#include "theme.h"
#include "cursors.h"
#include "font.h"
#include "widgets.h"
#include "view.h"
#include "bubbles.h"
#include "dialogs.h"
#include "browser.h"
#include "m_main.h"
#include "loader.h"
#ifdef ENABLE_UPDATES
#include "http.h"
#include "update.h"
#endif
#include "i18n.h"
#include "dvd.h"
#include "manage.h"
#include "xml.h"
#include "title.h"
// Languages
#include "spanish_mo.h"
#include "dutch_mo.h"
#include "german_mo.h"
#include "french_mo.h"
#include "italian_mo.h"
#include "japanese_mo.h"
#ifdef DEBUG_APP
//#define GDBSTUB
#else
#undef GDBSTUB
#endif
#define WARN_SPLIT 360
extern const u8 stub_bin[];
extern const u8 stub_bin_end;
extern const u32 stub_bin_size;
u64 *conf_magic = STUB_ADDR_MAGIC;
u64 *conf_title_id = STUB_ADDR_TITLE;
static bool should_exit;
static bool shutdown;
#ifdef GDBSTUB
static bool gdb;
#endif
static const char *text_delete;
static const char *text_error_delete;
s32 __IOS_LoadStartupIOS(void) {
#if 0
__ES_Init();
__IOS_LaunchNewIOS(58);
#endif
return 0;
}
#define MEM2_PROT 0x0D8B420A
#define ES_MODULE_START (u16*)0x939F0000
static const u16 ticket_check[] = {
0x685B, // ldr r3,[r3,#4] ; get TMD pointer
0x22EC, 0x0052, // movls r2, 0x1D8
0x189B, // adds r3, r3, r2; add offset of access rights field in TMD
0x681B, // ldr r3, [r3] ; load access rights (haxxme!)
0x4698, // mov r8, r3 ; store it for the DVD video bitcheck later
0x07DB // lsls r3, r3, #31; check AHBPROT bit
};
static int patch_ahbprot_reset(void)
{
u16 *patchme;
if ((read32(0x0D800064) == 0xFFFFFFFF) ? 1 : 0) {
write16(MEM2_PROT, 2);
for (patchme=ES_MODULE_START; patchme < ES_MODULE_START+0x4000; ++patchme) {
if (!memcmp(patchme, ticket_check, sizeof(ticket_check)))
{
// write16/uncached poke doesn't work for MEM2
patchme[4] = 0x23FF; // li r3, 0xFF
DCFlushRange(patchme+4, 2);
return 0;
}
}
return -1;
} else {
return -2;
}
}
static void reset_cb(void) {
#ifdef GDBSTUB
gdb = true;
#else
should_exit = true;
#endif
}
static void power_cb(void) {
should_exit = true;
shutdown = true;
}
void config_language(void) {
s32 language;
const void *mo;
// this is probably wrong, but we don't let the C library do any UTF-8 text
// processing worth mentioning anyway, and I'm scared of what might happen
// if I change this :P
setlocale(LC_CTYPE, "C-ISO-8859-1");
#ifdef FORCE_LANG
language = FORCE_LANG;
#else
language = CONF_GetLanguage();
if (language < 0)
language = CONF_LANG_ENGLISH;
#endif
mo = NULL;
switch (language) {
case CONF_LANG_ENGLISH:
mo = NULL;
break;
case CONF_LANG_SPANISH:
mo = spanish_mo;
break;
case CONF_LANG_FRENCH:
mo = french_mo;
break;
case CONF_LANG_GERMAN:
mo = german_mo;
break;
case CONF_LANG_DUTCH:
mo = dutch_mo;
break;
case CONF_LANG_ITALIAN:
mo = italian_mo;
break;
case CONF_LANG_JAPANESE:
if (theme.langs & TLANG_JA) {
mo = japanese_mo;
} else {
gprintf("language ja disabled due to missing theme support\n");
language = CONF_LANG_ENGLISH;
}
break;
default:
gprintf("unsupported language %ld, defaulting to English\n",
language);
language = CONF_LANG_ENGLISH;
}
gprintf("configuring language: %ld with mo file at %p\n", language, mo);
i18n_set_mo(mo);
}
static void main_pre(void) {
#ifdef DEBUG_APP
if(usb_isgeckoalive(USBGECKO_CHANNEL))
CON_EnableGecko(USBGECKO_CHANNEL, 1);
#ifdef GDBSTUB
DEBUG_Init(GDBSTUB_DEVICE_USB, USBGECKO_CHANNEL);
#endif
#endif
AUDIO_Init(NULL);
DSP_Init();
AUDIO_StopDMA();
AUDIO_RegisterDMACallback(NULL);
gfx_init_video();
PAD_Init();
SYS_SetResetCallback(reset_cb);
title_init();
SYS_SetPowerCallback(power_cb);
gprintf("installing stub (%lu)\n", stub_bin_size);
#ifdef DEBUG_APP
if (stub_bin_size > 0x1800)
gprintf("WARNING: stub too big!\n");
#endif
memcpy((u32 *) 0x80001800, stub_bin, stub_bin_size);
DCFlushRange((u32 *) 0x80001800, stub_bin_size);
*conf_magic = 0;
gprintf ("startup\n");
gprintf("IOS Version: IOS%ld %ld.%ld\n",
IOS_GetVersion(), IOS_GetRevisionMajor(), IOS_GetRevisionMinor());
ISFS_Initialize();
WiiDVD_StopMotorAsync();
gfx_init();
app_entry_init();
theme_xml_init();
theme_init(NULL, 0);
config_language();
loader_init();
controls_init();
cursors_init();
font_init();
widgets_init();
view_init();
dialogs_init();
}
static void load_text(void)
{
text_delete = _("Do you really want to delete this application?");
text_error_delete = _("Error deleting '%s'");
}
static void refresh_theme(view *v, app_entry *app, u8 *data, u32 data_len) {
browser_gen_view(BA_REMOVE, NULL);
view_fade(v, TEX_LAYER_CURSOR + 1, 0, 0, 0, 0, 32, 8);
font_clear();
theme_deinit();
theme_init(data, data_len);
config_language();
widgets_theme_reinit();
bubbles_theme_reinit();
view_theme_reinit();
browser_theme_reinit();
m_main_theme_reinit();
dialogs_theme_reinit();
view_fade(v, TEX_LAYER_CURSOR + 1, 0xff, 0xff, 0xff, 0xff, 31, -8);
browser_gen_view(BA_REFRESH, app);
load_text();
}
void main_real(void) {
view *v_last, *v_current, *v_m_main, *v_browser, *v_detail, *v_about;
u8 fhw;
u32 bd, bh;
s8 clicked;
s16 mm;
#ifdef ENABLE_UPDATES
s16 update_check = -1;
bool update_in_progress = false;
bool update_available = false;
#endif
app_entry *app_sel;
bool loading = false;
loader_result ld_res;
entry_point ep;
bool reloced;
bool ahb_access;
bool launch_bootmii;
u64 frame;
bool exit_about;
char charbuf[MAXPATHLEN];
load_text();
playtime_destroy();
if (settings_load()) {
app_entry_set_prefered(settings.device);
app_entry_set_sort(settings.sort_order);
if (settings.browse_mode == 1)
browser_switch_mode();
}
#ifdef ENABLE_UPDATES
update_check = 60;
#endif
app_sel = NULL;
v_browser = browser_init();
v_m_main = m_main_init ();
view_bubbles = true;
#ifdef ENABLE_UPDATES
http_init ();
#endif
fhw = font_get_y_spacing(FONT_MEMO);
should_exit = false;
shutdown = false;
#ifdef GDBSTUB
gdb = false;
#endif
reloced = false;
ahb_access = false;
launch_bootmii = false;
frame = 0;
exit_about = false;
v_last = v_current = v_browser;
v_detail = NULL;
v_about = NULL;
view_fade(v_current, TEX_LAYER_CURSOR + 1, 0xff, 0xff, 0xff, 0xff, 31, -8);
view_enable_cursor (true);
while (!should_exit) {
#ifdef GDBSTUB
if (gdb) {
gprintf("attach gdb now!\n");
_break();
gdb = false;
SYS_SetResetCallback (reset_cb);
}
#endif
memstats(false);
if (v_current == v_browser) {
switch (app_entry_action()) {
case AE_ACT_NONE:
break;
case AE_ACT_REMOVE:
app_sel = browser_sel();
if (app_sel) {
memset(settings.app_sel, 0, sizeof(settings.app_sel));
strcpy(settings.app_sel, app_sel->dirname);
}
bubble_popall();
browser_gen_view(BA_REMOVE, NULL);
app_entries_free();
memstats(true);
break;
case AE_ACT_ADD:
if (strlen(settings.app_sel) > 0)
app_sel = app_entry_find(settings.app_sel);
else
app_sel = NULL;
view_show_throbber(false);
browser_gen_view(BA_ADD, app_sel);
break;
}
}
if (loading != app_entry_is_loading()) {
loading = !loading;
view_show_throbber(loading);
}
if (loading)
view_throbber_tickle();
if ((frame % 30) == 0)
app_entry_scan();
view_plot (v_current, DIALOG_MASK_COLOR, &bd, &bh, NULL);
frame++;
if (v_last != v_current) {
frame = 0;
v_last = v_current;
}
if (bd & PADS_HOME) {
if (v_current == v_browser) {
m_main_update ();
v_current = v_m_main;
view_set_focus (v_m_main, 0);
continue;
} else {
if (v_current == v_m_main)
v_current = v_browser;
continue;
}
}
if (v_current == v_m_main) {
if (bd & PADS_B) {
v_current = v_browser;
continue;
}
if (bd & PADS_UP)
view_set_focus_prev (v_current);
if (bd & PADS_DOWN)
view_set_focus_next (v_current);
if (bd & PADS_A) {
switch (v_m_main->focus) {
case 0:
v_current = v_browser;
continue;
case 1:
v_about = dialog_about (v_m_main);
v_current = v_about;
view_enable_cursor (false);
dialog_fade (v_current, true);
exit_about = false;
continue;
case 2:
launch_bootmii = true;
should_exit = true;
break;
case 3:
should_exit = true;
continue;
case 4:
should_exit = true;
shutdown = true;
break;
}
}
continue;
}
if (v_current == v_browser) {
widget_set_flag (&v_browser->widgets[2], WF_ENABLED,
loader_gecko_initialized ());
if (!loader_tcp_initializing ())
widget_set_flag (&v_browser->widgets[3], WF_ENABLED,
loader_tcp_initialized ());
if (loader_tcp_initializing () && (frame % 20 == 0))
widget_toggle_flag (&v_browser->widgets[3], WF_ENABLED);
if (bd & PADS_NET_INIT)
loader_tcp_init ();
#ifdef ENABLE_UPDATES
if (loader_tcp_initialized () && (update_check > 0))
update_check--;
if (update_check == 0) {
update_check = -1;
update_in_progress = update_signal ();
}
if (update_in_progress) {
if (!loading && !update_busy(&update_available))
update_in_progress = false;
}
if (update_available) {
update_available = false;
reloced = update_execute (v_current, &ep);
should_exit = reloced;
continue;
}
#endif
if (bd & PADS_1) {
dialog_options_result options;
options = show_options_dialog(v_current);
if (options.confirmed) {
app_entry_set_sort(options.sort);
app_entry_set_device(options.device);
app_entry_set_prefered(options.device);
}
continue;
}
if (bd & PADS_2) {
browser_switch_mode();
continue;
}
if (bd & PADS_DPAD) {
browser_set_focus(bd);
continue;
}
if (bd & PADS_A) {
clicked = view_widget_at_ir (v_browser);
if (clicked == 0) {
browser_gen_view(BA_PREV, NULL);
continue;
}
if (clicked == 1) {
browser_gen_view(BA_NEXT, NULL);
continue;
}
if (clicked == 3) {
loader_tcp_init ();
continue;
}
app_sel = browser_sel();
if (!app_sel)
continue;
v_detail = dialog_app (app_sel, v_browser);
v_current = v_detail;
dialog_fade (v_current, true);
continue;
}
if ((bd | bh) & PADS_MINUS)
browser_gen_view(BA_PREV, NULL);
if ((bd | bh) & PADS_PLUS)
browser_gen_view(BA_NEXT, NULL);
if (loader_handshaked ()) {
loader_load (&ld_res, v_browser, NULL);
switch (ld_res.type) {
case LT_UNKNOWN:
break;
case LT_EXECUTABLE:
if (loader_load_executable(&ep, &ld_res, v_browser)) {
reloced = true;
ahb_access = true;
should_exit = true;
}
break;
case LT_ZIP_APP:
if (loader_handle_zip_app(&ld_res, v_browser)) {
app_sel = app_entry_add(ld_res.dirname);
if (app_sel)
browser_gen_view(BA_REFRESH, app_sel);
memstats(true);
}
break;
case LT_ZIP_THEME:
refresh_theme(v_current, app_sel, ld_res.data,
ld_res.data_len);
fhw = font_get_y_spacing(FONT_MEMO);
memstats(true);
break;
}
continue;
}
if (!reloced)
loader_signal_threads ();
continue;
}
if (v_current == v_detail) {
if (bd & PADS_LEFT)
view_set_focus_prev (v_current);
if (bd & PADS_RIGHT)
view_set_focus_next (v_current);
mm = 0;
if (bd & PADS_UP)
mm += fhw;
if (bd & PADS_DOWN)
mm -= fhw;
mm += controls_sticky() / 8;
if (v_current->drag && (v_current->drag_widget == 6)) {
mm += -v_current->drag_y / 32;
} else if (bd & PADS_B) {
dialog_fade (v_current, false);
v_current = v_browser;
view_free (v_detail);
v_detail = NULL;
continue;
}
widget_scroll_memo_deco (&v_detail->widgets[5], mm);
if ((bd & PADS_A) && v_detail->focus == 10) {
dialog_fade (v_current, false);
v_current = v_browser;
view_free (v_detail);
v_detail = NULL;
continue;
}
if ((bd & PADS_A) && v_detail->focus == 8) {
dialog_fade (v_current, false);
v_current = v_browser;
view_free (v_detail);
v_detail = NULL;
if (show_message (v_current, DLGMT_CONFIRM, DLGB_YESNO,
text_delete, 1) == 1)
continue;
browser_gen_view(BA_REMOVE, NULL);
if (!manage_run(v_current, app_sel->dirname, NULL, 0, 0)) {
sprintf(charbuf, text_error_delete, app_sel->dirname);
show_message(v_current, DLGMT_ERROR, DLGB_OK, charbuf, 0);
} else {
app_entry_remove(app_sel);
app_sel = NULL;
}
browser_gen_view(BA_REFRESH, NULL);
continue;
}
if ((bd & PADS_A) && v_detail->focus == 9) {
dialog_fade (v_current, false);
v_current = v_browser;
view_free (v_detail);
v_detail = NULL;
loader_load(&ld_res, v_browser, app_sel);
switch (ld_res.type) {
case LT_UNKNOWN:
break;
case LT_EXECUTABLE:
if (loader_load_executable(&ep, &ld_res, v_browser)) {
reloced = true;
if (app_sel && app_sel->meta)
ahb_access = app_sel->meta->ahb_access;
should_exit = true;
}
break;
case LT_ZIP_APP:
free(ld_res.data);
break;
case LT_ZIP_THEME:
refresh_theme(v_current, app_sel, ld_res.data,
ld_res.data_len);
break;
}
continue;
}
continue;
}
if (v_current == v_about) {
if (bd & (PADS_A | PADS_B))
exit_about = true;
if (exit_about) {
dialog_fade (v_current, false);
v_current = v_m_main;
view_free (v_about);
v_about = NULL;
view_enable_cursor (true);
continue;
}
if ((frame > 60 * 2) && (frame % 3) == 0)
widget_scroll_memo (&v_current->widgets[2], -1);
}
}
gprintf ("exiting\n");
view_enable_cursor (false);
if (v_current->sub_view)
dialog_fade (v_current, false);
view_fade (v_current, TEX_LAYER_CURSOR + 1, 0, 0, 0, 0, 32, 8);
WiiDVD_ShutDown();
controls_deinit();
app_sel = browser_sel();
if (app_sel) {
size_t i, s = strlen(app_sel->dirname);
memset(settings.app_sel, 0, sizeof(settings.app_sel));
for (i = 0; i < s; ++i)
settings.app_sel[i] = tolower((int) app_sel->dirname[i]);
}
// because the tcp thread is the only one that can block after the exit
// command is sent, deinit it first. this gives the other threads a chance
// to do any pending work if the tcp thread does block.
loader_deinit ();
#ifdef ENABLE_UPDATES
http_deinit ();
#endif
app_entry_deinit ();
gfx_deinit ();
cursors_deinit ();
browser_deinit ();
m_main_deinit ();
dialogs_deinit ();
view_deinit ();
widgets_deinit ();
font_deinit ();
theme_deinit();
settings_save();
if (launch_bootmii) {
gprintf ("launching BootMii\n");
__IOS_LaunchNewIOS(BOOTMII_IOS);
}
if (reloced) {
if (ahb_access) {
gprintf ("patching IOS for AHB access post-reload...\n");
int res = patch_ahbprot_reset();
if (res)
gprintf ("patch failed (%d)\n", res);
}
gprintf ("reloading to IOS%ld...\n", APPS_IOS_VERSION);
__IOS_LaunchNewIOS(APPS_IOS_VERSION);
if (ahb_access) {
gprintf ("reenabling DVD access...\n");
mask32(0x0D800180, 1<<21, 0);
}
gprintf ("branching to %p\n", ep);
loader_exec (ep);
}
if (shutdown) {
gprintf ("shutting down\n");
SYS_ResetSystem(SYS_POWEROFF, 0, 0);
}
gprintf ("returning to sysmenu\n");
SYS_ResetSystem (SYS_RETURNTOMENU, 0, 0);
}
int main(int argc, char *argv[]) {
main_pre();
main_real();
gprintf("uh oh\n");
return 0;
}

View File

@@ -0,0 +1,561 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <malloc.h>
#include <errno.h>
#include <ogcsys.h>
#include "../config.h"
#include "appentry.h"
#include "theme.h"
#include "unzip.h"
#include "dialogs.h"
#include "i18n.h"
#include "panic.h"
#include "manage.h"
s32 dir_exists(char *dirname) {
struct stat st;
if (stat(dirname, &st) != 0)
return 0;
if (S_ISDIR(st.st_mode))
return 1;
gprintf("'%s' exists, but is no directory\n", dirname);
return -1;
}
static s32 mkdir_hier(char *dirname) {
char dir[MAXPATHLEN];
size_t i;
s32 res;
strcpy(dir, dirname);
if (dir[strlen(dir) - 1] != '/')
strcat(dir, "/");
i = 1;
while (dir[i]) {
if (dir[i] == '/') {
dir[i] = 0;
res = dir_exists(dir);
if (res < 0)
return res;
if (!res) {
gprintf("mkdir '%s'\n", dir);
if (mkdir(dir, 0755)) {
gprintf("mkdir failed: %d\n", errno);
return -1;
}
}
dir[i] = '/';
}
i++;
}
return 0;
}
static s32 rmdir_hier_iter(const char *dirname) {
s32 res = -1;
DIR* d;
struct dirent *de;
gprintf("rmdir_hier_iter '%s'\n", dirname);
d = opendir(dirname);
if (!d) {
gprintf("opendir '%s' failed\n", dirname);
return -1;
}
char newpath[MAXPATHLEN];
while ((de = readdir(d))) {
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
strcpy(newpath, dirname);
if (newpath[strlen(newpath) - 1] != '/')
strcat(newpath, "/");
strcat(newpath, de->d_name);
if (de->d_type == DT_DIR) {
res = rmdir_hier_iter(newpath);
if (res)
goto exit;
}
gprintf("unlinking '%s'\n", newpath);
res = unlink(newpath);
if (res) {
gprintf("error unlinking '%s'\n", newpath);
goto exit;
}
}
res = 0;
exit:
closedir(d);
return res;
}
static s32 rmdir_hier(const char *dirname) {
char buf[MAXPATHLEN];
sprintf(buf, "%s/%s", app_path, dirname);
gprintf("rmdir_hier '%s'\n", buf);
s32 res = rmdir_hier_iter(buf);
if (!res) {
gprintf("unlinking dir '%s'\n", (buf));
res = unlink(buf);
if (res)
gprintf("error unlinking '%s'\n", buf);
}
return res;
}
bool manage_is_zip(const u8 *data) {
return memcmp(data, "PK\x03\x04", 4) == 0;
}
bool manage_check_zip_app(u8 *data, u32 data_len, char *dirname, u32 *bytes) {
unzFile uf;
int res, i;
bool ret = false;
unz_global_info gi;
uf = unzOpen(data, data_len);
if (!uf) {
gprintf("unzOpen failed\n");
return false;
}
res = unzGetGlobalInfo (uf, &gi);
if (res != UNZ_OK) {
gprintf("unzGetGlobalInfo failed: %d\n", res);
goto error;
}
if ((gi.number_entry < 2) || (gi.number_entry > 1024)) {
gprintf("invalid file count\n");
goto error;
}
char filename[256];
unz_file_info fi;
u8 got_elf = 0;
u8 got_dol = 0;
u8 got_theme = 0;
dirname[0] = 0;
*bytes = 0;
for (i = 0; i < gi.number_entry; ++i) {
res = unzGetCurrentFileInfo(uf, &fi, filename, sizeof(filename) ,NULL, 0, NULL, 0);
if (res != UNZ_OK) {
gprintf("unzGetCurrentFileInfo failed: %d\n", res);
goto error;
}
gprintf("found '%s' %lu -> %lu\n", filename, fi.compressed_size, fi.uncompressed_size);
if (filename[0] == '/' || strchr(filename, '\\') || strchr(filename, ':')) {
gprintf("invalid char in filename\n");
goto error;
}
if (fi.flag & 1) {
gprintf("encrypted entry\n");
goto error;
}
if (fi.uncompressed_size > 0) {
*bytes += fi.uncompressed_size;
if (!dirname[0]) {
char *p = strchr(filename, '/');
if (p) {
strncpy(dirname, filename, p - filename + 1);
dirname[p - filename + 1] = 0;
gprintf("dirname='%s'\n", dirname);
} else {
gprintf("missing pathname\n");
goto error;
}
} else {
if (strncmp(filename, dirname, strlen(dirname))) {
gprintf("additional pathname\n");
goto error;
}
}
if (!strcasecmp(filename + strlen(dirname), app_fn_boot_elf))
got_elf = 1;
else if (!strcasecmp(filename + strlen(dirname), app_fn_boot_dol))
got_dol = 1;
else if (!strcasecmp(filename + strlen(dirname), app_fn_theme))
got_theme = 1;
}
if (i != gi.number_entry - 1) {
res = unzGoToNextFile(uf);
if (res != UNZ_OK) {
gprintf("unzGoToNextFile failed: %d\n", res);
goto error;
}
}
}
if (strlen(dirname) && ((got_elf + got_dol + got_theme) == 1)) {
ret = true;
dirname[strlen(dirname) - 1] = 0;
}
error:
res = unzClose(uf);
if (res)
gprintf("unzClose failed: %d\n", res);
return ret;
}
bool manage_check_zip_theme(u8 *data, u32 data_len) {
unzFile uf;
int res, i;
bool ret = false;
unz_global_info gi;
if (data_len > MAX_THEME_ZIP_SIZE) {
gprintf("theme size too big: %lu\n", data_len);
return false;
}
uf = unzOpen(data, data_len);
if (!uf) {
gprintf("unzOpen failed\n");
return false;
}
res = unzGetGlobalInfo (uf, &gi);
if (res != UNZ_OK) {
gprintf("unzGetGlobalInfo failed: %d\n", res);
goto error;
}
if ((gi.number_entry < 1) || (gi.number_entry > 64)) {
gprintf("invalid file count\n");
goto error;
}
char filename[256];
unz_file_info fi;
bool got_xml = false;
for (i = 0; i < gi.number_entry; ++i) {
res = unzGetCurrentFileInfo(uf, &fi, filename, sizeof(filename) ,NULL, 0, NULL, 0);
if (res != UNZ_OK) {
gprintf("unzGetCurrentFileInfo failed: %d\n", res);
goto error;
}
gprintf("found '%s' %lu -> %lu\n", filename, fi.compressed_size, fi.uncompressed_size);
if (filename[0] == '/' || strchr(filename, '\\') || strchr(filename, ':')) {
gprintf("invalid char in filename\n");
goto error;
}
if (fi.flag & 1) {
gprintf("encrypted entry\n");
goto error;
}
if (fi.uncompressed_size > 0) {
char *p = strchr(filename, '/');
if (p) {
gprintf("directories not accepted\n");
goto error;
}
if (!strcasecmp(filename, theme_fn_xml)) {
got_xml = true;
} else if (!theme_is_valid_fn(filename)) {
gprintf("not a valid theme filename\n");
goto error;
}
}
if (i != gi.number_entry - 1) {
res = unzGoToNextFile(uf);
if (res != UNZ_OK) {
gprintf("unzGoToNextFile failed: %d\n", res);
goto error;
}
}
}
if (got_xml)
ret = true;
error:
res = unzClose(uf);
if (res)
gprintf("unzClose failed: %d\n", res);
return ret;
}
static bool manage_extract_zip(u8 *data, u32 data_len,
mutex_t *mutex, u32 *progress) {
unzFile uf;
int res, i;
bool ret = false;
unz_global_info gi;
u8 *buf = NULL;
uf = unzOpen(data, data_len);
if (!uf) {
gprintf("unzOpen failed\n");
return false;
}
res = unzGetGlobalInfo (uf, &gi);
if (res != UNZ_OK) {
gprintf("unzGetGlobalInfo failed: %d\n", res);
goto error;
}
unz_file_info fi;
char filename[256];
char sd_filename[MAXPATHLEN];
char *p;
int fd;
buf = (u8 *) pmalloc(8 * 1024);
for (i = 0; i < gi.number_entry; ++i) {
res = unzGetCurrentFileInfo(uf, &fi, filename, sizeof(filename) ,NULL, 0, NULL, 0);
if (res != UNZ_OK) {
gprintf("unzGetCurrentFileInfo failed: %d\n", res);
goto error;
}
gprintf("extracting '%s' %lu -> %lu\n", filename, fi.compressed_size, fi.uncompressed_size);
if (fi.uncompressed_size > 0) {
res = unzOpenCurrentFile(uf);
if (res != UNZ_OK) {
gprintf("unzOpenCurrentFile failed: %d\n", res);
goto error;
}
sprintf(sd_filename, "%s/%s", app_path, filename);
p = strrchr(sd_filename, '/');
if (!p) {
gprintf("invalid path: %s\n", sd_filename);
goto error;
}
*p = 0;
res = mkdir_hier(sd_filename);
if (res) {
gprintf("mkdir_hier failed: %d\n", res);
goto error;
}
*p = '/';
fd = open(sd_filename, O_CREAT|O_WRONLY|O_TRUNC);
if (fd < 0) {
gprintf("error opening file: %d\n", fd);
goto error;
}
do {
res = unzReadCurrentFile(uf, buf, 8 * 1024);
if (res < 0) {
gprintf("unzReadCurrentFile failed: %d\n", res);
break;
}
if (res > 0) {
if (res != write(fd, buf, res)) {
gprintf("short write");
res = -1;
break;
}
LWP_MutexLock (*mutex);
*progress += res;
LWP_MutexUnlock (*mutex);
}
} while (res > 0);
close(fd);
unzCloseCurrentFile(uf);
if (res < 0) {
gprintf("error extracting file: %d\n", res);
goto error;
}
}
if (i != gi.number_entry - 1) {
res = unzGoToNextFile(uf);
if (res != UNZ_OK) {
gprintf("unzGoToNextFile failed: %d\n", res);
goto error;
}
}
}
ret = true;
error:
free(buf);
res = unzClose(uf);
if (res)
gprintf("unzClose failed: %d\n", res);
return ret;
}
static lwpq_t manage_queue;
static lwp_t manage_thread;
static u8 manage_stack[MANAGE_THREAD_STACKSIZE] ATTRIBUTE_ALIGN (32);
typedef struct {
bool running;
bool extract;
// extract
u8 *data;
u32 data_len;
mutex_t mutex;
u32 progress;
// delete
const char *dirname;
bool success;
} manage_zip_arg;
static void *manage_func (void *arg) {
manage_zip_arg *ta = (manage_zip_arg *) arg;
if (ta->extract)
ta->success = manage_extract_zip(ta->data, ta->data_len, &ta->mutex, &ta->progress);
else
ta->success = 0 == rmdir_hier(ta->dirname);
ta->running = false;
return NULL;
}
bool manage_run(view *sub_view, const char *dirname,
u8 *data, u32 data_len, u32 bytes) {
s32 res;
u32 progress = 0;
char caption[MAXPATHLEN];
view *v;
manage_zip_arg ta;
res = LWP_MutexInit(&ta.mutex, false);
if (res) {
gprintf ("error creating mutex: %ld\n", res);
return false;
}
ta.running = true;
ta.data = data;
ta.data_len = data_len;
ta.progress = 0;
ta.dirname = dirname;
ta.extract = data != NULL;
memset(&manage_stack, 0, MANAGE_THREAD_STACKSIZE);
LWP_InitQueue(&manage_queue);
res = LWP_CreateThread(&manage_thread, manage_func, &ta, manage_stack,
MANAGE_THREAD_STACKSIZE, MANAGE_THREAD_PRIO);
if (res) {
gprintf ("error creating thread: %ld\n", res);
LWP_CloseQueue(manage_queue);
return false;
}
const char *text;
if (data) {
text = _("Extracting");
sprintf(caption, "%s '%s'...", text, dirname);
v = dialog_progress(sub_view, caption, bytes);
dialog_fade(v, true);
} else {
v = sub_view;
view_show_throbber(true);
}
while (true) {
LWP_MutexLock(ta.mutex);
if (!ta.running) {
LWP_MutexUnlock(ta.mutex);
break;
}
progress = ta.progress;
LWP_MutexUnlock (ta.mutex);
if (data)
dialog_set_progress(v, progress);
else
view_throbber_tickle();
view_plot(v, DIALOG_MASK_COLOR, NULL, NULL, NULL);
}
if (data) {
dialog_fade(v, false);
view_free(v);
} else {
view_show_throbber(false);
}
//LWP_SuspendThread(manage_thread);
LWP_CloseQueue(manage_queue);
LWP_MutexDestroy(ta.mutex);
return ta.success;
}

Some files were not shown because too many files have changed in this diff Show More