Commit fbf5e22 for mammothjs

commit fbf5e226ec9194ab67081cb9ecdd5f839cd87c3a
Author: Michael Williamson <mike@zwobble.org>
Date:   Sun Aug 9 14:33:12 2026 +0100

    Check image content type for backslashes

diff --git a/NEWS b/NEWS
index 02dd689..b4251ca 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+# 1.12.1
+
+* Fix: on Windows, when an image's content type includes a backslash in the
+  subpart, files may be written outside of the directory set by --output-dir.
+
 # 1.12.0

 * Handle hyperlinked wp:anchor and wp:inline elements.
diff --git a/lib/images.js b/lib/images.js
index 40aa378..7c49dbe 100644
--- a/lib/images.js
+++ b/lib/images.js
@@ -29,3 +29,9 @@ exports.dataUri = imgElement(function(element) {
         };
     });
 });
+
+function imageFilenameExtension(image) {
+    return image.contentType.split(/\/|\\/)[1];
+}
+
+exports.imageFilenameExtension = imageFilenameExtension;
diff --git a/lib/main.js b/lib/main.js
index f6e149f..54aeebb 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -13,22 +13,22 @@ function main(argv) {
     var outputDir = argv.output_dir;
     var outputFormat = argv.output_format;
     var styleMapPath = argv.style_map;
-
+
     readStyleMap(styleMapPath).then(function(styleMap) {
         var options = {
             styleMap: styleMap,
             outputFormat: outputFormat
         };
-
+
         if (outputDir) {
             var basename = path.basename(docxPath, ".docx");
             outputPath = path.join(outputDir, basename + ".html");
             var imageIndex = 0;
             options.convertImage = images.imgElement(function(element) {
                 imageIndex++;
-                var extension = element.contentType.split("/")[1];
-                var filename = imageIndex + "." + extension;
-
+                var extension = images.imageFilenameExtension(element);
+                var filename = imageIndex + (extension === undefined ? "" : "." + extension);
+
                 return element.read().then(function(imageBuffer) {
                     var imagePath = path.join(outputDir, filename);
                     return promises.nfcall(fs.writeFile, imagePath, imageBuffer);
@@ -37,16 +37,16 @@ function main(argv) {
                 });
             });
         }
-
+
         return mammoth.convert({path: docxPath}, options)
             .then(function(result) {
                 result.messages.forEach(function(message) {
                     process.stderr.write(message.message);
                     process.stderr.write("\n");
                 });
-
+
                 var outputStream = outputPath ? fs.createWriteStream(outputPath) : process.stdout;
-
+
                 outputStream.write(result.value);
             });
     }).done();
diff --git a/test/images.tests.js b/test/images.tests.js
index f308174..5bcf3ba 100644
--- a/test/images.tests.js
+++ b/test/images.tests.js
@@ -110,3 +110,45 @@ test('mammoth.images.imgElement()', {
         });
     }
 });
+
+test("imageFilenameExtension", {
+    "extension is derived from subtype of content type": function() {
+        var image = new documents.Image({
+            contentType: "image/gif"
+        });
+
+        var result = mammoth.images.imageFilenameExtension(image);
+
+        assertThat(result, equalTo("gif"));
+    },
+
+    "data after second slash is ignored": function() {
+        var image = new documents.Image({
+            contentType: "image/gif/jpeg"
+        });
+
+        var result = mammoth.images.imageFilenameExtension(image);
+
+        assertThat(result, equalTo("gif"));
+    },
+
+    "backslashes are treated as forward slashes": function() {
+        var image = new documents.Image({
+            contentType: "image\\gif\\..\\"
+        });
+
+        var result = mammoth.images.imageFilenameExtension(image);
+
+        assertThat(result, equalTo("gif"));
+    },
+
+    "when there is no subtype then null is returned": function() {
+        var image = new documents.Image({
+            contentType: "image"
+        });
+
+        var result = mammoth.images.imageFilenameExtension(image);
+
+        assertThat(result, equalTo(undefined));
+    }
+});