00001 ;(function (sax) {
00002 sax.parser = function (strict, opt) { return new SAXParser(strict, opt) }
00003 sax.SAXParser = SAXParser
00004 sax.SAXStream = SAXStream
00005 sax.createStream = createStream
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 sax.MAX_BUFFER_LENGTH = 64 * 1024
00017
00018 var buffers = [
00019 'comment', 'sgmlDecl', 'textNode', 'tagName', 'doctype',
00020 'procInstName', 'procInstBody', 'entity', 'attribName',
00021 'attribValue', 'cdata', 'script'
00022 ]
00023
00024 sax.EVENTS = [
00025 'text',
00026 'processinginstruction',
00027 'sgmldeclaration',
00028 'doctype',
00029 'comment',
00030 'opentagstart',
00031 'attribute',
00032 'opentag',
00033 'closetag',
00034 'opencdata',
00035 'cdata',
00036 'closecdata',
00037 'error',
00038 'end',
00039 'ready',
00040 'script',
00041 'opennamespace',
00042 'closenamespace'
00043 ]
00044
00045 function SAXParser (strict, opt) {
00046 if (!(this instanceof SAXParser)) {
00047 return new SAXParser(strict, opt)
00048 }
00049
00050 var parser = this
00051 clearBuffers(parser)
00052 parser.q = parser.c = ''
00053 parser.bufferCheckPosition = sax.MAX_BUFFER_LENGTH
00054 parser.opt = opt || {}
00055 parser.opt.lowercase = parser.opt.lowercase || parser.opt.lowercasetags
00056 parser.looseCase = parser.opt.lowercase ? 'toLowerCase' : 'toUpperCase'
00057 parser.tags = []
00058 parser.closed = parser.closedRoot = parser.sawRoot = false
00059 parser.tag = parser.error = null
00060 parser.strict = !!strict
00061 parser.noscript = !!(strict || parser.opt.noscript)
00062 parser.state = S.BEGIN
00063 parser.strictEntities = parser.opt.strictEntities
00064 parser.ENTITIES = parser.strictEntities ? Object.create(sax.XML_ENTITIES) : Object.create(sax.ENTITIES)
00065 parser.attribList = []
00066
00067
00068
00069
00070 if (parser.opt.xmlns) {
00071 parser.ns = Object.create(rootNS)
00072 }
00073
00074
00075 parser.trackPosition = parser.opt.position !== false
00076 if (parser.trackPosition) {
00077 parser.position = parser.line = parser.column = 0
00078 }
00079 emit(parser, 'onready')
00080 }
00081
00082 if (!Object.create) {
00083 Object.create = function (o) {
00084 function F () {}
00085 F.prototype = o
00086 var newf = new F()
00087 return newf
00088 }
00089 }
00090
00091 if (!Object.keys) {
00092 Object.keys = function (o) {
00093 var a = []
00094 for (var i in o) if (o.hasOwnProperty(i)) a.push(i)
00095 return a
00096 }
00097 }
00098
00099 function checkBufferLength (parser) {
00100 var maxAllowed = Math.max(sax.MAX_BUFFER_LENGTH, 10)
00101 var maxActual = 0
00102 for (var i = 0, l = buffers.length; i < l; i++) {
00103 var len = parser[buffers[i]].length
00104 if (len > maxAllowed) {
00105
00106
00107
00108
00109 switch (buffers[i]) {
00110 case 'textNode':
00111 closeText(parser)
00112 break
00113
00114 case 'cdata':
00115 emitNode(parser, 'oncdata', parser.cdata)
00116 parser.cdata = ''
00117 break
00118
00119 case 'script':
00120 emitNode(parser, 'onscript', parser.script)
00121 parser.script = ''
00122 break
00123
00124 default:
00125 error(parser, 'Max buffer length exceeded: ' + buffers[i])
00126 }
00127 }
00128 maxActual = Math.max(maxActual, len)
00129 }
00130
00131 var m = sax.MAX_BUFFER_LENGTH - maxActual
00132 parser.bufferCheckPosition = m + parser.position
00133 }
00134
00135 function clearBuffers (parser) {
00136 for (var i = 0, l = buffers.length; i < l; i++) {
00137 parser[buffers[i]] = ''
00138 }
00139 }
00140
00141 function flushBuffers (parser) {
00142 closeText(parser)
00143 if (parser.cdata !== '') {
00144 emitNode(parser, 'oncdata', parser.cdata)
00145 parser.cdata = ''
00146 }
00147 if (parser.script !== '') {
00148 emitNode(parser, 'onscript', parser.script)
00149 parser.script = ''
00150 }
00151 }
00152
00153 SAXParser.prototype = {
00154 end: function () { end(this) },
00155 write: write,
00156 resume: function () { this.error = null; return this },
00157 close: function () { return this.write(null) },
00158 flush: function () { flushBuffers(this) }
00159 }
00160
00161 var Stream
00162 try {
00163 Stream = require('stream').Stream
00164 } catch (ex) {
00165 Stream = function () {}
00166 }
00167
00168 var streamWraps = sax.EVENTS.filter(function (ev) {
00169 return ev !== 'error' && ev !== 'end'
00170 })
00171
00172 function createStream (strict, opt) {
00173 return new SAXStream(strict, opt)
00174 }
00175
00176 function SAXStream (strict, opt) {
00177 if (!(this instanceof SAXStream)) {
00178 return new SAXStream(strict, opt)
00179 }
00180
00181 Stream.apply(this)
00182
00183 this._parser = new SAXParser(strict, opt)
00184 this.writable = true
00185 this.readable = true
00186
00187 var me = this
00188
00189 this._parser.onend = function () {
00190 me.emit('end')
00191 }
00192
00193 this._parser.onerror = function (er) {
00194 me.emit('error', er)
00195
00196
00197
00198 me._parser.error = null
00199 }
00200
00201 this._decoder = null
00202
00203 streamWraps.forEach(function (ev) {
00204 Object.defineProperty(me, 'on' + ev, {
00205 get: function () {
00206 return me._parser['on' + ev]
00207 },
00208 set: function (h) {
00209 if (!h) {
00210 me.removeAllListeners(ev)
00211 me._parser['on' + ev] = h
00212 return h
00213 }
00214 me.on(ev, h)
00215 },
00216 enumerable: true,
00217 configurable: false
00218 })
00219 })
00220 }
00221
00222 SAXStream.prototype = Object.create(Stream.prototype, {
00223 constructor: {
00224 value: SAXStream
00225 }
00226 })
00227
00228 SAXStream.prototype.write = function (data) {
00229 if (typeof Buffer === 'function' &&
00230 typeof Buffer.isBuffer === 'function' &&
00231 Buffer.isBuffer(data)) {
00232 if (!this._decoder) {
00233 var SD = require('string_decoder').StringDecoder
00234 this._decoder = new SD('utf8')
00235 }
00236 data = this._decoder.write(data)
00237 }
00238
00239 this._parser.write(data.toString())
00240 this.emit('data', data)
00241 return true
00242 }
00243
00244 SAXStream.prototype.end = function (chunk) {
00245 if (chunk && chunk.length) {
00246 this.write(chunk)
00247 }
00248 this._parser.end()
00249 return true
00250 }
00251
00252 SAXStream.prototype.on = function (ev, handler) {
00253 var me = this
00254 if (!me._parser['on' + ev] && streamWraps.indexOf(ev) !== -1) {
00255 me._parser['on' + ev] = function () {
00256 var args = arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments)
00257 args.splice(0, 0, ev)
00258 me.emit.apply(me, args)
00259 }
00260 }
00261
00262 return Stream.prototype.on.call(me, ev, handler)
00263 }
00264
00265
00266 var whitespace = '\r\n\t '
00267
00268
00269
00270
00271
00272 var quote = '\'"'
00273 var attribEnd = whitespace + '>'
00274 var CDATA = '[CDATA['
00275 var DOCTYPE = 'DOCTYPE'
00276 var XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace'
00277 var XMLNS_NAMESPACE = 'http://www.w3.org/2000/xmlns/'
00278 var rootNS = { xml: XML_NAMESPACE, xmlns: XMLNS_NAMESPACE }
00279
00280 // turn all the string character sets into character class objects.
00281 whitespace = charClass(whitespace)
00282
00283 // http://www.w3.org/TR/REC-xml/#NT-NameStartChar
00284 // This implementation works on strings, a single character at a time
00285 // as such, it cannot ever support astral-plane characters (10000-EFFFF)
00286 // without a significant breaking change to either this parser, or the
00287 // JavaScript language. Implementation of an emoji-capable xml parser
00288 // is left as an exercise for the reader.
00289 var nameStart = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/
00290
00291 var nameBody = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/
00292
00293 var entityStart = /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/
00294 var entityBody = /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/
00295
00296 quote = charClass(quote)
00297 attribEnd = charClass(attribEnd)
00298
00299 function charClass (str) {
00300 return str.split('').reduce(function (s, c) {
00301 s[c] = true
00302 return s
00303 }, {})
00304 }
00305
00306 function isMatch (regex, c) {
00307 return regex.test(c)
00308 }
00309
00310 function is (charclass, c) {
00311 return charclass[c]
00312 }
00313
00314 function notMatch (regex, c) {
00315 return !isMatch(regex, c)
00316 }
00317
00318 function not (charclass, c) {
00319 return !is(charclass, c)
00320 }
00321
00322 var S = 0
00323 sax.STATE = {
00324 BEGIN: S++, // leading byte order mark or whitespace
00325 BEGIN_WHITESPACE: S++, // leading whitespace
00326 TEXT: S++, // general stuff
00327 TEXT_ENTITY: S++, // & and such.
00328 OPEN_WAKA: S++, // <
00329 SGML_DECL: S++, // <!BLARG
00330 SGML_DECL_QUOTED: S++, // <!BLARG foo "bar
00331 DOCTYPE: S++,
00332 DOCTYPE_QUOTED: S++,
00333 DOCTYPE_DTD: S++,
00334 DOCTYPE_DTD_QUOTED: S++,
00335 COMMENT_STARTING: S++,
00336 COMMENT: S++,
00337 COMMENT_ENDING: S++,
00338 COMMENT_ENDED: S++,
00339 CDATA: S++,
00340 CDATA_ENDING: S++,
00341 CDATA_ENDING_2: S++,
00342 PROC_INST: S++,
00343 PROC_INST_BODY: S++,
00344 PROC_INST_ENDING: S++,
00345 OPEN_TAG: S++,
00346 OPEN_TAG_SLASH: S++,
00347 ATTRIB: S++,
00348 ATTRIB_NAME: S++,
00349 ATTRIB_NAME_SAW_WHITE: S++,
00350 ATTRIB_VALUE: S++,
00351 ATTRIB_VALUE_QUOTED: S++,
00352 ATTRIB_VALUE_CLOSED: S++,
00353 ATTRIB_VALUE_UNQUOTED: S++,
00354 ATTRIB_VALUE_ENTITY_Q: S++,
00355 ATTRIB_VALUE_ENTITY_U: S++,
00356 CLOSE_TAG: S++,
00357 CLOSE_TAG_SAW_WHITE: S++,
00358 SCRIPT: S++,
00359 SCRIPT_ENDING: S++
00360 }
00361
00362 sax.XML_ENTITIES = {
00363 'amp': '&',
00364 'gt': '>',
00365 'lt': '<',
00366 'quot': '"',
00367 'apos': "'"
00368 }
00369
00370 sax.ENTITIES = {
00371 'amp': '&',
00372 'gt': '>',
00373 'lt': '<',
00374 'quot': '"',
00375 'apos': "'",
00376 'AElig': 198,
00377 'Aacute': 193,
00378 'Acirc': 194,
00379 'Agrave': 192,
00380 'Aring': 197,
00381 'Atilde': 195,
00382 'Auml': 196,
00383 'Ccedil': 199,
00384 'ETH': 208,
00385 'Eacute': 201,
00386 'Ecirc': 202,
00387 'Egrave': 200,
00388 'Euml': 203,
00389 'Iacute': 205,
00390 'Icirc': 206,
00391 'Igrave': 204,
00392 'Iuml': 207,
00393 'Ntilde': 209,
00394 'Oacute': 211,
00395 'Ocirc': 212,
00396 'Ograve': 210,
00397 'Oslash': 216,
00398 'Otilde': 213,
00399 'Ouml': 214,
00400 'THORN': 222,
00401 'Uacute': 218,
00402 'Ucirc': 219,
00403 'Ugrave': 217,
00404 'Uuml': 220,
00405 'Yacute': 221,
00406 'aacute': 225,
00407 'acirc': 226,
00408 'aelig': 230,
00409 'agrave': 224,
00410 'aring': 229,
00411 'atilde': 227,
00412 'auml': 228,
00413 'ccedil': 231,
00414 'eacute': 233,
00415 'ecirc': 234,
00416 'egrave': 232,
00417 'eth': 240,
00418 'euml': 235,
00419 'iacute': 237,
00420 'icirc': 238,
00421 'igrave': 236,
00422 'iuml': 239,
00423 'ntilde': 241,
00424 'oacute': 243,
00425 'ocirc': 244,
00426 'ograve': 242,
00427 'oslash': 248,
00428 'otilde': 245,
00429 'ouml': 246,
00430 'szlig': 223,
00431 'thorn': 254,
00432 'uacute': 250,
00433 'ucirc': 251,
00434 'ugrave': 249,
00435 'uuml': 252,
00436 'yacute': 253,
00437 'yuml': 255,
00438 'copy': 169,
00439 'reg': 174,
00440 'nbsp': 160,
00441 'iexcl': 161,
00442 'cent': 162,
00443 'pound': 163,
00444 'curren': 164,
00445 'yen': 165,
00446 'brvbar': 166,
00447 'sect': 167,
00448 'uml': 168,
00449 'ordf': 170,
00450 'laquo': 171,
00451 'not': 172,
00452 'shy': 173,
00453 'macr': 175,
00454 'deg': 176,
00455 'plusmn': 177,
00456 'sup1': 185,
00457 'sup2': 178,
00458 'sup3': 179,
00459 'acute': 180,
00460 'micro': 181,
00461 'para': 182,
00462 'middot': 183,
00463 'cedil': 184,
00464 'ordm': 186,
00465 'raquo': 187,
00466 'frac14': 188,
00467 'frac12': 189,
00468 'frac34': 190,
00469 'iquest': 191,
00470 'times': 215,
00471 'divide': 247,
00472 'OElig': 338,
00473 'oelig': 339,
00474 'Scaron': 352,
00475 'scaron': 353,
00476 'Yuml': 376,
00477 'fnof': 402,
00478 'circ': 710,
00479 'tilde': 732,
00480 'Alpha': 913,
00481 'Beta': 914,
00482 'Gamma': 915,
00483 'Delta': 916,
00484 'Epsilon': 917,
00485 'Zeta': 918,
00486 'Eta': 919,
00487 'Theta': 920,
00488 'Iota': 921,
00489 'Kappa': 922,
00490 'Lambda': 923,
00491 'Mu': 924,
00492 'Nu': 925,
00493 'Xi': 926,
00494 'Omicron': 927,
00495 'Pi': 928,
00496 'Rho': 929,
00497 'Sigma': 931,
00498 'Tau': 932,
00499 'Upsilon': 933,
00500 'Phi': 934,
00501 'Chi': 935,
00502 'Psi': 936,
00503 'Omega': 937,
00504 'alpha': 945,
00505 'beta': 946,
00506 'gamma': 947,
00507 'delta': 948,
00508 'epsilon': 949,
00509 'zeta': 950,
00510 'eta': 951,
00511 'theta': 952,
00512 'iota': 953,
00513 'kappa': 954,
00514 'lambda': 955,
00515 'mu': 956,
00516 'nu': 957,
00517 'xi': 958,
00518 'omicron': 959,
00519 'pi': 960,
00520 'rho': 961,
00521 'sigmaf': 962,
00522 'sigma': 963,
00523 'tau': 964,
00524 'upsilon': 965,
00525 'phi': 966,
00526 'chi': 967,
00527 'psi': 968,
00528 'omega': 969,
00529 'thetasym': 977,
00530 'upsih': 978,
00531 'piv': 982,
00532 'ensp': 8194,
00533 'emsp': 8195,
00534 'thinsp': 8201,
00535 'zwnj': 8204,
00536 'zwj': 8205,
00537 'lrm': 8206,
00538 'rlm': 8207,
00539 'ndash': 8211,
00540 'mdash': 8212,
00541 'lsquo': 8216,
00542 'rsquo': 8217,
00543 'sbquo': 8218,
00544 'ldquo': 8220,
00545 'rdquo': 8221,
00546 'bdquo': 8222,
00547 'dagger': 8224,
00548 'Dagger': 8225,
00549 'bull': 8226,
00550 'hellip': 8230,
00551 'permil': 8240,
00552 'prime': 8242,
00553 'Prime': 8243,
00554 'lsaquo': 8249,
00555 'rsaquo': 8250,
00556 'oline': 8254,
00557 'frasl': 8260,
00558 'euro': 8364,
00559 'image': 8465,
00560 'weierp': 8472,
00561 'real': 8476,
00562 'trade': 8482,
00563 'alefsym': 8501,
00564 'larr': 8592,
00565 'uarr': 8593,
00566 'rarr': 8594,
00567 'darr': 8595,
00568 'harr': 8596,
00569 'crarr': 8629,
00570 'lArr': 8656,
00571 'uArr': 8657,
00572 'rArr': 8658,
00573 'dArr': 8659,
00574 'hArr': 8660,
00575 'forall': 8704,
00576 'part': 8706,
00577 'exist': 8707,
00578 'empty': 8709,
00579 'nabla': 8711,
00580 'isin': 8712,
00581 'notin': 8713,
00582 'ni': 8715,
00583 'prod': 8719,
00584 'sum': 8721,
00585 'minus': 8722,
00586 'lowast': 8727,
00587 'radic': 8730,
00588 'prop': 8733,
00589 'infin': 8734,
00590 'ang': 8736,
00591 'and': 8743,
00592 'or': 8744,
00593 'cap': 8745,
00594 'cup': 8746,
00595 'int': 8747,
00596 'there4': 8756,
00597 'sim': 8764,
00598 'cong': 8773,
00599 'asymp': 8776,
00600 'ne': 8800,
00601 'equiv': 8801,
00602 'le': 8804,
00603 'ge': 8805,
00604 'sub': 8834,
00605 'sup': 8835,
00606 'nsub': 8836,
00607 'sube': 8838,
00608 'supe': 8839,
00609 'oplus': 8853,
00610 'otimes': 8855,
00611 'perp': 8869,
00612 'sdot': 8901,
00613 'lceil': 8968,
00614 'rceil': 8969,
00615 'lfloor': 8970,
00616 'rfloor': 8971,
00617 'lang': 9001,
00618 'rang': 9002,
00619 'loz': 9674,
00620 'spades': 9824,
00621 'clubs': 9827,
00622 'hearts': 9829,
00623 'diams': 9830
00624 }
00625
00626 Object.keys(sax.ENTITIES).forEach(function (key) {
00627 var e = sax.ENTITIES[key]
00628 var s = typeof e === 'number' ? String.fromCharCode(e) : e
00629 sax.ENTITIES[key] = s
00630 })
00631
00632 for (var s in sax.STATE) {
00633 sax.STATE[sax.STATE[s]] = s
00634 }
00635
00636
00637 S = sax.STATE
00638
00639 function emit (parser, event, data) {
00640 parser[event] && parser[event](data)
00641 }
00642
00643 function emitNode (parser, nodeType, data) {
00644 if (parser.textNode) closeText(parser)
00645 emit(parser, nodeType, data)
00646 }
00647
00648 function closeText (parser) {
00649 parser.textNode = textopts(parser.opt, parser.textNode)
00650 if (parser.textNode) emit(parser, 'ontext', parser.textNode)
00651 parser.textNode = ''
00652 }
00653
00654 function textopts (opt, text) {
00655 if (opt.trim) text = text.trim()
00656 if (opt.normalize) text = text.replace(/\s+/g, ' ')
00657 return text
00658 }
00659
00660 function error (parser, er) {
00661 closeText(parser)
00662 if (parser.trackPosition) {
00663 er += '\nLine: ' + parser.line +
00664 '\nColumn: ' + parser.column +
00665 '\nChar: ' + parser.c
00666 }
00667 er = new Error(er)
00668 parser.error = er
00669 emit(parser, 'onerror', er)
00670 return parser
00671 }
00672
00673 function end (parser) {
00674 if (parser.sawRoot && !parser.closedRoot) strictFail(parser, 'Unclosed root tag')
00675 if ((parser.state !== S.BEGIN) &&
00676 (parser.state !== S.BEGIN_WHITESPACE) &&
00677 (parser.state !== S.TEXT)) {
00678 error(parser, 'Unexpected end')
00679 }
00680 closeText(parser)
00681 parser.c = ''
00682 parser.closed = true
00683 emit(parser, 'onend')
00684 SAXParser.call(parser, parser.strict, parser.opt)
00685 return parser
00686 }
00687
00688 function strictFail (parser, message) {
00689 if (typeof parser !== 'object' || !(parser instanceof SAXParser)) {
00690 throw new Error('bad call to strictFail')
00691 }
00692 if (parser.strict) {
00693 error(parser, message)
00694 }
00695 }
00696
00697 function newTag (parser) {
00698 if (!parser.strict) parser.tagName = parser.tagName[parser.looseCase]()
00699 var parent = parser.tags[parser.tags.length - 1] || parser
00700 var tag = parser.tag = { name: parser.tagName, attributes: {} }
00701
00702
00703 if (parser.opt.xmlns) {
00704 tag.ns = parent.ns
00705 }
00706 parser.attribList.length = 0
00707 emitNode(parser, 'onopentagstart', tag)
00708 }
00709
00710 function qname (name, attribute) {
00711 var i = name.indexOf(':')
00712 var qualName = i < 0 ? [ '', name ] : name.split(':')
00713 var prefix = qualName[0]
00714 var local = qualName[1]
00715
00716
00717 if (attribute && name === 'xmlns') {
00718 prefix = 'xmlns'
00719 local = ''
00720 }
00721
00722 return { prefix: prefix, local: local }
00723 }
00724
00725 function attrib (parser) {
00726 if (!parser.strict) {
00727 parser.attribName = parser.attribName[parser.looseCase]()
00728 }
00729
00730 if (parser.attribList.indexOf(parser.attribName) !== -1 ||
00731 parser.tag.attributes.hasOwnProperty(parser.attribName)) {
00732 parser.attribName = parser.attribValue = ''
00733 return
00734 }
00735
00736 if (parser.opt.xmlns) {
00737 var qn = qname(parser.attribName, true)
00738 var prefix = qn.prefix
00739 var local = qn.local
00740
00741 if (prefix === 'xmlns') {
00742
00743 if (local === 'xml' && parser.attribValue !== XML_NAMESPACE) {
00744 strictFail(parser,
00745 'xml: prefix must be bound to ' + XML_NAMESPACE + '\n' +
00746 'Actual: ' + parser.attribValue)
00747 } else if (local === 'xmlns' && parser.attribValue !== XMLNS_NAMESPACE) {
00748 strictFail(parser,
00749 'xmlns: prefix must be bound to ' + XMLNS_NAMESPACE + '\n' +
00750 'Actual: ' + parser.attribValue)
00751 } else {
00752 var tag = parser.tag
00753 var parent = parser.tags[parser.tags.length - 1] || parser
00754 if (tag.ns === parent.ns) {
00755 tag.ns = Object.create(parent.ns)
00756 }
00757 tag.ns[local] = parser.attribValue
00758 }
00759 }
00760
00761
00762
00763
00764 parser.attribList.push([parser.attribName, parser.attribValue])
00765 } else {
00766
00767 parser.tag.attributes[parser.attribName] = parser.attribValue
00768 emitNode(parser, 'onattribute', {
00769 name: parser.attribName,
00770 value: parser.attribValue
00771 })
00772 }
00773
00774 parser.attribName = parser.attribValue = ''
00775 }
00776
00777 function openTag (parser, selfClosing) {
00778 if (parser.opt.xmlns) {
00779
00780 var tag = parser.tag
00781
00782
00783 var qn = qname(parser.tagName)
00784 tag.prefix = qn.prefix
00785 tag.local = qn.local
00786 tag.uri = tag.ns[qn.prefix] || ''
00787
00788 if (tag.prefix && !tag.uri) {
00789 strictFail(parser, 'Unbound namespace prefix: ' +
00790 JSON.stringify(parser.tagName))
00791 tag.uri = qn.prefix
00792 }
00793
00794 var parent = parser.tags[parser.tags.length - 1] || parser
00795 if (tag.ns && parent.ns !== tag.ns) {
00796 Object.keys(tag.ns).forEach(function (p) {
00797 emitNode(parser, 'onopennamespace', {
00798 prefix: p,
00799 uri: tag.ns[p]
00800 })
00801 })
00802 }
00803
00804
00805
00806
00807 for (var i = 0, l = parser.attribList.length; i < l; i++) {
00808 var nv = parser.attribList[i]
00809 var name = nv[0]
00810 var value = nv[1]
00811 var qualName = qname(name, true)
00812 var prefix = qualName.prefix
00813 var local = qualName.local
00814 var uri = prefix === '' ? '' : (tag.ns[prefix] || '')
00815 var a = {
00816 name: name,
00817 value: value,
00818 prefix: prefix,
00819 local: local,
00820 uri: uri
00821 }
00822
00823
00824
00825 if (prefix && prefix !== 'xmlns' && !uri) {
00826 strictFail(parser, 'Unbound namespace prefix: ' +
00827 JSON.stringify(prefix))
00828 a.uri = prefix
00829 }
00830 parser.tag.attributes[name] = a
00831 emitNode(parser, 'onattribute', a)
00832 }
00833 parser.attribList.length = 0
00834 }
00835
00836 parser.tag.isSelfClosing = !!selfClosing
00837
00838
00839 parser.sawRoot = true
00840 parser.tags.push(parser.tag)
00841 emitNode(parser, 'onopentag', parser.tag)
00842 if (!selfClosing) {
00843
00844 if (!parser.noscript && parser.tagName.toLowerCase() === 'script') {
00845 parser.state = S.SCRIPT
00846 } else {
00847 parser.state = S.TEXT
00848 }
00849 parser.tag = null
00850 parser.tagName = ''
00851 }
00852 parser.attribName = parser.attribValue = ''
00853 parser.attribList.length = 0
00854 }
00855
00856 function closeTag (parser) {
00857 if (!parser.tagName) {
00858 strictFail(parser, 'Weird empty close tag.')
00859 parser.textNode += '</>'
00860 parser.state = S.TEXT
00861 return
00862 }
00863
00864 if (parser.script) {
00865 if (parser.tagName !== 'script') {
00866 parser.script += '</' + parser.tagName + '>'
00867 parser.tagName = ''
00868 parser.state = S.SCRIPT
00869 return
00870 }
00871 emitNode(parser, 'onscript', parser.script)
00872 parser.script = ''
00873 }
00874
00875
00876
00877 var t = parser.tags.length
00878 var tagName = parser.tagName
00879 if (!parser.strict) {
00880 tagName = tagName[parser.looseCase]()
00881 }
00882 var closeTo = tagName
00883 while (t--) {
00884 var close = parser.tags[t]
00885 if (close.name !== closeTo) {
00886
00887 strictFail(parser, 'Unexpected close tag')
00888 } else {
00889 break
00890 }
00891 }
00892
00893
00894 if (t < 0) {
00895 strictFail(parser, 'Unmatched closing tag: ' + parser.tagName)
00896 parser.textNode += '</' + parser.tagName + '>'
00897 parser.state = S.TEXT
00898 return
00899 }
00900 parser.tagName = tagName
00901 var s = parser.tags.length
00902 while (s-- > t) {
00903 var tag = parser.tag = parser.tags.pop()
00904 parser.tagName = parser.tag.name
00905 emitNode(parser, 'onclosetag', parser.tagName)
00906
00907 var x = {}
00908 for (var i in tag.ns) {
00909 x[i] = tag.ns[i]
00910 }
00911
00912 var parent = parser.tags[parser.tags.length - 1] || parser
00913 if (parser.opt.xmlns && tag.ns !== parent.ns) {
00914
00915 Object.keys(tag.ns).forEach(function (p) {
00916 var n = tag.ns[p]
00917 emitNode(parser, 'onclosenamespace', { prefix: p, uri: n })
00918 })
00919 }
00920 }
00921 if (t === 0) parser.closedRoot = true
00922 parser.tagName = parser.attribValue = parser.attribName = ''
00923 parser.attribList.length = 0
00924 parser.state = S.TEXT
00925 }
00926
00927 function parseEntity (parser) {
00928 var entity = parser.entity
00929 var entityLC = entity.toLowerCase()
00930 var num
00931 var numStr = ''
00932
00933 if (parser.ENTITIES[entity]) {
00934 return parser.ENTITIES[entity]
00935 }
00936 if (parser.ENTITIES[entityLC]) {
00937 return parser.ENTITIES[entityLC]
00938 }
00939 entity = entityLC
00940 if (entity.charAt(0) === '#') {
00941 if (entity.charAt(1) === 'x') {
00942 entity = entity.slice(2)
00943 num = parseInt(entity, 16)
00944 numStr = num.toString(16)
00945 } else {
00946 entity = entity.slice(1)
00947 num = parseInt(entity, 10)
00948 numStr = num.toString(10)
00949 }
00950 }
00951 entity = entity.replace(/^0+/, '')
00952 if (numStr.toLowerCase() !== entity) {
00953 strictFail(parser, 'Invalid character entity')
00954 return '&' + parser.entity + ';'
00955 }
00956
00957 return String.fromCodePoint(num)
00958 }
00959
00960 function beginWhiteSpace (parser, c) {
00961 if (c === '<') {
00962 parser.state = S.OPEN_WAKA
00963 parser.startTagPosition = parser.position
00964 } else if (not(whitespace, c)) {
00965
00966
00967 strictFail(parser, 'Non-whitespace before first tag.')
00968 parser.textNode = c
00969 parser.state = S.TEXT
00970 }
00971 }
00972
00973 function charAt (chunk, i) {
00974 var result = ''
00975 if (i < chunk.length) {
00976 result = chunk.charAt(i)
00977 }
00978 return result
00979 }
00980
00981 function write (chunk) {
00982 var parser = this
00983 if (this.error) {
00984 throw this.error
00985 }
00986 if (parser.closed) {
00987 return error(parser,
00988 'Cannot write after close. Assign an onready handler.')
00989 }
00990 if (chunk === null) {
00991 return end(parser)
00992 }
00993 if (typeof chunk === 'object') {
00994 chunk = chunk.toString()
00995 }
00996 var i = 0
00997 var c = ''
00998 while (true) {
00999 c = charAt(chunk, i++)
01000 parser.c = c
01001
01002 if (!c) {
01003 break
01004 }
01005
01006 if (parser.trackPosition) {
01007 parser.position++
01008 if (c === '\n') {
01009 parser.line++
01010 parser.column = 0
01011 } else {
01012 parser.column++
01013 }
01014 }
01015
01016 switch (parser.state) {
01017 case S.BEGIN:
01018 parser.state = S.BEGIN_WHITESPACE
01019 if (c === '\uFEFF') {
01020 continue
01021 }
01022 beginWhiteSpace(parser, c)
01023 continue
01024
01025 case S.BEGIN_WHITESPACE:
01026 beginWhiteSpace(parser, c)
01027 continue
01028
01029 case S.TEXT:
01030 if (parser.sawRoot && !parser.closedRoot) {
01031 var starti = i - 1
01032 while (c && c !== '<' && c !== '&') {
01033 c = charAt(chunk, i++)
01034 if (c && parser.trackPosition) {
01035 parser.position++
01036 if (c === '\n') {
01037 parser.line++
01038 parser.column = 0
01039 } else {
01040 parser.column++
01041 }
01042 }
01043 }
01044 parser.textNode += chunk.substring(starti, i - 1)
01045 }
01046 if (c === '<' && !(parser.sawRoot && parser.closedRoot && !parser.strict)) {
01047 parser.state = S.OPEN_WAKA
01048 parser.startTagPosition = parser.position
01049 } else {
01050 if (not(whitespace, c) && (!parser.sawRoot || parser.closedRoot)) {
01051 strictFail(parser, 'Text data outside of root node.')
01052 }
01053 if (c === '&') {
01054 parser.state = S.TEXT_ENTITY
01055 } else {
01056 parser.textNode += c
01057 }
01058 }
01059 continue
01060
01061 case S.SCRIPT:
01062
01063 if (c === '<') {
01064 parser.state = S.SCRIPT_ENDING
01065 } else {
01066 parser.script += c
01067 }
01068 continue
01069
01070 case S.SCRIPT_ENDING:
01071 if (c === '/') {
01072 parser.state = S.CLOSE_TAG
01073 } else {
01074 parser.script += '<' + c
01075 parser.state = S.SCRIPT
01076 }
01077 continue
01078
01079 case S.OPEN_WAKA:
01080
01081 if (c === '!') {
01082 parser.state = S.SGML_DECL
01083 parser.sgmlDecl = ''
01084 } else if (is(whitespace, c)) {
01085
01086 } else if (isMatch(nameStart, c)) {
01087 parser.state = S.OPEN_TAG
01088 parser.tagName = c
01089 } else if (c === '/') {
01090 parser.state = S.CLOSE_TAG
01091 parser.tagName = ''
01092 } else if (c === '?') {
01093 parser.state = S.PROC_INST
01094 parser.procInstName = parser.procInstBody = ''
01095 } else {
01096 strictFail(parser, 'Unencoded <')
01097
01098 if (parser.startTagPosition + 1 < parser.position) {
01099 var pad = parser.position - parser.startTagPosition
01100 c = new Array(pad).join(' ') + c
01101 }
01102 parser.textNode += '<' + c
01103 parser.state = S.TEXT
01104 }
01105 continue
01106
01107 case S.SGML_DECL:
01108 if ((parser.sgmlDecl + c).toUpperCase() === CDATA) {
01109 emitNode(parser, 'onopencdata')
01110 parser.state = S.CDATA
01111 parser.sgmlDecl = ''
01112 parser.cdata = ''
01113 } else if (parser.sgmlDecl + c === '--') {
01114 parser.state = S.COMMENT
01115 parser.comment = ''
01116 parser.sgmlDecl = ''
01117 } else if ((parser.sgmlDecl + c).toUpperCase() === DOCTYPE) {
01118 parser.state = S.DOCTYPE
01119 if (parser.doctype || parser.sawRoot) {
01120 strictFail(parser,
01121 'Inappropriately located doctype declaration')
01122 }
01123 parser.doctype = ''
01124 parser.sgmlDecl = ''
01125 } else if (c === '>') {
01126 emitNode(parser, 'onsgmldeclaration', parser.sgmlDecl)
01127 parser.sgmlDecl = ''
01128 parser.state = S.TEXT
01129 } else if (is(quote, c)) {
01130 parser.state = S.SGML_DECL_QUOTED
01131 parser.sgmlDecl += c
01132 } else {
01133 parser.sgmlDecl += c
01134 }
01135 continue
01136
01137 case S.SGML_DECL_QUOTED:
01138 if (c === parser.q) {
01139 parser.state = S.SGML_DECL
01140 parser.q = ''
01141 }
01142 parser.sgmlDecl += c
01143 continue
01144
01145 case S.DOCTYPE:
01146 if (c === '>') {
01147 parser.state = S.TEXT
01148 emitNode(parser, 'ondoctype', parser.doctype)
01149 parser.doctype = true
01150 } else {
01151 parser.doctype += c
01152 if (c === '[') {
01153 parser.state = S.DOCTYPE_DTD
01154 } else if (is(quote, c)) {
01155 parser.state = S.DOCTYPE_QUOTED
01156 parser.q = c
01157 }
01158 }
01159 continue
01160
01161 case S.DOCTYPE_QUOTED:
01162 parser.doctype += c
01163 if (c === parser.q) {
01164 parser.q = ''
01165 parser.state = S.DOCTYPE
01166 }
01167 continue
01168
01169 case S.DOCTYPE_DTD:
01170 parser.doctype += c
01171 if (c === ']') {
01172 parser.state = S.DOCTYPE
01173 } else if (is(quote, c)) {
01174 parser.state = S.DOCTYPE_DTD_QUOTED
01175 parser.q = c
01176 }
01177 continue
01178
01179 case S.DOCTYPE_DTD_QUOTED:
01180 parser.doctype += c
01181 if (c === parser.q) {
01182 parser.state = S.DOCTYPE_DTD
01183 parser.q = ''
01184 }
01185 continue
01186
01187 case S.COMMENT:
01188 if (c === '-') {
01189 parser.state = S.COMMENT_ENDING
01190 } else {
01191 parser.comment += c
01192 }
01193 continue
01194
01195 case S.COMMENT_ENDING:
01196 if (c === '-') {
01197 parser.state = S.COMMENT_ENDED
01198 parser.comment = textopts(parser.opt, parser.comment)
01199 if (parser.comment) {
01200 emitNode(parser, 'oncomment', parser.comment)
01201 }
01202 parser.comment = ''
01203 } else {
01204 parser.comment += '-' + c
01205 parser.state = S.COMMENT
01206 }
01207 continue
01208
01209 case S.COMMENT_ENDED:
01210 if (c !== '>') {
01211 strictFail(parser, 'Malformed comment')
01212
01213
01214 parser.comment += '--' + c
01215 parser.state = S.COMMENT
01216 } else {
01217 parser.state = S.TEXT
01218 }
01219 continue
01220
01221 case S.CDATA:
01222 if (c === ']') {
01223 parser.state = S.CDATA_ENDING
01224 } else {
01225 parser.cdata += c
01226 }
01227 continue
01228
01229 case S.CDATA_ENDING:
01230 if (c === ']') {
01231 parser.state = S.CDATA_ENDING_2
01232 } else {
01233 parser.cdata += ']' + c
01234 parser.state = S.CDATA
01235 }
01236 continue
01237
01238 case S.CDATA_ENDING_2:
01239 if (c === '>') {
01240 if (parser.cdata) {
01241 emitNode(parser, 'oncdata', parser.cdata)
01242 }
01243 emitNode(parser, 'onclosecdata')
01244 parser.cdata = ''
01245 parser.state = S.TEXT
01246 } else if (c === ']') {
01247 parser.cdata += ']'
01248 } else {
01249 parser.cdata += ']]' + c
01250 parser.state = S.CDATA
01251 }
01252 continue
01253
01254 case S.PROC_INST:
01255 if (c === '?') {
01256 parser.state = S.PROC_INST_ENDING
01257 } else if (is(whitespace, c)) {
01258 parser.state = S.PROC_INST_BODY
01259 } else {
01260 parser.procInstName += c
01261 }
01262 continue
01263
01264 case S.PROC_INST_BODY:
01265 if (!parser.procInstBody && is(whitespace, c)) {
01266 continue
01267 } else if (c === '?') {
01268 parser.state = S.PROC_INST_ENDING
01269 } else {
01270 parser.procInstBody += c
01271 }
01272 continue
01273
01274 case S.PROC_INST_ENDING:
01275 if (c === '>') {
01276 emitNode(parser, 'onprocessinginstruction', {
01277 name: parser.procInstName,
01278 body: parser.procInstBody
01279 })
01280 parser.procInstName = parser.procInstBody = ''
01281 parser.state = S.TEXT
01282 } else {
01283 parser.procInstBody += '?' + c
01284 parser.state = S.PROC_INST_BODY
01285 }
01286 continue
01287
01288 case S.OPEN_TAG:
01289 if (isMatch(nameBody, c)) {
01290 parser.tagName += c
01291 } else {
01292 newTag(parser)
01293 if (c === '>') {
01294 openTag(parser)
01295 } else if (c === '/') {
01296 parser.state = S.OPEN_TAG_SLASH
01297 } else {
01298 if (not(whitespace, c)) {
01299 strictFail(parser, 'Invalid character in tag name')
01300 }
01301 parser.state = S.ATTRIB
01302 }
01303 }
01304 continue
01305
01306 case S.OPEN_TAG_SLASH:
01307 if (c === '>') {
01308 openTag(parser, true)
01309 closeTag(parser)
01310 } else {
01311 strictFail(parser, 'Forward-slash in opening tag not followed by >')
01312 parser.state = S.ATTRIB
01313 }
01314 continue
01315
01316 case S.ATTRIB:
01317
01318 if (is(whitespace, c)) {
01319 continue
01320 } else if (c === '>') {
01321 openTag(parser)
01322 } else if (c === '/') {
01323 parser.state = S.OPEN_TAG_SLASH
01324 } else if (isMatch(nameStart, c)) {
01325 parser.attribName = c
01326 parser.attribValue = ''
01327 parser.state = S.ATTRIB_NAME
01328 } else {
01329 strictFail(parser, 'Invalid attribute name')
01330 }
01331 continue
01332
01333 case S.ATTRIB_NAME:
01334 if (c === '=') {
01335 parser.state = S.ATTRIB_VALUE
01336 } else if (c === '>') {
01337 strictFail(parser, 'Attribute without value')
01338 parser.attribValue = parser.attribName
01339 attrib(parser)
01340 openTag(parser)
01341 } else if (is(whitespace, c)) {
01342 parser.state = S.ATTRIB_NAME_SAW_WHITE
01343 } else if (isMatch(nameBody, c)) {
01344 parser.attribName += c
01345 } else {
01346 strictFail(parser, 'Invalid attribute name')
01347 }
01348 continue
01349
01350 case S.ATTRIB_NAME_SAW_WHITE:
01351 if (c === '=') {
01352 parser.state = S.ATTRIB_VALUE
01353 } else if (is(whitespace, c)) {
01354 continue
01355 } else {
01356 strictFail(parser, 'Attribute without value')
01357 parser.tag.attributes[parser.attribName] = ''
01358 parser.attribValue = ''
01359 emitNode(parser, 'onattribute', {
01360 name: parser.attribName,
01361 value: ''
01362 })
01363 parser.attribName = ''
01364 if (c === '>') {
01365 openTag(parser)
01366 } else if (isMatch(nameStart, c)) {
01367 parser.attribName = c
01368 parser.state = S.ATTRIB_NAME
01369 } else {
01370 strictFail(parser, 'Invalid attribute name')
01371 parser.state = S.ATTRIB
01372 }
01373 }
01374 continue
01375
01376 case S.ATTRIB_VALUE:
01377 if (is(whitespace, c)) {
01378 continue
01379 } else if (is(quote, c)) {
01380 parser.q = c
01381 parser.state = S.ATTRIB_VALUE_QUOTED
01382 } else {
01383 strictFail(parser, 'Unquoted attribute value')
01384 parser.state = S.ATTRIB_VALUE_UNQUOTED
01385 parser.attribValue = c
01386 }
01387 continue
01388
01389 case S.ATTRIB_VALUE_QUOTED:
01390 if (c !== parser.q) {
01391 if (c === '&') {
01392 parser.state = S.ATTRIB_VALUE_ENTITY_Q
01393 } else {
01394 parser.attribValue += c
01395 }
01396 continue
01397 }
01398 attrib(parser)
01399 parser.q = ''
01400 parser.state = S.ATTRIB_VALUE_CLOSED
01401 continue
01402
01403 case S.ATTRIB_VALUE_CLOSED:
01404 if (is(whitespace, c)) {
01405 parser.state = S.ATTRIB
01406 } else if (c === '>') {
01407 openTag(parser)
01408 } else if (c === '/') {
01409 parser.state = S.OPEN_TAG_SLASH
01410 } else if (isMatch(nameStart, c)) {
01411 strictFail(parser, 'No whitespace between attributes')
01412 parser.attribName = c
01413 parser.attribValue = ''
01414 parser.state = S.ATTRIB_NAME
01415 } else {
01416 strictFail(parser, 'Invalid attribute name')
01417 }
01418 continue
01419
01420 case S.ATTRIB_VALUE_UNQUOTED:
01421 if (not(attribEnd, c)) {
01422 if (c === '&') {
01423 parser.state = S.ATTRIB_VALUE_ENTITY_U
01424 } else {
01425 parser.attribValue += c
01426 }
01427 continue
01428 }
01429 attrib(parser)
01430 if (c === '>') {
01431 openTag(parser)
01432 } else {
01433 parser.state = S.ATTRIB
01434 }
01435 continue
01436
01437 case S.CLOSE_TAG:
01438 if (!parser.tagName) {
01439 if (is(whitespace, c)) {
01440 continue
01441 } else if (notMatch(nameStart, c)) {
01442 if (parser.script) {
01443 parser.script += '</' + c
01444 parser.state = S.SCRIPT
01445 } else {
01446 strictFail(parser, 'Invalid tagname in closing tag.')
01447 }
01448 } else {
01449 parser.tagName = c
01450 }
01451 } else if (c === '>') {
01452 closeTag(parser)
01453 } else if (isMatch(nameBody, c)) {
01454 parser.tagName += c
01455 } else if (parser.script) {
01456 parser.script += '</' + parser.tagName
01457 parser.tagName = ''
01458 parser.state = S.SCRIPT
01459 } else {
01460 if (not(whitespace, c)) {
01461 strictFail(parser, 'Invalid tagname in closing tag')
01462 }
01463 parser.state = S.CLOSE_TAG_SAW_WHITE
01464 }
01465 continue
01466
01467 case S.CLOSE_TAG_SAW_WHITE:
01468 if (is(whitespace, c)) {
01469 continue
01470 }
01471 if (c === '>') {
01472 closeTag(parser)
01473 } else {
01474 strictFail(parser, 'Invalid characters in closing tag')
01475 }
01476 continue
01477
01478 case S.TEXT_ENTITY:
01479 case S.ATTRIB_VALUE_ENTITY_Q:
01480 case S.ATTRIB_VALUE_ENTITY_U:
01481 var returnState
01482 var buffer
01483 switch (parser.state) {
01484 case S.TEXT_ENTITY:
01485 returnState = S.TEXT
01486 buffer = 'textNode'
01487 break
01488
01489 case S.ATTRIB_VALUE_ENTITY_Q:
01490 returnState = S.ATTRIB_VALUE_QUOTED
01491 buffer = 'attribValue'
01492 break
01493
01494 case S.ATTRIB_VALUE_ENTITY_U:
01495 returnState = S.ATTRIB_VALUE_UNQUOTED
01496 buffer = 'attribValue'
01497 break
01498 }
01499
01500 if (c === ';') {
01501 parser[buffer] += parseEntity(parser)
01502 parser.entity = ''
01503 parser.state = returnState
01504 } else if (isMatch(parser.entity.length ? entityBody : entityStart, c)) {
01505 parser.entity += c
01506 } else {
01507 strictFail(parser, 'Invalid character in entity name')
01508 parser[buffer] += '&' + parser.entity + c
01509 parser.entity = ''
01510 parser.state = returnState
01511 }
01512
01513 continue
01514
01515 default:
01516 throw new Error(parser, 'Unknown state: ' + parser.state)
01517 }
01518 }
01519
01520 if (parser.position >= parser.bufferCheckPosition) {
01521 checkBufferLength(parser)
01522 }
01523 return parser
01524 }
01525
01527
01528 if (!String.fromCodePoint) {
01529 (function () {
01530 var stringFromCharCode = String.fromCharCode
01531 var floor = Math.floor
01532 var fromCodePoint = function () {
01533 var MAX_SIZE = 0x4000
01534 var codeUnits = []
01535 var highSurrogate
01536 var lowSurrogate
01537 var index = -1
01538 var length = arguments.length
01539 if (!length) {
01540 return ''
01541 }
01542 var result = ''
01543 while (++index < length) {
01544 var codePoint = Number(arguments[index])
01545 if (
01546 !isFinite(codePoint) ||
01547 codePoint < 0 ||
01548 codePoint > 0x10FFFF ||
01549 floor(codePoint) !== codePoint
01550 ) {
01551 throw RangeError('Invalid code point: ' + codePoint)
01552 }
01553 if (codePoint <= 0xFFFF) {
01554 codeUnits.push(codePoint)
01555 } else {
01556
01557 codePoint -= 0x10000
01558 highSurrogate = (codePoint >> 10) + 0xD800
01559 lowSurrogate = (codePoint % 0x400) + 0xDC00
01560 codeUnits.push(highSurrogate, lowSurrogate)
01561 }
01562 if (index + 1 === length || codeUnits.length > MAX_SIZE) {
01563 result += stringFromCharCode.apply(null, codeUnits)
01564 codeUnits.length = 0
01565 }
01566 }
01567 return result
01568 }
01569
01570 if (Object.defineProperty) {
01571 Object.defineProperty(String, 'fromCodePoint', {
01572 value: fromCodePoint,
01573 configurable: true,
01574 writable: true
01575 })
01576 } else {
01577 String.fromCodePoint = fromCodePoint
01578 }
01579 }())
01580 }
01581 })(typeof exports === 'undefined' ? this.sax = {} : exports)