<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2006 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "FFMpegDecoder.h"

#include "Player.h"
#include "../base/Exception.h"
#include "../base/Logger.h"
#include "../base/ScopeTimer.h"

#include <iostream>
#include <sstream>
#include <unistd.h>

using namespace std;

namespace avg {

bool FFMpegDecoder::m_bInitialized = false;

FFMpegDecoder::FFMpegDecoder ()
    : m_pFormatContext(0),
      m_pVStream(0),
      m_pPacketData(0)
{
    initVideoSupport();
}

FFMpegDecoder::~FFMpegDecoder ()
{
    if (m_pFormatContext) {
        close();
    }
}

void avcodecError(const string & filename, int err)
{
    switch(err) {
        case AVERROR_NUMEXPECTED:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Incorrect image filename syntax.");
            AVG_TRACE(Logger::ERROR,
                    "Use '%%d' to specify the image number:");
            AVG_TRACE(Logger::ERROR,
                    "  for img1.jpg, img2.jpg, ..., use 'img%%d.jpg';");
            AVG_TRACE(Logger::ERROR,
                    "  for img001.jpg, img002.jpg, ..., use 'img%%03d.jpg'.");
            break;
        case AVERROR_INVALIDDATA:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Error while parsing header");
            break;
        case AVERROR_NOFMT:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Unknown format");
            break;
        default:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Error while opening file (Num:" << err << ")");
            break;
    }
    // TODO: Continue without video.
    exit(-1);
}

void dump_stream_info(AVFormatContext *s)
{
    cerr << "Stream info: " << endl;
    if (s->track != 0)
        fprintf(stderr, "  Track: %d\n", s->track);
    if (s->title[0] != '\0')
        fprintf(stderr, "  Title: %s\n", s->title);
    if (s->author[0] != '\0')
        fprintf(stderr, "  Author: %s\n", s->author);
    if (s->album[0] != '\0')
        fprintf(stderr, "  Album: %s\n", s->album);
    if (s->year != 0)
        fprintf(stderr, "  Year: %d\n", s->year);
    if (s->genre[0] != '\0')
        fprintf(stderr, "  Genre: %s\n", s->genre);
}

bool FFMpegDecoder::open (const std::string& sFilename,
        int* pWidth, int* pHeight)
{
    AVFormatParameters params;
    int err;
    m_sFilename = sFilename;

    AVG_TRACE(Logger::PROFILE, "Opening " << sFilename);
    memset(&params, 0, sizeof(params));
    params.image_format = 0;

    err = av_open_input_file(&m_pFormatContext, sFilename.c_str(),
            0, 0, &params);
    if (err < 0) {
        avcodecError(sFilename, err);
    }

    err = av_find_stream_info(m_pFormatContext);
    if (err < 0) {
        AVG_TRACE(Logger::ERROR,
                    sFilename << ": Could not find codec parameters.");
        return false;
    }

    av_read_play(m_pFormatContext);

    m_VStreamIndex = -1;
    for(int i = 0; i < m_pFormatContext->nb_streams; i++) {
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
        AVCodecContext *enc = &m_pFormatContext->streams[i]->codec;
#else
        AVCodecContext *enc = m_pFormatContext->streams[i]->codec;
#endif
        switch(enc->codec_type) {
/*
           case CODEC_TYPE_AUDIO:
               if (audio_index < 0 && !audio_disable)
               audio_index = i;
               break;
*/
            case CODEC_TYPE_VIDEO:
                if (m_VStreamIndex < 0)
                    m_VStreamIndex = i;
                break;
            default:
                break;
        }
    }
//    dump_format(m_pFormatContext, 0, m_sFilename.c_str(), 0);
//    dump_stream_info(m_pFormatContext);
    if (m_VStreamIndex < 0) {
        AVG_TRACE(Logger::ERROR,
                    sFilename << " does not contain any video streams.");
        return false;
    }
    AVCodecContext *enc;
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    enc = &(m_pFormatContext->streams[m_VStreamIndex]->codec);
#else
    enc = m_pFormatContext->streams[m_VStreamIndex]->codec;
#endif
//    enc->debug = 0x0001; // see avcodec.h

    AVCodec * codec = avcodec_find_decoder(enc->codec_id);
    if (!codec ||
        avcodec_open(enc, codec) < 0)
    {
        AVG_TRACE(Logger::ERROR,
                    sFilename << ": could not open codec (?!).");
        return false;
    }
    m_pVStream = m_pFormatContext->streams[m_VStreamIndex];
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    *pWidth =  m_pVStream->codec.width;
    *pHeight = m_pVStream->codec.height;
#else
    *pWidth =  m_pVStream->codec->width;
    *pHeight = m_pVStream->codec->height;
#endif
    m_bFirstPacket = true;
    m_PacketLenLeft = 0;
    m_bEOF = false;
    return true;
}

void FFMpegDecoder::close()
{
    AVG_TRACE(Logger::PROFILE, "Closing " << m_sFilename);
    AVCodecContext * enc;
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    enc = &(m_pFormatContext->streams[m_VStreamIndex]->codec);
#else
    enc = m_pFormatContext->streams[m_VStreamIndex]->codec;
#endif
    if (!m_bFirstPacket) {
        av_free_packet(&m_Packet);
    }
    m_pPacketData = 0;
    avcodec_close(enc);
    m_pVStream = 0;
    av_close_input_file(m_pFormatContext);
    m_pFormatContext = 0;
}

void FFMpegDecoder::seek(int DestFrame, int CurFrame)
{
#if LIBAVFORMAT_BUILD <= 4616
    av_seek_frame(m_pFormatContext, m_VStreamIndex,
            int((double(DestFrame)*1000000*1000)/m_pVStream->r_frame_rate));
#else
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    av_seek_frame(m_pFormatContext, m_VStreamIndex,
            int((double(DestFrame)*1000000*1000)/m_pVStream->r_frame_rate), 0);
#else
    double framerate = (m_pVStream->r_frame_rate.num)/m_pVStream->r_frame_rate.den;
    av_seek_frame(m_pFormatContext, m_VStreamIndex,
            int((double(DestFrame)*1000000*1000)/framerate), 0);
#endif
#endif
}

int FFMpegDecoder::getNumFrames()
{
    // This is broken for some videos, but the code here is correct.
    // So fix the videos or ffmpeg :-).
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    return m_pVStream->r_frame_rate*(m_pVStream->duration/AV_TIME_BASE);
#else
    return (m_pVStream->r_frame_rate.num/m_pVStream->r_frame_rate.den)*(m_pVStream->duration/AV_TIME_BASE);
#endif
}

double FFMpegDecoder::getFPS()
{
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    return m_pVStream->r_frame_rate;
#else
    return (m_pVStream->r_frame_rate.num/m_pVStream->r_frame_rate.den);
#endif
}

static ProfilingZone RenderToBmpProfilingZone("      FFMpeg: renderToBmp");
static ProfilingZone ImgConvertProfilingZone("        FFMpeg: img_convert");

bool FFMpegDecoder::renderToBmp(BitmapPtr pBmp)
{
    ScopeTimer Timer(RenderToBmpProfilingZone);
    AVFrame Frame;
    readFrame(Frame);
    if (!m_bEOF) {
        AVPicture DestPict;
        unsigned char * pDestBits = pBmp->getPixels();
        DestPict.data[0] = pDestBits;
        DestPict.data[1] = pDestBits+1;
        DestPict.data[2] = pDestBits+2;
        DestPict.data[3] = pDestBits+3;
        DestPict.linesize[0] = pBmp->getStride();
        DestPict.linesize[1] = pBmp->getStride();
        DestPict.linesize[2] = pBmp->getStride();
        DestPict.linesize[3] = pBmp->getStride();
        int DestFmt;
        switch(pBmp->getPixelFormat()) {
            case R8G8B8X8:
                DestFmt = PIX_FMT_RGBA32;
                break;
            case B8G8R8X8:
                // This isn't supported directly by FFMpeg.
                DestFmt = PIX_FMT_RGBA32;
                DestPict.data[1] = pDestBits+3;
                DestPict.data[3] = pDestBits+1;
                break;
            case R8G8B8:
                DestFmt = PIX_FMT_RGB24;
                break;
            case B8G8R8:
                DestFmt = PIX_FMT_BGR24;
                break;
            case YCbCr422:
                DestFmt = PIX_FMT_YUV422;
                break;
            default:
                AVG_TRACE(Logger::ERROR, "FFMpegDecoder: Dest format "
                        << pBmp->getPixelFormatString() << " not supported.");
                assert(false);
        }
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
        AVCodecContext *enc = &m_pVStream->codec;
#else
        AVCodecContext *enc = m_pVStream->codec;
#endif
        {
            ScopeTimer Timer(ImgConvertProfilingZone);
            img_convert(&DestPict, DestFmt,
                    (AVPicture*)&Frame, enc->pix_fmt,
                    enc->width, enc->height);
        }
    }
    return m_bEOF;
}

bool FFMpegDecoder::isYCbCrSupported()
{
    return true;
}

bool FFMpegDecoder::canRenderToBuffer(int BPP)
{
//TODO: This is a bug: We should enable direct rendering if DFB is being
//      used and not just compiled in!
#ifdef AVG_ENABLE_DFB
    return (BPP == 24);
#else
    return false;
#endif
}

void FFMpegDecoder::initVideoSupport()
{
    if (!m_bInitialized) {
        av_register_all();
        m_bInitialized = true;
        // Avoid libavcodec console spam - turn this up again when libavcodec
        // doesn't spam anymore :-).
//        av_log_set_level(AV_LOG_DEBUG);
        av_log_set_level(AV_LOG_QUIET);
    }
}

void FFMpegDecoder::readFrame(AVFrame& Frame)
{
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
        AVCodecContext *enc = &m_pVStream->codec;
#else
        AVCodecContext *enc = m_pVStream->codec;
#endif
    if (enc->codec_id == CODEC_ID_RAWVIDEO) {
        AVPacket Packet;
        m_bEOF = getNextVideoPacket(Packet);
        if (m_bEOF) {
            return ;
        }
        avpicture_fill((AVPicture*)&Frame, Packet.data,
                enc->pix_fmt,
                enc->width, enc->height);
        av_free_packet(&Packet);
    } else {
        int gotPicture = 0;
        while (!gotPicture) {
            if (m_PacketLenLeft <= 0) {
                if (!m_bFirstPacket) {
                    av_free_packet(&m_Packet);
                }
                m_bFirstPacket = false;
                m_bEOF = getNextVideoPacket(m_Packet);
                if (m_bEOF) {
                    return ;
                }
                m_PacketLenLeft = m_Packet.size;
                m_pPacketData = m_Packet.data;
            }
            int Len1 = avcodec_decode_video(enc, &Frame,
                    &gotPicture, m_pPacketData, m_PacketLenLeft);
            if (Len1 < 0) {
                AVG_TRACE(Logger::WARNING, "Error decoding " <<
                        m_sFilename);
                // TODO: simulate eof.
            }
            m_pPacketData += Len1;
            m_PacketLenLeft -= Len1;
        }
/*
        cerr << "coded_picture_number: " << Frame.coded_picture_number <<
                ", display_picture_number: " << Frame.display_picture_number <<
                ", pts: " << Frame.pts << endl;

        cerr << "key_frame: " << Frame.key_frame <<
               ", pict_type: " << Frame.pict_type << endl;
        AVFrac spts = m_pVStream->pts;
        cerr << "Stream.pts: " << spts.val + double(spts.num)/spts.den << endl;
*/
    }
}

bool FFMpegDecoder::getNextVideoPacket(AVPacket & Packet) {
    AVPacket CurPacket;
    int err = av_read_frame(m_pFormatContext, &CurPacket);
    if (err < 0) {
        return true;
    }
    while (CurPacket.stream_index != m_VStreamIndex) {
        av_free_packet(&CurPacket);
        int err = av_read_frame(m_pFormatContext, &CurPacket);
        if (err < 0) {
            return true;
        }
    }
    Packet = CurPacket;
/*    if (Packet.pts != AV_NOPTS_VALUE) {
        cerr << "Packet.pts: " <<
            double(Packet.pts)*m_pFormatContext->pts_num/m_pFormatContext->pts_den << endl;
    }
*/
    return false;
}

}

<commit_msg>Fixed seek with newer ffmpeg.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2006 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "FFMpegDecoder.h"

#include "Player.h"
#include "../base/Exception.h"
#include "../base/Logger.h"
#include "../base/ScopeTimer.h"

#include <iostream>
#include <sstream>
#include <unistd.h>

using namespace std;

namespace avg {

bool FFMpegDecoder::m_bInitialized = false;

FFMpegDecoder::FFMpegDecoder ()
    : m_pFormatContext(0),
      m_pVStream(0),
      m_pPacketData(0)
{
    initVideoSupport();
}

FFMpegDecoder::~FFMpegDecoder ()
{
    if (m_pFormatContext) {
        close();
    }
}

void avcodecError(const string & filename, int err)
{
    switch(err) {
        case AVERROR_NUMEXPECTED:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Incorrect image filename syntax.");
            AVG_TRACE(Logger::ERROR,
                    "Use '%%d' to specify the image number:");
            AVG_TRACE(Logger::ERROR,
                    "  for img1.jpg, img2.jpg, ..., use 'img%%d.jpg';");
            AVG_TRACE(Logger::ERROR,
                    "  for img001.jpg, img002.jpg, ..., use 'img%%03d.jpg'.");
            break;
        case AVERROR_INVALIDDATA:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Error while parsing header");
            break;
        case AVERROR_NOFMT:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Unknown format");
            break;
        default:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Error while opening file (Num:" << err << ")");
            break;
    }
    // TODO: Continue without video.
    exit(-1);
}

void dump_stream_info(AVFormatContext *s)
{
    cerr << "Stream info: " << endl;
    if (s->track != 0)
        fprintf(stderr, "  Track: %d\n", s->track);
    if (s->title[0] != '\0')
        fprintf(stderr, "  Title: %s\n", s->title);
    if (s->author[0] != '\0')
        fprintf(stderr, "  Author: %s\n", s->author);
    if (s->album[0] != '\0')
        fprintf(stderr, "  Album: %s\n", s->album);
    if (s->year != 0)
        fprintf(stderr, "  Year: %d\n", s->year);
    if (s->genre[0] != '\0')
        fprintf(stderr, "  Genre: %s\n", s->genre);
}

bool FFMpegDecoder::open (const std::string& sFilename,
        int* pWidth, int* pHeight)
{
    AVFormatParameters params;
    int err;
    m_sFilename = sFilename;

    AVG_TRACE(Logger::PROFILE, "Opening " << sFilename);
    memset(&params, 0, sizeof(params));
    params.image_format = 0;

    err = av_open_input_file(&m_pFormatContext, sFilename.c_str(),
            0, 0, &params);
    if (err < 0) {
        avcodecError(sFilename, err);
    }

    err = av_find_stream_info(m_pFormatContext);
    if (err < 0) {
        AVG_TRACE(Logger::ERROR,
                    sFilename << ": Could not find codec parameters.");
        return false;
    }

    av_read_play(m_pFormatContext);

    m_VStreamIndex = -1;
    for(int i = 0; i < m_pFormatContext->nb_streams; i++) {
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
        AVCodecContext *enc = &m_pFormatContext->streams[i]->codec;
#else
        AVCodecContext *enc = m_pFormatContext->streams[i]->codec;
#endif
        switch(enc->codec_type) {
/*
           case CODEC_TYPE_AUDIO:
               if (audio_index < 0 && !audio_disable)
               audio_index = i;
               break;
*/
            case CODEC_TYPE_VIDEO:
                if (m_VStreamIndex < 0)
                    m_VStreamIndex = i;
                break;
            default:
                break;
        }
    }
//    dump_format(m_pFormatContext, 0, m_sFilename.c_str(), 0);
//    dump_stream_info(m_pFormatContext);
    if (m_VStreamIndex < 0) {
        AVG_TRACE(Logger::ERROR,
                    sFilename << " does not contain any video streams.");
        return false;
    }
    AVCodecContext *enc;
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    enc = &(m_pFormatContext->streams[m_VStreamIndex]->codec);
#else
    enc = m_pFormatContext->streams[m_VStreamIndex]->codec;
#endif
//    enc->debug = 0x0001; // see avcodec.h

    AVCodec * codec = avcodec_find_decoder(enc->codec_id);
    if (!codec ||
        avcodec_open(enc, codec) < 0)
    {
        AVG_TRACE(Logger::ERROR,
                    sFilename << ": could not open codec (?!).");
        return false;
    }
    m_pVStream = m_pFormatContext->streams[m_VStreamIndex];
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    *pWidth =  m_pVStream->codec.width;
    *pHeight = m_pVStream->codec.height;
#else
    *pWidth =  m_pVStream->codec->width;
    *pHeight = m_pVStream->codec->height;
#endif
    m_bFirstPacket = true;
    m_PacketLenLeft = 0;
    m_bEOF = false;
    return true;
}

void FFMpegDecoder::close()
{
    AVG_TRACE(Logger::PROFILE, "Closing " << m_sFilename);
    AVCodecContext * enc;
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    enc = &(m_pFormatContext->streams[m_VStreamIndex]->codec);
#else
    enc = m_pFormatContext->streams[m_VStreamIndex]->codec;
#endif
    if (!m_bFirstPacket) {
        av_free_packet(&m_Packet);
    }
    m_pPacketData = 0;
    avcodec_close(enc);
    m_pVStream = 0;
    av_close_input_file(m_pFormatContext);
    m_pFormatContext = 0;
}

void FFMpegDecoder::seek(int DestFrame, int CurFrame)
{
#if LIBAVFORMAT_BUILD <= 4616
    av_seek_frame(m_pFormatContext, m_VStreamIndex,
            int((double(DestFrame)*1000000*1000)/m_pVStream->r_frame_rate));
#else
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    av_seek_frame(m_pFormatContext, m_VStreamIndex,
            int((double(DestFrame)*1000000*1000)/m_pVStream->r_frame_rate), 0);
#else
    double framerate = (m_pVStream->r_frame_rate.num)/m_pVStream->r_frame_rate.den;

    av_seek_frame(m_pFormatContext, m_VStreamIndex,
            int((double(DestFrame)*AV_TIME_BASE)/framerate), 0);
#endif
#endif
}

int FFMpegDecoder::getNumFrames()
{
    // This is broken for some videos, but the code here is correct.
    // So fix the videos or ffmpeg :-).
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    return m_pVStream->r_frame_rate*(m_pVStream->duration/AV_TIME_BASE);
#else
    return (m_pVStream->r_frame_rate.num/m_pVStream->r_frame_rate.den)*(m_pVStream->duration/AV_TIME_BASE);
#endif
}

double FFMpegDecoder::getFPS()
{
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    return m_pVStream->r_frame_rate;
#else
    return (m_pVStream->r_frame_rate.num/m_pVStream->r_frame_rate.den);
#endif
}

static ProfilingZone RenderToBmpProfilingZone("      FFMpeg: renderToBmp");
static ProfilingZone ImgConvertProfilingZone("        FFMpeg: img_convert");

bool FFMpegDecoder::renderToBmp(BitmapPtr pBmp)
{
    ScopeTimer Timer(RenderToBmpProfilingZone);
    AVFrame Frame;
    readFrame(Frame);
    if (!m_bEOF) {
        AVPicture DestPict;
        unsigned char * pDestBits = pBmp->getPixels();
        DestPict.data[0] = pDestBits;
        DestPict.data[1] = pDestBits+1;
        DestPict.data[2] = pDestBits+2;
        DestPict.data[3] = pDestBits+3;
        DestPict.linesize[0] = pBmp->getStride();
        DestPict.linesize[1] = pBmp->getStride();
        DestPict.linesize[2] = pBmp->getStride();
        DestPict.linesize[3] = pBmp->getStride();
        int DestFmt;
        switch(pBmp->getPixelFormat()) {
            case R8G8B8X8:
                DestFmt = PIX_FMT_RGBA32;
                break;
            case B8G8R8X8:
                // This isn't supported directly by FFMpeg.
                DestFmt = PIX_FMT_RGBA32;
                DestPict.data[1] = pDestBits+3;
                DestPict.data[3] = pDestBits+1;
                break;
            case R8G8B8:
                DestFmt = PIX_FMT_RGB24;
                break;
            case B8G8R8:
                DestFmt = PIX_FMT_BGR24;
                break;
            case YCbCr422:
                DestFmt = PIX_FMT_YUV422;
                break;
            default:
                AVG_TRACE(Logger::ERROR, "FFMpegDecoder: Dest format "
                        << pBmp->getPixelFormatString() << " not supported.");
                assert(false);
        }
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
        AVCodecContext *enc = &m_pVStream->codec;
#else
        AVCodecContext *enc = m_pVStream->codec;
#endif
        {
            ScopeTimer Timer(ImgConvertProfilingZone);
            img_convert(&DestPict, DestFmt,
                    (AVPicture*)&Frame, enc->pix_fmt,
                    enc->width, enc->height);
        }
    }
    return m_bEOF;
}

bool FFMpegDecoder::isYCbCrSupported()
{
    return true;
}

bool FFMpegDecoder::canRenderToBuffer(int BPP)
{
//TODO: This is a bug: We should enable direct rendering if DFB is being
//      used and not just compiled in!
#ifdef AVG_ENABLE_DFB
    return (BPP == 24);
#else
    return false;
#endif
}

void FFMpegDecoder::initVideoSupport()
{
    if (!m_bInitialized) {
        av_register_all();
        m_bInitialized = true;
        // Avoid libavcodec console spam - turn this up again when libavcodec
        // doesn't spam anymore :-).
//        av_log_set_level(AV_LOG_DEBUG);
        av_log_set_level(AV_LOG_QUIET);
    }
}

void FFMpegDecoder::readFrame(AVFrame& Frame)
{
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
        AVCodecContext *enc = &m_pVStream->codec;
#else
        AVCodecContext *enc = m_pVStream->codec;
#endif
    if (enc->codec_id == CODEC_ID_RAWVIDEO) {
        AVPacket Packet;
        m_bEOF = getNextVideoPacket(Packet);
        if (m_bEOF) {
            return ;
        }
        avpicture_fill((AVPicture*)&Frame, Packet.data,
                enc->pix_fmt,
                enc->width, enc->height);
        av_free_packet(&Packet);
    } else {
        int gotPicture = 0;
        while (!gotPicture) {
            if (m_PacketLenLeft <= 0) {
                if (!m_bFirstPacket) {
                    av_free_packet(&m_Packet);
                }
                m_bFirstPacket = false;
                m_bEOF = getNextVideoPacket(m_Packet);
                if (m_bEOF) {
                    return ;
                }
                m_PacketLenLeft = m_Packet.size;
                m_pPacketData = m_Packet.data;
            }
            int Len1 = avcodec_decode_video(enc, &Frame,
                    &gotPicture, m_pPacketData, m_PacketLenLeft);
            if (Len1 < 0) {
                AVG_TRACE(Logger::WARNING, "Error decoding " <<
                        m_sFilename);
                // TODO: simulate eof.
            }
            m_pPacketData += Len1;
            m_PacketLenLeft -= Len1;
        }
/*
        cerr << "coded_picture_number: " << Frame.coded_picture_number <<
                ", display_picture_number: " << Frame.display_picture_number <<
                ", pts: " << Frame.pts << endl;

        cerr << "key_frame: " << Frame.key_frame <<
               ", pict_type: " << Frame.pict_type << endl;
        AVFrac spts = m_pVStream->pts;
        cerr << "Stream.pts: " << spts.val + double(spts.num)/spts.den << endl;
*/
    }
}

bool FFMpegDecoder::getNextVideoPacket(AVPacket & Packet) {
    AVPacket CurPacket;
    int err = av_read_frame(m_pFormatContext, &CurPacket);
    if (err < 0) {
        return true;
    }
    while (CurPacket.stream_index != m_VStreamIndex) {
        av_free_packet(&CurPacket);
        int err = av_read_frame(m_pFormatContext, &CurPacket);
        if (err < 0) {
            return true;
        }
    }
    Packet = CurPacket;
/*    if (Packet.pts != AV_NOPTS_VALUE) {
        cerr << "Packet.pts: " <<
            double(Packet.pts)*m_pFormatContext->pts_num/m_pFormatContext->pts_den << endl;
    }
*/
    return false;
}

}

<|endoftext|>


<commit_before>#include <algorithm>
#include <numeric>
#include <iostream>

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include "mem.h"

using Buffer = std::vector<uint8_t>;

int main(int argc, char** argv) {

  //if (argc != 2) {
  //  std::cerr << "provide image filename" << std::endl;
  //  return 1;
  //}

  //const std::string filename(argv[1]);

  //cv::Mat rgb = cv::imread(filename);

  //if (rgb.empty()) {
  //  std::cerr << "empty image";
  //  return 1;
  //}
  //
  cv::VideoCapture cap(0);
  if (!cap.isOpened())
    return -1;

  if (!cap.set(CV_CAP_PROP_FRAME_WIDTH, 640.0))
    return -1;

  if (!cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480.0))
    return -1;

  const size_t n_pixels = 640 * 480;
  cv::Mat rgb = cv::Mat(cv::Size(640, 480), CV_8UC3, cv::Scalar::all(0));
  cv::Mat dog = cv::Mat(cv::Size(640, 480), CV_8UC3, cv::Scalar::all(0));
  cv::Mat grey = cv::Mat(cv::Size(640, 480), CV_8UC1, cv::Scalar(0));

  double total_duration = 0.0;
  int count = 0;

  Buffer b(n_pixels);
  Buffer g(n_pixels);
  Buffer r(n_pixels);
  Buffer dog_r(n_pixels);

  std::vector<cv::Mat> channels;
  channels.push_back(cv::Mat(rgb.size(), CV_8UC1, cv::Scalar(0)));
  channels.push_back(cv::Mat(rgb.size(), CV_8UC1, cv::Scalar(0)));
  channels.push_back(cv::Mat(rgb.size(), CV_8UC1, cv::Scalar(0)));

  while (true) {

    cap >> rgb;

    auto t1 = cv::getTickCount();

    cv::split(rgb, channels);

    std::copy(channels.at(0).data, channels.at(0).data + channels.at(0).cols * channels.at(0).rows, b.begin());
    std::copy(channels.at(1).data, channels.at(1).data + channels.at(0).cols * channels.at(0).rows, g.begin());
    std::copy(channels.at(2).data, channels.at(2).data + channels.at(0).cols * channels.at(0).rows, r.begin());

    Buffer& dog_b = b;

    auto color_corrector =
      [] (const uint8_t g, const uint8_t r) -> uint8_t {
        return (static_cast<uint64_t>(g) + static_cast<uint64_t>(r)) / 2;
      };
    std::transform(g.begin(), g.end(), r.begin(), dog_r.begin(), color_corrector);
    Buffer& dog_g = dog_r;

    cv::cvtColor(rgb, grey, cv::COLOR_RGB2GRAY);
    double avg_brightness = cv::mean(grey)[0];

    auto averager =
      [avg_brightness] (const uint8_t n) -> uint8_t {
        return uint8_t((static_cast<double>(n) + avg_brightness) / 2.0);
      };

    std::transform(dog_b.begin(), dog_b.end(), dog_b.begin(), averager);
    std::transform(dog_g.begin(), dog_g.end(), dog_g.begin(), averager);
    std::transform(dog_r.begin(), dog_r.end(), dog_r.begin(), averager);

    for (size_t i = 0; i < dog.rows * dog.cols; ++i) {
      dog.at<cv::Vec3b>(i) = cv::Vec3b(dog_b[i], dog_g[i], dog_r[i]);
    }

    cv::GaussianBlur(dog, dog, cv::Size(3, 3), 0, 0);
    cv::GaussianBlur(dog, dog, cv::Size(5, 5), 0, 0);
    cv::GaussianBlur(dog, dog, cv::Size(7, 7), 0, 0);

    auto t2 = cv::getTickCount();

    auto duration = ((double)t2-t1) / cv::getTickFrequency();
    total_duration += duration;
    ++count;
    std::cout << "mean fps: " << 1.0 / (total_duration / static_cast<double>(count))
      << " mem usage: " << getCurrentRSS() / (1024 * 1024) << "mb peak: " << getPeakRSS() / (1024*1024) << "mb"
      << std::endl;

    cv::namedWindow("original");
    cv::moveWindow("original", 0, 0);
    cv::resize(rgb, rgb, cv::Size(640,480));
    cv::imshow("original", rgb);

    cv::namedWindow("dog");
    cv::moveWindow("dog", rgb.cols, 0);
    cv::resize(dog, dog, cv::Size(640, 480));
    cv::imshow("dog", dog);
    if (cv::waitKey(1) >= 0) break;

    //if (count > 90)
    //  break;
  }

  return 0;
}
<commit_msg>more cleanup<commit_after>#include <algorithm>
#include <numeric>
#include <iostream>

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include "mem.h"

using Buffer = std::vector<uint8_t>;

int main(int argc, char** argv) {

  cv::VideoCapture cap(0);
  if (!cap.isOpened())
    return -1;

  if (!cap.set(CV_CAP_PROP_FRAME_WIDTH, 640.0))
    return -1;

  if (!cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480.0))
    return -1;

  const size_t n_pixels = 640 * 480;
  cv::Mat rgb = cv::Mat(cv::Size(640, 480), CV_8UC3, cv::Scalar::all(0));
  cv::Mat dog = cv::Mat(cv::Size(640, 480), CV_8UC3, cv::Scalar::all(0));
  cv::Mat grey = cv::Mat(cv::Size(640, 480), CV_8UC1, cv::Scalar(0));

  double total_duration = 0.0;
  int count = 0;

  Buffer b(n_pixels);
  Buffer g(n_pixels);
  Buffer r(n_pixels);
  Buffer dog_r(n_pixels);

  std::vector<cv::Mat> channels;
  channels.push_back(cv::Mat(rgb.size(), CV_8UC1, cv::Scalar(0)));
  channels.push_back(cv::Mat(rgb.size(), CV_8UC1, cv::Scalar(0)));
  channels.push_back(cv::Mat(rgb.size(), CV_8UC1, cv::Scalar(0)));

  cv::namedWindow("original");
  cv::moveWindow("original", 0, 0);
  cv::namedWindow("dog");
  cv::moveWindow("dog", rgb.cols, 0);

  while (true) {

    cap >> rgb;

    auto t1 = cv::getTickCount();

    cv::split(rgb, channels);

    std::copy(channels.at(0).data, channels.at(0).data + channels.at(0).cols * channels.at(0).rows, b.begin());
    std::copy(channels.at(1).data, channels.at(1).data + channels.at(0).cols * channels.at(0).rows, g.begin());
    std::copy(channels.at(2).data, channels.at(2).data + channels.at(0).cols * channels.at(0).rows, r.begin());

    Buffer& dog_b = b;

    auto color_corrector =
      [] (const uint8_t g, const uint8_t r) -> uint8_t {
        return (static_cast<uint64_t>(g) + static_cast<uint64_t>(r)) / 2;
      };
    std::transform(g.begin(), g.end(), r.begin(), dog_r.begin(), color_corrector);
    Buffer& dog_g = dog_r;

    cv::cvtColor(rgb, grey, cv::COLOR_RGB2GRAY);
    double avg_brightness = cv::mean(grey)[0];

    auto averager =
      [avg_brightness] (const uint8_t n) -> uint8_t {
        return uint8_t((static_cast<double>(n) + avg_brightness) / 2.0);
      };

    std::transform(dog_b.begin(), dog_b.end(), dog_b.begin(), averager);
    std::transform(dog_g.begin(), dog_g.end(), dog_g.begin(), averager);
    std::transform(dog_r.begin(), dog_r.end(), dog_r.begin(), averager);

    for (size_t i = 0; i < dog.rows * dog.cols; ++i) {
      dog.at<cv::Vec3b>(i) = cv::Vec3b(dog_b[i], dog_g[i], dog_r[i]);
    }

    cv::GaussianBlur(dog, dog, cv::Size(3, 3), 0, 0);
    cv::GaussianBlur(dog, dog, cv::Size(5, 5), 0, 0);
    cv::GaussianBlur(dog, dog, cv::Size(7, 7), 0, 0);

    auto t2 = cv::getTickCount();

    auto duration = ((double)t2-t1) / cv::getTickFrequency();
    total_duration += duration;
    ++count;
    std::cout << "mean fps: " << 1.0 / (total_duration / static_cast<double>(count))
      << " mem usage: " << getCurrentRSS() / (1024 * 1024) << "mb peak: " << getPeakRSS() / (1024*1024) << "mb"
      << std::endl;

    cv::resize(rgb, rgb, cv::Size(640,480));
    cv::imshow("original", rgb);

    cv::resize(dog, dog, cv::Size(640, 480));
    cv::imshow("dog", dog);
    if (cv::waitKey(1) >= 0) break;

  }

  return 0;
}
<|endoftext|>


<commit_before>#include "SceneFactory.hpp"

#include <algorithm>
#include <assert.h>
#include "../Image/ImageLoader.hpp"
#include "../Geometry/ModelLoader.hpp"
#include "../../Util/FileLoad.hpp"

SceneFactory::SceneFactory(TextureStore* tStore, ModelStore* mdlStore, MaterialStore* matStore, ScreenContext::FileDataCache* fdc)
    : mTextureStore(tStore)
    , mModelStore(mdlStore)
    , mMaterialStore(matStore)
    , mFileDataCache(fdc)
{
}

std::unique_ptr<Scene> SceneFactory::CreateFromSceneFile(const SceneFile& sceneFile)
{
    std::unique_ptr<Scene> scene(std::make_unique<Scene>());

    LoadTextures(sceneFile.textures, sceneFile.images);
    LoadMaterials(sceneFile.materials);
    LoadGeometries(sceneFile.geometries);

    BakeScene(scene.get(), sceneFile.object.children);

    return std::move(scene);
}

void SceneFactory::LoadTextures(const std::vector<SceneFile::Texture>& textures, const std::vector<SceneFile::Image>& images)
{
    // The ImageLoader object
    ImageLoader imageLoader;

    for(auto& texture : textures)
    {
        // Ignore that texture if it has already been loaded
        if((*mTextureStore)[std::to_string(texture.id)] != nullptr)
            continue;

        // Find the coresponding image
        auto img = std::find_if(std::begin(images), std::end(images),
            [&texture](const SceneFile::Image& image)->bool
            {
                return texture.image == image.id;
            }
        );

        // Assert if no image with the given UUID exists in scene file
        assert(img != std::end(images));

        std::string ext = img->url.substr(img->url.find_last_of(".") + 1);
        RawImage<> pb = imageLoader.Load(*(*mFileDataCache)[img->url], ext);
        mTextureStore->Load(std::to_string(texture.id), pb);
    }
}

void SceneFactory::LoadMaterials(const std::vector<SceneFile::Material>& materials)
{
    for(auto& material : materials)
    {
        // Ignore that material if it has already been loaded
        if((*mMaterialStore)[std::to_string(material.id)] != nullptr)
            continue;

        Material newMat;

        const std::string& diffId      = std::to_string(material.map);
        const std::string& specId      = std::to_string(material.specMap);
        const std::string& normalMapId = std::to_string(material.nmap);

        if(diffId.compare("") != 0)
            newMat.SetDiffuseTexture((*mTextureStore)[diffId]->texId);

        // Add specular
        if(specId.compare("") != 0)
            newMat.SetSpecularTexture((*mTextureStore)[specId]->texId);

        // Add normal map
        if(normalMapId.compare("") != 0)
            newMat.SetNormalMapTexture((*mTextureStore)[normalMapId]->texId);

        // Add color
        newMat.SetDiffuseColor(glm::vec3(material.color.r, material.color.g, material.color.b));
        newMat.SetShininess(material.shininess);

        mMaterialStore->Load(std::to_string(material.id), newMat);
    }
}

void SceneFactory::LoadGeometries(const std::vector<SceneFile::Geometry>& geometries)
{
    // Model loader instance
    ModelLoader modelLoader;

    for(auto& geometry : geometries)
    {
        // Ignore that geometry if it has alredy been loaded
        if((*mModelStore)[std::to_string(geometry.id)] != nullptr)
            continue;

        // Check if path not empty
        if(geometry.url.empty())
            continue;

        // Check if model is already loaded and if not, load it now!
        if((*mFileDataCache).find(geometry.url) == std::end(*mFileDataCache))
        {
            mFileDataCache->emplace(geometry.url, FileLoad<BufferType>(geometry.url));
            if(!(*mFileDataCache)[geometry.url])
                throw std::runtime_error("Couldn't load file (" + geometry.url + ")");
        }

        // Find the file
        auto& file = (*mFileDataCache)[geometry.url];

        // Find file extension
        std::string ext = geometry.url.substr(geometry.url.find_last_of(".") + 1);

        // Load model
        ModelData model = modelLoader.Load(*file, ext.c_str());
        if(model.meshes.size() == 0)
            throw std::runtime_error("Couldn't load model (" + geometry.url + ")");

        mModelStore->Load(std::to_string(geometry.id), std::move(model));

        //(*mModelStore)[geometry.uuid.ToString()]->material = *(*mMaterialStore)[m.material];
    }
}

void SceneFactory::BakeScene(Scene* const sceneToBake, const std::vector<SceneFile::Object::Child>& children)
{
    // Add objects to scene
    for(auto& child : children)
    {
        // Find the right geometry
        ModelDescription* model = (*mModelStore)[std::to_string(child.geometry)];

        // Find the right category
        Category category = (child.type.compare("Mesh") == 0) ? Category::Normal : Category::Light;

        // Create Scene Node
        const auto& initAABB = model->localAABB;
        std::vector<std::string> materials;
        for (const auto& mat : child.materials)
            materials.push_back(std::to_string(mat));
        sceneToBake->CreateNode(std::to_string(child.geometry), materials, child.name, category, initAABB);

        // Set initial transformation
        SceneNode* node = sceneToBake->FindNodeByUuid(child.name);
        node->Move(child.transform.position);
        node->Scale(child.transform.scale);
        node->Rotate(RotationAxis::X, child.transform.rotation.x);
        node->Rotate(RotationAxis::Y, child.transform.rotation.y);
        node->Rotate(RotationAxis::Z, child.transform.rotation.z);
    }
}
<commit_msg>Specular color values are now taken into account when building scene<commit_after>#include "SceneFactory.hpp"

#include <algorithm>
#include <assert.h>
#include "../Image/ImageLoader.hpp"
#include "../Geometry/ModelLoader.hpp"
#include "../../Util/FileLoad.hpp"

SceneFactory::SceneFactory(TextureStore* tStore, ModelStore* mdlStore, MaterialStore* matStore, ScreenContext::FileDataCache* fdc)
    : mTextureStore(tStore)
    , mModelStore(mdlStore)
    , mMaterialStore(matStore)
    , mFileDataCache(fdc)
{
}

std::unique_ptr<Scene> SceneFactory::CreateFromSceneFile(const SceneFile& sceneFile)
{
    std::unique_ptr<Scene> scene(std::make_unique<Scene>());

    LoadTextures(sceneFile.textures, sceneFile.images);
    LoadMaterials(sceneFile.materials);
    LoadGeometries(sceneFile.geometries);

    BakeScene(scene.get(), sceneFile.object.children);

    return std::move(scene);
}

void SceneFactory::LoadTextures(const std::vector<SceneFile::Texture>& textures, const std::vector<SceneFile::Image>& images)
{
    // The ImageLoader object
    ImageLoader imageLoader;

    for(auto& texture : textures)
    {
        // Ignore that texture if it has already been loaded
        if((*mTextureStore)[std::to_string(texture.id)] != nullptr)
            continue;

        // Find the coresponding image
        auto img = std::find_if(std::begin(images), std::end(images),
            [&texture](const SceneFile::Image& image)->bool
            {
                return texture.image == image.id;
            }
        );

        // Assert if no image with the given UUID exists in scene file
        assert(img != std::end(images));

        std::string ext = img->url.substr(img->url.find_last_of(".") + 1);
        RawImage<> pb = imageLoader.Load(*(*mFileDataCache)[img->url], ext);
        mTextureStore->Load(std::to_string(texture.id), pb);
    }
}

void SceneFactory::LoadMaterials(const std::vector<SceneFile::Material>& materials)
{
    for(auto& material : materials)
    {
        // Ignore that material if it has already been loaded
        if((*mMaterialStore)[std::to_string(material.id)] != nullptr)
            continue;

        Material newMat;

        const std::string& diffId      = std::to_string(material.map);
        const std::string& specId      = std::to_string(material.specMap);
        const std::string& normalMapId = std::to_string(material.nmap);

        if(diffId.compare("") != 0)
            newMat.SetDiffuseTexture((*mTextureStore)[diffId]->texId);

        // Add specular
        if(specId.compare("") != 0)
            newMat.SetSpecularTexture((*mTextureStore)[specId]->texId);

        // Add normal map
        if(normalMapId.compare("") != 0)
            newMat.SetNormalMapTexture((*mTextureStore)[normalMapId]->texId);

        // Add color
        newMat.SetDiffuseColor(glm::vec3(material.color.r, material.color.g, material.color.b));
        newMat.SetSpecularColor(glm::vec3(material.specular.r, material.specular.g, material.specular.b));
        newMat.SetShininess(material.shininess);

        mMaterialStore->Load(std::to_string(material.id), newMat);
    }
}

void SceneFactory::LoadGeometries(const std::vector<SceneFile::Geometry>& geometries)
{
    // Model loader instance
    ModelLoader modelLoader;

    for(auto& geometry : geometries)
    {
        // Ignore that geometry if it has alredy been loaded
        if((*mModelStore)[std::to_string(geometry.id)] != nullptr)
            continue;

        // Check if path not empty
        if(geometry.url.empty())
            continue;

        // Check if model is already loaded and if not, load it now!
        if((*mFileDataCache).find(geometry.url) == std::end(*mFileDataCache))
        {
            mFileDataCache->emplace(geometry.url, FileLoad<BufferType>(geometry.url));
            if(!(*mFileDataCache)[geometry.url])
                throw std::runtime_error("Couldn't load file (" + geometry.url + ")");
        }

        // Find the file
        auto& file = (*mFileDataCache)[geometry.url];

        // Find file extension
        std::string ext = geometry.url.substr(geometry.url.find_last_of(".") + 1);

        // Load model
        ModelData model = modelLoader.Load(*file, ext.c_str());
        if(model.meshes.size() == 0)
            throw std::runtime_error("Couldn't load model (" + geometry.url + ")");

        mModelStore->Load(std::to_string(geometry.id), std::move(model));

        //(*mModelStore)[geometry.uuid.ToString()]->material = *(*mMaterialStore)[m.material];
    }
}

void SceneFactory::BakeScene(Scene* const sceneToBake, const std::vector<SceneFile::Object::Child>& children)
{
    // Add objects to scene
    for(auto& child : children)
    {
        // Find the right geometry
        ModelDescription* model = (*mModelStore)[std::to_string(child.geometry)];

        // Find the right category
        Category category = (child.type.compare("Mesh") == 0) ? Category::Normal : Category::Light;

        // Create Scene Node
        const auto& initAABB = model->localAABB;
        std::vector<std::string> materials;
        for (const auto& mat : child.materials)
            materials.push_back(std::to_string(mat));
        sceneToBake->CreateNode(std::to_string(child.geometry), materials, child.name, category, initAABB);

        // Set initial transformation
        SceneNode* node = sceneToBake->FindNodeByUuid(child.name);
        node->Move(child.transform.position);
        node->Scale(child.transform.scale);
        node->Rotate(RotationAxis::X, child.transform.rotation.x);
        node->Rotate(RotationAxis::Y, child.transform.rotation.y);
        node->Rotate(RotationAxis::Z, child.transform.rotation.z);
    }
}
<|endoftext|>


<commit_before>#include "common.h"

#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
#include "llvm/Instruction.h"
#include "llvm/Type.h"

using namespace spirsim;
using namespace std;

namespace spirsim
{
  TypedValue clone(const TypedValue& source)
  {
    TypedValue dest;
    dest.size = source.size;
    dest.data = new unsigned char[dest.size];
    memcpy(dest.data, source.data, dest.size);
    return dest;
  }

  void dumpInstruction(const llvm::Instruction& instruction, bool align)
  {
    cout << setfill(' ');

    size_t resultSize = getInstructionResultSize(instruction);
    if (resultSize > 0)
    {
      cout << "%" << setw(12) <<  left
           << instruction.getName().str()
           << "(" << resultSize << ") = ";
    }
    else if (align)
    {
      cout << setw(19) << " ";
    }

    cout << left << setw(align?14:0) << instruction.getOpcodeName();

    llvm::User::const_op_iterator opItr;
    for (opItr = instruction.op_begin(); opItr != instruction.op_end(); opItr++)
    {
      // TODO: Constant values
      cout << " %" << opItr->get()->getName().str();
    }

    cout << right << endl;
  }

  size_t getInstructionResultSize(const llvm::Instruction& instruction)
  {
    size_t bits = instruction.getType()->getPrimitiveSizeInBits();
    size_t resultSize = bits >> 3;

    // Special case for GEP
    if (instruction.getOpcode() == llvm::Instruction::GetElementPtr)
    {
      resultSize = sizeof(size_t);
    }

    // Special case for boolean results
    if (bits == 1)
    {
      resultSize = sizeof(bool);
    }

    return resultSize;
  }

  size_t getTypeSize(const llvm::Type *type)
  {
    if (type->isArrayTy())
    {
      size_t num = type->getArrayNumElements();
      size_t sz = getTypeSize(type->getArrayElementType());
      return num*sz;
    }
    else if (type->isStructTy())
    {
      size_t size = 0;
      for (int i = 0; i < type->getStructNumElements(); i++)
      {
        size += getTypeSize(type->getStructElementType(i));
      }
      return size;
    }
    else
    {
      return ((llvm::Type*)type)->getScalarSizeInBits()>>3;
    }
  }

  bool isConstantOperand(const llvm::Value *operand)
  {
    unsigned id = operand->getValueID();
    return (id >= llvm::Value::ConstantFirstVal &&
            id <= llvm::Value::ConstantLastVal);
  }
}
<commit_msg>Added support for vector types sizes.<commit_after>#include "common.h"

#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
#include "llvm/Instruction.h"
#include "llvm/Type.h"

using namespace spirsim;
using namespace std;

namespace spirsim
{
  TypedValue clone(const TypedValue& source)
  {
    TypedValue dest;
    dest.size = source.size;
    dest.data = new unsigned char[dest.size];
    memcpy(dest.data, source.data, dest.size);
    return dest;
  }

  void dumpInstruction(const llvm::Instruction& instruction, bool align)
  {
    cout << setfill(' ');

    size_t resultSize = getInstructionResultSize(instruction);
    if (resultSize > 0)
    {
      cout << "%" << setw(12) <<  left
           << instruction.getName().str()
           << "(" << resultSize << ") = ";
    }
    else if (align)
    {
      cout << setw(19) << " ";
    }

    cout << left << setw(align?14:0) << instruction.getOpcodeName();

    llvm::User::const_op_iterator opItr;
    for (opItr = instruction.op_begin(); opItr != instruction.op_end(); opItr++)
    {
      // TODO: Constant values
      cout << " %" << opItr->get()->getName().str();
    }

    cout << right << endl;
  }

  size_t getInstructionResultSize(const llvm::Instruction& instruction)
  {
    size_t bits = instruction.getType()->getPrimitiveSizeInBits();
    size_t resultSize = bits >> 3;

    // Special case for GEP
    if (instruction.getOpcode() == llvm::Instruction::GetElementPtr)
    {
      resultSize = sizeof(size_t);
    }

    // Special case for boolean results
    if (bits == 1)
    {
      resultSize = sizeof(bool);
    }

    return resultSize;
  }

  size_t getTypeSize(const llvm::Type *type)
  {
    if (type->isArrayTy())
    {
      size_t num = type->getArrayNumElements();
      size_t sz = getTypeSize(type->getArrayElementType());
      return num*sz;
    }
    else if (type->isStructTy())
    {
      size_t size = 0;
      for (int i = 0; i < type->getStructNumElements(); i++)
      {
        size += getTypeSize(type->getStructElementType(i));
      }
      return size;
    }
    else if (type->isVectorTy())
    {
      size_t num = type->getVectorNumElements();
      size_t sz = getTypeSize(type->getVectorElementType());
      return num*sz;
    }
    else
    {
      return ((llvm::Type*)type)->getScalarSizeInBits()>>3;
    }
  }

  bool isConstantOperand(const llvm::Value *operand)
  {
    unsigned id = operand->getValueID();
    return (id >= llvm::Value::ConstantFirstVal &&
            id <= llvm::Value::ConstantLastVal);
  }
}
<|endoftext|>


<commit_before>#ifndef __STAN__IO__WRITER_HPP__
#define __STAN__IO__WRITER_HPP__

#include <cstddef>
#include <stdexcept>
#include <vector>

#include <boost/multi_array.hpp>
#include <boost/throw_exception.hpp>

#include <stan/math/matrix.hpp>
#include <stan/math/special_functions.hpp>

#include <stan/prob/transform.hpp>

namespace stan {

  namespace io {

    /**
     * A stream-based writer for integer, scalar, vector, matrix
     * and array data types, which transforms from constrained to
     * a sequence of constrained variables.
     *
     *
This class converts constrained values to unconstrained
     * values with mappings that invert those defined in
     * stan::io::reader to convert unconstrained values
     * to constrained values.
     *
     * @tparam T Basic scalar type.
     */
    template <typename T>
    class writer {
    private:
      std::vector<T> data_r_;
      std::vector<int> data_i_;
    public:

      typedef typename stan::math::EigenType<T>::matrix matrix_t;
      typedef typename stan::math::EigenType<T>::vector vector_t;
      typedef typename stan::math::EigenType<T>::row_vector row_vector_t;

      typedef Eigen::Array<T,Eigen::Dynamic,1> array_vec_t;

      /**
       * This is the tolerance for checking arithmetic bounds
       * in rank and in simplexes.  The current value is 1E-8.
       */
      const double CONSTRAINT_TOLERANCE;

      /**
       * Construct a writer that writes to the specified
       * scalar and integer vectors.
       *
       * @param data_r Scalar values.
       * @param data_i Integer values.
       */
      writer(std::vector<T>& data_r,
             std::vector<int>& data_i)
        : data_r_(data_r),
          data_i_(data_i),
          CONSTRAINT_TOLERANCE(1E-8) {
      }

      /**
       * Destroy this writer.
       */
      ~writer() { }

      /**
       * Return a reference to the underlying vector of real values
       * that have been written.
       *
       * @return Values that have been written.
       */
      std::vector<T>& data_r() {
        return &data_r_;
      }

      /**
       * Return a reference to the underlying vector of integer values
       * that have been written.
       *
       * @return Values that have been written.
       */
      std::vector<int>& data_i() {
        return &data_i_;
      }

      /**
       * Write the specified integer to the sequence of integer values.
       *
       * @param n Integer to write.
       */
      void integer(int n) {
        data_i_.push_back(n);
      }

      /**
       * Write the unconstrained value corresponding to the specified
       * scalar.  Here, the unconstrain operation is a no-op, which
       * matches reader::scalar_constrain().
       *
       * @param y The value.
       */
      void scalar_unconstrain(T& y) {
        data_r_.push_back(y);
      }

      /**
       * Write the unconstrained value corresponding to the specified
       * positive-constrained scalar.  The transformation applied is
       * log(y), which is the inverse of constraining
       * transform specified in reader::scalar_pos_constrain().
       *
       *
This method will fail if the argument is not non-negative.
       *
       * @param y The positive value.
       * @throw std::runtime_error if y is negative.
       */
      void scalar_pos_unconstrain(T& y) {
        if (y < 0.0)
          BOOST_THROW_EXCEPTION(std::runtime_error ("y is negative"));
        data_r_.push_back(log(y));
      }

      /**
       * Return the unconstrained version of the specified input,
       * which is constrained to be above the specified lower bound.
       * The unconstraining transform is log(y - lb), which
       * inverts the constraining
       * transform defined in reader::scalar_lb_constrain(double),
       *
       * @param lb Lower bound.
       * @param y Lower-bounded value.
       * @throw std::runtime_error if y is lower than the lower bound provided.
       */
      void scalar_lb_unconstrain(double lb, T& y) {
        if (y < lb)
          BOOST_THROW_EXCEPTION(std::runtime_error ("y is lower than the lower bound"));
        data_r_.push_back(log(y - lb));
      }

      /**
       * Write the unconstrained value corresponding to the specified
       * lower-bounded value.  The unconstraining transform is
       * log(ub - y), which reverses the constraining
       * transform defined in reader::scalar_ub_constrain(double).
       *
       * @param ub Upper bound.
       * @param y Constrained value.
       * @throw std::runtime_error if y is higher than the upper bound provided.
       */
      void scalar_ub_unconstrain(double ub, T& y) {
        if (y > ub)
          BOOST_THROW_EXCEPTION(std::runtime_error ("y is higher than the lower bound"));
        data_r_.push_back(log(ub - y));
      }

      /**
       * Write the unconstrained value corresponding to the specified
       * value with the specified bounds.  The unconstraining
       * transform is given by reader::logit((y-L)/(U-L)), which
       * inverts the constraining transform defined in
       * scalar_lub_constrain(double,double).
       *
       * @param lb Lower bound.
       * @param ub Upper bound.
       * @param y Bounded value.
       * @throw std::runtime_error if y is not between the lower and upper bounds
       */
      void scalar_lub_unconstrain(double lb, double ub, T& y) {
        if (y < lb || y > ub)
          BOOST_THROW_EXCEPTION(std::runtime_error ("y is not between the lower and upper bounds"));
        data_r_.push_back(stan::math::logit((y - lb) / (ub - lb)));
      }

      /**
       * Write the unconstrained value corresponding to the specified
       * correlation-constrained variable.
       *
       *
The unconstraining transform is atanh(y), which
       * reverses the transfrom in corr_constrain().
       *
       * @param y Correlation value.
       * @throw std::runtime_error if y is not between -1.0 and 1.0
       */
      void corr_unconstrain(T& y) {
        if (y > 1.0 || y < -1.0)
          BOOST_THROW_EXCEPTION(std::runtime_error ("y is not between -1.0 and 1.0"));
        data_r_.push_back(atanh(y));
      }

      /**
       * Write the unconstrained value corresponding to the
       * specified probability value.
       *
       *
The unconstraining transform is logit(y),
       * which inverts the constraining transform defined in
       * prob_constrain().
       *
       * @param y Probability value.
       * @throw std::runtime_error if y is not between 0.0 and 1.0
        */
      void prob_unconstrain(T& y) {
        if (y > 1.0 || y < 0.0)
          BOOST_THROW_EXCEPTION(std::runtime_error ("y is not between 0.0 and 1.0"));
        data_r_.push_back(stan::math::logit(y));
      }

      /**
       * Write the unconstrained vector that corresponds to the specified
       * positive ordered vector.
       *
       *
The unconstraining transform is defined for input vector y
       * to produce an output vector x of the same size, defined
       * by x[0] = log(y[0]) and by
       * x[k] = log(y[k] - y[k-1]) for k > 0.  This
       * unconstraining transform inverts the constraining transform specified
       * in pos_ordered_constrain(size_t).
       *
       * @param y Positive, ordered vector.
       * @return Unconstrained vector corresponding to the specified vector.
       * @throw std::runtime_error if vector is not positive ordered
       */
      void pos_ordered_unconstrain(vector_t& y) {
        if (y.size() == 0) return;
        if(!stan::prob::pos_ordered_validate(y))
          BOOST_THROW_EXCEPTION(std::runtime_error ("vector is not positive ordered"));
        data_r_.push_back(log(y[0]));
        for (size_t i = 1; i < y.size(); ++i) {
          data_r_.push_back(log(y[i] - y[i-1]));
        }
      }

      /**
       * Write the specified unconstrained vector.
       *
       * @param y Vector to write.
       */
      void vector_unconstrain(const vector_t& y) {
        for (size_t i = 0; i < y.size(); ++i)
          data_r_.push_back(y[i]);
      }

      /**
       * Write the specified unconstrained vector.
       *
       * @param y Vector to write.
       */
      void row_vector_unconstrain(const vector_t& y) {
        for (size_t i = 0; i < y.size(); ++i)
          data_r_.push_back(y[i]);
      }

      /**
       * Write the specified unconstrained matrix.
       *
       * @param y Matrix to write.
       */
      void matrix_unconstrain(const matrix_t& y) {
        for (size_t i = 0; i < y.rows(); ++i)
          for (size_t j = 0; j < y.cols(); ++j)
            data_r_.push_back(y(i,j));
      }

      /**
       * Write the unconstrained vector corresponding to the specified simplex
       * value.  If the specified constrained simplex is of size K,
       * the returned unconstrained vector is of size K-1.
       *
       *
The transform takes y = y[1],...,y[K] and
       * produces the unconstrained vector x = log(y[1]) -
       * log(y[K]), ..., log(y[K-1]) - log(y[K]).  This inverts
       * the constraining transform of
       * simplex_constrain(size_t).
       *
       * @param y Simplex constrained value.
       * @return Unconstrained value.
       * @throw std::runtime_error if the vector is not a simplex.
       */
      void simplex_unconstrain(vector_t& y) {
        if (!stan::prob::simplex_validate(y))
          BOOST_THROW_EXCEPTION(std::runtime_error("y is not a simplex"));
        size_t k_minus_1 = y.size() - 1;
        double log_y_k = log(y[k_minus_1]);
        for (size_t i = 0; i < k_minus_1; ++i) {
          data_r_.push_back(log(y[i]) - log_y_k);
        }
      }

      /**
       * Writes the unconstrained correlation matrix corresponding
       * to the specified constrained correlation matrix.
       *
       *
The unconstraining operation is the inverse of the
       * constraining operation in
       * corr_matrix_constrain(Matrix<T,Dynamic,Dynamic).
       *
       * @param y Constrained correlation matrix.
       * @throw std::runtime_error if the correlation matrix has no elements or
       *    is not a square matrix.
       * @throw std::runtime_error if the correlation matrix cannot be factorized
       *    by factor_cov_matrix() or if the sds returned by factor_cov_matrix()
       *    on log scale are unconstrained.
       */
      void corr_matrix_unconstrain(matrix_t& y) {
        if (!stan::prob::corr_matrix_validate(y))
          BOOST_THROW_EXCEPTION(std::runtime_error ("y is not a valid correlation matrix"));
        size_t k = y.rows();
        size_t k_choose_2 = (k * (k-1)) / 2;
        array_vec_t cpcs(k_choose_2);
        array_vec_t sds(k);
        bool successful = stan::prob::factor_cov_matrix(cpcs,sds,y);
        if (!successful)
          BOOST_THROW_EXCEPTION(std::runtime_error ("y cannot be factorized by factor_cov_matrix"));
        for (size_t i = 0; i < k; ++i) {
          // sds on log scale unconstrained
          if (fabs(sds[i] - 0.0) >= CONSTRAINT_TOLERANCE)
            BOOST_THROW_EXCEPTION(std::runtime_error ("sds on log scale are unconstrained"));
        }
        for (size_t i = 0; i < k_choose_2; ++i)
          data_r_.push_back(cpcs[i]);
      }

      /**
       * Writes the unconstrained covariance matrix corresponding
       * to the specified constrained correlation matrix.
       *
       *
The unconstraining operation is the inverse of the
       * constraining operation in
       * cov_matrix_constrain(Matrix<T,Dynamic,Dynamic).
       *
       * @param y Constrained covariance matrix.
       * @throw std::runtime_error if y has no elements or if it is not square
       */
      void cov_matrix_unconstrain(matrix_t& y) {
        size_t k = y.rows();
        if (k == 0 || y.cols() != k)
          BOOST_THROW_EXCEPTION(
              std::runtime_error ("y must have elements and y must be a square matrix"));
        size_t k_choose_2 = (k * (k-1)) / 2;
        array_vec_t cpcs(k_choose_2);
        array_vec_t sds(k);
        bool successful = stan::prob::factor_cov_matrix(cpcs,sds,y);
        if(!successful)
          BOOST_THROW_EXCEPTION(std::runtime_error ("factor_cov_matrix failed"));
        for (size_t i = 0; i < k_choose_2; ++i)
          data_r_.push_back(cpcs[i]);
        for (size_t i = 0; i < k; ++i)
          data_r_.push_back(sds[i]);
      }
    };
  }

}

#endif
<commit_msg>removed unsigned int warnings for test/io/writer<commit_after>#ifndef __STAN__IO__WRITER_HPP__
#define __STAN__IO__WRITER_HPP__

#include <cstddef>
#include <stdexcept>
#include <vector>

#include <boost/multi_array.hpp>
#include <boost/throw_exception.hpp>

#include <stan/math/matrix.hpp>
#include <stan/math/special_functions.hpp>

#include <stan/prob/transform.hpp>

namespace stan {

  namespace io {

    /**
     * A stream-based writer for integer, scalar, vector, matrix
     * and array data types, which transforms from constrained to
     * a sequence of constrained variables.
     *
     *
This class converts constrained values to unconstrained
     * values with mappings that invert those defined in
     * stan::io::reader to convert unconstrained values
     * to constrained values.
     *
     * @tparam T Basic scalar type.
     */
    template <typename T>
    class writer {
    private:
      std::vector<T> data_r_;
      std::vector<int> data_i_;
    public:

      typedef typename stan::math::EigenType<T>::matrix matrix_t;
      typedef typename stan::math::EigenType<T>::vector vector_t;
      typedef typename stan::math::EigenType<T>::row_vector row_vector_t;

      typedef Eigen::Array<T,Eigen::Dynamic,1> array_vec_t;

      /**
       * This is the tolerance for checking arithmetic bounds
       * in rank and in simplexes.  The current value is 1E-8.
       */
      const double CONSTRAINT_TOLERANCE;

      /**
       * Construct a writer that writes to the specified
       * scalar and integer vectors.
       *
       * @param data_r Scalar values.
       * @param data_i Integer values.
       */
      writer(std::vector<T>& data_r,
             std::vector<int>& data_i)
        : data_r_(data_r),
          data_i_(data_i),
          CONSTRAINT_TOLERANCE(1E-8) {
      }

      /**
       * Destroy this writer.
       */
      ~writer() { }

      /**
       * Return a reference to the underlying vector of real values
       * that have been written.
       *
       * @return Values that have been written.
       */
      std::vector<T>& data_r() {
        return &data_r_;
      }

      /**
       * Return a reference to the underlying vector of integer values
       * that have been written.
       *
       * @return Values that have been written.
       */
      std::vector<int>& data_i() {
        return &data_i_;
      }

      /**
       * Write the specified integer to the sequence of integer values.
       *
       * @param n Integer to write.
       */
      void integer(int n) {
        data_i_.push_back(n);
      }

      /**
       * Write the unconstrained value corresponding to the specified
       * scalar.  Here, the unconstrain operation is a no-op, which
       * matches reader::scalar_constrain().
       *
       * @param y The value.
       */
      void scalar_unconstrain(T& y) {
        data_r_.push_back(y);
      }

      /**
       * Write the unconstrained value corresponding to the specified
       * positive-constrained scalar.  The transformation applied is
       * log(y), which is the inverse of constraining
       * transform specified in reader::scalar_pos_constrain().
       *
       *
This method will fail if the argument is not non-negative.
       *
       * @param y The positive value.
       * @throw std::runtime_error if y is negative.
       */
      void scalar_pos_unconstrain(T& y) {
        if (y < 0.0)
          BOOST_THROW_EXCEPTION(std::runtime_error ("y is negative"));
        data_r_.push_back(log(y));
      }

      /**
       * Return the unconstrained version of the specified input,
       * which is constrained to be above the specified lower bound.
       * The unconstraining transform is log(y - lb), which
       * inverts the constraining
       * transform defined in reader::scalar_lb_constrain(double),
       *
       * @param lb Lower bound.
       * @param y Lower-bounded value.
       * @throw std::runtime_error if y is lower than the lower bound provided.
       */
      void scalar_lb_unconstrain(double lb, T& y) {
        if (y < lb)
          BOOST_THROW_EXCEPTION(std::runtime_error ("y is lower than the lower bound"));
        data_r_.push_back(log(y - lb));
      }

      /**
       * Write the unconstrained value corresponding to the specified
       * lower-bounded value.  The unconstraining transform is
       * log(ub - y), which reverses the constraining
       * transform defined in reader::scalar_ub_constrain(double).
       *
       * @param ub Upper bound.
       * @param y Constrained value.
       * @throw std::runtime_error if y is higher than the upper bound provided.
       */
      void scalar_ub_unconstrain(double ub, T& y) {
        if (y > ub)
          BOOST_THROW_EXCEPTION(std::runtime_error ("y is higher than the lower bound"));
        data_r_.push_back(log(ub - y));
      }

      /**
       * Write the unconstrained value corresponding to the specified
       * value with the specified bounds.  The unconstraining
       * transform is given by reader::logit((y-L)/(U-L)), which
       * inverts the constraining transform defined in
       * scalar_lub_constrain(double,double).
       *
       * @param lb Lower bound.
       * @param ub Upper bound.
       * @param y Bounded value.
       * @throw std::runtime_error if y is not between the lower and upper bounds
       */
      void scalar_lub_unconstrain(double lb, double ub, T& y) {
        if (y < lb || y > ub)
          BOOST_THROW_EXCEPTION(std::runtime_error ("y is not between the lower and upper bounds"));
        data_r_.push_back(stan::math::logit((y - lb) / (ub - lb)));
      }

      /**
       * Write the unconstrained value corresponding to the specified
       * correlation-constrained variable.
       *
       *
The unconstraining transform is atanh(y), which
       * reverses the transfrom in corr_constrain().
       *
       * @param y Correlation value.
       * @throw std::runtime_error if y is not between -1.0 and 1.0
       */
      void corr_unconstrain(T& y) {
        if (y > 1.0 || y < -1.0)
          BOOST_THROW_EXCEPTION(std::runtime_error ("y is not between -1.0 and 1.0"));
        data_r_.push_back(atanh(y));
      }

      /**
       * Write the unconstrained value corresponding to the
       * specified probability value.
       *
       *
The unconstraining transform is logit(y),
       * which inverts the constraining transform defined in
       * prob_constrain().
       *
       * @param y Probability value.
       * @throw std::runtime_error if y is not between 0.0 and 1.0
        */
      void prob_unconstrain(T& y) {
        if (y > 1.0 || y < 0.0)
          BOOST_THROW_EXCEPTION(std::runtime_error ("y is not between 0.0 and 1.0"));
        data_r_.push_back(stan::math::logit(y));
      }

      /**
       * Write the unconstrained vector that corresponds to the specified
       * positive ordered vector.
       *
       *
The unconstraining transform is defined for input vector y
       * to produce an output vector x of the same size, defined
       * by x[0] = log(y[0]) and by
       * x[k] = log(y[k] - y[k-1]) for k > 0.  This
       * unconstraining transform inverts the constraining transform specified
       * in pos_ordered_constrain(size_t).
       *
       * @param y Positive, ordered vector.
       * @return Unconstrained vector corresponding to the specified vector.
       * @throw std::runtime_error if vector is not positive ordered
       */
      void pos_ordered_unconstrain(vector_t& y) {
        if (y.size() == 0) return;
        if(!stan::prob::pos_ordered_validate(y))
          BOOST_THROW_EXCEPTION(std::runtime_error ("vector is not positive ordered"));
        data_r_.push_back(log(y[0]));
        for (typename vector_t::size_type i = 1; i < y.size(); ++i) {
          data_r_.push_back(log(y[i] - y[i-1]));
        }
      }

      /**
       * Write the specified unconstrained vector.
       *
       * @param y Vector to write.
       */
      void vector_unconstrain(const vector_t& y) {
        for (size_t i = 0; i < y.size(); ++i)
          data_r_.push_back(y[i]);
      }

      /**
       * Write the specified unconstrained vector.
       *
       * @param y Vector to write.
       */
      void row_vector_unconstrain(const vector_t& y) {
        for (size_t i = 0; i < y.size(); ++i)
          data_r_.push_back(y[i]);
      }

      /**
       * Write the specified unconstrained matrix.
       *
       * @param y Matrix to write.
       */
      void matrix_unconstrain(const matrix_t& y) {
        for (size_t i = 0; i < y.rows(); ++i)
          for (size_t j = 0; j < y.cols(); ++j)
            data_r_.push_back(y(i,j));
      }

      /**
       * Write the unconstrained vector corresponding to the specified simplex
       * value.  If the specified constrained simplex is of size K,
       * the returned unconstrained vector is of size K-1.
       *
       *
The transform takes y = y[1],...,y[K] and
       * produces the unconstrained vector x = log(y[1]) -
       * log(y[K]), ..., log(y[K-1]) - log(y[K]).  This inverts
       * the constraining transform of
       * simplex_constrain(size_t).
       *
       * @param y Simplex constrained value.
       * @return Unconstrained value.
       * @throw std::runtime_error if the vector is not a simplex.
       */
      void simplex_unconstrain(vector_t& y) {
        if (!stan::prob::simplex_validate(y))
          BOOST_THROW_EXCEPTION(std::runtime_error("y is not a simplex"));
        size_t k_minus_1 = y.size() - 1;
        double log_y_k = log(y[k_minus_1]);
        for (size_t i = 0; i < k_minus_1; ++i) {
          data_r_.push_back(log(y[i]) - log_y_k);
        }
      }

      /**
       * Writes the unconstrained correlation matrix corresponding
       * to the specified constrained correlation matrix.
       *
       *
The unconstraining operation is the inverse of the
       * constraining operation in
       * corr_matrix_constrain(Matrix<T,Dynamic,Dynamic).
       *
       * @param y Constrained correlation matrix.
       * @throw std::runtime_error if the correlation matrix has no elements or
       *    is not a square matrix.
       * @throw std::runtime_error if the correlation matrix cannot be factorized
       *    by factor_cov_matrix() or if the sds returned by factor_cov_matrix()
       *    on log scale are unconstrained.
       */
      void corr_matrix_unconstrain(matrix_t& y) {
        if (!stan::prob::corr_matrix_validate(y))
          BOOST_THROW_EXCEPTION(std::runtime_error ("y is not a valid correlation matrix"));
        size_t k = y.rows();
        size_t k_choose_2 = (k * (k-1)) / 2;
        array_vec_t cpcs(k_choose_2);
        array_vec_t sds(k);
        bool successful = stan::prob::factor_cov_matrix(cpcs,sds,y);
        if (!successful)
          BOOST_THROW_EXCEPTION(std::runtime_error ("y cannot be factorized by factor_cov_matrix"));
        for (size_t i = 0; i < k; ++i) {
          // sds on log scale unconstrained
          if (fabs(sds[i] - 0.0) >= CONSTRAINT_TOLERANCE)
            BOOST_THROW_EXCEPTION(std::runtime_error ("sds on log scale are unconstrained"));
        }
        for (size_t i = 0; i < k_choose_2; ++i)
          data_r_.push_back(cpcs[i]);
      }

      /**
       * Writes the unconstrained covariance matrix corresponding
       * to the specified constrained correlation matrix.
       *
       *
The unconstraining operation is the inverse of the
       * constraining operation in
       * cov_matrix_constrain(Matrix<T,Dynamic,Dynamic).
       *
       * @param y Constrained covariance matrix.
       * @throw std::runtime_error if y has no elements or if it is not square
       */
      void cov_matrix_unconstrain(matrix_t& y) {
        typename matrix_t::size_type k = y.rows();
        if (k == 0 || y.cols() != k)
          BOOST_THROW_EXCEPTION(
              std::runtime_error ("y must have elements and y must be a square matrix"));
        typename matrix_t::size_type k_choose_2 = (k * (k-1)) / 2;
        array_vec_t cpcs(k_choose_2);
        array_vec_t sds(k);
        bool successful = stan::prob::factor_cov_matrix(cpcs,sds,y);
        if(!successful)
          BOOST_THROW_EXCEPTION(std::runtime_error ("factor_cov_matrix failed"));
        for (typename matrix_t::size_type i = 0; i < k_choose_2; ++i)
          data_r_.push_back(cpcs[i]);
        for (typename matrix_t::size_type i = 0; i < k; ++i)
          data_r_.push_back(sds[i]);
      }
    };
  }

}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2003-2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * XSEC
 *
 * XSCryptCryptoBase64 := Internal implementation of a base64
 * encoder/decoder
 *
 * Author(s): Berin Lautenbach
 *
 * $Id$
 *
 */

#include <xsec/enc/XSCrypt/XSCryptCryptoBase64.hpp>
#include <xsec/enc/XSECCryptoException.hpp>

// --------------------------------------------------------------------------------
//           Lookup tables and macros
// --------------------------------------------------------------------------------

char Base64LookupTable[] = {
	'A','B','C','D','E','F','G','H','I','J','K','L','M',
	'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
	'a','b','c','d','e','f','g','h','i','j','k','l','m',
	'n','o','p','q','r','s','t','u','v','w','x','y','z',
	'0','1','2','3','4','5','6','7','8','9','+','/',
};

#define IS_UPPER(c) (c >= 'A' && c <= 'Z')
#define IS_LOWER(c) (c >= 'a' && c <= 'z')
#define IS_NUMBR(c) (c >= '0' && c <= '9')
#define IS_OTHER(c) (c == '+' || c == '/')
#define IS_B64CH(c) (IS_LOWER(c) || IS_UPPER(c) || IS_NUMBR(c) || IS_OTHER(c))
#define IS_B64OE(c) (IS_B64CH(c) || c == '=')

// --------------------------------------------------------------------------------
//           Decoding
// --------------------------------------------------------------------------------

unsigned char decodeCh(unsigned char c) {

	if (IS_UPPER(c))
		return c - 'A';

	if (IS_LOWER(c))
		return (c - 'a') + 26;

	if (IS_NUMBR(c))
		return (c - '0') + 52;

	if (c == '+')
		return 62;
	if (c == '/')
		return 63;

	if (c == '=')
		return 64;

	return 65;		// error;

}

void XSCryptCryptoBase64::canonicaliseInput(const unsigned char *inData,
											unsigned int inLength) {

	// Canonicalise the input buffer into m_inputBuffer

	unsigned char buf[400];			// Do 400 bytes at a time

	unsigned int i, j;
	j = 0;

	for (i = 0; i < inLength; ++i) {

		if (IS_B64OE(inData[i])) {

			// Have a base64 or '=' char
			buf[j++] = inData[i];

			if (j == 400) {
				m_inputBuffer.sbMemcpyIn(m_remainingInput, buf, 400);
				m_remainingInput += 400;
				j = 0;
			}
		}
	}

	if (j > 0) {
		m_inputBuffer.sbMemcpyIn(m_remainingInput, buf, j);
		m_remainingInput += j;
	}

}

void XSCryptCryptoBase64::decodeInit(void) {

	m_remainingInput = m_remainingOutput = 0;
	m_allDone = false;
	m_state = B64_DECODE;

}

unsigned int XSCryptCryptoBase64::decode(const unsigned char * inData,
						 	    unsigned int inLength,
								unsigned char * outData,
								unsigned int outLength) {

	// Ensure we are in an appropriate state
	if (m_state != B64_DECODE) {

		throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Attempt to decode when not in decode state");

	}

	// Copy the data into our input buffer
	canonicaliseInput(inData, inLength);

	unsigned int i = 0;
	unsigned char t;

	while (m_allDone != true && m_remainingInput - i >= 4) {

		// BYTE 1

		t = decodeCh(m_inputBuffer[i++]);

		if (t > 63) {

			throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Invalid character at start of base 64 block");

		}

		m_outputBuffer[m_remainingOutput] = (t << 2);

		// BYTE 2

		t = decodeCh(m_inputBuffer[i++]);

		if (t > 63) {

			throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Invalid character at start of base 64 block");

		}

		// Take top two bits and place at end of current byte
		m_outputBuffer[m_remainingOutput] = m_outputBuffer[m_remainingOutput] |
			(t >> 4);

		m_remainingOutput++;		// Have a new complete byte

		// Take remaining 4 bits and add to outputBuffer
		m_outputBuffer[m_remainingOutput] = ( t << 4);

		// BYTE 3

		t = decodeCh(m_inputBuffer[i++]);

		if (t > 64) {

			throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Invalid character at start of base 64 block");

		}

		if (t == 64) {

			// '=' character found

			m_allDone = true;
			break;

		}

		// Take 4 bits and append to current buffer

		m_outputBuffer[m_remainingOutput] = m_outputBuffer[m_remainingOutput] | (t >> 2);
		m_remainingOutput++;

		// Take last 2 bits and append to buffer

		m_outputBuffer[m_remainingOutput] = (t << 6);

		// BYTE 4

		t = decodeCh(m_inputBuffer[i++]);

		if (t > 64) {

			throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Invalid character at start of base 64 block");

		}

		if (t == 64) {

			m_allDone = true;
			break;

		}

		// Place all six bits and end of current byte

		m_outputBuffer[m_remainingOutput] = m_outputBuffer[m_remainingOutput] | t;
		m_remainingOutput++;

	}

	// Now whatever we've decoded can be placed in the output buffer

	unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);

	m_outputBuffer.sbMemcpyOut(outData, cpyOut);

	// Move the buffers down
	if (cpyOut != m_remainingOutput) {
		m_remainingOutput = m_remainingOutput - cpyOut;
		m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
	}
	else
		m_remainingOutput = 0;

	if (i != m_remainingInput) {
		m_remainingInput -= i;
		m_inputBuffer.sbMemshift(0, i, m_remainingInput);
	}
	else
		m_remainingInput = 0;

	// Return however much we have decoded
	return cpyOut;

}

unsigned int XSCryptCryptoBase64::decodeFinish(unsigned char * outData,
							 	      unsigned int outLength) {

	if (m_state != B64_DECODE) {

		throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Attempt to complete a decode when not in decode state");

	}

	m_allDone = true;
	unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);

	m_outputBuffer.sbMemcpyOut(outData, cpyOut);

	// Move the buffers down
	if (cpyOut != m_remainingOutput) {
		m_remainingOutput = m_remainingOutput - cpyOut;
		m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
	}
	else {
		m_remainingOutput = 0;
	}

	return cpyOut;
}

// --------------------------------------------------------------------------------
//           Encoding
// --------------------------------------------------------------------------------

void XSCryptCryptoBase64::encodeInit(void) {

	m_remainingInput = m_remainingOutput = 0;
	m_allDone = false;
	m_charCount = 0;
	m_state = B64_ENCODE;

}

unsigned int XSCryptCryptoBase64::encode(const unsigned char * inData,
						 	    unsigned int inLength,
								unsigned char * outData,
								unsigned int outLength) {

	if (m_state != B64_ENCODE) {

		throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Attempt to encode when not in encoding state");

	}

	// Copy input data into end of input buffer
	m_inputBuffer.sbMemcpyIn(m_remainingInput, inData, inLength);
	m_remainingInput += inLength;

	unsigned int i = 0;
	unsigned char t;

	while (m_allDone == false && m_remainingInput - i >= 3) {

		// Have a complete block of three bytes to encode

		// First 6 bits;
		t = (m_inputBuffer[i] >> 2);
		m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];

		// 2 bits from byte one and 4 from byte 2
		t = ((m_inputBuffer[i++] << 4) & 0x30) | (m_inputBuffer[i] >> 4);
		m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];

		// 4 from byte 2 and 2 from byte 3
		t = ((m_inputBuffer[i++] << 2) & 0x3C) | (m_inputBuffer[i] >> 6);
		m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];

		// last 6 bits from byte 3
		t = m_inputBuffer[i++] & 0x3F;
		m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];

		m_charCount += 4;

		if (m_charCount >= 76) {

			m_outputBuffer[m_remainingOutput++] = '\n';
			m_charCount = 0;

		}

	}

	// Now copy data out to output buffer

	unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);

	m_outputBuffer.sbMemcpyOut(outData, cpyOut);

	// Move the buffers down
	if (cpyOut != m_remainingOutput) {
		m_remainingOutput = m_remainingOutput - cpyOut;
		m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
	}
	else
		m_remainingOutput = 0;

	if (i != m_remainingInput) {
		m_remainingInput -= i;
		m_inputBuffer.sbMemshift(0, i, m_remainingInput);
	}

	else

		m_remainingInput = 0;

	// Return however much we have decoded
	return cpyOut;

}

unsigned int XSCryptCryptoBase64::encodeFinish(unsigned char * outData,
							 	      unsigned int outLength) {

	if (m_state != B64_ENCODE) {

		throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Attempt to complete an encode when not in encoding state");

	}

	if (m_allDone == false && m_remainingInput > 0) {

		// Will always be < 3 characters remaining in inputBuffer
		// If necessary - terminate the Base64 string

		if (m_remainingInput >= 3) {

			throw XSECCryptoException(XSECCryptoException::Base64Error,
				"XSCrypt:Base64 - Too much remaining input in input buffer");

		}

		// First 6 bits;
		unsigned int t = (m_inputBuffer[0] >> 2);
		m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];

		// 2 bits from byte one and 4 from byte 2
		t = ((m_inputBuffer[0] << 4) & 0x30);

		if (m_remainingInput == 1) {
			m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
			m_outputBuffer[m_remainingOutput++] = '=';
			m_outputBuffer[m_remainingOutput++] = '=';
		}

		else {

			t |= (m_inputBuffer[1] >> 4);
			m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];

			// 4 from byte 2
			t = ((m_inputBuffer[1] << 2) & 0x3C);
			m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
			m_outputBuffer[m_remainingOutput++] = '=';
		}

	}

	m_allDone = true;

	// Copy out
	unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);

	m_outputBuffer.sbMemcpyOut(outData, cpyOut);

	// Move the buffers down
	if (cpyOut != m_remainingOutput) {
		m_remainingOutput = m_remainingOutput - cpyOut;
		m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
	}
	else {
		m_remainingOutput = 0;
	}

	return cpyOut;
}
<commit_msg>Bug in encode() fixed.<commit_after>/*
 * Copyright 2003-2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * XSEC
 *
 * XSCryptCryptoBase64 := Internal implementation of a base64
 * encoder/decoder
 *
 * Author(s): Berin Lautenbach
 *
 * $Id$
 *
 */

#include <xsec/enc/XSCrypt/XSCryptCryptoBase64.hpp>
#include <xsec/enc/XSECCryptoException.hpp>

// --------------------------------------------------------------------------------
//           Lookup tables and macros
// --------------------------------------------------------------------------------

char Base64LookupTable[] = {
	'A','B','C','D','E','F','G','H','I','J','K','L','M',
	'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
	'a','b','c','d','e','f','g','h','i','j','k','l','m',
	'n','o','p','q','r','s','t','u','v','w','x','y','z',
	'0','1','2','3','4','5','6','7','8','9','+','/',
};

#define IS_UPPER(c) (c >= 'A' && c <= 'Z')
#define IS_LOWER(c) (c >= 'a' && c <= 'z')
#define IS_NUMBR(c) (c >= '0' && c <= '9')
#define IS_OTHER(c) (c == '+' || c == '/')
#define IS_B64CH(c) (IS_LOWER(c) || IS_UPPER(c) || IS_NUMBR(c) || IS_OTHER(c))
#define IS_B64OE(c) (IS_B64CH(c) || c == '=')

// --------------------------------------------------------------------------------
//           Decoding
// --------------------------------------------------------------------------------

unsigned char decodeCh(unsigned char c) {

	if (IS_UPPER(c))
		return c - 'A';

	if (IS_LOWER(c))
		return (c - 'a') + 26;

	if (IS_NUMBR(c))
		return (c - '0') + 52;

	if (c == '+')
		return 62;
	if (c == '/')
		return 63;

	if (c == '=')
		return 64;

	return 65;		// error;

}

void XSCryptCryptoBase64::canonicaliseInput(const unsigned char *inData,
											unsigned int inLength) {

	// Canonicalise the input buffer into m_inputBuffer

	unsigned char buf[400];			// Do 400 bytes at a time

	unsigned int i, j;
	j = 0;

	for (i = 0; i < inLength; ++i) {

		if (IS_B64OE(inData[i])) {

			// Have a base64 or '=' char
			buf[j++] = inData[i];

			if (j == 400) {
				m_inputBuffer.sbMemcpyIn(m_remainingInput, buf, 400);
				m_remainingInput += 400;
				j = 0;
			}
		}
	}

	if (j > 0) {
		m_inputBuffer.sbMemcpyIn(m_remainingInput, buf, j);
		m_remainingInput += j;
	}

}

void XSCryptCryptoBase64::decodeInit(void) {

	m_remainingInput = m_remainingOutput = 0;
	m_allDone = false;
	m_state = B64_DECODE;

}

unsigned int XSCryptCryptoBase64::decode(const unsigned char * inData,
						 	    unsigned int inLength,
								unsigned char * outData,
								unsigned int outLength) {

	// Ensure we are in an appropriate state
	if (m_state != B64_DECODE) {

		throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Attempt to decode when not in decode state");

	}

	// Copy the data into our input buffer
	canonicaliseInput(inData, inLength);

	unsigned int i = 0;
	unsigned char t;

	while (m_allDone != true && m_remainingInput - i >= 4) {

		// BYTE 1

		t = decodeCh(m_inputBuffer[i++]);

		if (t > 63) {

			throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Invalid character at start of base 64 block");

		}

		m_outputBuffer[m_remainingOutput] = (t << 2);

		// BYTE 2

		t = decodeCh(m_inputBuffer[i++]);

		if (t > 63) {

			throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Invalid character at start of base 64 block");

		}

		// Take top two bits and place at end of current byte
		m_outputBuffer[m_remainingOutput] = m_outputBuffer[m_remainingOutput] |
			(t >> 4);

		m_remainingOutput++;		// Have a new complete byte

		// Take remaining 4 bits and add to outputBuffer
		m_outputBuffer[m_remainingOutput] = ( t << 4);

		// BYTE 3

		t = decodeCh(m_inputBuffer[i++]);

		if (t > 64) {

			throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Invalid character at start of base 64 block");

		}

		if (t == 64) {

			// '=' character found

			m_allDone = true;
			break;

		}

		// Take 4 bits and append to current buffer

		m_outputBuffer[m_remainingOutput] = m_outputBuffer[m_remainingOutput] | (t >> 2);
		m_remainingOutput++;

		// Take last 2 bits and append to buffer

		m_outputBuffer[m_remainingOutput] = (t << 6);

		// BYTE 4

		t = decodeCh(m_inputBuffer[i++]);

		if (t > 64) {

			throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Invalid character at start of base 64 block");

		}

		if (t == 64) {

			m_allDone = true;
			break;

		}

		// Place all six bits and end of current byte

		m_outputBuffer[m_remainingOutput] = m_outputBuffer[m_remainingOutput] | t;
		m_remainingOutput++;

	}

	// Now whatever we've decoded can be placed in the output buffer

	unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);

	m_outputBuffer.sbMemcpyOut(outData, cpyOut);

	// Move the buffers down
	if (cpyOut != m_remainingOutput) {
		m_remainingOutput = m_remainingOutput - cpyOut;
		m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
	}
	else
		m_remainingOutput = 0;

	if (i != m_remainingInput) {
		m_remainingInput -= i;
		m_inputBuffer.sbMemshift(0, i, m_remainingInput);
	}
	else
		m_remainingInput = 0;

	// Return however much we have decoded
	return cpyOut;

}

unsigned int XSCryptCryptoBase64::decodeFinish(unsigned char * outData,
							 	      unsigned int outLength) {

	if (m_state != B64_DECODE) {

		throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Attempt to complete a decode when not in decode state");

	}

	m_allDone = true;
	unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);

	m_outputBuffer.sbMemcpyOut(outData, cpyOut);

	// Move the buffers down
	if (cpyOut != m_remainingOutput) {
		m_remainingOutput = m_remainingOutput - cpyOut;
		m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
	}
	else {
		m_remainingOutput = 0;
	}

	return cpyOut;
}

// --------------------------------------------------------------------------------
//           Encoding
// --------------------------------------------------------------------------------

void XSCryptCryptoBase64::encodeInit(void) {

	m_remainingInput = m_remainingOutput = 0;
	m_allDone = false;
	m_charCount = 0;
	m_state = B64_ENCODE;

}

unsigned int XSCryptCryptoBase64::encode(const unsigned char * inData,
						 	    unsigned int inLength,
								unsigned char * outData,
								unsigned int outLength) {

	if (m_state != B64_ENCODE) {

		throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Attempt to encode when not in encoding state");

	}

	// Copy input data into end of input buffer
	m_inputBuffer.sbMemcpyIn(m_remainingInput, inData, inLength);
	m_remainingInput += inLength;

	unsigned int i = 0;
	unsigned char t;

	while (m_allDone == false && m_remainingInput - i >= 3) {

		// Have a complete block of three bytes to encode

		// First 6 bits;
		t = (m_inputBuffer[i] >> 2);
		m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];

		// 2 bits from byte one and 4 from byte 2
		t = ((m_inputBuffer[i++] << 4) & 0x30);
		t |= (m_inputBuffer[i] >> 4);
		m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];

		// 4 from byte 2 and 2 from byte 3
		t = ((m_inputBuffer[i++] << 2) & 0x3C);
		t |= (m_inputBuffer[i] >> 6);
		m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];

		// last 6 bits from byte 3
		t = m_inputBuffer[i++] & 0x3F;
		m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];

		m_charCount += 4;

		if (m_charCount >= 76) {

			m_outputBuffer[m_remainingOutput++] = '\n';
			m_charCount = 0;

		}

	}

	// Now copy data out to output buffer

	unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);

	m_outputBuffer.sbMemcpyOut(outData, cpyOut);

	// Move the buffers down
	if (cpyOut != m_remainingOutput) {
		m_remainingOutput = m_remainingOutput - cpyOut;
		m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
	}
	else
		m_remainingOutput = 0;

	if (i != m_remainingInput) {
		m_remainingInput -= i;
		m_inputBuffer.sbMemshift(0, i, m_remainingInput);
	}

	else

		m_remainingInput = 0;

	// Return however much we have decoded
	return cpyOut;

}

unsigned int XSCryptCryptoBase64::encodeFinish(unsigned char * outData,
							 	      unsigned int outLength) {

	if (m_state != B64_ENCODE) {

		throw XSECCryptoException(XSECCryptoException::Base64Error,
			"XSCrypt:Base64 - Attempt to complete an encode when not in encoding state");

	}

	if (m_allDone == false && m_remainingInput > 0) {

		// Will always be < 3 characters remaining in inputBuffer
		// If necessary - terminate the Base64 string

		if (m_remainingInput >= 3) {

			throw XSECCryptoException(XSECCryptoException::Base64Error,
				"XSCrypt:Base64 - Too much remaining input in input buffer");

		}

		// First 6 bits;
		unsigned int t = (m_inputBuffer[0] >> 2);
		m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];

		// 2 bits from byte one and 4 from byte 2
		t = ((m_inputBuffer[0] << 4) & 0x30);

		if (m_remainingInput == 1) {
			m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
			m_outputBuffer[m_remainingOutput++] = '=';
			m_outputBuffer[m_remainingOutput++] = '=';
		}

		else {

			t |= (m_inputBuffer[1] >> 4);
			m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];

			// 4 from byte 2
			t = ((m_inputBuffer[1] << 2) & 0x3C);
			m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
			m_outputBuffer[m_remainingOutput++] = '=';
		}

	}

	m_allDone = true;

	// Copy out
	unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);

	m_outputBuffer.sbMemcpyOut(outData, cpyOut);

	// Move the buffers down
	if (cpyOut != m_remainingOutput) {
		m_remainingOutput = m_remainingOutput - cpyOut;
		m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
	}
	else {
		m_remainingOutput = 0;
	}

	return cpyOut;
}
<|endoftext|>