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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Webworker spec says that the worker global object is called self. That's
// a terrible name since we use it all over the chrome codebase to capture
// the 'this' keyword in lambdas.
var global = self;
// All of these scripts could be imported with a single call to importScripts,
// but then load and compile time errors would all be reported from the same
// line.
importScripts('metadata_parser.js');
importScripts('byte_reader.js');
/**
* Dispatches metadata requests to the correct parser.
*/
function MetadataDispatcher() {
importScripts('exif_parser.js');
importScripts('mpeg_parser.js');
importScripts('id3_parser.js');
var patterns = [];
for (var i = 0; i < MetadataDispatcher.parserClasses_.length; i++) {
var parserClass = MetadataDispatcher.parserClasses_[i];
this.log('new parser: ' + parserClass.parserType);
var parser = new parserClass(this);
this.parserInstances_.push(parser);
patterns.push(parser.urlFilter.source);
}
this.parserRegexp_ = new RegExp('(' + patterns.join('|') + ')', 'i');
}
MetadataDispatcher.parserClasses_ = [];
MetadataDispatcher.registerParserClass = function(parserClass) {
MetadataDispatcher.parserClasses_.push(parserClass);
};
MetadataDispatcher.prototype.parserInstances_ = [];
/**
* Verbose logging for the dispatcher.
*
* Individual parsers also take this as their default verbosity setting.
*/
MetadataDispatcher.prototype.verbose = false;
MetadataDispatcher.prototype.messageHandlers = {
init: function() {
this.postMessage('filter', [this.parserRegexp_]);
this.log('initialized with URL filter ' + this.parserRegexp_);
},
request: function(fileURL) {
var self = this;
try {
this.processOneFile(fileURL, function callback(metadata) {
self.postMessage('result', [fileURL, metadata]);
});
} catch (ex) {
this.error(ex);
}
}
};
/**
* Indicate to the caller that an operation has failed.
*
* No other messages relating to the failed operation should be sent.
*/
MetadataDispatcher.prototype.error = function(var_args) {
var ary = Array.apply(null, arguments);
this.postMessage('error', ary);
};
/**
* Send a log message to the caller.
*
* Callers must not parse log messages for control flow.
*/
MetadataDispatcher.prototype.log = function(var_args) {
var ary = Array.apply(null, arguments);
this.postMessage('log', ary);
};
/**
* Send a log message to the caller only if this.verbose is true.
*/
MetadataDispatcher.prototype.vlog = function(var_args) {
if (this.verbose)
this.log.apply(this, arguments);
};
/**
* Post a properly formatted message to the caller.
*/
MetadataDispatcher.prototype.postMessage = function(verb, arguments) {
global.postMessage({verb: verb, arguments: arguments});
};
MetadataDispatcher.prototype.onMessage = function(event) {
var data = event.data;
if (this.messageHandlers.hasOwnProperty(data.verb)) {
this.messageHandlers[data.verb].apply(this, data.arguments);
} else {
this.log('Unknown message from client: ' + data.verb, data);
}
};
MetadataDispatcher.prototype.processOneFile = function(fileURL, callback) {
var self = this;
var currentStep = -1;
function nextStep(var_args) {
self.vlog('nextStep: ' + steps[currentStep + 1].name);
steps[++currentStep].apply(self, arguments);
}
function onError(err, stepName) {
self.error(fileURL, stepName || steps[currentStep].name, err);
}
var steps =
[ // Step one, find the parser matching the url.
function detectFormat() {
for (var i = 0; i != self.parserInstances_.length; i++) {
var parser = self.parserInstances_[i];
if (fileURL.match(parser.urlFilter)) {
nextStep(parser);
return;
}
}
onError('unsupported format');
},
// Step two, turn the url into an entry.
function getEntry(parser) {
webkitResolveLocalFileSystemURL(
fileURL,
function(entry) { nextStep(entry, parser) },
onError);
},
// Step three, turn the entry into a file.
function getFile(entry, parser) {
entry.file(function(file) { nextStep(file, parser) }, onError);
},
// Step four, parse the file content.
function parseContent(file, parser) {
parser.parse(file, callback, onError);
}
];
nextStep();
};
var dispatcher = new MetadataDispatcher();
global.onmessage = dispatcher.onMessage.bind(dispatcher);
|