Tizen 2.0 Release
[platform/framework/web/web-ui-fw.git] / libs / js / jquery-mobile-1.2.0 / node_modules / grunt / node_modules / connect / node_modules / formidable / lib / multipart_parser.js
1 var Buffer = require('buffer').Buffer,
2     s = 0,
3     S =
4     { PARSER_UNINITIALIZED: s++,
5       START: s++,
6       START_BOUNDARY: s++,
7       HEADER_FIELD_START: s++,
8       HEADER_FIELD: s++,
9       HEADER_VALUE_START: s++,
10       HEADER_VALUE: s++,
11       HEADER_VALUE_ALMOST_DONE: s++,
12       HEADERS_ALMOST_DONE: s++,
13       PART_DATA_START: s++,
14       PART_DATA: s++,
15       PART_END: s++,
16       END: s++,
17     },
18
19     f = 1,
20     F =
21     { PART_BOUNDARY: f,
22       LAST_BOUNDARY: f *= 2,
23     },
24
25     LF = 10,
26     CR = 13,
27     SPACE = 32,
28     HYPHEN = 45,
29     COLON = 58,
30     A = 97,
31     Z = 122,
32
33     lower = function(c) {
34       return c | 0x20;
35     };
36
37 for (var s in S) {
38   exports[s] = S[s];
39 }
40
41 function MultipartParser() {
42   this.boundary = null;
43   this.boundaryChars = null;
44   this.lookbehind = null;
45   this.state = S.PARSER_UNINITIALIZED;
46
47   this.index = null;
48   this.flags = 0;
49 };
50 exports.MultipartParser = MultipartParser;
51
52 MultipartParser.stateToString = function(stateNumber) {
53   for (var state in S) {
54     var number = S[state];
55     if (number === stateNumber) return state;
56   }
57 };
58
59 MultipartParser.prototype.initWithBoundary = function(str) {
60   this.boundary = new Buffer(str.length+4);
61   this.boundary.write('\r\n--', 'ascii', 0);
62   this.boundary.write(str, 'ascii', 4);
63   this.lookbehind = new Buffer(this.boundary.length+8);
64   this.state = S.START;
65
66   this.boundaryChars = {};
67   for (var i = 0; i < this.boundary.length; i++) {
68     this.boundaryChars[this.boundary[i]] = true;
69   }
70 };
71
72 MultipartParser.prototype.write = function(buffer) {
73   var self = this,
74       i = 0,
75       len = buffer.length,
76       prevIndex = this.index,
77       index = this.index,
78       state = this.state,
79       flags = this.flags,
80       lookbehind = this.lookbehind,
81       boundary = this.boundary,
82       boundaryChars = this.boundaryChars,
83       boundaryLength = this.boundary.length,
84       boundaryEnd = boundaryLength - 1,
85       bufferLength = buffer.length,
86       c,
87       cl,
88
89       mark = function(name) {
90         self[name+'Mark'] = i;
91       },
92       clear = function(name) {
93         delete self[name+'Mark'];
94       },
95       callback = function(name, buffer, start, end) {
96         if (start !== undefined && start === end) {
97           return;
98         }
99
100         var callbackSymbol = 'on'+name.substr(0, 1).toUpperCase()+name.substr(1);
101         if (callbackSymbol in self) {
102           self[callbackSymbol](buffer, start, end);
103         }
104       },
105       dataCallback = function(name, clear) {
106         var markSymbol = name+'Mark';
107         if (!(markSymbol in self)) {
108           return;
109         }
110
111         if (!clear) {
112           callback(name, buffer, self[markSymbol], buffer.length);
113           self[markSymbol] = 0;
114         } else {
115           callback(name, buffer, self[markSymbol], i);
116           delete self[markSymbol];
117         }
118       };
119
120   for (i = 0; i < len; i++) {
121     c = buffer[i];
122     switch (state) {
123       case S.PARSER_UNINITIALIZED:
124         return i;
125       case S.START:
126         index = 0;
127         state = S.START_BOUNDARY;
128       case S.START_BOUNDARY:
129         if (index == boundary.length - 2) {
130           if (c != CR) {
131             return i;
132           }
133           index++;
134           break;
135         } else if (index - 1 == boundary.length - 2) {
136           if (c != LF) {
137             return i;
138           }
139           index = 0;
140           callback('partBegin');
141           state = S.HEADER_FIELD_START;
142           break;
143         }
144
145         if (c != boundary[index+2]) {
146           return i;
147         }
148         index++;
149         break;
150       case S.HEADER_FIELD_START:
151         state = S.HEADER_FIELD;
152         mark('headerField');
153         index = 0;
154       case S.HEADER_FIELD:
155         if (c == CR) {
156           clear('headerField');
157           state = S.HEADERS_ALMOST_DONE;
158           break;
159         }
160
161         index++;
162         if (c == HYPHEN) {
163           break;
164         }
165
166         if (c == COLON) {
167           if (index == 1) {
168             // empty header field
169             return i;
170           }
171           dataCallback('headerField', true);
172           state = S.HEADER_VALUE_START;
173           break;
174         }
175
176         cl = lower(c);
177         if (cl < A || cl > Z) {
178           return i;
179         }
180         break;
181       case S.HEADER_VALUE_START:
182         if (c == SPACE) {
183           break;
184         }
185
186         mark('headerValue');
187         state = S.HEADER_VALUE;
188       case S.HEADER_VALUE:
189         if (c == CR) {
190           dataCallback('headerValue', true);
191           callback('headerEnd');
192           state = S.HEADER_VALUE_ALMOST_DONE;
193         }
194         break;
195       case S.HEADER_VALUE_ALMOST_DONE:
196         if (c != LF) {
197           return i;
198         }
199         state = S.HEADER_FIELD_START;
200         break;
201       case S.HEADERS_ALMOST_DONE:
202         if (c != LF) {
203           return i;
204         }
205
206         callback('headersEnd');
207         state = S.PART_DATA_START;
208         break;
209       case S.PART_DATA_START:
210         state = S.PART_DATA
211         mark('partData');
212       case S.PART_DATA:
213         prevIndex = index;
214
215         if (index == 0) {
216           // boyer-moore derrived algorithm to safely skip non-boundary data
217           i += boundaryEnd;
218           while (i < bufferLength && !(buffer[i] in boundaryChars)) {
219             i += boundaryLength;
220           }
221           i -= boundaryEnd;
222           c = buffer[i];
223         }
224
225         if (index < boundary.length) {
226           if (boundary[index] == c) {
227             if (index == 0) {
228               dataCallback('partData', true);
229             }
230             index++;
231           } else {
232             index = 0;
233           }
234         } else if (index == boundary.length) {
235           index++;
236           if (c == CR) {
237             // CR = part boundary
238             flags |= F.PART_BOUNDARY;
239           } else if (c == HYPHEN) {
240             // HYPHEN = end boundary
241             flags |= F.LAST_BOUNDARY;
242           } else {
243             index = 0;
244           }
245         } else if (index - 1 == boundary.length)  {
246           if (flags & F.PART_BOUNDARY) {
247             index = 0;
248             if (c == LF) {
249               // unset the PART_BOUNDARY flag
250               flags &= ~F.PART_BOUNDARY;
251               callback('partEnd');
252               callback('partBegin');
253               state = S.HEADER_FIELD_START;
254               break;
255             }
256           } else if (flags & F.LAST_BOUNDARY) {
257             if (c == HYPHEN) {
258               callback('partEnd');
259               callback('end');
260               state = S.END;
261             } else {
262               index = 0;
263             }
264           } else {
265             index = 0;
266           }
267         }
268
269         if (index > 0) {
270           // when matching a possible boundary, keep a lookbehind reference
271           // in case it turns out to be a false lead
272           lookbehind[index-1] = c;
273         } else if (prevIndex > 0) {
274           // if our boundary turned out to be rubbish, the captured lookbehind
275           // belongs to partData
276           callback('partData', lookbehind, 0, prevIndex);
277           prevIndex = 0;
278           mark('partData');
279
280           // reconsider the current character even so it interrupted the sequence
281           // it could be the beginning of a new sequence
282           i--;
283         }
284
285         break;
286       case S.END:
287         break;
288       default:
289         return i;
290     }
291   }
292
293   dataCallback('headerField');
294   dataCallback('headerValue');
295   dataCallback('partData');
296
297   this.index = index;
298   this.state = state;
299   this.flags = flags;
300
301   return len;
302 };
303
304 MultipartParser.prototype.end = function() {
305   if (this.state != S.END) {
306     return new Error('MultipartParser.end(): stream ended unexpectedly: ' + this.explain());
307   }
308 };
309
310 MultipartParser.prototype.explain = function() {
311   return 'state = ' + MultipartParser.stateToString(this.state);
312 };