/* 
 * $Id: CSVAnalyzer.cpp,v 1.5 2005/10/19 14:05:44 ozawa Exp $
 *
 * Copyright 2005- ONGS Inc. All rights reserved.
 * 
 * author: Masanori OZAWA (ozawa@ongs.co.jp)
 * version: $Revision: 1.5 $
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY ONGS INC ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL ONGS INC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * The views and conclusions contained in the software and documentation are
 * those of the authors and should not be interpreted as representing official
 * policies, either expressed or implied, of the ONGS Inc.
 * 
 */
 
 #include "xdtp.h"
 #include "CSVAnalyzer.h"
 #include "Utilities.h"

using namespace XDTP;

CSVAnalyzer::CSVAnalyzer()
{
}

CSVAnalyzer::~CSVAnalyzer()
{
}

/**
 * CSV データを解析し、List データ構造に格納します。
 * 
 * @param aLine
 *            解析元のCSVデータ1行
 * @return List データ構造に格納した CSV データ
 */
bool CSVAnalyzer::analyzeLine(const Glib::ustring& aLine, StringList& aList)
{
    // 切出の最初の位置
    Glib::ustring::size_type startPoint = 0;

    // 切出の終りの位置
    Glib::ustring::size_type nextPoint = 0;

    // 解析文字列の長さ
    Glib::ustring::size_type csvLenght = aLine.length();

    Glib::ustring token;

    aList.clear();

    nextPoint = nextCommaPoint(startPoint, aLine);
    while (nextPoint != Glib::ustring::npos &&
           nextPoint >= startPoint && nextPoint <= csvLenght)
    {
        token = aLine.substr(startPoint, nextPoint - startPoint);

        // 囲っているダブルクォーテーションを取り除く
        if (1 < token.length() && '"' == token.at(0)) {
            token = token.substr(1, token.length() -2);
        }

        // エスケープされたダブルクォーテーションを元に戻す
        token = Utilities::strReplaceAll(token, "\"\"", "\"");

        aList.push_back(token);
        startPoint = nextPoint + 1;
        nextPoint = nextCommaPoint(startPoint, aLine);
    }

    // ダブルクォーテーションの囲いを抜けていない場合は false を返す
    if (nextPoint == Glib::ustring::npos) {
        aList.clear();
        return false;
    }

    return true;
}

/**
 * 指定された場所以降で, 次に区切りのカンマが現れる場所を返します。
 * 次にカンマが見当たらない場合, 解析対象の文字列の長さが還ります。
 * ただし、データが妥当でない(たとえばダブルクォーテーションの囲いが
 * 終了していないのに行が終わっている場合)は -1 を返します。
 * 
 * @param aStartPoint
 *            解析開始位置
 * @param aLine
 *            解析元CSVデータ1行
 * @return 次に区切りのカンマが来る位置か, データの長さ。データが 妥当でない場合は -1 が返ります。
 */
Glib::ustring::size_type CSVAnalyzer::nextCommaPoint
    (Glib::ustring::size_type aStartPoint, const Glib::ustring& aLine)
{
    // 次のカンマが現れるまでインクリメントされる位置ポイント
    Glib::ustring::size_type targetPoint = aStartPoint;

    // 解析文字列の長さ
    Glib::ustring::size_type csvLength = aLine.length();
    
    // 解析対象の文字
    Glib::ustring::value_type value;

    // ダブルクォーテーションの内部にあるかないかを表します。CSV データ
    // は, データ内にカンマがある場合, そのデータをダブルクォーテーショ
    // ンで囲むことで区切りのカンマと区別します。本真偽値はその判定に利用
    // されます。
    bool isQuoted = false;

    // 次の区切りカンマが来るか, または
    for (; targetPoint < csvLength; targetPoint++) {
        value = aLine.at(targetPoint);
        if (',' == value && !isQuoted) {
            // ダブルクォーテーション内部ではないカンマの場合に次のカンマ
            // が来たと判断し処理を抜けます。
            break;
        }
        else if ('"' == value) {
            // CSV データは, データ内にダブルクォーテーションがある場合,
            // そのデータを二つのダブルクォーテーションに変換します。
            // 次の処理は, 連続した二つのダブルクォーテーションには影響
            // を与えずに囲みのダブルクォーテーションを調べることができ
            // ます。
            isQuoted = !isQuoted;
        }
    }

    // ダブルクォーテーションの囲いを抜けていない場合は -1 を返します。
    if (isQuoted) {
        targetPoint = Glib::ustring::npos;
    }

    return targetPoint;
}


syntax highlighted by Code2HTML, v. 0.9.1