CHANS
This article is a stub. You can help WiiBrew by expanding it. |
ChannelScript (abbreviated as CHANS) is the system used by the Wii's system menu to display "dynamic" banners. It seems to be some form of interpreted bytecode, which resembles JavaScript in many ways. The same bytecode can also apparently be interpreted on the Starlet while the Wii is off; this is performed by the /dev/net/kd module and forms the basis of WiiConnect24.
This page shall describe said bytecode and the header for CHANS files. You may find a CHANS file in the News Channel as content index 5.
A parser, written by Parlane (Matt_P): http://github.com/Parlane/Parse-Channel-Script
Here is what is known of the structure for the header:
This data is in no way 100% complete, or even 100% proven.
typedef struct { //START: Main Header u32 head; // 0x00000000 u32 version; // 0x00000004 u32 file_size; // 0x00000008 u8 unk[0x14]; // 0x0000000C //END: Main Header // All offsets are from 0x20 u32 unk10; // 0x00000020 u32 unk20; // 0x00000024 u32 unk30; // 0x00000028 // First data section (this is the bytecode) u32 fds_size; // 0x0000002C u32 fds_offset; // 0x00000030 u32 table4_count; // 0x00000034 u32 unk5; // 0x00000038 u32 unk6; // 0x0000003C // Table 1 is made up of 8 byte chunks u32 table1_count; // 0x00000040 u32 table1_offset; // 0x00000044 // Table 2 is the method name list u32 table2_count; // 0x00000048 u32 table2_offset; // 0x0000004C // Table 3 is a string literal table. // Each string is in utf-16, preceded by a u16 which specifies BYTE length of utf-18 string u32 table3_count; // 0x00000050 u32 table3_offset; // 0x00000054 // Possibly unused table u32 unk7; // 0x00000058 u32 unk8; // 0x0000005C u32 table4_offset; // 0x00000060 u32 unk9_offset; // 0x00000064 u32 unk11; // 0x00000068 u32 unk12; // 0x0000006C u8 unk13[0x10]; // 0x00000070 } chans_header; typedef struct { u32 offset; u16 table4_method; // Points to an id in table 4, index is 0 based u8 paramcount; //maybe u8 unk1; } table1_chunk; typedef struct { u8 length; u8 padding; u16 offset; } table2_entry;
Here's a list of method names extracted from the IOS "KD" module:
length, join, new2d, pop, push, shift, slice, unshift getDate, getDay, getFullYear, getHours, getMilliseconds, getMinutes, getMonth, getSeconds, getTime, getRTC charAt, *fromCharCode, indexOf, lastIndexOf, replace, search, slice, split, toLowerCase, toUpperCase *create, seek, skip, isEqual, getLength, setLength, fill, getU8, getU16, getU32, getS8, getS16, getS32, getS64, setU8, setU16, setU32, setS8, setS16, setS32, setS64, getString, getWString, setString, setWString, getBlob, setBlob, getHexString, copyRangeFrom, calcSHA1Digest, calcMD5Digest, calcCRC16, calcCRC32, calcHMAC, calcRangeSHA1Digest, calcRangeMD5Digest, calcRangeCRC16, calcRangeCRC32, calcRangeHMAC, pack, unpack verbose, logLevel, stat_result, stat_permission, stat_lastCriticalError, stat_newMsgFlag, stat_taskStage, stat_numErrors, stat_numMsgSent, stat_numMsgReceived, stat_numMsgSaved, stat_numMsgRejected, stat_numMsgFiltered, stat_countMailChk, stat_countMailRcv, stat_countMailSav, stat_countMailSnd, stat_countDL, stat_countEstablished, stat_mailTaskTrace, stat_dlTaskTrace, stat_countMailPrc, stat_countForceRecv, stat_countMailIdle, stat_countScriptExec, stat_errorLog getMyUserId, getReceivedMsg, getReplyMsg, getStorage, getRandom, isStandbyMode, launchApplication, getHomeDir, isSucceed, isFailed getId getType getAppId readToId readToAddr readFromAddr getFromId readFromId readSubject readAltName readText getCommand getScriptParameter getScriptTtl getTag getSequenceNumber getDate hasMii readField readAttached getNumAttached getAttachedSize getAttachedType setToId setToAddr setSubject setAltName setMBNoReply setMBRegDate setMBDelay setText setLedPattern setIconNewSign setIconNewSignEx setDesignatedTime setExecScript setTag setSequenceNumber copyMiiFrom copyFromFrom setAttached commit _commitNow status name fdId wiiId mailAddr check isEstablished isWiiFriend read _write _update _delete isExist searchBy Id searchByAddr getNum getNumReg getNumRegisterd getNumEst getNumEstablished
Bytecode:
Opcode | Format | Meaning | Description |
---|---|---|---|
0x00 | 0x00 | End | End of Code marker. |
0x01 | 0x01 | Return ACC | Returns ACC. |
0x04 | 0x04 | Push ACC | Push ACC to the stack. |
0x06 | 0x06 | Add ACC to POP | Pops a value off the stack, adds ACC to it, and the result is stored into ACC. |
0x07 | 0x07 | Subtract ACC from POP | Pops a value off the stack, subtracts ACC from it, and the result is stored into ACC. |
0x08 | 0x08 | Multiply POP by ACC | Pops a value off the stack, multiplies it by ACC, and the result is stored into ACC. |
0x09 | 0x09 | Divide POP by ACC | Pops a value off the stack, divides it by ACC, and the result is stored into ACC. |
0x0A | 0x0A | Modulo POP by ACC | Pops a value off the stack, modulus' it by ACC, and the result is stored into ACC. |
0x0B | 0x0B | AND POP with ACC | Pops a value off the stack and ANDs it with ACC. The result is stored in ACC. |
0x0C | 0x0C | OR POP with ACC | Pops a value off the stack and ORs it with ACC. The result is stored in ACC. |
0x0D | 0x0D | XOR POP with ACC | Pops a value off the stack and XORs it with ACC. The result is stored in ACC. |
0x0E | 0x0E | Shift POP left ACC bits | Pops a value off the stack and shifts it left by ACC bits. The result is stored in ACC. |
0x0F | 0x0F | Shift POP right ACC bits | Pops a value off the stack and shifts it right by ACC bits. The result is stored in ACC. |
0x10 | 0x10 | Set ACC to 1 if(POP == ACC) | Pops a value off the stack and compares it to ACC. If they are equal, ACC is set to 1, otherwise, it is set to 0. |
0x11 | 0x11 | Set ACC to 1 if(POP != ACC) | Pops a value off the stack and compares it to ACC. If they are not equal, ACC is set to 1, otherwise, it is set to 0. |
0x12 | 0x12 | Set ACC to 1 if(POP < ACC) | Pops a value off the stack and compares it to ACC. If POP is less than ACC, ACC is set to 1, otherwise, it is set to 0. |
0x13 | 0x13 | Set ACC to 1 if(POP > ACC) | Pops a value off the stack and compares it to ACC. If POP is greater than ACC, ACC is set to 1, otherwise, it is set to 0. |
0x14 | 0x14 | Set ACC to 1 if(POP <= ACC) | Pops a value off the stack and compares it to ACC. If POP is less than or equal to ACC, ACC is set to 1, otherwise, it is set to 0. |
0x15 | 0x15 | Set ACC to 1 if(POP >= ACC) | Pops a value off the stack and compares it to ACC. If POP is greater than or equal to ACC, ACC is set to 1, otherwise, it is set to 0. |
0x17 | 0x17 | ACC = !ACC | Sets ACC to NOT ACC. |
0x18 | 0x18 XX | ACC = XX | Sets ACC to XX (Signed char). |
0x19 | 0x19 XX | Add XX to ACC | Adds XX to ACC. |
0x1A | 0x1A XX | Add XX to ACC | Subtracts XX from ACC. |
0x1B | 0x1B XX | Multiply ACC by XX | Multiplies ACC by XX. |
0x1C | 0x1C XX | Divide ACC by XX | Divides ACC by XX. |
0x1D | 0x1D XX | Modulo ACC by XX | Modulus' ACC by XX. |
0x1E | 0x1E XX | AND ACC with XX | ANDs ACC with XX. |
0x1F | 0x1F XX | OR ACC with XX | ORs ACC with XX. |
0x20 | 0x20 XX | XOR ACC with XX | XORs ACC with XX. |
0x21 | 0x21 XX | Set ACC to 1 if(XX == ACC) | If XX is equal to ACC, ACC is set to 1, otherwise, it is set to 0. |
0x22 | 0x22 XX | Set ACC to 1 if(XX != ACC) | If XX is not equal to ACC, ACC is set to 1, otherwise, it is set to 0. |
0x23 | 0x23 XX | Set ACC to 1 if(XX < ACC) | If XX is less than ACC, ACC is set to 1, otherwise, it is set to 0. |
0x24 | 0x24 XX | Set ACC to 1 if(XX > ACC) | If XX is greater than ACC, ACC is set to 1, otherwise, it is set to 0. |
0x25 | 0x25 XX | Set ACC to 1 if(XX <= ACC) | If XX is less than or equal to ACC, ACC is set to 1, otherwise, it is set to 0. |
0x26 | 0x26 XX | Set ACC to 1 if(XX >= ACC) | If XX is greater than or equal to ACC, ACC is set to 1, otherwise, it is set to 0. |
0x27 | 0x27 XXXX | ACC = XXXX | Sets ACC to XXXX (Unsigned short int) |
0x28 | 0x28 XXXXXXXX | ACC = XXXXXXXX | Sets ACC to XXXXXXXX (Unsigned int) |
0x2A | 0x2A XXXXXXXXXXXXXXXX | ACC = XXXXXXXXXXXXXXXX | Sets ACC to XXXXXXXXXXXXXXXX (double) |
0x2C | 0x2C XXXX | ACC = table3[XXXX] | Grab a string literal from Table 3, at index XXXX |
0x30 | 0x30 XXXX YY | Call table2[XXXX] with YY parameters from stack. | Call the method at Table 2, offset by XXXX, with YY parameters from the stack. Return value is saved in ACC. |
0x31 | 0x31 XX | Call ACC with XX parameters from stack. | Calls the function in ACC, with parameters from the stack. XX is the number of parameters to use. Return value is saved in ACC. |
0x4X | 0x4X XX | ACC = table4[XXX] | Grab a variable or method from Table 4, index XXX, and store it in ACC. |
0x5X | 0x5X XX | ACC = temporary_vars[XXX] | Grab data from temporary variable XXX, and store it in ACC. |
0x6X | 0x6X XX | table4[XXX] = ACC | Set a variable or method in Table 4, index XXX, to ACC. |
0x7X | 0x7X XX | temporary_vars[XXX] = ACC | Set temporary variable XXX to ACC. |
0xAX | 0xAX XX | Jump to XXX + 2 | Pops a variable off the stack. If that variable is 0, jump to XXX + 2. |
0xDX | 0xDX XX | Jump to a location relative to XXX | Pops a variable off the stack. If that variable is 1, do nothing. Elsewise, Jump to XXX + 0xF001 If (XXX + 1) & 0x800. Otherwise, jump to XXX + 1. |
0xEX | 0xEX XX | Jump to XXX + 2 | Jumps to XXX + 2. |
TODO: A lot! Keep adding data, people!