11cb0ef41Sopenharmony_ci// Copyright 2009 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Redistribution and use in source and binary forms, with or without
31cb0ef41Sopenharmony_ci// modification, are permitted provided that the following conditions are
41cb0ef41Sopenharmony_ci// met:
51cb0ef41Sopenharmony_ci//
61cb0ef41Sopenharmony_ci//     * Redistributions of source code must retain the above copyright
71cb0ef41Sopenharmony_ci//       notice, this list of conditions and the following disclaimer.
81cb0ef41Sopenharmony_ci//     * Redistributions in binary form must reproduce the above
91cb0ef41Sopenharmony_ci//       copyright notice, this list of conditions and the following
101cb0ef41Sopenharmony_ci//       disclaimer in the documentation and/or other materials provided
111cb0ef41Sopenharmony_ci//       with the distribution.
121cb0ef41Sopenharmony_ci//     * Neither the name of Google Inc. nor the names of its
131cb0ef41Sopenharmony_ci//       contributors may be used to endorse or promote products derived
141cb0ef41Sopenharmony_ci//       from this software without specific prior written permission.
151cb0ef41Sopenharmony_ci//
161cb0ef41Sopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171cb0ef41Sopenharmony_ci// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181cb0ef41Sopenharmony_ci// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191cb0ef41Sopenharmony_ci// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201cb0ef41Sopenharmony_ci// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211cb0ef41Sopenharmony_ci// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221cb0ef41Sopenharmony_ci// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231cb0ef41Sopenharmony_ci// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241cb0ef41Sopenharmony_ci// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251cb0ef41Sopenharmony_ci// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261cb0ef41Sopenharmony_ci// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci/**
301cb0ef41Sopenharmony_ci * Creates a CSV lines parser.
311cb0ef41Sopenharmony_ci */
321cb0ef41Sopenharmony_ciexport class CsvParser {
331cb0ef41Sopenharmony_ci  /**
341cb0ef41Sopenharmony_ci   * Converts \x00 and \u0000 escape sequences in the given string.
351cb0ef41Sopenharmony_ci   *
361cb0ef41Sopenharmony_ci   * @param {string} input field.
371cb0ef41Sopenharmony_ci   **/
381cb0ef41Sopenharmony_ci  escapeField(string) {
391cb0ef41Sopenharmony_ci    let nextPos = string.indexOf("\\");
401cb0ef41Sopenharmony_ci    if (nextPos === -1) return string;
411cb0ef41Sopenharmony_ci    let result = [string.substring(0, nextPos)];
421cb0ef41Sopenharmony_ci    // Escape sequences of the form \x00 and \u0000;
431cb0ef41Sopenharmony_ci    let pos = 0;
441cb0ef41Sopenharmony_ci    while (nextPos !== -1) {
451cb0ef41Sopenharmony_ci      const escapeIdentifier = string[nextPos + 1];
461cb0ef41Sopenharmony_ci      pos = nextPos + 2;
471cb0ef41Sopenharmony_ci      if (escapeIdentifier === 'n') {
481cb0ef41Sopenharmony_ci        result.push('\n');
491cb0ef41Sopenharmony_ci        nextPos = pos;
501cb0ef41Sopenharmony_ci      } else if (escapeIdentifier === '\\') {
511cb0ef41Sopenharmony_ci        result.push('\\');
521cb0ef41Sopenharmony_ci        nextPos = pos;
531cb0ef41Sopenharmony_ci      } else {
541cb0ef41Sopenharmony_ci        if (escapeIdentifier === 'x') {
551cb0ef41Sopenharmony_ci          // \x00 ascii range escapes consume 2 chars.
561cb0ef41Sopenharmony_ci          nextPos = pos + 2;
571cb0ef41Sopenharmony_ci        } else {
581cb0ef41Sopenharmony_ci          // \u0000 unicode range escapes consume 4 chars.
591cb0ef41Sopenharmony_ci          nextPos = pos + 4;
601cb0ef41Sopenharmony_ci        }
611cb0ef41Sopenharmony_ci        // Convert the selected escape sequence to a single character.
621cb0ef41Sopenharmony_ci        const escapeChars = string.substring(pos, nextPos);
631cb0ef41Sopenharmony_ci        if (escapeChars === '2C') {
641cb0ef41Sopenharmony_ci            result.push(',');
651cb0ef41Sopenharmony_ci        } else {
661cb0ef41Sopenharmony_ci          result.push(String.fromCharCode(parseInt(escapeChars, 16)));
671cb0ef41Sopenharmony_ci        }
681cb0ef41Sopenharmony_ci      }
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci      // Continue looking for the next escape sequence.
711cb0ef41Sopenharmony_ci      pos = nextPos;
721cb0ef41Sopenharmony_ci      nextPos = string.indexOf("\\", pos);
731cb0ef41Sopenharmony_ci      // If there are no more escape sequences consume the rest of the string.
741cb0ef41Sopenharmony_ci      if (nextPos === -1) {
751cb0ef41Sopenharmony_ci        result.push(string.substr(pos));
761cb0ef41Sopenharmony_ci        break;
771cb0ef41Sopenharmony_ci      } else if (pos !== nextPos) {
781cb0ef41Sopenharmony_ci        result.push(string.substring(pos, nextPos));
791cb0ef41Sopenharmony_ci      }
801cb0ef41Sopenharmony_ci    }
811cb0ef41Sopenharmony_ci    return result.join('');
821cb0ef41Sopenharmony_ci  }
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci  /**
851cb0ef41Sopenharmony_ci   * Parses a line of CSV-encoded values. Returns an array of fields.
861cb0ef41Sopenharmony_ci   *
871cb0ef41Sopenharmony_ci   * @param {string} line Input line.
881cb0ef41Sopenharmony_ci   */
891cb0ef41Sopenharmony_ci  parseLine(line) {
901cb0ef41Sopenharmony_ci    let pos = 0;
911cb0ef41Sopenharmony_ci    const endPos = line.length;
921cb0ef41Sopenharmony_ci    const fields = [];
931cb0ef41Sopenharmony_ci    if (endPos == 0) return fields;
941cb0ef41Sopenharmony_ci    let nextPos = 0;
951cb0ef41Sopenharmony_ci    while(nextPos !== -1) {
961cb0ef41Sopenharmony_ci      nextPos = line.indexOf(',', pos);
971cb0ef41Sopenharmony_ci      let field;
981cb0ef41Sopenharmony_ci      if (nextPos === -1) {
991cb0ef41Sopenharmony_ci        field = line.substr(pos);
1001cb0ef41Sopenharmony_ci      } else {
1011cb0ef41Sopenharmony_ci        field = line.substring(pos, nextPos);
1021cb0ef41Sopenharmony_ci      }
1031cb0ef41Sopenharmony_ci      fields.push(this.escapeField(field));
1041cb0ef41Sopenharmony_ci      pos = nextPos + 1;
1051cb0ef41Sopenharmony_ci    };
1061cb0ef41Sopenharmony_ci    return fields
1071cb0ef41Sopenharmony_ci  }
1081cb0ef41Sopenharmony_ci}
109