CHANS

From WiiBrew
Jump to navigation Jump to search

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.
0x02 0x02 XX ACC = new ACC(XX) Call the constructor on the class stored in ACC with XX arguments from the stack, and store the resulting object in ACC.
0x03 0x03 XXXX ACC = new ARRAY [XXXX] Create a new array with XXXX values from the stack, and store it in ACC. (The top of the stack is the first value.)
0x04 0x04 Push ACC Push ACC to the stack.
0x05 0x05 ACC = POP Pop ACC from 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.
0x16 0x16 ACC = ~ACC Sets ACC to the bitwise NOT of ACC (strings get parsed to integers)
0x17 0x17 ACC = !ACC Set ACC to 1 if ACC is falsey (undefined, 0, or ""). Elsewise, set ACC to 0.
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)
0x29 0x29 XXXXXXXXXXXXXXXX ACC = XXXXXXXXXXXXXXXX Sets ACC to XXXXXXXXXXXXXXXX (Signed 64-bit 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
0x2D 37 0x2D 37 POP[ACC] = undefined; ACC = 1 Set index ACC of array POP to undefined, then clear ACC to 1.
0x2D 3E 0x2D 3E ACC = POP[ACC] Set ACC to index ACC of array POP.
0x2D 3F 0x2D 3F POP[ACC] = POP2 Set index ACC of array POP (first pop) to POP2 (second pop).
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.
0x32 0x32 XXXX Get ACC.table2[XXXX]. Calls the get function for the property identified by the name in table2[XXXX] on ACC. Return value is saved in ACC.
0x33 0x33 XXXX Set ACC.table2[XXXX] = POP. Calls the set function for the property identified by the name in table2[XXXX] on ACC with a value popped from the stack.
0x35 0x35 XXXXXX Branches far with offset of XXXXXX. If the branch is positive, the new program counter is XXXXXX bytes after the END of this instruction. Otherwise, it is XXXXXX bytes before the beginning.
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.
0x8X/0x9X 0b100XXXXX XXXXXXXX POP and relative jump by XXXXXXXXXXXXX if ACC == PEEK If ACC and the top of the stack are strongly equivalent (same type and value), POP and branch like 0b111?????.
0xAX/0xBX 0b101XXXXX XXXXXXXX Branch by XXXXXXXXXXXXX if !ACC If ACC is falsey, branch like 0b111?????.
0xCX/0xDX 0b110XXXXX XXXXXXXX Branch by XXXXXXXXXXXXX if ACC If ACC is truthy, branch like 0b111?????.
0xEX/0xFX 0b111XXXXX XXXXXXXX Branch by XXXXXXXXXXXXX If 0bXXXXXXXXXXXXX's top bit is unset, jump to PC + 2 + XXXXXXXXXXXXX. Elsewise, jump to PC + XXXXXXXXXXXXX - 0x1FFF.

TODO: A lot! Keep adding data, people!