Skip to content

Repository files navigation

NitroOffice

An office suite for the Nintendo DSi. Read and write Word, Excel, OpenDocument, EPUB and PDF files off your SD card, on a handheld from 2008.

Licence Platform Release

The editor: a document on one page, the tool palette on the other

The editor. The document takes one page and the tool palette the other — here the text tab, with bold/italic/underline/strike, outline and shadow, superscript and subscript, the size stepper, the face picker and the ink swatches. L swaps the two over. The status line reports the draft name, the zoom, and what L and R do.

The settings page, explaining the reading-hand choice

Settings. Every row explains itself on the facing page rather than in a manual. This is the reading-hand question, which is the first thing a fresh install asks: only the bottom screen can be touched, so the book turns over to put that screen under your stylus hand — and turns the d-pad with it.


What it is

NitroOffice renders documents as a book across both screens — the ratio of a DS spread is much closer to a page than a single screen is, so a two-page spread reads like a paperback rather than like a scrolling window.

Everything on screen is drawn by the CPU: the glyphs come out of FreeType straight into VRAM, and the whole interface is generated in code rather than built from textures or a bitmap font. There is no 3D and no tilemap. Every format the program reads is parsed into one internal document model, so the reader, the spreadsheet grid, the editor and the exporters all work on the same thing regardless of what the file on the card happened to be.

Features

Formats

Format Extension Read Write
Word (OOXML) .docx
Word 97–2003 .doc
Excel (OOXML) .xlsx
Excel 97–2003 .xls
OpenDocument Text .odt
OpenDocument Spreadsheet .ods
EPUB .epub
PDF .pdf
Images .png .jpg .jpeg .gif .bmp
NitroOffice document .nof

.nof is the program's own format and the only lossless one: it is the whole document model written straight out, so a document saved and reopened is exactly what it was. The DOCX and ODT writers produce real packages that open in Word and LibreOffice.

A file is identified by its extension and by its first bytes (ZIP, OLE2, %PDF-, NOC1). When the two disagree the info page says so, instead of failing halfway through an import with nothing to explain it.

Reading

  • Two-page spread or one page at a time.
  • Paper, Sepia and Night colour schemes; the document's own colours are kept and only moved as far as the scheme needs.
  • Four text sizes (10/12/14/16 px, shown as 83 %–133 %). Everything the document made larger or smaller keeps its proportion, so a heading stays a heading.
  • Line spacing, margins, forced or suppressed justification, optional hyphenation.
  • A Contents list built from the document's headings, and a Jump to a place bar for documents that have none.
  • Form controls — check boxes and radio buttons — can be answered from the reader. A questionnaire somebody sent you is something to fill in, not something to open an editor for.
  • Spreadsheets get their own screen: a scrollable grid, one sheet at a time, with number formats applied.

Editing

Five palette tabs, on whichever of the two screens you put them:

Tab What is on it
text bold, italic, underline, strike · outline, shadow · superscript, subscript · size · font face · ink colour (four quick swatches plus a full picker)
para left / centre / right / justified · left indent · first-line indent · space before and after · page break before
insert table (rows × columns) · picture · line break · tab · new page · check box · radio button
table add and delete rows and columns
file new · save · on-screen keyboard · "dpad types" · undo / redo · drafts · save to card · close

There is an on-screen keyboard, and the d-pad can be handed to it so text can be typed without the stylus. Undo and redo are held in a 256 KB history, which is dozens of typing steps or a handful of table snapshots; the oldest entries are dropped when it fills.

Typography and fonts

Six faces ship in the ROM: DejaVu Sans, Serif and Sans Mono for the three generic classes, and Liberation Sans, Serif and Mono as metric-compatible substitutes for Arial, Times New Roman and Courier New — same advance widths, so a document written against those keeps its line breaks. A substitution table maps thirty-odd real font names onto these six.

Each face is subset at build time to Latin-1 plus the punctuation the program actually emits; a full DejaVu Sans is ~750 KB and six unsubsetted families would be most of a ROM. Bold is synthesized by a one-pixel spread and italic by a twelve-degree slant, which divides the number of embedded faces by four.

You can add your own faces — see Your own fonts.

Caching

Opening a large DOCX takes a moment; opening it a second time does not. Imported documents are written to a cache on the card in the internal format, and the browser and info page tell you which documents will reopen instantly. Unsaved new documents live there too, as drafts, and the File tab lists them so a draft can never be saved and then lost. Edits are kept there as well — see Saving and exporting.

Install

Requirements

  • A Nintendo DSi with homebrew, and an SD card. NitroOffice is built as a DSi application and uses the DSi's extended memory — it will not run on an original DS or DS Lite.
  • Or melonDS in DSi mode, with a DSi NAND image.

Steps

  1. Download nitrooffice.nds from the latest release.
  2. Copy it to your SD card. Put it in the folder your documents are in — the file browser opens in the directory the ROM was launched from, so the documents are already in front of you. Anywhere works; that is just the shortest route.
  3. Launch it from the DSi menu (Unlaunch) or from TWiLight Menu++.
  4. On the first run it asks which hand you hold the stylus in. Answer it once and every screen afterwards is drawn the right way round.

Opening a document directly

A launcher that passes arguments, such as an .argv file, can hand NitroOffice a document to open. The first argument after the ROM opens in the reader instead of the file browser. Backing out of it lands in the document's own folder.

  • sd:/Documents/report.docx is used as written.
  • /Documents/report.docx is looked for on the card the ROM runs from.
  • report.docx is looked for in the folder the ROM runs from.
  • If the path is not on the card it names, the other card is tried with the same path, since loaders do not agree on whether the SD card is sd:/ or fat:/.
  • A document that cannot be read stops on its info page, which says why. A folder opens in the browser.

Hold SELECT at boot to see the argument the launcher passed and the path it was resolved to.

Opening documents from TWiLight Menu++

Run NitroOffice once from TWiLight Menu++ and your documents appear in the menu's own file list, each with its own icon. Selecting one opens it in NitroOffice. This needs a TWiLight Menu++ build that reads extras/config.<ext>.ini launcher configs.

On a card that has _nds/TWiLightMenu, every launch checks and, if needed, writes:

<card>/_nds/nitrooffice.nds                               a copy of the ROM
<card>/_nds/TWiLightMenu/extras/config.<ext>.ini          one per format
<card>/_nds/TWiLightMenu/icons/NitroOffice/<ext>.png      the file-list icons

The formats are .docx .doc .odt .nof .xlsx .xls .ods .pdf .epub.

  • The ROM copy is what the configs launch, so it has to live somewhere fixed. It is copied only when it is missing or from a different build, a chunk per frame so the first screen is not held up, and under a temporary name until it is complete.
  • A config written by NitroOffice starts with ; Written by NitroOffice. and is updated whenever a newer NitroOffice writes it differently. To keep your own edits, delete that line. A config without it, including one you wrote by hand before installing, is never touched. Delete it to get NitroOffice's.
  • Nothing is written to a card without TWiLight Menu++.

The SELECT self check reports whether the ROM copy is up to date.

Where NitroOffice keeps its files

<card>/_nds/NitroOffice/
    settings.dat            your choices, in the internal format
    cache/index.dat         the cache table
    cache/<id>.doc          one cached document each
    fonts/                  faces you added yourself (see below)

<card>/NitroOffice/         where "save to card" writes by default

A card with nowhere to write is not an error: settings fall back to defaults and the cache simply never hits.

Your own fonts

Drop TrueType files into <card>/_nds/NitroOffice/fonts and they appear in the editor's face picker.

  • .ttf only. The toolchain has no CFF driver, so .otf will not load.
  • 768 KB total. A face is resident for the whole session, so the budget is fixed at boot.
  • The folder is read once, at boot. Faces that will not load are listed with a reason rather than hidden, so you can tell "wrong format" from "not read at all".

Using it

Only the bottom screen is touchable, which is why the reading-hand setting exists: choosing your hand turns the whole book over so the touchable screen falls under your stylus, and remaps the d-pad to match. Every direction below is the direction you actually press, whichever way round the console is held.

Volume list

Input Action
d-pad, A Choose a drive (SD card, flashcart)
START Font specimen sheet
SELECT Settings

File browser

Input Action
d-pad, A, tap Move and open
B Up a level; from a drive root, back to the volume list
X New blank document
START Font specimen sheet
SELECT Settings

Selecting a file opens an info page first — format, size, whether it is cached, read speed, and its first bytes. From there A reads it and X opens it in the editor (spreadsheets are read-only, so they offer only A). B goes back.

Reader

Input Action
L, left, up Previous page
R, right, down, A Next page
Tap the far / near half of the touch page Next / previous page
X / Y Larger / smaller text
SELECT Menu: Contents · Jump to a place · Text size · Edit this document · Reading options
B, START Close the document

Tapping a check box or radio button in the document answers it.

Spreadsheet

Input Action
d-pad Move a cell
Drag Scroll the grid
L / R Previous / next sheet
X / Y Larger / smaller text
B, START Close

Editor

Input Action
Tap the document Place the caret; tapping a check box or radio button answers it instead
Drag on the document Select text
Tap a tool or a key Press it
R Next palette tab
L Swap the palette and the document between the two screens
START Save
d-pad Types on the on-screen keyboard when dpad types is on; otherwise moves the caret, when the document is on the far page and the stylus cannot reach it
Hold SELECT + d-pad Extend the selection
B Leave a picker page (font, colour, save-as)

B does not close the document. Closing is the File tab's close, which is something you go and find — losing your place and your undo history to a reflex is not something an editor should allow.

Settings

Input Action
d-pad Move between rows
A Change the value
B, SELECT Back

Rows: Reading hand · Text size · Pages · Paper · Line spacing · Margins · Justify · Hyphens. The facing page explains whichever row is selected.

Saving and exporting

These are two different things, and the difference matters:

  • save (File tab, or START) keeps your edits in the cache, filed under the document they came from, so reopening that file brings the edited version back on the page you left it. A brand-new document becomes a draft there and is listed in the File tab. Your original file on the card is not touched.
  • save to card writes a real file you can take off the console: .nof, .docx or .odt. The default destination is <card>/NitroOffice/, and you can browse to another folder. Pressing B during an export cancels it and takes the half-written temporary with it — the destination is never left damaged.

So: save often, save to card when you want the document to exist outside NitroOffice.

Font specimen

START from the browser or the volume list opens a specimen sheet: up/down change the size, A cycles the family, B toggles bold, Y toggles italic, and START leaves. It is there to prove the text engine and the glyph cache are behaving.

Diagnostics

Hold SELECT while the program boots for a self-check console: what mounted, what is in the start directory (filenames in text and in hex, which settles whether the filesystem is handing back UTF-8), whether a document opens, how many supplied fonts were found, and how much contiguous memory is free.

Building from source

Prerequisites

  • The Wonderful toolchain with BlocksDS (WONDERFUL_TOOLCHAIN, BLOCKSDS, BLOCKSDSEXT).
  • nitro-engine-advanced installed under ${BLOCKSDSEXT}.
  • Python 3, and g++ if you want to run the host tests.

FreeType, libpng and zlib come from the toolchain. pugixml, miniz, yas, the read half of PDFio and stb_image are vendored in thirdparty/.

Build

./setup-env.sh          # once: creates ./env and installs architectds_nea_mod
./make.sh               # build -> nitrooffice.nds
./make_debug.sh         # build with DEBUG_BUILD (repaint timings, stderr log)
./clean.sh              # remove build outputs
./make.sh --compdb      # generate compile_commands.json for clangd

make.sh activates the venv and exports the toolchain variables itself, so it works from a bare IDE terminal. The same commands are wired up as VS Code tasks in .vscode/tasks.json.

Two things worth knowing:

  • Read the build output, not the exit code. make.sh can exit 0 even when ninja failed to compile something.
  • The build is memory-heavy. On a modest machine, drive ninja with -j 2.

Tests

There are 37 host-side suites covering the parts that are pure logic — the document model, the ZIP reader, the XML pull parser, every importer, the layout engine, the exporters, the image decoders. They compile the project's own sources against the stubs in tests/host/stubs/, so nothing here is a copy of the code under test, and no DS toolchain is needed.

./tests/host/run.sh              # build and run everything
./tests/host/run.sh test_zip     # one suite
SAN=1 ./tests/host/run.sh        # with ASan and UBSan

Some extractor tests read real documents that are not in this repository; point NITROOFFICE_TEST_DOCS at a folder of them, or let those tests skip.

Project layout

Directory What is in it
source/app/ Screens, input, settings, the on-screen keyboard
source/doc/ The document model, styles, editing, undo, cache
source/import/ DOCX, DOC, XLSX, XLS, ODT, ODS, EPUB, PDF, ZIP, CFB, XML
source/export/ The DOCX, ODT and PNG writers
source/fs/ Volumes, paths, file reading and safe writing
source/media/ PNG, JPEG, GIF and BMP decoders
source/render/ Book view, widgets, icons, themes, drawing
source/text/ FreeType, metrics, line breaking, pagination
thirdparty/ pugixml, miniz, yas, PDFio (read side), stb_image

Known limits in 0.1.2

  • Latin script only. The bundled faces are subset to Latin-1 and there is no shaper, so complex scripts and right-to-left text are not laid out.
  • PDF is read-only, and is reflowed into the document model rather than reproduced page-for-page. A PDF that is mostly layout will not survive it.
  • Export is limited to .nof, .docx and .odt. Spreadsheets cannot be written back at all.
  • User fonts must be TrueType, within a 768 KB budget.
  • DSi only — the build uses the DSi's extended EWRAM.
  • Progressive JPEG and interlaced PNG go through a fallback decoder inside a fixed memory budget; very large ones of either may be refused.
  • Very large documents are truncated rather than failing, and the reader says "first part only" when that happened.

Licence and credits

NitroOffice is licensed under the Apache License 2.0.

Full third-party and font attributions are in NOTICE — pugixml, miniz, yas, PDFio, stb_image, libnds/BlocksDS, Nitro Engine Advanced, libpng, zlib, and the DejaVu and Liberation font families.

Portions of this software are copyright © The FreeType Project (www.freetype.org). All rights reserved.

Liberation is a trademark of Red Hat, Inc.

About

A nintendo DSi homebrew application to read and write documents

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages