Skip to content

KWZ Format

James edited this page Jul 11, 2020 · 48 revisions

The KWZ format is used to store Flipnote animations. The body of the file is structured into sections, each of which begins with an 8-byte header. The last 256 bytes of a KWZ is an SHA-256 RSA-2048 signature over the whole file.

Variants of the format are also used for folder icons and comments.

Section Headers

Type Details
char[4] Section magic
uint32 Section size (not including header)

The first 3 chars of the section magic identify the section type, and the last char seems to be used for flags of some kind but the meaning of these isn't known.

Sections

KFH (File Header)

Offset Type Details
0x0 uint32 CRC32 checksum
0x4 uint32 Creation timestamp
0x8 uint32 Last edit timestamp
0xC uint32 App version? - seen as 0, 1 or 3 so far
0x10 hex[10] Root author ID
0x1A hex[10] Parent author ID
0x24 hex[10] Current author ID
0x2E wchar[11] Root author name
0x44 wchar[11] Parent author name
0x5A wchar[11] Current author name
0x70 char[28] Root filename
0x8C char[28] Parent filename
0xA8 char[28] Current filename
0xC4 uint16 Frame count
0xC6 uint16 Thumbnail frame index
0xC8 uint16 Flags
0xCA uint8 Frame speed
0xCB uint8 Layer visibility flags

Timestamps are stored as the number of seconds since midnight 1 Jan 2000.

Author names are null-padded UTF-16 LE strings, author IDs are usually displayed with dashes like xxxx-xxxx-xxxx-xxxxxx (using lowercase hex).

Filenames are base32-encoded using a custom character sequence of cwmfjordvegbalksnthpyxquiz012345. The decoded filename can be unpacked to get the author ID, creation timestamp and modified timestamp.

Layer visibility flags

Bit index (0 = lowest) Details
0 Layer A invisible
1 Layer B invisible
2 Layer C invisible

KFH flags

Bit index (0 = lowest) Details
0 Lock flag
1 Loop playback flag
4 Toolset flag

Flipnote Playback Speeds:

Value Frames / Seconds
0 1 / 5
1 1 / 2
2 1 / 1
3 2 / 1
4 4 / 1
5 6 / 1
6 8 / 1
7 12 / 1
8 20 / 1
9 24 / 1
10 30 / 1

KTN (Thumbnail)

This section starts with a CRC32 checksum followed by the Flipnote's thumbnail stored as JPEG image data. Thumbnails are 80px x 64px, with a black line at the bottom which is normally cropped when displayed in the app.

KMC (Frame Data)

Starts with a CRC32 checksum followed by compressed frame data. Frames are stored in playback sequence, and split into separate images for layer A, layer B, and layer C.

The frame size is 320 x 240 pixels, although under normal circumstances the outer edges can't be drawn on since the app puts a border around the bottom screen.

Layers are divided into 8x8 tiles; 1200 in total. Every horizontal line in the tile references a line table index. The line table contains every possible combination of pixels for a line.

Bitpacking is used to achieve minimal data size.

Tile arrangement

8x8 tiles (shown in red) are grouped into larger tiles (shown in blue) which are 128x128 unless they fall off the edge of the frame. Tiles are stored in sequence from left-to-right, top to bottom.

The following pseudocode shows how we currently deal with this:

for large_tile_y = 0; large_tile_y < 240; large_tile_y += 128:

  for large_tile_x = 0; large_tile_x < 320; large_tile_x += 128:

    for tile_y = 0; tile_y < 128; tile_y += 8:
      y = large_tile_y + tile_y
      # if the tile falls off the bottom of the frame, jump to the next large tile
      if y >= 240: break

      for tile_x = 0; tile_x < 128; tile_x += 8:
        x = large_tile_x + tile_x
        # if the tile falls off the right of the frame, jump to the next small tile row
        if x >= 320: break

        # ... decode tile -- (x, y) is the position of the tile's top-left corner

Tile decompression

Each tile starts with a 3-bit value which gives the type of compression it uses:

Tile type 0

All lines are the same and use one of the commonly occurring line indexes defined in table 1. A single 5-bit value provides an index for table 1, which in turn gives the linetable index.

Pseudocode:

line_index = table1[read_bits(5)]
line = linetable[line_index]
tile = [
 line,
 line,
 line,
 line,
 line,
 line,
 line,
 line,
]

Tile type 1

All lines are the same like in type 0, but instead a 13-bit value gives the line index directly.

Pseudocode:

line_index = read_bits(13)
line = linetable[line_index]
tile = [
 line,
 line,
 line,
 line,
 line,
 line,
 line,
 line,
]

Tile type 2

Like type 0, all lines use a commonly occurring line index, given by a single 5-bit value. However, every other line is rotated one pixel to the left, so table 1 is used to get the index for odd lines and table 2 is used for even ones.

This tile type is most commonly used for pixel patterns created with the paintbrush tool:

Pseudocode:

index = read_bits(5)
line_index_a = table1[index]
line_index_b = table2[index]
a = linetable[line_index_a]
b = linetable[line_index_b]
tile = [a, b, a, b, a, b, a, b]

Tile type 3

Same as type 3, except a 13-bit value gives the line index for odd lines directly. Indexes for even lines are translates using table 3.

Pseudocode:

line_index_a = read_bits(13)
line_index_b = table3[line_index_a]
a = linetable[line_index_a]
b = linetable[line_index_b]
tile = [a, b, a, b, a, b, a, b]

Tile type 4

Each line can either be a 5-bit common line index from table 1, or a 13-bit line index. The tile starts with an 8-bit mask which indicates which to use for each line.

Pseudocode:

mask = read_bits(8)
for i in range(8):
  if mask & (1 << i):
    line_index = table1[read_bits(5)]
  else:
    line_index = read_bits(13)
  tile[i] = linetable[line_index]

Tile type 5

This indicates that one or more tiles have not changed since the previous frame, so they can be skipped. A 5-bit value gives the number of tiles to skip after the current one.

Tile type 6

Not used.

Tile type 7

The lines in this tile are arranged in a pattern of two components (A and B). A 2-bit value describes the pattern type (detailed below), followed by a 1-bit value.

If the 1-bit value is set to 1, then A and B should be read as 5-bit table 1 indexes, and the pattern type should also be incremented by 1.

If the 1-bit value is 0, then A and B should be read as 13-bit line indexes.

Pattern Type Pattern
0 A B A B A B A B
1 A A B A A B A A
2 A B A A B A A B
3 A B B A B B A B

Pseudocode:

pattern = read_bits(2)
use_table = read_bits(1)

if use_table:
  line_index_a = table1[read_bits(5)]
  line_index_b = table1[read_bits(5)]
  pattern = (pattern + 1) % 4
else:
  line_index_a = read_bits(13)
  line_index_b = read_bits(13)

a = linetable[line_index_a]
b = linetable[line_index_b]

if pattern == 0: tile = [a, b, a, b, a, b, a, b]
if pattern == 1: tile = [a, a, b, a, a, b, a, a]
if pattern == 2: tile = [a, b, a, a, b, a, a, b]
if pattern == 3: tile = [a, b, b, a, b, b, a, b]

Decompression tables

Table 1

Represents indexes for commonly occurring lines:

0x0000, 0x0CD0, 0x19A0, 0x02D9, 0x088B, 0x0051, 0x00F3, 0x0009,
0x001B, 0x0001, 0x0003, 0x05B2, 0x1116, 0x00A2, 0x01E6, 0x0012,
0x0036, 0x0002, 0x0006, 0x0B64, 0x08DC, 0x0144, 0x00FC, 0x0024,
0x001C, 0x0004, 0x0334, 0x099C, 0x0668, 0x1338, 0x1004, 0x166C

Table 2

Represents the same common lines as table 1, but their pixels are rotated one place to the left, so they have different offsets:

0x0000, 0x0CD0, 0x19A0, 0x0003, 0x02D9, 0x088B, 0x0051, 0x00F3, 
0x0009, 0x001B, 0x0001, 0x0006, 0x05B2, 0x1116, 0x00A2, 0x01E6, 
0x0012, 0x0036, 0x0002, 0x02DC, 0x0B64, 0x08DC, 0x0144, 0x00FC, 
0x0024, 0x001C, 0x099C, 0x0334, 0x1338, 0x0668, 0x166C, 0x1004

Table 3

Represents indexes for all possible lines, but where the line's pixels are first rotated one place to the left. This table is 6561 items long, but fortunately it is possible to generate it:

table3 = Array(6561)
index = 0
for a = 0; a < 2187; a += 729:
  for b = 0; b < 729; b += 243:
    for c = 0; c < 243; c += 81:
      for d = 0; d < 81; d += 27:
        for e = 0; e < 27; e += 9:
          for f = 0; f < 9; f += 3:
            for g = 0; g < 3; g += 1:
              for h = 0; h < 6561; h += 2187:
                table3[index] = a + b + c + d + e + f + g + h
                index += 1

Line table

Contains every possible combination of pixels for an 8-pixel line. This can be generated too -- our method creates the linetable as an array of 6561 items, where each item represents a line of 8 pixels. Pixel values are 0 for transparent, 1 for layer color 1 and 2 for layer color 2:

# for this example, the line table is a 2d array of size [6561][8]
# linetable should be of type uint8[][]
linetable = Array(6561, 8)
index = 0
for a = 0; a < 3; a += 1:
  for b = 0; b < 3; b += 1:
    for c = 0; c < 3; c += 1:
      for d = 0; d < 3; d += 1:
        for e = 0; e < 3; e += 1:
          for f = 0; f < 3; f += 1:
            for g = 0; g < 3; g += 1:
              for h = 0; h < 3; h += 1:
                linetable[index] = [b, a, d, c, f, e, h, g]
                index += 1

Just for reference, the linetable Nintendo uses for the app is 4-bits-per-pixel, where the packed pixel order is 2, 1, 4, 3, 6, 5, 8, 7 and pixel values are 0x0 for transparent, 0x1 for layer color 1 and 0xF for layer color 2. This can be generated like so:

linetable = Array(6561)
values = [0, 1, 0xF, 0x10, 0x11, 0x1F, 0xF0, 0xF1, 0xFF]
index = 0
for a = 0; a < 9; a += 1:
  for b = 0; b < 9; b += 1:
    for c = 0; c < 9; c += 1:
      for d = 0; d < 9; d += 1:
        linetable[index] = (values[d] << 24) | (values[c] << 16) | (values[d] << 8) | values[a]
        index += 1

We find that using generating the linetable our way is easier to work with though, since pixel values and order are a bit more workable.

KMI (Frame Meta)

This section starts contains a table of metadata for each frame. Each entry in the table is 28 bytes long:

Frame Meta Entry

Type Details
4 bits Diffing flags
4 bits Layer A color 1
4 bits Layer A color 2
4 bits Layer B color 1
4 bits Layer B color 2
4 bits Layer C color 1
4 bits Layer C color 2
uint16 Layer A size
uint16 Layer B size
uint16 Layer C size
hex[10] Frame author ID
uint8 Layer A depth
uint8 Layer B depth
uint8 Layer C depth
uint8 Sound flags
uint32 Camera flag

Layer depths range from 0 (nearest) to 6 (furthest).

The camera flag is usually 0, but will be 0x0007 if the frame uses a photo.

Diffing flags are stored in the order of Layer A, layer B, layer C starting from the lowest bit. The bit will be set to 0 if the layer is based on the same layer from the previous frame.

Each color is stored as a palette index.

Frame Palette

Index Name HEX color
0 white #ffffff
1 black #141414
2 red #ff1717
3 yellow #ffe600
4 green #008232
5 blue #06aeff
6 transparent (paper only) -

KSN (Sound Data)

Sound Header

Type Description
uint32 Flipnote speed when recorded
uint32 BGM size
uint32 Sound effect 1 (A) size
uint32 Sound effect 2 (X) size
uint32 Sound effect 3 (Y) size
uint32 Sound effect 4 (up) size
uint32 CRC32 checksum of the audio tracks

After the header, the audio tracks are stored in the order of BGM, SE1, SE2, SE3, and SE4.

Sound data

Sound data is mono-channel IMA ADPCM sampled at 16364Hz. That said, Nintendo's implementation differs from the norm ever so slightly (of course!), and these differences need to be accounted for in order to accurately decode audio.

Typically 4-bit IMA ADPCM data is used, however in order to save space, the audio may switch into a 2-bit sample mode in places where the audio signal is relatively flat. The decoder will read the next sample as a 2-bit value if the previous sample was below 18, or if it is only possible to read 2 bits from the current byte (conveniently, the audio encoder avoids 4-bit samples that overlap byte boundaries).

In addition, there are a couple of small divergences from the IMA ADPCM standard:

  • The decoder uses the standard IMA ADPCM step table, but with an extra 0 at the end. The reason for this isn't exactly clear.
  • The step index is clamped between 0 and 79, compared to the standard 0 to 88.
  • The diff is clamped to between -2047 and 2047, compared to the standard -32767 to 32767.
  • The diff value is also multiplied by 16 after being clamped.
  • The initial decoder state is diff = 0, step index = 40

The full step table is:

7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767, 0

Since this is fairly complex, here is pseudocode to convert the sound data to 16-bit signed PCM:

# track_length is assumed to be the size of the audio track, in bytes
# track_data is assumed to be the audio data, as an array of bytes

# index table for 2-bit samples
index_table_2 = [
  -1,  2,
  -1,  2,
]

# index table for 4-bit samples
index_table_4 = [
  -1, -1, -1, -1, 2, 4, 6, 8,
  -1, -1, -1, -1, 2, 4, 6, 8,
]

# we don't know how long the unpacked audio is, 
# so create an output buffer with enough space for 60 seconds of audio at 16364 Hz
# output_buffer should be of type int16[]
output_buffer = Array(16364 * 60)
output_offset = 0

# initial decoder state:
prev_diff = 0
prev_step_index = 40

for track_offset = 0; track_offset < track_length; track_offset += 1:
  byte = track_buffer[track_offset]
  bit_pos = 0
  while bit_pos < 8:
    if prev_step_index < 18 or bit_pos == 6:
      # read 2-bit sample
      sample = (byte >> bit_pos) & 0x3
      # get diff
      step = step_table[prev_step_index];
      diff = step >> 3
      if sample & 1: diff += step
      if sample & 2: diff = -diff
      diff = prev_diff + diff
      # get step index
      step_index = prev_step_index + index_table_2[sample]
      bit_pos += 2
    else:
      # read 4-bit sample
      sample = (byte >> bit_pos) & 0xF
      # get diff
      step = step_table[prev_step_index];
      diff = step >> 3
      if sample & 4: diff += step
      if sample & 2: diff += step >> 1
      if sample & 1: diff += step >> 2
      if sample & 8: diff = -diff
      diff = prev_diff + diff
      # get step index
      step_index = prev_step_index + index_table_4[sample]
      bit_pos += 4

    # clamp step index and diff
    step_index = max(0, min(step_index, 79))
    diff = max(-2047, min(diff, 2047)) * 16

    output_buffer[output_offset] = diff
    output_offset +=1
    
    # set prev decoder state
    prev_step_index = step_index
    prev_diff = diff

Notes

Comments

Flipnote Gallery World comments use a variant of the KWZ format with the extension .kwc. The only difference is that comments do not have KTN or KSN sections, and can only ever have 1 frame. Additionally, the diffing flag in the frame's meta entry is always 0x7.

Folder Icons

Icons used for SD card folders are also a variant of the KWZ format, which only use the KMC and KMI sections.

RSA Signature

The final 256 bytes of a KWZ file should consist of an SHA-256 RSA-2048 signature over the rest of the file.

The DER format private key for signing a KWZ file can be found as plaintext in memory. It will begin with the bytes 30 82 04 and end with the bytes E4 07 50, resulting in a total of 1,218 bytes overall. Its SHA-256 checksum should match E6892FF794E8A768C9ECC76152C4E72823514366B3A206298F5CB603D5EB797A.