Initial commit
10
channel/channelapp/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
stub.bin
|
||||
*.dol
|
||||
*.elf
|
||||
.*.swp
|
||||
dist
|
||||
build
|
||||
i18n/merge
|
||||
i18n/*.gen
|
||||
*.map
|
||||
|
||||
230
channel/channelapp/Makefile
Normal 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
@@ -0,0 +1,3 @@
|
||||
twintig
|
||||
banner.bin
|
||||
|
||||
11
channel/channelapp/banner/Makefile
Normal 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
|
||||
|
||||
4
channel/channelapp/banner/banner.ppm
Normal file
4
channel/channelapp/banner/icon.ppm
Normal file
BIN
channel/channelapp/banner/title
Normal file
103
channel/channelapp/banner/twintig.c
Normal 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
@@ -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
|
||||
|
||||
BIN
channel/channelapp/data/about.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
channel/channelapp/data/apps_grid.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
channel/channelapp/data/apps_grid_hover.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
channel/channelapp/data/apps_list.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
channel/channelapp/data/apps_list_hover.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
channel/channelapp/data/apps_next.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
channel/channelapp/data/apps_next_hover.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
channel/channelapp/data/apps_previous.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
channel/channelapp/data/apps_previous_hover.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
channel/channelapp/data/background.png
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
channel/channelapp/data/background_wide.png
Normal file
|
After Width: | Height: | Size: 149 KiB |
BIN
channel/channelapp/data/bubble1.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
channel/channelapp/data/bubble2.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
channel/channelapp/data/bubble3.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
channel/channelapp/data/button.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
channel/channelapp/data/button_focus.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
channel/channelapp/data/button_small.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
channel/channelapp/data/button_small_focus.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
channel/channelapp/data/button_tiny.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
channel/channelapp/data/button_tiny_focus.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
channel/channelapp/data/content_arrow_down.png
Normal file
|
After Width: | Height: | Size: 383 B |
BIN
channel/channelapp/data/content_arrow_up.png
Normal file
|
After Width: | Height: | Size: 369 B |
BIN
channel/channelapp/data/cursor_drag.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
channel/channelapp/data/cursor_drag_shade.png
Normal file
|
After Width: | Height: | Size: 670 B |
BIN
channel/channelapp/data/cursor_pic.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
channel/channelapp/data/cursor_shade.png
Normal file
|
After Width: | Height: | Size: 628 B |
BIN
channel/channelapp/data/dialog_background.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
channel/channelapp/data/dlg_confirm.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
channel/channelapp/data/dlg_error.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
channel/channelapp/data/dlg_info.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
channel/channelapp/data/dlg_warning.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
channel/channelapp/data/droid.ttf
Normal file
BIN
channel/channelapp/data/droidbold.ttf
Normal file
BIN
channel/channelapp/data/icon_network.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
channel/channelapp/data/icon_network_active.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
channel/channelapp/data/icon_usbgecko.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
channel/channelapp/data/icon_usbgecko_active.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
channel/channelapp/data/logo.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
channel/channelapp/data/progress.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
channel/channelapp/data/throbber.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
4
channel/channelapp/gdb.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
target remote /dev/ttyUSB0
|
||||
info threads
|
||||
bt
|
||||
|
||||
257
channel/channelapp/i18n/dutch.po
Normal 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"
|
||||
261
channel/channelapp/i18n/french.po
Normal 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"
|
||||
256
channel/channelapp/i18n/german.po
Normal 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"
|
||||
267
channel/channelapp/i18n/italian.po
Normal 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"
|
||||
253
channel/channelapp/i18n/japanese.po
Normal 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 "<詳細情報はありません >"
|
||||
258
channel/channelapp/i18n/spanish.po
Normal 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"
|
||||
244
channel/channelapp/i18n/template.pot
Normal 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 ""
|
||||
306
channel/channelapp/newrvl.ld
Normal 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);
|
||||
2
channel/channelapp/newrvl.spec
Normal file
@@ -0,0 +1,2 @@
|
||||
*link_start_rvl:
|
||||
-T newrvl.ld%s
|
||||
713
channel/channelapp/source/appentry.c
Normal 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;
|
||||
}
|
||||
|
||||
80
channel/channelapp/source/appentry.h
Normal 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
|
||||
|
||||
340
channel/channelapp/source/asm.h
Normal 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__
|
||||
84
channel/channelapp/source/blob.c
Normal 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);
|
||||
}
|
||||
|
||||
9
channel/channelapp/source/blob.h
Normal 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
|
||||
330
channel/channelapp/source/browser.c
Normal 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;
|
||||
}
|
||||
|
||||
26
channel/channelapp/source/browser.h
Normal 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
|
||||
|
||||
233
channel/channelapp/source/bubbles.c
Normal 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);
|
||||
}
|
||||
|
||||
15
channel/channelapp/source/bubbles.h
Normal 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
|
||||
|
||||
240
channel/channelapp/source/controls.c
Normal 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);
|
||||
}
|
||||
}
|
||||
36
channel/channelapp/source/controls.h
Normal 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
|
||||
|
||||
55
channel/channelapp/source/cursors.c
Normal 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;
|
||||
}
|
||||
|
||||
28
channel/channelapp/source/cursors.h
Normal 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
|
||||
|
||||
88
channel/channelapp/source/debug.c
Normal 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
|
||||
623
channel/channelapp/source/dialogs.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
46
channel/channelapp/source/dialogs.h
Normal 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
|
||||
|
||||
79
channel/channelapp/source/dvd.c
Normal 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");
|
||||
}
|
||||
}
|
||||
|
||||
10
channel/channelapp/source/dvd.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef _DVD_H_
|
||||
#define _DVD_H_
|
||||
|
||||
#include <gctypes.h>
|
||||
|
||||
s32 WiiDVD_StopMotorAsync(void);
|
||||
void WiiDVD_ShutDown(void);
|
||||
|
||||
#endif
|
||||
|
||||
413
channel/channelapp/source/ecdsa.c
Normal 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
|
||||
8
channel/channelapp/source/ecdsa.h
Normal 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
|
||||
594
channel/channelapp/source/elf_abi.h
Normal 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 */
|
||||
|
||||
774
channel/channelapp/source/font.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
54
channel/channelapp/source/font.h
Normal 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
|
||||
|
||||
539
channel/channelapp/source/gfx.c
Normal 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 ();
|
||||
}
|
||||
|
||||
96
channel/channelapp/source/gfx.h
Normal 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
|
||||
|
||||
67
channel/channelapp/source/ggets.c
Normal 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 */
|
||||
45
channel/channelapp/source/ggets.h
Normal 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 */
|
||||
455
channel/channelapp/source/http.c
Normal 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
|
||||
33
channel/channelapp/source/http.h
Normal 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
|
||||
|
||||
86
channel/channelapp/source/i18n.c
Normal 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;
|
||||
}
|
||||
13
channel/channelapp/source/i18n.h
Normal 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
|
||||
|
||||
129
channel/channelapp/source/isfs.c
Normal 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;
|
||||
}
|
||||
|
||||
9
channel/channelapp/source/isfs.h
Normal 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
|
||||
1009
channel/channelapp/source/loader.c
Normal file
48
channel/channelapp/source/loader.h
Normal 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
|
||||
|
||||
283
channel/channelapp/source/loader_reloc.c
Normal 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");
|
||||
}
|
||||
|
||||
13
channel/channelapp/source/loader_reloc.h
Normal 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
|
||||
|
||||
141
channel/channelapp/source/m_main.c
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
15
channel/channelapp/source/m_main.h
Normal 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
|
||||
|
||||
825
channel/channelapp/source/main.c
Normal 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;
|
||||
}
|
||||
|
||||
561
channel/channelapp/source/manage.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||