123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- var Mode = require('./mode')
- var NumericData = require('./numeric-data')
- var AlphanumericData = require('./alphanumeric-data')
- var ByteData = require('./byte-data')
- var KanjiData = require('./kanji-data')
- var Regex = require('./regex')
- var Utils = require('./utils')
- var dijkstra = require('dijkstrajs')
- function getStringByteLength (str) {
- return unescape(encodeURIComponent(str)).length
- }
- function getSegments (regex, mode, str) {
- var segments = []
- var result
- while ((result = regex.exec(str)) !== null) {
- segments.push({
- data: result[0],
- index: result.index,
- mode: mode,
- length: result[0].length
- })
- }
- return segments
- }
- function getSegmentsFromString (dataStr) {
- var numSegs = getSegments(Regex.NUMERIC, Mode.NUMERIC, dataStr)
- var alphaNumSegs = getSegments(Regex.ALPHANUMERIC, Mode.ALPHANUMERIC, dataStr)
- var byteSegs
- var kanjiSegs
- if (Utils.isKanjiModeEnabled()) {
- byteSegs = getSegments(Regex.BYTE, Mode.BYTE, dataStr)
- kanjiSegs = getSegments(Regex.KANJI, Mode.KANJI, dataStr)
- } else {
- byteSegs = getSegments(Regex.BYTE_KANJI, Mode.BYTE, dataStr)
- kanjiSegs = []
- }
- var segs = numSegs.concat(alphaNumSegs, byteSegs, kanjiSegs)
- return segs
- .sort(function (s1, s2) {
- return s1.index - s2.index
- })
- .map(function (obj) {
- return {
- data: obj.data,
- mode: obj.mode,
- length: obj.length
- }
- })
- }
- function getSegmentBitsLength (length, mode) {
- switch (mode) {
- case Mode.NUMERIC:
- return NumericData.getBitsLength(length)
- case Mode.ALPHANUMERIC:
- return AlphanumericData.getBitsLength(length)
- case Mode.KANJI:
- return KanjiData.getBitsLength(length)
- case Mode.BYTE:
- return ByteData.getBitsLength(length)
- }
- }
- function mergeSegments (segs) {
- return segs.reduce(function (acc, curr) {
- var prevSeg = acc.length - 1 >= 0 ? acc[acc.length - 1] : null
- if (prevSeg && prevSeg.mode === curr.mode) {
- acc[acc.length - 1].data += curr.data
- return acc
- }
- acc.push(curr)
- return acc
- }, [])
- }
- function buildNodes (segs) {
- var nodes = []
- for (var i = 0; i < segs.length; i++) {
- var seg = segs[i]
- switch (seg.mode) {
- case Mode.NUMERIC:
- nodes.push([seg,
- { data: seg.data, mode: Mode.ALPHANUMERIC, length: seg.length },
- { data: seg.data, mode: Mode.BYTE, length: seg.length }
- ])
- break
- case Mode.ALPHANUMERIC:
- nodes.push([seg,
- { data: seg.data, mode: Mode.BYTE, length: seg.length }
- ])
- break
- case Mode.KANJI:
- nodes.push([seg,
- { data: seg.data, mode: Mode.BYTE, length: getStringByteLength(seg.data) }
- ])
- break
- case Mode.BYTE:
- nodes.push([
- { data: seg.data, mode: Mode.BYTE, length: getStringByteLength(seg.data) }
- ])
- }
- }
- return nodes
- }
- function buildGraph (nodes, version) {
- var table = {}
- var graph = {'start': {}}
- var prevNodeIds = ['start']
- for (var i = 0; i < nodes.length; i++) {
- var nodeGroup = nodes[i]
- var currentNodeIds = []
- for (var j = 0; j < nodeGroup.length; j++) {
- var node = nodeGroup[j]
- var key = '' + i + j
- currentNodeIds.push(key)
- table[key] = { node: node, lastCount: 0 }
- graph[key] = {}
- for (var n = 0; n < prevNodeIds.length; n++) {
- var prevNodeId = prevNodeIds[n]
- if (table[prevNodeId] && table[prevNodeId].node.mode === node.mode) {
- graph[prevNodeId][key] =
- getSegmentBitsLength(table[prevNodeId].lastCount + node.length, node.mode) -
- getSegmentBitsLength(table[prevNodeId].lastCount, node.mode)
- table[prevNodeId].lastCount += node.length
- } else {
- if (table[prevNodeId]) table[prevNodeId].lastCount = node.length
- graph[prevNodeId][key] = getSegmentBitsLength(node.length, node.mode) +
- 4 + Mode.getCharCountIndicator(node.mode, version)
- }
- }
- }
- prevNodeIds = currentNodeIds
- }
- for (n = 0; n < prevNodeIds.length; n++) {
- graph[prevNodeIds[n]]['end'] = 0
- }
- return { map: graph, table: table }
- }
- function buildSingleSegment (data, modesHint) {
- var mode
- var bestMode = Mode.getBestModeForData(data)
- mode = Mode.from(modesHint, bestMode)
-
- if (mode !== Mode.BYTE && mode.bit < bestMode.bit) {
- throw new Error('"' + data + '"' +
- ' cannot be encoded with mode ' + Mode.toString(mode) +
- '.\n Suggested mode is: ' + Mode.toString(bestMode))
- }
-
- if (mode === Mode.KANJI && !Utils.isKanjiModeEnabled()) {
- mode = Mode.BYTE
- }
- switch (mode) {
- case Mode.NUMERIC:
- return new NumericData(data)
- case Mode.ALPHANUMERIC:
- return new AlphanumericData(data)
- case Mode.KANJI:
- return new KanjiData(data)
- case Mode.BYTE:
- return new ByteData(data)
- }
- }
- exports.fromArray = function fromArray (array) {
- return array.reduce(function (acc, seg) {
- if (typeof seg === 'string') {
- acc.push(buildSingleSegment(seg, null))
- } else if (seg.data) {
- acc.push(buildSingleSegment(seg.data, seg.mode))
- }
- return acc
- }, [])
- }
- exports.fromString = function fromString (data, version) {
- var segs = getSegmentsFromString(data, Utils.isKanjiModeEnabled())
- var nodes = buildNodes(segs)
- var graph = buildGraph(nodes, version)
- var path = dijkstra.find_path(graph.map, 'start', 'end')
- var optimizedSegs = []
- for (var i = 1; i < path.length - 1; i++) {
- optimizedSegs.push(graph.table[path[i]].node)
- }
- return exports.fromArray(mergeSegments(optimizedSegs))
- }
- exports.rawSplit = function rawSplit (data) {
- return exports.fromArray(
- getSegmentsFromString(data, Utils.isKanjiModeEnabled())
- )
- }
|