docs: function DBCSCodec(codecOptions, iconv) {
      this.encodingName = codecOptions.encodingName;
      if (!codecOptions)
          throw new Error("DBCS codec is called without the data.")
      if (!codecOptions.table)
          throw new Error("Encoding '" + this.encodingName + "' has no data.");
  
      // Load tables.
      var mappingTable = codecOptions.table();
  
  
      // Decode tables: MBCS -> Unicode.
  
      // decodeTables is a trie, encoded as an array of arrays of integers. Internal arrays are trie nodes and all have len = 256.
      // Trie root is decodeTables[0].
      // Values: >=  0 -> unicode character code. can be > 0xFFFF
      //         == UNASSIGNED -> unknown/unassigned sequence.
      //         == GB18030_CODE -> this is the end of a GB18030 4-byte sequence.
      //         <= NODE_START -> index of the next node in our trie to process next byte.
      //         <= SEQ_START  -> index of the start of a character code sequence, in decodeTableSeq.
      this.decodeTables = [];
      this.decodeTables[0] = UNASSIGNED_NODE.slice(0); // Create root node.
  
      // Sometimes a MBCS char corresponds to a sequence of unicode chars. We store them as arrays of integers here. 
      this.decodeTableSeq = [];
  
      // Actual mapping tables consist of chunks. Use them to fill up decode tables.
      for (var i = 0; i < mappingTable.length; i++)
          this._addDecodeChunk(mappingTable[i]);
  
      this.defaultCharUnicode = iconv.defaultCharUnicode;
  
      
      // Encode tables: Unicode -> DBCS.
  
      // `encodeTable` is array mapping from unicode char to encoded char. All its values are integers for performance.
      // Because it can be sparse, it is represented as array of buckets by 256 chars each. Bucket can be null.
      // Values: >=  0 -> it is a normal char. Write the value (if <=256 then 1 byte, if <=65536 then 2 bytes, etc.).
      //         == UNASSIGNED -> no conversion found. Output a default char.
      //         <= SEQ_START  -> it's an index in encodeTableSeq, see below. The character starts a sequence.
      this.encodeTable = [];
      
      // `encodeTableSeq` is used when a sequence of unicode characters is encoded as a single code. We use a tree of
      // objects where keys correspond to characters in sequence and leafs are the encoded dbcs values. A special DEF_CHAR key
      // means end of sequence (needed when one sequence is a strict subsequence of another).
      // Objects are kept separately from encodeTable to increase performance.
      this.encodeTableSeq = [];
  
      // Some chars can be decoded, but need not be encoded.
      var skipEncodeChars = {};
      if (codecOptions.encodeSkipVals)
          for (var i = 0; i < codecOptions.encodeSkipVals.length; i++) {
              var val = codecOptions.encodeSkipVals[i];
              if (typeof val === 'number')
                  skipEncodeChars[val] = true;
              else
                  for (var j = val.from; j <= val.to; j++)
                      skipEncodeChars[j] = true;
          }
          
      // Use decode trie to recursively fill out encode tables.
      this._fillEncodeTable(0, 0, skipEncodeChars);
  
      // Add more encoding pairs when needed.
      if (codecOptions.encodeAdd) {
          for (var uChar in codecOptions.encodeAdd)
              if (Object.prototype.hasOwnProperty.call(codecOptions.encodeAdd, uChar))
                  this._setEncodeChar(uChar.charCodeAt(0), codecOptions.encodeAdd[uChar]);
      }
  
      this.defCharSB  = this.encodeTable[0][iconv.defaultCharSingleByte.charCodeAt(0)];
      if (this.defCharSB === UNASSIGNED) this.defCharSB = this.encodeTable[0]['?'];
      if (this.defCharSB === UNASSIGNED) this.defCharSB = "?".charCodeAt(0);
  
  
      // Load & create GB18030 tables when needed.
      if (typeof codecOptions.gb18030 === 'function') {
          this.gb18030 = codecOptions.gb18030(); // Load GB18030 ranges.
  
          // Add GB18030 decode tables.
          var thirdByteNodeIdx = this.decodeTables.length;
          var thirdByteNode = this.decodeTables[thirdByteNodeIdx] = UNASSIGNED_NODE.slice(0);
  
          var fourthByteNodeIdx = this.decodeTables.length;
          var fourthByteNode = this.decodeTables[fourthByteNodeIdx] = UNASSIGNED_NODE.slice(0);
  
          for (var i = 0x81; i <= 0xFE; i++) {
              var secondByteNodeIdx = NODE_START - this.decodeTables[0][i];
              var secondByteNode = this.decodeTables[secondByteNodeIdx];
              for (var j = 0x30; j <= 0x39; j++)
                  secondByteNode[j] = NODE_START - thirdByteNodeIdx;
          }
          for (var i = 0x81; i <= 0xFE; i++)
              thirdByteNode[i] = NODE_START - fourthByteNodeIdx;
          for (var i = 0x30; i <= 0x39; i++)
              fourthByteNode[i] = GB18030_CODE
      }        
  }