Skip to content

TIKA-4831: Add content-based detection and a parser for GeoGebra files (ggb, ggs, ggt) - #3044

Open
dschmidt wants to merge 3 commits into
apache:mainfrom
dschmidt:feat/geogebra
Open

TIKA-4831: Add content-based detection and a parser for GeoGebra files (ggb, ggs, ggt)#3044
dschmidt wants to merge 3 commits into
apache:mainfrom
dschmidt:feat/geogebra

Conversation

@dschmidt

Copy link
Copy Markdown
Contributor

Adds detection and parsing support for the GeoGebra file formats.

Issue: https://issues.apache.org/jira/browse/TIKA-4831

Detection

  • application/vnd.geogebra.file (*.ggb) and application/vnd.geogebra.tool (*.ggt) are now sub-class-of application/zip, so the filename hint survives magic detection instead of being discarded in favor of plain application/zip
  • new mime types: application/vnd.geogebra.slides (*.ggs, zip-based) and application/vnd.geogebra.pinboard (*.ggp, JSON-based)
  • a new GeoGebraDetector (zip container detector, ZipFile and streaming mode) recognizes the formats without a filename by their well-known entries: geogebra.xml (worksheet), structure.json + _slideN/geogebra.xml (Notes/Slides), geogebra_macro.xml (tool). Since a worksheet with macros contains both geogebra.xml and geogebra_macro.xml, the decision is made after all entry names have been seen
  • ZipParser.ZIP_SPECIALIZATIONS is kept in sync with the new registry entries

Parser

A new GeoGebraParser (miscoffice module) for ggb/ggs/ggt:

  • metadata: construction title/author/date become dc:title/dc:creator/geogebra:date, plus geogebra:appName, geogebra:appVersion, geogebra:formatVersion, geogebra:id; Notes/Slides set xmpTPg:NPages
  • content: user-visible text as XHTML paragraphs - string-literal expression elements of text objects, rich-text content runs (JSON), element captions, macro names and help texts; Notes/Slides emit one div per slide in structure.json order
  • the representative rendering (geogebra_thumbnail.png at the root, or the first slide's thumbnail) is emitted as an embedded document marked embeddedResourceType=THUMBNAIL, following the existing convention in the OOXML, ODF and iWork parsers, so /unpack/all sidecars identify the preview image; other slides' thumbnails are redundant renderings and are skipped
  • any other embedded file (e.g. inserted pictures) is emitted as an embedded document

XML is parsed through XMLReaderUtils.parseSAX like the other parsers in the module; structure.json and rich-text runs use Jackson (new jackson-databind dependency in the miscoffice module, version managed by the existing BOM import).

Testing

  • new unit tests: GeoGebraDetectionTest (zip-commons) and GeoGebraParserTest (miscoffice) with crafted ggb/ggs/ggt fixtures; the ggs fixture deliberately orders _slide1 before _slide0 in structure.json to pin the ordering behavior
  • full test suites of tika-core, tika-parser-zip-commons, tika-parser-miscoffice-module and tika-parser-pkg-module pass, plus CompositeZipContainerDetectorTest in the integration tests
  • verified end-to-end against a real-world GeoGebra Notes file: detected as vnd.geogebra.slides, text extracted, thumbnail emitted with the THUMBNAIL marker

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class GeoGebra support to Apache Tika by introducing content-based detection for GeoGebra zip containers and a dedicated parser that extracts both metadata and user-visible text (plus a representative thumbnail as an embedded resource).

Changes:

  • Added a GeoGebraDetector (zip-commons) to recognize ggb/ggs/ggt by zip entry names (including streaming detection).
  • Added a GeoGebraParser + GeoGebraXMLHandler (miscoffice) to extract GeoGebra metadata/text and emit the thumbnail as an embedded document.
  • Updated mime registry, zip specializations, module dependencies, and tests to cover new media types and parsing behavior.

Reviewed changes

Copilot reviewed 11 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-zip-commons/src/test/java/org/apache/tika/detect/zip/GeoGebraDetectionTest.java Adds detection tests for GeoGebra zip-based formats.
tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-zip-commons/src/main/resources/META-INF/services/org.apache.tika.detect.zip.ZipContainerDetector Registers GeoGebraDetector via ServiceLoader.
tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-zip-commons/src/main/java/org/apache/tika/detect/zip/GeoGebraDetector.java Implements content-based container detection for GeoGebra zip formats.
tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/main/java/org/apache/tika/parser/pkg/ZipParser.java Adds GeoGebra media types to zip specialization set.
tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/test/java/org/apache/tika/parser/geogebra/GeoGebraParserTest.java Adds parser tests for metadata, slide ordering, and thumbnail embedding behavior.
tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/geogebra/GeoGebraXMLHandler.java SAX handler for extracting metadata/text from GeoGebra XML + inline rich text JSON.
tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/geogebra/GeoGebraParser.java New parser for ggb/ggs/ggt, including embedded thumbnail + embedded resources.
tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/pom.xml Adds jackson-databind dependency for parsing structure.json and rich-text runs.
tika-core/src/test/java/org/apache/tika/TikaDetectionTest.java Extends extension-based detection coverage for .ggp and .ggs.
tika-core/src/main/resources/org/apache/tika/mime/tika-mimetypes.xml Adds .ggp mime type and marks GeoGebra zip-based types as sub-class-of application/zip.
CHANGES.txt Documents new GeoGebra detection/parsing support (TIKA-4831).

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 17 changed files in this pull request and generated 1 comment.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 19 changed files in this pull request and generated 2 comments.

Mark application/vnd.geogebra.file and .tool as sub-classes of
application/zip so the filename hint survives magic detection, and add
the (IANA-registered) application/vnd.geogebra.slides (*.ggs) and
application/vnd.geogebra.pinboard (*.ggp) types.

Add a GeoGebraDetector to the zip container detectors that recognizes
the formats without a filename by their well-known entries: geogebra.xml
(worksheet), structure.json plus _slideN/geogebra.xml (Notes/Slides) and
geogebra_macro.xml (tool), in ZipFile and streaming mode. The detection
tests parse nameless streams so they exercise the container detector
rather than the globs.

Keep ZipParser.ZIP_SPECIALIZATIONS in sync with the new registry
entries.
Parse geogebra.xml and, when present, geogebra_macro.xml with the
pooled, hardened SAX path: construction title/author/date and the app
name/version/format/id become metadata, and the user-visible text
(string-literal expressions, rich-text content runs, captions, macro
names and help texts) is emitted as XHTML paragraphs. Notes/Slides files
emit one div per slide in structure.json order and set xmpTPg:NPages.

The representative rendering - geogebra_thumbnail.png at the root, or
the first slide's thumbnail - is emitted as an embedded document marked
embeddedResourceType=THUMBNAIL so unpack sidecars identify the preview
image; other slides' thumbnails are redundant renderings and are
skipped. Any other embedded file (e.g. inserted pictures) is emitted as
an embedded document under its full zip entry name.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 19 changed files in this pull request and generated no new comments.

A crafted _slide id with more digits than an int holds threw an uncaught
NumberFormatException out of the sort comparator; compare the digit strings
by length then lexicographically instead. The regression test builds a
two-slide container with an oversized id.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 19 changed files in this pull request and generated no new comments.

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-zip-commons/src/main/java/org/apache/tika/detect/zip/GeoGebraDetector.java:71

  • In streaming detection mode, this detector always returns null from streamingDetectUpdate and waits for streamingDetectFinal to decide. Once both structure.json and a _slideN/geogebra.xml have been seen, the result is unambiguously GeoGebra Slides (GGS) and cannot be overturned by later entries, so returning GGS early would let DefaultZipContainerDetector/StreamingZipContainerDetector stop scanning the rest of a large ZIP.
    public MediaType streamingDetectUpdate(ZipArchiveEntry zae, InputStream zis,
                                           StreamingDetectContext detectContext) {
        Names names = detectContext.get(Names.class);
        if (names == null) {
            names = new Names();
            detectContext.set(Names.class, names);
        }
        names.update(zae.getName());
        return null;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants