/******************************************************************************
 * mod_uploader / UploadItemReader.cpp
 ******************************************************************************
 * Copyright (C) 2005 Tetsuya Kimata <kimata@acapulco.dyndns.org>
 *
 * All rights reserved.
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any
 * damages arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any
 * purpose, including commercial applications, and to alter it and
 * redistribute it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must
 *    not claim that you wrote the original software. If you use this
 *    software in a product, an acknowledgment in the product
 *    documentation would be appreciated but is not bcktuired.
 *
 * 2. Altered source versions must be plainly marked as such, and must
 *    not be misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source
 *    distribution.
 *
 * $Id: UploadItemReader.cpp 676 2005-09-14 14:43:48Z svn $
 *****************************************************************************/

#include "UploadItemReader.h"
#include "Auxiliary.h"
#include "Misc.h"

#define APR_WANT_STRFUNC
#include "apr_want.h"

#ifdef DEBUG
#include <iostream>
#endif

/******************************************************************************
 * public メソッド
 *****************************************************************************/
UploadItemReader::UploadItemReader(apr_pool_t *pool, const char *file_dir)
    : pool_(pool),
      file_dir_(file_dir)
{

}

UploadItem::header *UploadItemReader::read(const char *file_name,
                                           apr_file_t **file)
{
    return read(file_name, file, pool_);
}

UploadItem::header *UploadItemReader::read(const char *file_name,
                                           apr_file_t **file,
                                           apr_pool_t *pool)
{
    char *file_path;
    apr_size_t size;
    apr_off_t offset;
    UploadItem::header *header;

    if (apr_filepath_merge(&file_path, file_dir_, file_name,
                           APR_FILEPATH_NOTABOVEROOT, pool) != APR_SUCCESS) {
        throw "アップロードファイルの名前を構成できませんでした．";
    }

    if (apr_file_open(file, file_path, APR_READ|APR_BINARY|APR_BUFFERED|APR_SENDFILE_ENABLED,
                      APR_OS_DEFAULT, pool) != APR_SUCCESS) {
        throw "アップロードファイルを開けませんでした．";
    }

    APR_PCALLOC(header, UploadItem::header *, pool, sizeof(UploadItem::header));

    if ((apr_file_read_full(*file, header, sizeof(UploadItem::header), &size) != APR_SUCCESS) ||
        (size != sizeof(UploadItem::header))) {
        throw "アップロードデータを読み込めませんでした．";
    }

    if (strncmp(header->identifier, PACKAGE_NAME, strlen(PACKAGE_NAME)) != 0) {
        throw "未知の形式のファイルです．";
    }

    offset = sizeof(UploadItem::header);
    if ((apr_file_seek(*file, APR_SET, &offset) != APR_SUCCESS) ||
        (static_cast<apr_size_t>(offset) != sizeof(UploadItem::header))) {
        throw "ファイルの seek に失敗しました．";
    }

    return header;
}


/******************************************************************************
 * テスト
 *****************************************************************************/
#ifdef DEBUG_UploadItemReader
#include "apr_general.h"
#include "apr_strings.h"

#include "RFC1867ParserImpl.h"
#include "UploadItem.h"
#include "UploadItemCreator.h"
#include "UploadItemWriter.h"

static const apr_size_t  BUFSIZE        = 256;
static const char FILE_DIR[]            = "/tmp";
static const char CONTENT_TYPE_TMPL[]   = "multipart/form-data; boundary=%s";

// ダミー
char *ap_escape_html(apr_pool_t *pool, const char *str)
{
    return const_cast<char *>(str);
}

void usage(const char *prog_name)
{
    cerr << "Usage: " << prog_name << " <INPUT>" << endl;
}

int main(int argc, const char * const *argv)
{
    char content_type[BUFSIZE];
    apr_pool_t *pool;
    apr_file_t *fd;
    apr_off_t offset;
    UploadItem::header *header;
    const char *tmp_path;
    const char *file_path;

    apr_app_initialize(&argc, &argv, NULL);
    apr_pool_create(&pool, NULL);

    try {
        if (argc != 2) {
            throw "入力用のファイルが指定されていません．";
        }

        if (apr_file_open(&fd, argv[1], APR_READ|APR_BINARY,
                          APR_OS_DEFAULT, pool) != APR_SUCCESS) {
            throw "入力用のファイルを開けませんでした．";
        }

        if (apr_file_gets(content_type, sizeof(content_type), fd) != APR_SUCCESS) {
            throw "入力用のファイルの read に失敗しました．";
        }
        offset = 0;
        if (apr_file_seek(fd, APR_SET, &offset) != APR_SUCCESS) {
            throw "入力用のファイルの seek に失敗しました．";
        }

        UploadParser parser (FILE_DIR, 10*1024*1024, 32*1024*1024, 5,
                             sizeof(UploadItem::header));

        auto_ptr<UploadParser::query_map>
            qmap(parser.parse(pool, fd,
                              apr_psprintf(pool, CONTENT_TYPE_TMPL, content_type+2)));

        UploadItemWriter writer(pool, FILE_DIR);
        header = UploadItemCreator::create_header(pool, qmap.get(), &tmp_path);

        file_path = writer.write(header, tmp_path);

        UploadItemReader reader(pool, FILE_DIR);
        header = reader.read(basename_ex(file_path), &fd);

        UploadParser::clean_tmp_file(pool, qmap.get());
        UploadItem::dump_header(header);
    } catch(const char *message) {
        cerr << "Error: " << message << endl;
        usage(argv[0]);

        return EXIT_FAILURE;
    }

    apr_terminate();

    return EXIT_SUCCESS;
}
#endif

// Local Variables:
// mode: c++
// buffer-file-coding-system: euc-japan-dos
// End:
