aboutsummaryrefslogtreecommitdiff
path: root/lib/docx-reader.js
blob: 35f162765bda1d8977369907b3121fa9a3ef191b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
exports.read = read;

var q = require("q");
var _ = require("underscore");
var unzip = require("unzip");
var path = require("path");
var fs = require("fs");
var Buffers = require("buffers");

var xmlreader = require("./xmlreader");
var documents = require("./documents");
var DocumentXmlReader = require("./document-xml-reader").DocumentXmlReader;
var Result = require("./results").Result;


function read(docxFile) {
    if (_.isString(docxFile)) {
        var zipPath = docxFile;
        docxFile = openZip(zipPath);
    }
    return q.when(docxFile, function(docxFile) {
    
        return q.all([
            readXmlFile(docxFile, "word/_rels/document.xml.rels"),
            readXmlFile(docxFile, "word/document.xml")
        ]).spread(function(relationshipsXml, documentXml) {
            var relationships = relationshipsXml ? readRelationships(relationshipsXml) : {};
            var reader = new DocumentXmlReader(relationships, docxFile);
            return reader.convertXmlToDocument(documentXml);
        });
    });
}

function openZip(zipPath) {
    var deferred = q.defer();
    var names = [];
    var files = {};
    
    fs.createReadStream(zipPath)
        .pipe(unzip.Parse())
        .on("entry", function(entry) {
            names.push(entry.path);
            files[entry.path] = readEntry(entry);
        })
        .on("close", function() {
            deferred.resolve(zipFile);
        })
        .on("error", function(err) {
            deferred.reject(err);
        });
    
    var exists = function(path) {
        return names.indexOf(path) !== -1;
    }
            
    function readEntry(entry) {
        var readDeferred = q.defer();
        var buffers = new Buffers();
        
        entry
            .on("data", function(data) {
                buffers.push(data);
            })
            .on("end", function() {
                readDeferred.resolve(buffers);
            })
            .on("error", readDeferred.reject.bind(readDeferred))
            
        return readDeferred.promise;
    }
    var zipFile = {
        read: function(path, encoding) {
            if (!exists(path)) {
                return q.reject(new Error("No file in zip: " + path));
            }
            return files[path].then(function(buffer) {
                if (encoding) {
                    return buffer.toString(encoding);
                } else {
                    return buffer;
                }
            });
        },
        exists: exists
    };
    return deferred.promise;
}

function readXmlFile(docxFile, path) {
    if (docxFile.exists(path)) {
        return docxFile.read(path, "utf-8")
            .then(xmlreader.read);
    } else {
        return null;
    }
}

function readRelationships(relationshipsXml) {
    var relationships = {};
    relationshipsXml.root.children.forEach(function(child) {
        if (child.name === "Relationship") {
            relationships[child.attributes.Id] = {
                target: child.attributes.Target
            };
        }
    });
    return relationships;
}

function parseXml(string) {
    return xmlreader.read(string);
}