<commit_before>#include <boost/scoped_array.hpp>
#include <stdio.h>
#include "TextureManager.h"
#include "Exceptions.h"

namespace typing
{
    //////////////////////////////////////////////////////////////////////////
    // Texture
    //////////////////////////////////////////////////////////////////////////

    void Texture::Load(const std::string& textureName)
    {
        FILE *textureFile = fopen(textureName.c_str(), "rb");

        if (!textureFile)
        {
            throw FileNotFoundException(textureName);
        }

        unsigned char expectedHeader[12] = { 0,0,2,0,0,0,0,0,0,0,0,0 };
        unsigned char header[12];
        if (fread(header, sizeof(unsigned char), sizeof(header), textureFile) != sizeof(header) ||
            memcmp(header, expectedHeader, sizeof(expectedHeader)))
        {
            fclose(textureFile);
            throw FileCorruptException(textureName);
        }

        unsigned char info[6];
        if (fread(info, sizeof(unsigned char), sizeof(info), textureFile) != sizeof(info))
        {
            fclose(textureFile);
            throw FileCorruptException(textureName);
        }

        unsigned int width  = info[1] * 256 + info[0];
        unsigned int height = info[3] * 256 + info[2];
        unsigned int bpp    = info[4];

        if (width == 0 || height == 0 || (bpp != 24 && bpp != 32))
        {
            fclose(textureFile);
            throw FileCorruptException(textureName);
        }
        unsigned int size = width * height * (bpp / 8);

        boost::scoped_array<unsigned char> data(new unsigned char[size]);
        if (!data.get())
        {
            fclose(textureFile);
            throw MemoryAllocationError(__FUNCTION__);
        }

        if (fread(data.get(), 1, size, textureFile) != size)
        {
            fclose(textureFile);
            throw FileCorruptException(textureName);
        }

        unsigned char temp;
        for (unsigned int i = 0; i < size; i += (bpp / 8))
        {
            temp        = data[i];
            data[i]     = data[i + 2];
            data[i + 2] = temp;
        }

        fclose(textureFile);

        glGenTextures(1, &m_id);
        glBindTexture(GL_TEXTURE_2D, m_id);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, data.get());
    }

    void Texture::Bind() const
    {
        glBindTexture(GL_TEXTURE_2D, m_id);
    }

    //////////////////////////////////////////////////////////////////////////
    // TextureManager
    //////////////////////////////////////////////////////////////////////////

    std::auto_ptr<TextureManager> TextureManager::m_singleton(new TextureManager);
    TextureManager& TextureManager::GetTextureManager()
    {
        return *(m_singleton.get());
    }

    void TextureManager::Add(const std::string& textureName)
    {
        if (m_textureMap.find(textureName) == m_textureMap.end())
        {
            TexturePtr texture(new Texture());
            texture->Load(textureName);
            m_textureMap[textureName] = texture;
        }
    }

    const Texture& TextureManager::Get(const std::string& textureName) const
    {
        TextureMap::const_iterator iter = m_textureMap.find(textureName);
        if (iter == m_textureMap.end())
        {
            throw MediaNotLoadedException(textureName);
        }
        else
        {
            return *(iter->second);
        }
    }

    void TextureManager::Bind(const std::string& textureName) const
    {
        Get(textureName).Bind();
    }
}
<commit_msg>Pass correct pixel formats to glTexture2D. Fixes #6<commit_after>#include <boost/scoped_array.hpp>
#include <stdio.h>
#include "TextureManager.h"
#include "Exceptions.h"

namespace typing
{
    //////////////////////////////////////////////////////////////////////////
    // Texture
    //////////////////////////////////////////////////////////////////////////

    void Texture::Load(const std::string& textureName)
    {
        FILE *textureFile = fopen(textureName.c_str(), "rb");

        if (!textureFile)
        {
            throw FileNotFoundException(textureName);
        }

        unsigned char expectedHeader[12] = { 0,0,2,0,0,0,0,0,0,0,0,0 };
        unsigned char header[12];
        if (fread(header, sizeof(unsigned char), sizeof(header), textureFile) != sizeof(header) ||
            memcmp(header, expectedHeader, sizeof(expectedHeader)))
        {
            fclose(textureFile);
            throw FileCorruptException(textureName);
        }

        unsigned char info[6];
        if (fread(info, sizeof(unsigned char), sizeof(info), textureFile) != sizeof(info))
        {
            fclose(textureFile);
            throw FileCorruptException(textureName);
        }

        unsigned int width  = info[1] * 256 + info[0];
        unsigned int height = info[3] * 256 + info[2];
        unsigned int bpp    = info[4];

        if (width == 0 || height == 0 || (bpp != 24 && bpp != 32))
        {
            fclose(textureFile);
            throw FileCorruptException(textureName);
        }
        unsigned int size = width * height * (bpp / 8);

        boost::scoped_array<unsigned char> data(new unsigned char[size]);
        if (!data.get())
        {
            fclose(textureFile);
            throw MemoryAllocationError(__FUNCTION__);
        }

        if (fread(data.get(), 1, size, textureFile) != size)
        {
            fclose(textureFile);
            throw FileCorruptException(textureName);
        }

        unsigned char temp;
        for (unsigned int i = 0; i < size; i += (bpp / 8))
        {
            temp        = data[i];
            data[i]     = data[i + 2];
            data[i + 2] = temp;
        }

        fclose(textureFile);

        glGenTextures(1, &m_id);
        glBindTexture(GL_TEXTURE_2D, m_id);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);

        glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
        glPixelStorei(GL_UNPACK_ALIGNMENT, bpp == 32 ? 2 : 1);
        glTexImage2D(GL_TEXTURE_2D, 0,
                     bpp == 32 ? GL_RGBA8 : GL_RGB8,
                     width, height, 0,
                     bpp == 32 ? GL_BGRA : GL_BGR,
                     GL_UNSIGNED_BYTE, data.get());
    }

    void Texture::Bind() const
    {
        glBindTexture(GL_TEXTURE_2D, m_id);
    }

    //////////////////////////////////////////////////////////////////////////
    // TextureManager
    //////////////////////////////////////////////////////////////////////////

    std::auto_ptr<TextureManager> TextureManager::m_singleton(new TextureManager);
    TextureManager& TextureManager::GetTextureManager()
    {
        return *(m_singleton.get());
    }

    void TextureManager::Add(const std::string& textureName)
    {
        if (m_textureMap.find(textureName) == m_textureMap.end())
        {
            TexturePtr texture(new Texture());
            texture->Load(textureName);
            m_textureMap[textureName] = texture;
        }
    }

    const Texture& TextureManager::Get(const std::string& textureName) const
    {
        TextureMap::const_iterator iter = m_textureMap.find(textureName);
        if (iter == m_textureMap.end())
        {
            throw MediaNotLoadedException(textureName);
        }
        else
        {
            return *(iter->second);
        }
    }

    void TextureManager::Bind(const std::string& textureName) const
    {
        Get(textureName).Bind();
    }
}
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------*\
 *                                OpenSG                                     *
 *                                                                           *
 *                                                                           *
 *                   Copyright (C) 2007 by the OpenSG Forum                  *
 *                                                                           *
 *                            www.opensg.org                                 *
 *                                                                           *
 *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                License                                    *
 *                                                                           *
 * This library is free software; you can redistribute it and/or modify it   *
 * under the terms of the GNU Library General Public License as published    *
 * by the Free Software Foundation, version 2.                               *
 *                                                                           *
 * 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         *
 * Library General Public License for more details.                          *
 *                                                                           *
 * You should have received a copy of the GNU Library General Public         *
 * License along with this library; if not, write to the Free Software       *
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                Changes                                    *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
\*---------------------------------------------------------------------------*/

#include "OSGOSBImageElement.h"

#include "OSGOSBRootElement.h"
#include "OSGImage.h"
#include "OSGImageFileHandler.h"

OSG_USING_NAMESPACE

/*-------------------------------------------------------------------------*/
/* OSBImageElement                                                         */
/*-------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------*/
/* Static members                                                          */

OSBElementRegistrationHelper<OSBImageElement>
    OSBImageElement::_regHelper =
        OSBElementRegistrationHelper<OSBImageElement>("Image");

const UInt8 OSBImageElement::FlagPixelDataCompressedMask;
const UInt8 OSBImageElement::FlagPixelDataCompressed;
const UInt8 OSBImageElement::FlagPixelDataOutOfLineMask;
const UInt8 OSBImageElement::FlagPixelDataOutOfLine;

/*-------------------------------------------------------------------------*/
/* Constructor                                                             */

OSBImageElement::OSBImageElement(OSBRootElement *root)
    : Inherited      (root, OSGOSBHeaderVersion200),
      _hasJPEGSupport(false                        ),
      _version       (OSGOSBHeaderVersion200      )
{
}

/*-------------------------------------------------------------------------*/
/* Destructor                                                              */

OSBImageElement::~OSBImageElement(void)
{
}

/*-------------------------------------------------------------------------*/
/* Reading                                                                 */

void
OSBImageElement::read(const std::string &typeName)
{
    FDEBUG(("OSBImageElement::read [%s]\n", typeName.c_str()));

    const OSBRootElement *root      = getRoot();
    BinaryReadHandler     *rh        = editRoot()->getReadHandler();
    UInt8                  fcPtrType;

    if(root->getHeaderVersion() >= OSGOSBHeaderVersion200)
    {
        if(root->getHeaderVersion() > OSGOSBHeaderVersion200)
        {
            FINFO(("OSBImageElement::read: "
                   "Unknown version, trying to process as latest.\n"));
        }

        rh->getValue(fcPtrType);
    }

    ImageUnrecPtr img = Image::create();
    setContainer(img);

    rh->getValue(_version);

    if(_version >= OSGOSBHeaderVersion200)
    {
        UInt8 flags;
        rh->getValue(flags);

        if(flags & FlagPixelDataCompressedMask)
        {
            std::string endMarker = "'pixel'";
            std::string fieldName = readFields("", endMarker);

            if(fieldName == "pixel")
            {
                readCompressedPixelData();
            }
        }
        else if(flags & FlagPixelDataOutOfLineMask)
        {
            readFields("", "");

            // read out-of-line image data
            const std::string &fileName = img->getName();
            img = ImageFileHandler::the()->read(fileName.c_str());
            setContainer(img);
        }
    }
    else if(_version >= OSGOSBHeaderVersion100)
    {
        std::string endMarker = "'cpixel'";
        std::string fieldName = readFields("", endMarker);

        // read compressed pixel data - should be the last field
        if(fieldName == "cpixel")
        {
            readCompressedPixelData();
        }

        // read any remaining fields - should be none, but this is safe to do.
        readFieldsContinue(fieldName, "", "");

        // read out-of-line image data
        if(img->getMFPixel()->empty())
        {
            const std::string &fileName = img->getName();
            img = ImageFileHandler::the()->read(fileName.c_str());
            setContainer(img);
        }
    }
}

void
OSBImageElement::postRead(void)
{
    // nothing to do
}

/*-------------------------------------------------------------------------*/
/* Writing                                                                 */

void
OSBImageElement::preWrite(FieldContainer * const fc)
{
    FDEBUG(("OSBImageElement::preWrite\n"));

    preWriteFieldContainer(fc, "");
}

void
OSBImageElement::write(void)
{
    FDEBUG(("OSBImageElement::write\n"));

    if(getContainer() == NULL)
    {
        FWARNING(("OSBImageElement::write: Attempt to write NULL.\n"));
        return;
    }

    Image                *img   = dynamic_cast<Image *>(getContainer());
    BinaryWriteHandler   *wh    = editRoot()->getWriteHandler();
    const OSBRootElement *root  = getRoot();
    UInt8                 flags = 0;

    wh->putValue(getFCPtrType(getContainer()));
    wh->putValue(getVersion()                );

    std::string excludeFields    = "";
    bool        compressTextures = false;

    if(getRoot()->getOptions().inlineTextures() == false)
    {
        // only write "name" field
        flags |= FlagPixelDataOutOfLine;
        excludeFields.append("'dimension' 'width' 'height' 'depth' 'bpp' "
                             "'mipMapCount' 'frameCount' 'frameDelay' "
                             "'pixelFormat' 'pixel' 'frameSize' "         );
    }
    else
    {
        if(_hasJPEGSupport && root->getOptions().compressTextures() &&
           (img->getDataType() == Image::OSG_UINT8_IMAGEDATA)       &&
           ((img->getBpp() == 1) || (img->getBpp() == 3))             )
        {
            compressTextures =  true;
            flags            |= FlagPixelDataCompressed;
            excludeFields.append("'pixel'");
        }
    }

    // write flags
    wh->putValue(flags);

    // write all fields that do not require special handling
    writeFields(excludeFields, false);

    if(compressTextures)
        writeCompressedPixelData();

    writeEndMarker();
}

/*-------------------------------------------------------------------------*/
/* Reading Helper Functions                                                */

void
OSBImageElement::readCompressedPixelData(void)
{
    BinaryReadHandler *rh  = editRoot()->getReadHandler();
    Image             *img = dynamic_cast<Image *>(getContainer());

    std::string        fieldTypeName;
    UInt32             fieldSize;
    UInt32             byteSize;
    std::vector<UInt8> buffer;

    rh->getValue(fieldTypeName);
    rh->getValue(fieldSize    );

    if(!_hasJPEGSupport)
    {
        FWARNING(("OSBImageElement::readCompressedPixelData: "
                  "JPEG Support not available, skipping compressed "
                  "texture data.\n"));
        rh->skip(fieldSize);
        return;
    }

    rh->getValue(byteSize);

    // allocate and fill buffer
    buffer.resize(byteSize);
    rh->getValues(&buffer.front(), byteSize);

    img->restore(&buffer.front(), byteSize);
}

/*-------------------------------------------------------------------------*/
/* Writing Helper Functions                                                */

void
OSBImageElement::writeCompressedPixelData(void)
{
    // FIXME Inline Images are disabled right now. A more recent versin of
    //       the ImageFileHandler from CVS needs to be ported to OpenSG 2.

    const OSBRootElement *root = getRoot();
    BinaryWriteHandler   *wh   = editRoot()->getWriteHandler();

    Image       *img       = dynamic_cast<Image *>(getContainer());
    std::string imageType = root->getOptions().texturesImageType();
//     std::string imageType = "jpeg";

    std::vector<UInt8> buffer;
    UInt32             factor = 1;

    // JPEG always uses RGB, so single channel images need additional memory
    if((imageType == "jpeg") && (img->getBpp() == 1))
        factor = 3;

    // some extra space is needed for the image header
    UInt32 bufferSize =
       ImageFileHandler::the()->getDefaultType()->maxBufferSize(img) * factor +
           16384;

    buffer.resize(bufferSize);
    UInt64 compressedSize = img->store(imageType.c_str(), &buffer.front());
//     UInt64 compressedSize = 0;

    UInt32 byteSize  = static_cast<UInt32>(compressedSize);
    UInt32 fieldSize = sizeof(UInt32) + sizeof(UInt8) * byteSize;

    wh->putValue (fieldSize                );
    wh->putValue (byteSize                 );
    wh->putValues(&buffer.front(), byteSize);
}
<commit_msg><commit_after>/*---------------------------------------------------------------------------*\
 *                                OpenSG                                     *
 *                                                                           *
 *                                                                           *
 *                   Copyright (C) 2007 by the OpenSG Forum                  *
 *                                                                           *
 *                            www.opensg.org                                 *
 *                                                                           *
 *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                License                                    *
 *                                                                           *
 * This library is free software; you can redistribute it and/or modify it   *
 * under the terms of the GNU Library General Public License as published    *
 * by the Free Software Foundation, version 2.                               *
 *                                                                           *
 * 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         *
 * Library General Public License for more details.                          *
 *                                                                           *
 * You should have received a copy of the GNU Library General Public         *
 * License along with this library; if not, write to the Free Software       *
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                Changes                                    *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
\*---------------------------------------------------------------------------*/

#include "OSGOSBImageElement.h"

#include "OSGOSBRootElement.h"
#include "OSGImage.h"
#include "OSGImageFileHandler.h"

OSG_USING_NAMESPACE

/*-------------------------------------------------------------------------*/
/* OSBImageElement                                                         */
/*-------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------*/
/* Static members                                                          */

OSBElementRegistrationHelper<OSBImageElement>
    OSBImageElement::_regHelper =
        OSBElementRegistrationHelper<OSBImageElement>("Image");

const UInt8 OSBImageElement::FlagPixelDataCompressedMask;
const UInt8 OSBImageElement::FlagPixelDataCompressed;
const UInt8 OSBImageElement::FlagPixelDataOutOfLineMask;
const UInt8 OSBImageElement::FlagPixelDataOutOfLine;

/*-------------------------------------------------------------------------*/
/* Constructor                                                             */

OSBImageElement::OSBImageElement(OSBRootElement *root)
    : Inherited      (root, OSGOSBHeaderVersion200),
      _hasJPEGSupport(false                        ),
      _version       (OSGOSBHeaderVersion200      )
{
}

/*-------------------------------------------------------------------------*/
/* Destructor                                                              */

OSBImageElement::~OSBImageElement(void)
{
}

/*-------------------------------------------------------------------------*/
/* Reading                                                                 */

void
OSBImageElement::read(const std::string &typeName)
{
    FDEBUG(("OSBImageElement::read [%s]\n", typeName.c_str()));

    const OSBRootElement *root      = getRoot();
    BinaryReadHandler     *rh        = editRoot()->getReadHandler();
    UInt8                  fcPtrType;

    if(root->getHeaderVersion() >= OSGOSBHeaderVersion200)
    {
        if(root->getHeaderVersion() > OSGOSBHeaderVersion200)
        {
            FINFO(("OSBImageElement::read: "
                   "Unknown version, trying to process as latest.\n"));
        }

        rh->getValue(fcPtrType);
    }

    ImageUnrecPtr img = Image::create();
    setContainer(img);

    rh->getValue(_version);

    if(_version >= OSGOSBHeaderVersion200)
    {
        UInt8 flags;
        rh->getValue(flags);

        if(flags & FlagPixelDataCompressedMask)
        {
            // compressed inline texture
            std::string endMarker = "'pixel'";
            std::string fieldName = readFields("", endMarker);

            if(fieldName == "pixel")
            {
                readCompressedPixelData();
            }
        }
        else
        {
            // read fields stored in file
            readFields("", "");

            if(flags & FlagPixelDataOutOfLineMask)
            {
                // read out-of-line image data
                const std::string &fileName = img->getName();
                img = ImageFileHandler::the()->read(fileName.c_str());
                setContainer(img);
            }
        }
    }
    else if(_version >= OSGOSBHeaderVersion100)
    {
        std::string endMarker = "'cpixel'";
        std::string fieldName = readFields("", endMarker);

        // read compressed pixel data - should be the last field
        if(fieldName == "cpixel")
        {
            readCompressedPixelData();
        }

        // read any remaining fields - should be none, but this is safe to do.
        readFieldsContinue(fieldName, "", "");

        // read out-of-line image data
        if(img->getMFPixel()->empty())
        {
            const std::string &fileName = img->getName();
            img = ImageFileHandler::the()->read(fileName.c_str());
            setContainer(img);
        }
    }
}

void
OSBImageElement::postRead(void)
{
    // nothing to do
}

/*-------------------------------------------------------------------------*/
/* Writing                                                                 */

void
OSBImageElement::preWrite(FieldContainer * const fc)
{
    FDEBUG(("OSBImageElement::preWrite\n"));

    preWriteFieldContainer(fc, "");
}

void
OSBImageElement::write(void)
{
    FDEBUG(("OSBImageElement::write\n"));

    if(getContainer() == NULL)
    {
        FWARNING(("OSBImageElement::write: Attempt to write NULL.\n"));
        return;
    }

    Image                *img   = dynamic_cast<Image *>(getContainer());
    BinaryWriteHandler   *wh    = editRoot()->getWriteHandler();
    const OSBRootElement *root  = getRoot();
    UInt8                 flags = 0;

    wh->putValue(getFCPtrType(getContainer()));
    wh->putValue(getVersion()                );

    std::string excludeFields    = "";
    bool        compressTextures = false;

    if(getRoot()->getOptions().inlineTextures() == false)
    {
        // only write "name" field
        flags |= FlagPixelDataOutOfLine;
        excludeFields.append("'dimension' 'width' 'height' 'depth' 'bpp' "
                             "'mipMapCount' 'frameCount' 'frameDelay' "
                             "'pixelFormat' 'pixel' 'frameSize' "         );
    }
    else
    {
        if(_hasJPEGSupport && root->getOptions().compressTextures() &&
           (img->getDataType() == Image::OSG_UINT8_IMAGEDATA)       &&
           ((img->getBpp() == 1) || (img->getBpp() == 3))             )
        {
            compressTextures =  true;
            flags            |= FlagPixelDataCompressed;
            excludeFields.append("'pixel'");
        }
    }

    // write flags
    wh->putValue(flags);

    // write all fields that do not require special handling
    writeFields(excludeFields, false);

    if(compressTextures)
        writeCompressedPixelData();

    writeEndMarker();
}

/*-------------------------------------------------------------------------*/
/* Reading Helper Functions                                                */

void
OSBImageElement::readCompressedPixelData(void)
{
    BinaryReadHandler *rh  = editRoot()->getReadHandler();
    Image             *img = dynamic_cast<Image *>(getContainer());

    std::string        fieldTypeName;
    UInt32             fieldSize;
    UInt32             byteSize;
    std::vector<UInt8> buffer;

    rh->getValue(fieldTypeName);
    rh->getValue(fieldSize    );

    if(!_hasJPEGSupport)
    {
        FWARNING(("OSBImageElement::readCompressedPixelData: "
                  "JPEG Support not available, skipping compressed "
                  "texture data.\n"));
        rh->skip(fieldSize);
        return;
    }

    rh->getValue(byteSize);

    // allocate and fill buffer
    buffer.resize(byteSize);
    rh->getValues(&buffer.front(), byteSize);

    img->restore(&buffer.front(), byteSize);
}

/*-------------------------------------------------------------------------*/
/* Writing Helper Functions                                                */

void
OSBImageElement::writeCompressedPixelData(void)
{
    // FIXME Inline Images are disabled right now. A more recent versin of
    //       the ImageFileHandler from CVS needs to be ported to OpenSG 2.

    const OSBRootElement *root = getRoot();
    BinaryWriteHandler   *wh   = editRoot()->getWriteHandler();

    Image       *img       = dynamic_cast<Image *>(getContainer());
    std::string  imageType = root->getOptions().texturesImageType();
//     std::string imageType = "jpeg";

    std::vector<UInt8> buffer;
    UInt32             factor = 1;

    // JPEG always uses RGB, so single channel images need additional memory
    if((imageType == "jpeg") && (img->getBpp() == 1))
        factor = 3;

    // some extra space is needed for the image header
    UInt32 bufferSize =
       ImageFileHandler::the()->getDefaultType()->maxBufferSize(img) * factor +
           16384;

    buffer.resize(bufferSize);
    UInt64 compressedSize = img->store(imageType.c_str(), &buffer.front());
//     UInt64 compressedSize = 0;

    UInt32 byteSize  = static_cast<UInt32>(compressedSize);
    UInt32 fieldSize = sizeof(UInt32) + sizeof(UInt8) * byteSize;

    wh->putValue (fieldSize                );
    wh->putValue (byteSize                 );
    wh->putValues(&buffer.front(), byteSize);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010 Google, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "core/html/parser/HTMLParserScheduler.h"

#include "core/dom/Document.h"
#include "core/html/parser/HTMLDocumentParser.h"
#include "core/frame/FrameView.h"

namespace WebCore {

// parserChunkSize is used to define how many tokens the parser will
// process before checking against parserTimeLimit and possibly yielding.
// This is a performance optimization to prevent checking after every token.
const int HTMLParserScheduler::parserChunkSize = 4096;

// parserTimeLimit is the seconds the parser will run in one write() call
// before yielding. Inline <script> execution can cause it to exceed the limit.
const double HTMLParserScheduler::parserTimeLimit = 0.2;

ActiveParserSession::ActiveParserSession(Document* document)
    : m_document(document)
{
    if (!m_document)
        return;
    m_document->incrementActiveParserCount();
}

ActiveParserSession::~ActiveParserSession()
{
    if (!m_document)
        return;
    m_document->decrementActiveParserCount();
}

PumpSession::PumpSession(unsigned& nestingLevel, Document* document)
    : NestingLevelIncrementer(nestingLevel)
    , ActiveParserSession(document)
    // Setting processedTokens to INT_MAX causes us to check for yields
    // after any token during any parse where yielding is allowed.
    // At that time we'll initialize startTime.
    , processedTokens(INT_MAX)
    , startTime(0)
    , needsYield(false)
    , didSeeScript(false)
{
}

PumpSession::~PumpSession()
{
}

HTMLParserScheduler::HTMLParserScheduler(HTMLDocumentParser* parser)
    : m_parser(parser)
    , m_continueNextChunkTimer(this, &HTMLParserScheduler::continueNextChunkTimerFired)
    , m_isSuspendedWithActiveTimer(false)
{
}

HTMLParserScheduler::~HTMLParserScheduler()
{
    m_continueNextChunkTimer.stop();
}

void HTMLParserScheduler::continueNextChunkTimerFired(Timer<HTMLParserScheduler>* timer)
{
    ASSERT_UNUSED(timer, timer == &m_continueNextChunkTimer);
    // FIXME: The timer class should handle timer priorities instead of this code.
    // If a layout is scheduled, wait again to let the layout timer run first.
    // FIXME: We should fix this by reducing the max-parse-time instead of
    // artificially forcing the parser to yield agressively before first layout.
    if (m_parser->document()->shouldParserYieldAgressivelyBeforeScriptExecution()) {
        m_continueNextChunkTimer.startOneShot(0, FROM_HERE);
        return;
    }
    m_parser->resumeParsingAfterYield();
}

void HTMLParserScheduler::checkForYieldBeforeScript(PumpSession& session)
{
    // If we've never painted before and a layout is pending, yield prior to running
    // scripts to give the page a chance to paint earlier.
    Document* document = m_parser->document();
    bool needsFirstPaint = document->view() && !document->view()->hasEverPainted();
    if (needsFirstPaint && document->shouldParserYieldAgressivelyBeforeScriptExecution())
        session.needsYield = true;
    session.didSeeScript = true;
}

void HTMLParserScheduler::scheduleForResume()
{
    m_continueNextChunkTimer.startOneShot(0, FROM_HERE);
}

void HTMLParserScheduler::suspend()
{
    ASSERT(!m_isSuspendedWithActiveTimer);
    if (!m_continueNextChunkTimer.isActive())
        return;
    m_isSuspendedWithActiveTimer = true;
    m_continueNextChunkTimer.stop();
}

void HTMLParserScheduler::resume()
{
    ASSERT(!m_continueNextChunkTimer.isActive());
    if (!m_isSuspendedWithActiveTimer)
        return;
    m_isSuspendedWithActiveTimer = false;
    m_continueNextChunkTimer.startOneShot(0, FROM_HERE);
}

}
<commit_msg>Remove hack in HTMLParserScheduler for deferring to layout while parsing.<commit_after>/*
 * Copyright (C) 2010 Google, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "core/html/parser/HTMLParserScheduler.h"

#include "core/dom/Document.h"
#include "core/html/parser/HTMLDocumentParser.h"
#include "core/frame/FrameView.h"

namespace WebCore {

// parserChunkSize is used to define how many tokens the parser will
// process before checking against parserTimeLimit and possibly yielding.
// This is a performance optimization to prevent checking after every token.
const int HTMLParserScheduler::parserChunkSize = 4096;

// parserTimeLimit is the seconds the parser will run in one write() call
// before yielding. Inline <script> execution can cause it to exceed the limit.
const double HTMLParserScheduler::parserTimeLimit = 0.2;

ActiveParserSession::ActiveParserSession(Document* document)
    : m_document(document)
{
    if (!m_document)
        return;
    m_document->incrementActiveParserCount();
}

ActiveParserSession::~ActiveParserSession()
{
    if (!m_document)
        return;
    m_document->decrementActiveParserCount();
}

PumpSession::PumpSession(unsigned& nestingLevel, Document* document)
    : NestingLevelIncrementer(nestingLevel)
    , ActiveParserSession(document)
    // Setting processedTokens to INT_MAX causes us to check for yields
    // after any token during any parse where yielding is allowed.
    // At that time we'll initialize startTime.
    , processedTokens(INT_MAX)
    , startTime(0)
    , needsYield(false)
    , didSeeScript(false)
{
}

PumpSession::~PumpSession()
{
}

HTMLParserScheduler::HTMLParserScheduler(HTMLDocumentParser* parser)
    : m_parser(parser)
    , m_continueNextChunkTimer(this, &HTMLParserScheduler::continueNextChunkTimerFired)
    , m_isSuspendedWithActiveTimer(false)
{
}

HTMLParserScheduler::~HTMLParserScheduler()
{
    m_continueNextChunkTimer.stop();
}

void HTMLParserScheduler::continueNextChunkTimerFired(Timer<HTMLParserScheduler>* timer)
{
    ASSERT_UNUSED(timer, timer == &m_continueNextChunkTimer);
    m_parser->resumeParsingAfterYield();
}

void HTMLParserScheduler::checkForYieldBeforeScript(PumpSession& session)
{
    // If we've never painted before and a layout is pending, yield prior to running
    // scripts to give the page a chance to paint earlier.
    Document* document = m_parser->document();
    bool needsFirstPaint = document->view() && !document->view()->hasEverPainted();
    if (needsFirstPaint && document->shouldParserYieldAgressivelyBeforeScriptExecution())
        session.needsYield = true;
    session.didSeeScript = true;
}

void HTMLParserScheduler::scheduleForResume()
{
    m_continueNextChunkTimer.startOneShot(0, FROM_HERE);
}

void HTMLParserScheduler::suspend()
{
    ASSERT(!m_isSuspendedWithActiveTimer);
    if (!m_continueNextChunkTimer.isActive())
        return;
    m_isSuspendedWithActiveTimer = true;
    m_continueNextChunkTimer.stop();
}

void HTMLParserScheduler::resume()
{
    ASSERT(!m_continueNextChunkTimer.isActive());
    if (!m_isSuspendedWithActiveTimer)
        return;
    m_isSuspendedWithActiveTimer = false;
    m_continueNextChunkTimer.startOneShot(0, FROM_HERE);
}

}
<|endoftext|>


<commit_before>/**
 * This file is part of TelepathyQt4
 *
 * @copyright Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * @license LGPL 2.1
 *
 * 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/PendingStreamTubeConnection>

#include "TelepathyQt4/_gen/pending-stream-tube-connection.moc.hpp"

#include "TelepathyQt4/debug-internal.h"

#include <TelepathyQt4/IncomingStreamTubeChannel>
#include <TelepathyQt4/PendingVariant>
#include <TelepathyQt4/Types>

namespace Tp
{

struct TELEPATHY_QT4_NO_EXPORT PendingStreamTubeConnection::Private
{
    Private(PendingStreamTubeConnection *parent);
    ~Private();

    // Public object
    PendingStreamTubeConnection *parent;

    IncomingStreamTubeChannelPtr tube;
    SocketAddressType type;
    QHostAddress hostAddress;
    quint16 port;
    QString socketPath;
    bool requiresCredentials;
    uchar credentialByte;
};

PendingStreamTubeConnection::Private::Private(PendingStreamTubeConnection *parent)
    : parent(parent),
      requiresCredentials(false),
      credentialByte(0)
{

}

PendingStreamTubeConnection::Private::~Private()
{

}

PendingStreamTubeConnection::PendingStreamTubeConnection(
        PendingVariant *acceptOperation,
        SocketAddressType type,
        bool requiresCredentials,
        uchar credentialByte,
        const IncomingStreamTubeChannelPtr &channel)
    : PendingOperation(channel),
      mPriv(new Private(this))
{
    mPriv->tube = channel;
    mPriv->type = type;
    mPriv->requiresCredentials = requiresCredentials;
    mPriv->credentialByte = credentialByte;

    /* keep track of channel invalidation */
    connect(channel.data(),
            SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
            SLOT(onChannelInvalidated(Tp::DBusProxy*,QString,QString)));

    connect(acceptOperation,
            SIGNAL(finished(Tp::PendingOperation*)),
            SLOT(onAcceptFinished(Tp::PendingOperation*)));
}

/**
 * \class PendingStreamTubeConnection
 * \ingroup clientchannel
 * \headerfile TelepathyQt4/incoming-stream-tube-channel.h <TelepathyQt4/PendingStreamTubeConnection>
 *
 * \brief The PendingStreamTubeConnection class represents an asynchronous
 * operation for accepting a stream tube.
 *
 * When the operation is finished, you can access the resulting device
 * through device().
 * Otherwise, you can access the bare address through either tcpAddress() or
 * localAddress().
 */

PendingStreamTubeConnection::PendingStreamTubeConnection(
        const QString& errorName,
        const QString& errorMessage,
        const IncomingStreamTubeChannelPtr &channel)
    : PendingOperation(channel),
      mPriv(new PendingStreamTubeConnection::Private(this))
{
    setFinishedWithError(errorName, errorMessage);
}

/**
 * Class destructor.
 */
PendingStreamTubeConnection::~PendingStreamTubeConnection()
{
    delete mPriv;
}

/**
 * This method returns the address type of the opened socket.
 *
 * Calling this method when the operation has not been completed or has failed, will cause it
 * to return an unmeaningful value.
 *
 * \return The type of socket this PendingStreamTubeConnection has created
 *
 * \note This function will return a valid value only after the operation has been
 *       finished successfully.
 *
 * \see localAddress
 * \see tcpAddress
 */
SocketAddressType PendingStreamTubeConnection::addressType() const
{
    return mPriv->tube->addressType();
}

/**
 * This method returns the local address of the opened socket.
 *
 * Calling this method when the operation has not been completed or has failed, will cause it
 * to return an unmeaningful value. The same will happen if the socket which has been opened has a
 * different type from SocketAddressTypeUnix or SocketAddressTypeAbstractUnix. Use #ipAddress if
 * that is the case.
 *
 * \return The local address obtained from this PendingStreamTubeConnection as a QString,
 *         if the connection has been estabilished through a SocketAddressTypeUnix or
 *         a SocketAddressTypeAbstractUnix.
 *
 * \note This function will return a valid value only after the operation has been
 *       finished successfully.
 *
 * \see addressType
 */
QString PendingStreamTubeConnection::localAddress() const
{
    return mPriv->tube->localAddress();
}

/**
 * This method returns the IP address of the opened socket.
 *
 * Calling this method when the operation has not been completed or has failed, will cause it
 * to return an unmeaningful value. The same will happen if the socket which has been opened has a
 * different type from SocketAddressTypeIpv4 or SocketAddressTypeIPv6. Use #localAddress if
 * that is the case.
 *
 * \return The IP address and port obtained from this PendingStreamTubeConnection as a QHostAddress,
 *         if the connection has been estabilished through a SocketAddressTypeIpv4 or
 *         a SocketAddressTypeIPv6.
 *
 * \note This function will return a valid value only after the operation has been
 *       finished successfully.
 *
 * \see addressType
 */
QPair<QHostAddress, quint16> PendingStreamTubeConnection::ipAddress() const
{
    return mPriv->tube->ipAddress();
}

/**
 * Return whether sending a credential byte once connecting to the socket is required.
 *
 * Note that if this method returns \c true, one should send a SCM_CREDS or SCM_CREDENTIALS
 * and the credentialByte() once connected. If SCM_CREDS or SCM_CREDENTIALS cannot be sent,
 * the credentialByte() should still be sent.
 *
 * \return \c true if sending credentials is required, \c false otherwise.
 * \sa credentialByte()
 */
bool PendingStreamTubeConnection::requiresCredentials() const
{
    return mPriv->requiresCredentials;
}

/**
 * Return the credential byte to send once connecting to the socket if requiresCredentials() is \c
 * true.
 *
 * \return The credential byte.
 * \sa requiresCredentials()
 */
uchar PendingStreamTubeConnection::credentialByte() const
{
    return mPriv->credentialByte;
}

void PendingStreamTubeConnection::onChannelInvalidated(DBusProxy *proxy,
        const QString &errorName, const QString &errorMessage)
{
    Q_UNUSED(proxy);

    if (isFinished()) {
        return;
    }

    setFinishedWithError(errorName, errorMessage);
}

void PendingStreamTubeConnection::onAcceptFinished(PendingOperation *op)
{
    if (isFinished()) {
        return;
    }

    if (op->isError()) {
        setFinishedWithError(op->errorName(), op->errorMessage());
        return;
    }

    debug() << "Accept tube finished successfully";

    PendingVariant *pv = qobject_cast<PendingVariant *>(op);
    // Build the address
    if (mPriv->type == SocketAddressTypeIPv4) {
        SocketAddressIPv4 addr = qdbus_cast<SocketAddressIPv4>(pv->result());
        debug().nospace() << "Got address " << addr.address <<
                ":" << addr.port;
        mPriv->hostAddress = QHostAddress(addr.address);
        mPriv->port = addr.port;
    } else if (mPriv->type == SocketAddressTypeIPv6) {
        SocketAddressIPv6 addr = qdbus_cast<SocketAddressIPv6>(pv->result());
        debug().nospace() << "Got address " << addr.address <<
                ":" << addr.port;
        mPriv->hostAddress = QHostAddress(addr.address);
        mPriv->port = addr.port;
    } else {
        // Unix socket
        mPriv->socketPath = QLatin1String(qdbus_cast<QByteArray>(pv->result()));
        debug() << "Got socket " << mPriv->socketPath;
    }

    // It might have been already opened - check
    if (mPriv->tube->state() == TubeChannelStateOpen) {
        onTubeStateChanged(mPriv->tube->state());
    } else {
        // Wait until the tube gets opened on the other side
        connect(mPriv->tube.data(), SIGNAL(stateChanged(Tp::TubeChannelState)),
                this, SLOT(onTubeStateChanged(Tp::TubeChannelState)));
    }
}

void PendingStreamTubeConnection::onTubeStateChanged(TubeChannelState state)
{
    debug() << "Tube state changed to " << state;
    if (state == TubeChannelStateOpen) {
        // The tube is ready, populate its properties
        if (mPriv->type == SocketAddressTypeIPv4 || mPriv->type == SocketAddressTypeIPv6) {
            mPriv->tube->setIpAddress(qMakePair<QHostAddress, quint16>(mPriv->hostAddress,
                    mPriv->port));
        } else {
            // Unix socket
            mPriv->tube->setLocalAddress(mPriv->socketPath);
        }

        // Mark the operation as finished
        setFinished();
    } else if (state != TubeChannelStateLocalPending) {
        // Something happened
        setFinishedWithError(QLatin1String("Connection refused"),
                QLatin1String("The connection to this tube was refused"));
    }
}

}
<commit_msg>PendingStreamTubeConnection: Improve debugs.<commit_after>/**
 * This file is part of TelepathyQt4
 *
 * @copyright Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * @license LGPL 2.1
 *
 * 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/PendingStreamTubeConnection>

#include "TelepathyQt4/_gen/pending-stream-tube-connection.moc.hpp"

#include "TelepathyQt4/debug-internal.h"

#include <TelepathyQt4/IncomingStreamTubeChannel>
#include <TelepathyQt4/PendingVariant>
#include <TelepathyQt4/Types>

namespace Tp
{

struct TELEPATHY_QT4_NO_EXPORT PendingStreamTubeConnection::Private
{
    Private(PendingStreamTubeConnection *parent);
    ~Private();

    // Public object
    PendingStreamTubeConnection *parent;

    IncomingStreamTubeChannelPtr tube;
    SocketAddressType type;
    QHostAddress hostAddress;
    quint16 port;
    QString socketPath;
    bool requiresCredentials;
    uchar credentialByte;
};

PendingStreamTubeConnection::Private::Private(PendingStreamTubeConnection *parent)
    : parent(parent),
      requiresCredentials(false),
      credentialByte(0)
{

}

PendingStreamTubeConnection::Private::~Private()
{

}

PendingStreamTubeConnection::PendingStreamTubeConnection(
        PendingVariant *acceptOperation,
        SocketAddressType type,
        bool requiresCredentials,
        uchar credentialByte,
        const IncomingStreamTubeChannelPtr &channel)
    : PendingOperation(channel),
      mPriv(new Private(this))
{
    mPriv->tube = channel;
    mPriv->type = type;
    mPriv->requiresCredentials = requiresCredentials;
    mPriv->credentialByte = credentialByte;

    /* keep track of channel invalidation */
    connect(channel.data(),
            SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
            SLOT(onChannelInvalidated(Tp::DBusProxy*,QString,QString)));

    connect(acceptOperation,
            SIGNAL(finished(Tp::PendingOperation*)),
            SLOT(onAcceptFinished(Tp::PendingOperation*)));
}

/**
 * \class PendingStreamTubeConnection
 * \ingroup clientchannel
 * \headerfile TelepathyQt4/incoming-stream-tube-channel.h <TelepathyQt4/PendingStreamTubeConnection>
 *
 * \brief The PendingStreamTubeConnection class represents an asynchronous
 * operation for accepting a stream tube.
 *
 * When the operation is finished, you can access the resulting device
 * through device().
 * Otherwise, you can access the bare address through either tcpAddress() or
 * localAddress().
 */

PendingStreamTubeConnection::PendingStreamTubeConnection(
        const QString& errorName,
        const QString& errorMessage,
        const IncomingStreamTubeChannelPtr &channel)
    : PendingOperation(channel),
      mPriv(new PendingStreamTubeConnection::Private(this))
{
    setFinishedWithError(errorName, errorMessage);
}

/**
 * Class destructor.
 */
PendingStreamTubeConnection::~PendingStreamTubeConnection()
{
    delete mPriv;
}

/**
 * This method returns the address type of the opened socket.
 *
 * Calling this method when the operation has not been completed or has failed, will cause it
 * to return an unmeaningful value.
 *
 * \return The type of socket this PendingStreamTubeConnection has created
 *
 * \note This function will return a valid value only after the operation has been
 *       finished successfully.
 *
 * \see localAddress
 * \see tcpAddress
 */
SocketAddressType PendingStreamTubeConnection::addressType() const
{
    return mPriv->tube->addressType();
}

/**
 * This method returns the local address of the opened socket.
 *
 * Calling this method when the operation has not been completed or has failed, will cause it
 * to return an unmeaningful value. The same will happen if the socket which has been opened has a
 * different type from SocketAddressTypeUnix or SocketAddressTypeAbstractUnix. Use #ipAddress if
 * that is the case.
 *
 * \return The local address obtained from this PendingStreamTubeConnection as a QString,
 *         if the connection has been estabilished through a SocketAddressTypeUnix or
 *         a SocketAddressTypeAbstractUnix.
 *
 * \note This function will return a valid value only after the operation has been
 *       finished successfully.
 *
 * \see addressType
 */
QString PendingStreamTubeConnection::localAddress() const
{
    return mPriv->tube->localAddress();
}

/**
 * This method returns the IP address of the opened socket.
 *
 * Calling this method when the operation has not been completed or has failed, will cause it
 * to return an unmeaningful value. The same will happen if the socket which has been opened has a
 * different type from SocketAddressTypeIpv4 or SocketAddressTypeIPv6. Use #localAddress if
 * that is the case.
 *
 * \return The IP address and port obtained from this PendingStreamTubeConnection as a QHostAddress,
 *         if the connection has been estabilished through a SocketAddressTypeIpv4 or
 *         a SocketAddressTypeIPv6.
 *
 * \note This function will return a valid value only after the operation has been
 *       finished successfully.
 *
 * \see addressType
 */
QPair<QHostAddress, quint16> PendingStreamTubeConnection::ipAddress() const
{
    return mPriv->tube->ipAddress();
}

/**
 * Return whether sending a credential byte once connecting to the socket is required.
 *
 * Note that if this method returns \c true, one should send a SCM_CREDS or SCM_CREDENTIALS
 * and the credentialByte() once connected. If SCM_CREDS or SCM_CREDENTIALS cannot be sent,
 * the credentialByte() should still be sent.
 *
 * \return \c true if sending credentials is required, \c false otherwise.
 * \sa credentialByte()
 */
bool PendingStreamTubeConnection::requiresCredentials() const
{
    return mPriv->requiresCredentials;
}

/**
 * Return the credential byte to send once connecting to the socket if requiresCredentials() is \c
 * true.
 *
 * \return The credential byte.
 * \sa requiresCredentials()
 */
uchar PendingStreamTubeConnection::credentialByte() const
{
    return mPriv->credentialByte;
}

void PendingStreamTubeConnection::onChannelInvalidated(DBusProxy *proxy,
        const QString &errorName, const QString &errorMessage)
{
    Q_UNUSED(proxy);

    if (isFinished()) {
        return;
    }

    warning().nospace() << "StreamTube.Accept failed because channel was invalidated with " <<
        errorName << ": " << errorMessage;

    setFinishedWithError(errorName, errorMessage);
}

void PendingStreamTubeConnection::onAcceptFinished(PendingOperation *op)
{
    if (isFinished()) {
        return;
    }

    if (op->isError()) {
        warning().nospace() << "StreamTube.Accept failed with " <<
            op->errorName() << ": " << op->errorMessage();
        setFinishedWithError(op->errorName(), op->errorMessage());
        return;
    }

    debug() << "StreamTube.Accept finished successfully";

    PendingVariant *pv = qobject_cast<PendingVariant *>(op);
    // Build the address
    if (mPriv->type == SocketAddressTypeIPv4) {
        SocketAddressIPv4 addr = qdbus_cast<SocketAddressIPv4>(pv->result());
        debug().nospace() << "Got address " << addr.address << ":" << addr.port;
        mPriv->hostAddress = QHostAddress(addr.address);
        mPriv->port = addr.port;
    } else if (mPriv->type == SocketAddressTypeIPv6) {
        SocketAddressIPv6 addr = qdbus_cast<SocketAddressIPv6>(pv->result());
        debug().nospace() << "Got address " << addr.address << ":" << addr.port;
        mPriv->hostAddress = QHostAddress(addr.address);
        mPriv->port = addr.port;
    } else {
        // Unix socket
        mPriv->socketPath = QLatin1String(qdbus_cast<QByteArray>(pv->result()));
        debug() << "Got socket " << mPriv->socketPath;
    }

    // It might have been already opened - check
    if (mPriv->tube->state() == TubeChannelStateOpen) {
        onTubeStateChanged(mPriv->tube->state());
    } else {
        // Wait until the tube gets opened on the other side
        connect(mPriv->tube.data(), SIGNAL(stateChanged(Tp::TubeChannelState)),
                this, SLOT(onTubeStateChanged(Tp::TubeChannelState)));
    }
}

void PendingStreamTubeConnection::onTubeStateChanged(TubeChannelState state)
{
    debug() << "Tube state changed to " << state;
    if (state == TubeChannelStateOpen) {
        // The tube is ready, populate its properties
        if (mPriv->type == SocketAddressTypeIPv4 || mPriv->type == SocketAddressTypeIPv6) {
            mPriv->tube->setIpAddress(qMakePair<QHostAddress, quint16>(mPriv->hostAddress,
                    mPriv->port));
        } else {
            // Unix socket
            mPriv->tube->setLocalAddress(mPriv->socketPath);
        }

        // Mark the operation as finished
        setFinished();
    } else if (state != TubeChannelStateLocalPending) {
        // Something happened
        setFinishedWithError(QLatin1String("Connection refused"),
                QLatin1String("The connection to this tube was refused"));
    }
}

}
<|endoftext|>


<commit_before>//
// WFSClient.cpp
//
// Web Feature Server Client
//
// Copyright (c) 2002 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

// C:\APIs\w3c-libwww-5.4.0\Library\src

#include "Features.h"
#include "config_vtdata.h"
#include "FilePath.h"

// The dependency on Libwww is optional.  If not desired, skip this file.
#if SUPPORT_HTTP

// Includes for libwww (used for HTTP requests)
// first, avoid preprocessor conflicts between GDAL(cpl) and WWWLib
#undef HAVE_VPRINTF
#undef STDC_HEADERS
// avoid preprocessor conflict between MSVC errno.h and WWWlib
#undef EINVAL
#include "WWWLib.h"
#include "WWWInit.h"

#ifdef _MSC_VER
// We will now need to link with several of the Libwww libraries.  This can
// be done automatically with MSVC as follows:
#pragma comment(lib, "wwwapp.lib")
#pragma comment(lib, "wwwcore.lib")
#pragma comment(lib, "wwwinit.lib")
#pragma comment(lib, "wwwutils.lib")
#endif

#define DEFAULT_TIMEOUT	10				  /* timeout in secs */
#define MILLIES			1000

#include "xmlhelper/easyxml.hpp"

class ReqContext
{
public:
	ReqContext();
	~ReqContext();
	char *GetURL(const char *url);

	HTRequest *	request;
	HTAnchor *	anchor;
	char *		cwd;				  /* Current dir URL */

	char *		realm;			/* For automated authentication */
	char *		user;
	char *		password;
};

PRIVATE int printer (const char * fmt, va_list pArgs)
{
	char buf[20000];
	int ret = vsprintf(buf, fmt, pArgs);
	OutputDebugString(buf);
	return ret;
}

PRIVATE int tracer (const char * fmt, va_list pArgs)
{
	char buf[20000];
	int ret = vsprintf(buf, fmt, pArgs);
	OutputDebugString(buf);
	return ret;
}

PRIVATE BOOL PromptUsernameAndPassword (HTRequest * request, HTAlertOpcode op,
					int msgnum, const char * dfault,
					void * input, HTAlertPar * reply)
{
	return NO;
}

PRIVATE int term_handler (HTRequest * request, HTResponse * response,
				   void * param, int status)
{
	/* Check for status */
	HTPrint("Load resulted in status %d\n", status);

	/* we're not handling other requests */
	HTEventList_stopLoop ();

	/* stop here */
	return HT_ERROR;
}

//-------------------------------------------------------------------------

ReqContext::ReqContext()
{
	static bFirst = true;
	if (bFirst)
	{
		HTList * converters = HTList_new();		/* List of converters */
		HTList * encodings = HTList_new();		/* List of encoders */

		/* Initialize libwww core */
		HTLibInit("vtdata", __DATE__);

		/* Need our own trace and print functions */
		HTPrint_setCallback(printer);
		HTTrace_setCallback(tracer);

		/* On windows we must always set up the eventloop */
#ifdef WIN32
		HTEventInit();
#endif

		/* Register the default set of transport protocols */
		HTTransportInit();

		/* Register the default set of protocol modules */
		HTProtocolInit();

		/* Register the default set of BEFORE and AFTER callback functions */
		HTNetInit();

		/* Register the default set of converters */
		HTConverterInit(converters);
		HTFormat_setConversion(converters);

		/* Register the default set of transfer encoders and decoders */
		HTTransferEncoderInit(encodings);
		HTFormat_setTransferCoding(encodings);

		/* Register the default set of MIME header parsers */
		HTMIMEInit();

		/* Add our own filter to handle termination */
		HTNet_addAfter(term_handler, NULL, NULL, HT_ALL, HT_FILTER_LAST);

		/* Setting event timeout */
		int timer = DEFAULT_TIMEOUT*MILLIES;
		HTHost_setEventTimeout(timer);

		// Don't know what this will do, just trying:
		HTHost_setActiveTimeout(timer);

		bFirst = false;
	}

	cwd = HTGetCurrentDirectoryURL();

	/* Bind the ConLine object together with the Request Object */
	request = HTRequest_new();
	HTRequest_setOutputFormat(request, WWW_SOURCE);

	// Setting preemptive to NO doesn't seem to make a difference
	HTRequest_setPreemptive(request, YES);

	HTRequest_setContext(request, this);
}

ReqContext::~ReqContext()
{
	HTRequest_delete(request);
	HT_FREE(cwd);
}

char *ReqContext::GetURL(const char *url)
{
	HTChunk * chunk = NULL;

	char *absolute_url = HTParse(url, cwd, PARSE_ALL);
	anchor = HTAnchor_findAddress(absolute_url);
	chunk = HTLoadAnchorToChunk(anchor, request);
	HT_FREE(absolute_url);

	/* If chunk != NULL then we have the data */
	if (!chunk)
		return NULL;

	char *string;
	/* wait until the request is over */
	HTEventList_loop(request);
	string = HTChunk_toCString(chunk);
//	HTPrint("%s", string ? string : "no text");
	return string;
}

bool vtFeatures::ReadFeaturesFromWFS(const char *szServerURL, const char *layername)
{
	vtString url = szServerURL;
	url += "GetFeature?typeName=";
	url += layername;

	ReqContext cl;
	char *string = cl.GetURL(url);
	if (!string)
		return false;

	char *temp_fname = "C:/temp/gml_temp.gml";
	FILE *fp = fopen(temp_fname, "wb");
	if (!fp)
		return false;

	fwrite(string, 1, strlen(string), fp);
	fclose(fp);
	HT_FREE(string);

	return LoadFromGML(temp_fname);
}

////////////////////////////////////////////////////////////////////////
// Visitor class, for XML parsing of WFS Layer List files.
////////////////////////////////////////////////////////////////////////

class LayerListVisitor : public XMLVisitor
{
public:
	LayerListVisitor(WFSLayerArray *pLayers) :
		m_pLayers(pLayers), _level(0) {}

	virtual ~LayerListVisitor () {}

	void startXML ();
	void endXML ();
	void startElement (const char * name, const XMLAttributes &atts);
	void endElement (const char * name);
	void data (const char * s, int length);

private:
	string _data;
	int _level;

	WFSLayerArray *m_pLayers;
	vtTagArray *m_pTags;
};

void LayerListVisitor::startXML ()
{
	_level = 0;
}

void LayerListVisitor::endXML ()
{
	_level = 0;
}

void LayerListVisitor::startElement (const char * name, const XMLAttributes &atts)
{
	if (_level == 0)
	{
		if (string(name) == "FeatureType")
		{
			_level = 1;
			m_pTags = new vtTagArray;
		}
	}
	_data = "";
}

void LayerListVisitor::endElement(const char * name)
{
	if (_level == 1)
	{
		if (string(name) == "FeatureType")
		{
			m_pLayers->Append(m_pTags);
			_level = 0;
			return;
		}
		const char *value = _data.c_str();
		m_pTags->AddTag(name, value);
	}
}

void LayerListVisitor::data(const char *s, int length)
{
	if (_level == 1)
		_data.append(string(s, length));
}

//
//
//
bool GetLayersFromWFS(const char *szServerURL, WFSLayerArray &layers)
{
	vtString url = szServerURL;
	url += "GetCapabilities?version=0.0.14";

	ReqContext cl;
	char *string = cl.GetURL(url);
	if (!string)
		return false;

	char *temp_fname = "C:/temp/layers_temp.xml";
	FILE *fp = fopen(temp_fname, "wb");
	if (!fp)
		return false;
	fwrite(string, 1, strlen(string), fp);
	HT_FREE(string);
	fclose(fp);

	LayerListVisitor visitor(&layers);
	try
	{
		readXML(temp_fname, visitor);
	}
	catch (xh_exception &)
	{
		// TODO: would be good to pass back the error message.
		return false;
	}
	return true;
}

#else
// no support for HTTP
bool vtFeatures::ReadFeaturesFromWFS(const char *url)
{
	return false;
}
#endif	// SUPPORT_HTTP
<commit_msg>fixes to !SUPPORT_HTTP case<commit_after>//
// WFSClient.cpp
//
// Web Feature Server Client
//
// Copyright (c) 2002 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

// C:\APIs\w3c-libwww-5.4.0\Library\src

#include "Features.h"
#include "config_vtdata.h"
#include "FilePath.h"

// The dependency on Libwww is optional.  If not desired, skip this file.
#if SUPPORT_HTTP

// Includes for libwww (used for HTTP requests)
// first, avoid preprocessor conflicts between GDAL(cpl) and WWWLib
#undef HAVE_VPRINTF
#undef STDC_HEADERS
// avoid preprocessor conflict between MSVC errno.h and WWWlib
#undef EINVAL
#include "WWWLib.h"
#include "WWWInit.h"

#ifdef _MSC_VER
// We will now need to link with several of the Libwww libraries.  This can
// be done automatically with MSVC as follows:
#pragma comment(lib, "wwwapp.lib")
#pragma comment(lib, "wwwcore.lib")
#pragma comment(lib, "wwwinit.lib")
#pragma comment(lib, "wwwutils.lib")
#endif

#define DEFAULT_TIMEOUT	10				  /* timeout in secs */
#define MILLIES			1000

#include "xmlhelper/easyxml.hpp"

class ReqContext
{
public:
	ReqContext();
	~ReqContext();
	char *GetURL(const char *url);

	HTRequest *	request;
	HTAnchor *	anchor;
	char *		cwd;				  /* Current dir URL */

	char *		realm;			/* For automated authentication */
	char *		user;
	char *		password;
};

PRIVATE int printer (const char * fmt, va_list pArgs)
{
	char buf[20000];
	int ret = vsprintf(buf, fmt, pArgs);
	OutputDebugString(buf);
	return ret;
}

PRIVATE int tracer (const char * fmt, va_list pArgs)
{
	char buf[20000];
	int ret = vsprintf(buf, fmt, pArgs);
	OutputDebugString(buf);
	return ret;
}

PRIVATE BOOL PromptUsernameAndPassword (HTRequest * request, HTAlertOpcode op,
					int msgnum, const char * dfault,
					void * input, HTAlertPar * reply)
{
	return NO;
}

PRIVATE int term_handler (HTRequest * request, HTResponse * response,
				   void * param, int status)
{
	/* Check for status */
	HTPrint("Load resulted in status %d\n", status);

	/* we're not handling other requests */
	HTEventList_stopLoop ();

	/* stop here */
	return HT_ERROR;
}

//-------------------------------------------------------------------------

ReqContext::ReqContext()
{
	static bFirst = true;
	if (bFirst)
	{
		HTList * converters = HTList_new();		/* List of converters */
		HTList * encodings = HTList_new();		/* List of encoders */

		/* Initialize libwww core */
		HTLibInit("vtdata", __DATE__);

		/* Need our own trace and print functions */
		HTPrint_setCallback(printer);
		HTTrace_setCallback(tracer);

		/* On windows we must always set up the eventloop */
#ifdef WIN32
		HTEventInit();
#endif

		/* Register the default set of transport protocols */
		HTTransportInit();

		/* Register the default set of protocol modules */
		HTProtocolInit();

		/* Register the default set of BEFORE and AFTER callback functions */
		HTNetInit();

		/* Register the default set of converters */
		HTConverterInit(converters);
		HTFormat_setConversion(converters);

		/* Register the default set of transfer encoders and decoders */
		HTTransferEncoderInit(encodings);
		HTFormat_setTransferCoding(encodings);

		/* Register the default set of MIME header parsers */
		HTMIMEInit();

		/* Add our own filter to handle termination */
		HTNet_addAfter(term_handler, NULL, NULL, HT_ALL, HT_FILTER_LAST);

		/* Setting event timeout */
		int timer = DEFAULT_TIMEOUT*MILLIES;
		HTHost_setEventTimeout(timer);

		// Don't know what this will do, just trying:
		HTHost_setActiveTimeout(timer);

		bFirst = false;
	}

	cwd = HTGetCurrentDirectoryURL();

	/* Bind the ConLine object together with the Request Object */
	request = HTRequest_new();
	HTRequest_setOutputFormat(request, WWW_SOURCE);

	// Setting preemptive to NO doesn't seem to make a difference
	HTRequest_setPreemptive(request, YES);

	HTRequest_setContext(request, this);
}

ReqContext::~ReqContext()
{
	HTRequest_delete(request);
	HT_FREE(cwd);
}

char *ReqContext::GetURL(const char *url)
{
	HTChunk * chunk = NULL;

	char *absolute_url = HTParse(url, cwd, PARSE_ALL);
	anchor = HTAnchor_findAddress(absolute_url);
	chunk = HTLoadAnchorToChunk(anchor, request);
	HT_FREE(absolute_url);

	/* If chunk != NULL then we have the data */
	if (!chunk)
		return NULL;

	char *string;
	/* wait until the request is over */
	HTEventList_loop(request);
	string = HTChunk_toCString(chunk);
//	HTPrint("%s", string ? string : "no text");
	return string;
}

bool vtFeatures::ReadFeaturesFromWFS(const char *szServerURL, const char *layername)
{
	vtString url = szServerURL;
	url += "GetFeature?typeName=";
	url += layername;

	ReqContext cl;
	char *string = cl.GetURL(url);
	if (!string)
		return false;

	char *temp_fname = "C:/temp/gml_temp.gml";
	FILE *fp = fopen(temp_fname, "wb");
	if (!fp)
		return false;

	fwrite(string, 1, strlen(string), fp);
	fclose(fp);
	HT_FREE(string);

	return LoadFromGML(temp_fname);
}

////////////////////////////////////////////////////////////////////////
// Visitor class, for XML parsing of WFS Layer List files.
////////////////////////////////////////////////////////////////////////

class LayerListVisitor : public XMLVisitor
{
public:
	LayerListVisitor(WFSLayerArray *pLayers) :
		m_pLayers(pLayers), _level(0) {}

	virtual ~LayerListVisitor () {}

	void startXML ();
	void endXML ();
	void startElement (const char * name, const XMLAttributes &atts);
	void endElement (const char * name);
	void data (const char * s, int length);

private:
	string _data;
	int _level;

	WFSLayerArray *m_pLayers;
	vtTagArray *m_pTags;
};

void LayerListVisitor::startXML ()
{
	_level = 0;
}

void LayerListVisitor::endXML ()
{
	_level = 0;
}

void LayerListVisitor::startElement (const char * name, const XMLAttributes &atts)
{
	if (_level == 0)
	{
		if (string(name) == "FeatureType")
		{
			_level = 1;
			m_pTags = new vtTagArray;
		}
	}
	_data = "";
}

void LayerListVisitor::endElement(const char * name)
{
	if (_level == 1)
	{
		if (string(name) == "FeatureType")
		{
			m_pLayers->Append(m_pTags);
			_level = 0;
			return;
		}
		const char *value = _data.c_str();
		m_pTags->AddTag(name, value);
	}
}

void LayerListVisitor::data(const char *s, int length)
{
	if (_level == 1)
		_data.append(string(s, length));
}

//
//
//
bool GetLayersFromWFS(const char *szServerURL, WFSLayerArray &layers)
{
	vtString url = szServerURL;
	url += "GetCapabilities?version=0.0.14";

	ReqContext cl;
	char *string = cl.GetURL(url);
	if (!string)
		return false;

	char *temp_fname = "C:/temp/layers_temp.xml";
	FILE *fp = fopen(temp_fname, "wb");
	if (!fp)
		return false;
	fwrite(string, 1, strlen(string), fp);
	HT_FREE(string);
	fclose(fp);

	LayerListVisitor visitor(&layers);
	try
	{
		readXML(temp_fname, visitor);
	}
	catch (xh_exception &)
	{
		// TODO: would be good to pass back the error message.
		return false;
	}
	return true;
}

#else
// no support for HTTP
bool vtFeatures::ReadFeaturesFromWFS(const char *, const char *)
{
	return false;
}
#endif	// SUPPORT_HTTP
<|endoftext|>


<commit_before>/*******************************
 *
 *  Monarch decoder v1.0.0
 *  Author: Roger Hsiao
 *
 *  Works with mbc_code.c v5.2.3 and above
 *  Usage: ./decoder.exe [packets] [date.log | 0] [time.log | 0] [light out file] [temp out file]
 *
 *  v1.0.0:
 *    Added automatic time translation
 *
 *  v1.0.1:
 *    Decoding doesn't halt when encountering an Unrecognized code anymore
 *
 *  v1.0.2:
 *    Updated decoder to use local date instead of epoch date
 *
 *  v1.0.3:
 *    Not subtracting timezone difference in time.log to get GMT time
 *
 *  v1.0.4:
 *    Fixed decoder index bug that doesn't update index properly, which causes a timeshift
 *
 *
 *******************************/

#include <iostream>
#include <fstream>
#include <bitset>
#include <string>
#include <map>
#include <cmath>
#include "../pre_v20e/software/mbc_code/huffman_encodings.h"
// #include "/home/rogerhh/M-ulator/platforms/m3/pre_v20e/software/mbc_code/huffman_encodings.h"

#define DAWN 0
#define NOON 1
#define DUSK 2
#define NIGHT 3

using namespace std;

using Unit = bitset<272>;

Unit create_unit(const string packets[]);
uint32_t get_data(Unit& u, int len);

uint16_t resample_indices[4] = {32, 40, 44, 1000};
uint16_t intervals[4] = {1, 2, 8, 32};

class LightParser {
public:
    uint32_t sys_time_in_min = 0;
    int day_state = 0;
    int index = 0;
    map<uint32_t, double> data;
    map<int, map<int, int>> codes;

    void parse_unit(Unit& u);
    void read_header(Unit& u);
    void read_timestamp(Unit& u);

    LightParser();
};

class TempParser {
public:
    map<uint32_t, double> data;
    map<int, map<int, int>> codes;

    void parse_unit(Unit& u);

    TempParser();
};

int main(int argc, char** argv) {
    if(argc != 6) {
        cerr << "Usage: ./decoder.exe [packet file] [date.log] [time.log] [light output file] [temp output file]" << endl;
        return 1;
    }

    string packet_filename = string(argv[1]);
    ifstream fin(packet_filename);
    if(!fin.is_open()) {
        cerr << "Error opening: " << packet_filename << endl;
        return 1;
    }
    string date_log = string(argv[2]);
    ifstream date_fin(date_log);
    if(date_log != "0" && !date_fin.is_open()) {
        cerr << "Error opening: " << date_log << endl;
        return 1;
    }
    string time_log = string(argv[3]);
    ifstream time_fin(time_log);
    if(time_log != "0" && !time_fin.is_open()) {
        cerr << "Error opening: " << time_log << endl;
        return 1;
    }
    bool no_time_translation = date_log == "0";

    string light_filename = string(argv[4]);
    ofstream light_fout(light_filename);
    if(!light_fout.is_open()) {
        cerr << "Error opening: " << light_filename << endl;
        return 1;
    }
    string temp_filename = string(argv[5]);
    ofstream temp_fout(temp_filename);
    if(!temp_fout.is_open()) {
        cerr << "Error opening: " << temp_filename << endl;
        return 1;
    }

    double abs_time = 0, programmed_time = 0, tz = 0, trigger_fire_date = 0, date_tz = 0;

    if(!no_time_translation) {
        // Read UTC offset
        int programmed_date = 0;
        string trash;
        getline(date_fin, trash, ':');
        date_fin >> trigger_fire_date;
        getline(date_fin, trash, ':');
        date_fin >> date_tz;
        getline(date_fin, trash, ':');
        date_fin >> programmed_date;
        cout << trigger_fire_date << " " << programmed_date << endl;

        char c;
        getline(time_fin, trash, ':');
        time_fin >> abs_time;
        getline(time_fin, trash, ':');
        time_fin >> programmed_time >> c >> c >> tz;

        cout << programmed_date << " " << (int) abs_time << " " << programmed_time << " " << tz << endl;
    }
    else {
        cout << "No auto time translation" << endl;
    }

    LightParser lp;
    TempParser tp;

    string packets[4];
    while(fin >> packets[0] >> packets[1] >> packets[2] >> packets[3]) {
        auto u = create_unit(packets);
        if(stoi(packets[0].substr(0, 1), 0, 16) & 0b1000) {
            // is light
            lp.parse_unit(u);
        }
        else {
            // is temp
            tp.parse_unit(u);
        }
    }

    for(auto p : lp.data) {
        // Not doing anything with timezone because it seems like it's already done by python
        light_fout << fixed << p.first << " " << p.first + abs_time + 0 * tz << " " << p.second << " " << pow(2, (p.second / 32.0)) << endl;
    }
    for(auto p : tp.data) {
        temp_fout << fixed << p.first + trigger_fire_date * 86400 - date_tz << " " << pow(2, ((p.second + 128) / 16.0)) << endl;
    }
}

Unit create_unit(const string packets[]) {
    Unit u = Unit(0);
    for(int i = 0; i < 4; i++) {
        for(int j = 3; j < packets[i].size(); j++) {
            u <<= 4;
            u |= Unit(stoi(packets[i].substr(j, 1), 0, 16));
        }
    }
    cout << u << endl;
    return u;
}

uint32_t get_data(Unit& u, int len) {
    uint32_t mask = (1 << len) - 1;
    auto temp = u;
    temp >>= (272 - len);
    temp &= mask;
    u <<= len;
    return temp.to_ulong();
}

LightParser::LightParser() {
    // preprocess codes
    for(int i = 0; i < 67; i++) {
        auto code = light_diff_codes[i];
        auto len = light_code_lengths[i];
        if(i == 64) {
            codes[len][code] = 0x1FF;
        }
        else if(i == 65) {
            codes[len][code] = 0x7FF;
        }
        else if(i == 66) {
            codes[len][code] = 0x1000;
        }
        else {
            codes[len][code] = i - 32;
        }
    }
}

uint32_t sign_extend(uint32_t src, int len) {
    if(src & (1 << (len - 1))) {
        cout << "sign extend neg" << endl;
        return src - (1 << len);
    }
    else {
        return src;
    }
}

void LightParser::read_timestamp(Unit& u) {
    auto t = get_data(u, 17);
    // Not worried about overflow for now
    sys_time_in_min = t;
    cout << "parsed time in min = " << sys_time_in_min << endl;
}

void LightParser::read_header(Unit& u) {
    day_state = get_data(u, 2);
    cout << "day state = " << day_state << endl;
    if(day_state == NIGHT) {
        throw runtime_error("Invalid day state!");
    }

    index = get_data(u, 7);
    cout << "index: " << index << endl;
    cout << "day state = " << day_state << endl;
}

void LightParser::parse_unit(Unit& u) {
    bool has_header = false;
    bool has_timestamp = false;
    bool has_cur = false;
    int cur = 0;

    cout << "light_unit" << endl;

    while(u.any()) {
        cout << "u any = " << u.any() << " " << u << endl;
        if(!has_timestamp) {
            read_timestamp(u);
            has_timestamp = true;
        }
        if(!has_header) {
            read_header(u);
            has_header = true;
        }
        if(!has_cur) {
            // read initial val
            cur = get_data(u, 11);
            has_cur = true;
        }
        else {
            // else read code
            int len = 0;
            int tmp = 0;
            bool flag = false;
            while(len < 12) {
                int b = get_data(u, 1);
                tmp <<= 1;
                tmp |= b;
                len++;
                cout << "codes: " << len << " " << tmp << " " << bitset<12>(tmp) << endl;
                auto it = codes.find(len);
                if(it == codes.end()) {
                    continue;
                }
                auto it2 = codes[len].find(tmp);
                if(it2 == codes[len].end()) {
                    continue;
                }
                auto code = it2->second;

                cout << "code: " << code << endl;

                if(code == 0x1000) {
                    day_state = (day_state + 1) & 0b11;
                    if(day_state == NIGHT) {
                        day_state = DAWN;
                    }
                    index = 0;
                    cout << "end day state" << endl;
                    cout << "day state = " << day_state << "; index = " << 0 << endl;
                    has_timestamp = false;
                }
                else if(code == 0x7FF) {
                    // don't use diff
                    code = get_data(u, 11);
                    cout << "diff 11" << endl;
                    cur = code;
                }
                else if(code == 0x1FF) {
                    code = get_data(u, 9);
                    cout << "diff 9: code: " << bitset<9>(code) << endl;
                    code = sign_extend(code, 9);
                    cout << "exteneded: " << code << endl;
                    cur += code;
                }
                else {
                    cur += code;
                }
                flag = true;
                break;
            }
            if(!flag) {
                cout << u << endl;
                cout << "Unrecognized code" << endl;
                continue;
                throw runtime_error("Unrecognized code: " + to_string(tmp));

            }
            if(!has_timestamp) {
                continue;
            }
        }
        data[sys_time_in_min * 60] = cur;
        cout << sys_time_in_min << " " << sys_time_in_min * 60 << " " << cur << endl;
        index++;

        // update sys_time_in_min
        if(u.any()) {
            if(day_state == DAWN) {
                for(int i = 0; i < 4; i++) {
                    if(index < resample_indices[i]) {
                        sys_time_in_min += intervals[i];
                        cout << " test" << endl;
                        break;
                    }
                }
            }
            else if(day_state == DUSK) {
                for(int i = 0; i < 4; i++) {
                    if(index < resample_indices[i]) {
                        sys_time_in_min -= intervals[i];
                        break;
                    }
                }
            }
            else {
                sys_time_in_min += 32;
            }
        }
    }
    cout << "End unit. sys_time_in_min = " << sys_time_in_min << endl << endl;

    return;
}

void TempParser::parse_unit(Unit& u) {
    uint32_t day_count = get_data(u, 7);
    uint32_t timestamp_in_half_hour = get_data(u, 6);
    uint32_t cur_value = get_data(u, 7);

    data[day_count * 86400 + timestamp_in_half_hour * 1800] = cur_value;

    while(u.any()) {
        cout << u << endl;
        int len = 0;
        int tmp = 0;
        bool flag = false;
        while(len < 4) {
            int b = get_data(u, 1);
            tmp <<= 1;
            tmp |= b;
            len++;
            cout << "temp codes: " << len << " " << tmp << " " << bitset<4>(tmp) << endl;
            auto it = codes.find(len);
            if(it == codes.end()) {
                continue;
            }
            auto it2 = codes[len].find(tmp);
            if(it2 == codes[len].end()) {
                continue;
            }
            auto code = it2->second;

            cout << "temp code: " << code << endl;

            if(code == 0x7F) {
                code = get_data(u, 7);
                cout << "diff 7" << endl;
                cur_value = code;
            }
            else {
                cur_value += code;
            }
            flag = true;
            break;
        }

        if(!flag) {
            cout << "Unrecognized code" << endl;
            continue;
            throw runtime_error("Unrecognized code: " + to_string(tmp));
        }

        timestamp_in_half_hour++;
        if(timestamp_in_half_hour >= 48) {
            timestamp_in_half_hour = 0;
            day_count++;
        }

        data[day_count * 86400 + timestamp_in_half_hour * 1800] = cur_value;
        cout << day_count << " " << timestamp_in_half_hour << endl;
        cout << day_count * 86400 + timestamp_in_half_hour * 1800 << " " << cur_value << endl;

    }

    cout << "End temp unit" << endl;

    return;
}

TempParser::TempParser() {
    // preprocess codes
    for(int i = 0; i < 5; i++) {
        auto code = temp_diff_codes[i];
        auto len = temp_code_lengths[i];
        if(i == 4) {
            codes[len][code] = 0x7F;
        }
        else {
            codes[len][code] = i - 2;
        }
    }
}

<commit_msg>decoder v1.0.4<commit_after>/*******************************
 *
 *  Monarch decoder v1.0.0
 *  Author: Roger Hsiao
 *
 *  Works with mbc_code.c v5.2.3 and above
 *  Usage: ./decoder.exe [packets] [date.log | 0] [time.log | 0] [light out file] [temp out file]
 *
 *  v1.0.0:
 *    Added automatic time translation
 *
 *  v1.0.1:
 *    Decoding doesn't halt when encountering an Unrecognized code anymore
 *
 *  v1.0.2:
 *    Updated decoder to use local date instead of epoch date
 *
 *  v1.0.3:
 *    Not subtracting timezone difference in time.log to get GMT time
 *
 *  v1.0.4:
 *    Fixed decoder index bug that doesn't update index properly, which causes a timeshift
 *    Removed timezone shift in decoded data, so now the decoded data is strictly GMT
 *
 *
 *******************************/

#include <iostream>
#include <fstream>
#include <bitset>
#include <string>
#include <map>
#include <cmath>
#include "../pre_v20e/software/mbc_code/huffman_encodings.h"
// #include "/home/rogerhh/M-ulator/platforms/m3/pre_v20e/software/mbc_code/huffman_encodings.h"

#define DAWN 0
#define NOON 1
#define DUSK 2
#define NIGHT 3

using namespace std;

using Unit = bitset<272>;

Unit create_unit(const string packets[]);
uint32_t get_data(Unit& u, int len);

uint16_t resample_indices[4] = {32, 40, 44, 1000};
uint16_t intervals[4] = {1, 2, 8, 32};

class LightParser {
public:
    uint32_t sys_time_in_min = 0;
    int day_state = 0;
    int index = 0;
    map<uint32_t, double> data;
    map<int, map<int, int>> codes;

    void parse_unit(Unit& u);
    void read_header(Unit& u);
    void read_timestamp(Unit& u);

    LightParser();
};

class TempParser {
public:
    map<uint32_t, double> data;
    map<int, map<int, int>> codes;

    void parse_unit(Unit& u);

    TempParser();
};

int main(int argc, char** argv) {
    if(argc != 6) {
        cerr << "Usage: ./decoder.exe [packet file] [date.log] [time.log] [light output file] [temp output file]" << endl;
        return 1;
    }

    string packet_filename = string(argv[1]);
    ifstream fin(packet_filename);
    if(!fin.is_open()) {
        cerr << "Error opening: " << packet_filename << endl;
        return 1;
    }
    string date_log = string(argv[2]);
    ifstream date_fin(date_log);
    if(date_log != "0" && !date_fin.is_open()) {
        cerr << "Error opening: " << date_log << endl;
        return 1;
    }
    string time_log = string(argv[3]);
    ifstream time_fin(time_log);
    if(time_log != "0" && !time_fin.is_open()) {
        cerr << "Error opening: " << time_log << endl;
        return 1;
    }
    bool no_time_translation = date_log == "0";

    string light_filename = string(argv[4]);
    ofstream light_fout(light_filename);
    if(!light_fout.is_open()) {
        cerr << "Error opening: " << light_filename << endl;
        return 1;
    }
    string temp_filename = string(argv[5]);
    ofstream temp_fout(temp_filename);
    if(!temp_fout.is_open()) {
        cerr << "Error opening: " << temp_filename << endl;
        return 1;
    }

    double abs_time = 0, programmed_time = 0, tz = 0, trigger_fire_date = 0, date_tz = 0;

    if(!no_time_translation) {
        // Read UTC offset
        int programmed_date = 0;
        string trash;
        getline(date_fin, trash, ':');
        date_fin >> trigger_fire_date;
        getline(date_fin, trash, ':');
        date_fin >> date_tz;
        getline(date_fin, trash, ':');
        date_fin >> programmed_date;
        cout << trigger_fire_date << " " << programmed_date << endl;

        char c;
        getline(time_fin, trash, ':');
        time_fin >> abs_time;
        getline(time_fin, trash, ':');
        time_fin >> programmed_time >> c >> c >> tz;

        cout << programmed_date << " " << (int) abs_time << " " << programmed_time << " " << tz << endl;
    }
    else {
        cout << "No auto time translation" << endl;
    }

    LightParser lp;
    TempParser tp;

    string packets[4];
    while(fin >> packets[0] >> packets[1] >> packets[2] >> packets[3]) {
        auto u = create_unit(packets);
        if(stoi(packets[0].substr(0, 1), 0, 16) & 0b1000) {
            // is light
            lp.parse_unit(u);
        }
        else {
            // is temp
            tp.parse_unit(u);
        }
    }

    for(auto p : lp.data) {
        // Not doing anything with timezone because it seems like it's already done by python
        light_fout << fixed << p.first << " " << p.first + abs_time + 0 * tz << " " << p.second << " " << pow(2, (p.second / 32.0)) << endl;
    }
    for(auto p : tp.data) {
        temp_fout << fixed << p.first + trigger_fire_date * 86400 - date_tz << " " << pow(2, ((p.second + 128) / 16.0)) << endl;
    }
}

Unit create_unit(const string packets[]) {
    Unit u = Unit(0);
    for(int i = 0; i < 4; i++) {
        for(int j = 3; j < packets[i].size(); j++) {
            u <<= 4;
            u |= Unit(stoi(packets[i].substr(j, 1), 0, 16));
        }
    }
    cout << u << endl;
    return u;
}

uint32_t get_data(Unit& u, int len) {
    uint32_t mask = (1 << len) - 1;
    auto temp = u;
    temp >>= (272 - len);
    temp &= mask;
    u <<= len;
    return temp.to_ulong();
}

LightParser::LightParser() {
    // preprocess codes
    for(int i = 0; i < 67; i++) {
        auto code = light_diff_codes[i];
        auto len = light_code_lengths[i];
        if(i == 64) {
            codes[len][code] = 0x1FF;
        }
        else if(i == 65) {
            codes[len][code] = 0x7FF;
        }
        else if(i == 66) {
            codes[len][code] = 0x1000;
        }
        else {
            codes[len][code] = i - 32;
        }
    }
}

uint32_t sign_extend(uint32_t src, int len) {
    if(src & (1 << (len - 1))) {
        cout << "sign extend neg" << endl;
        return src - (1 << len);
    }
    else {
        return src;
    }
}

void LightParser::read_timestamp(Unit& u) {
    auto t = get_data(u, 17);
    // Not worried about overflow for now
    sys_time_in_min = t;
    cout << "parsed time in min = " << sys_time_in_min << endl;
}

void LightParser::read_header(Unit& u) {
    day_state = get_data(u, 2);
    cout << "day state = " << day_state << endl;
    if(day_state == NIGHT) {
        throw runtime_error("Invalid day state!");
    }

    index = get_data(u, 7);
    cout << "index: " << index << endl;
    cout << "day state = " << day_state << endl;
}

void LightParser::parse_unit(Unit& u) {
    bool has_header = false;
    bool has_timestamp = false;
    bool has_cur = false;
    int cur = 0;

    cout << "light_unit" << endl;

    while(u.any()) {
        cout << "u any = " << u.any() << " " << u << endl;
        if(!has_timestamp) {
            read_timestamp(u);
            has_timestamp = true;
        }
        if(!has_header) {
            read_header(u);
            has_header = true;
        }
        if(!has_cur) {
            // read initial val
            cur = get_data(u, 11);
            has_cur = true;
        }
        else {
            // else read code
            int len = 0;
            int tmp = 0;
            bool flag = false;
            while(len < 12) {
                int b = get_data(u, 1);
                tmp <<= 1;
                tmp |= b;
                len++;
                cout << "codes: " << len << " " << tmp << " " << bitset<12>(tmp) << endl;
                auto it = codes.find(len);
                if(it == codes.end()) {
                    continue;
                }
                auto it2 = codes[len].find(tmp);
                if(it2 == codes[len].end()) {
                    continue;
                }
                auto code = it2->second;

                cout << "code: " << code << endl;

                if(code == 0x1000) {
                    day_state = (day_state + 1) & 0b11;
                    if(day_state == NIGHT) {
                        day_state = DAWN;
                    }
                    index = 0;
                    cout << "end day state" << endl;
                    cout << "day state = " << day_state << "; index = " << 0 << endl;
                    has_timestamp = false;
                }
                else if(code == 0x7FF) {
                    // don't use diff
                    code = get_data(u, 11);
                    cout << "diff 11" << endl;
                    cur = code;
                }
                else if(code == 0x1FF) {
                    code = get_data(u, 9);
                    cout << "diff 9: code: " << bitset<9>(code) << endl;
                    code = sign_extend(code, 9);
                    cout << "exteneded: " << code << endl;
                    cur += code;
                }
                else {
                    cur += code;
                }
                flag = true;
                break;
            }
            if(!flag) {
                cout << u << endl;
                cout << "Unrecognized code" << endl;
                continue;
                throw runtime_error("Unrecognized code: " + to_string(tmp));

            }
            if(!has_timestamp) {
                continue;
            }
        }
        data[sys_time_in_min * 60] = cur;
        cout << sys_time_in_min << " " << sys_time_in_min * 60 << " " << cur << endl;
        index++;

        // update sys_time_in_min
        if(u.any()) {
            if(day_state == DAWN) {
                for(int i = 0; i < 4; i++) {
                    if(index < resample_indices[i]) {
                        sys_time_in_min += intervals[i];
                        cout << " test" << endl;
                        break;
                    }
                }
            }
            else if(day_state == DUSK) {
                for(int i = 0; i < 4; i++) {
                    if(index < resample_indices[i]) {
                        sys_time_in_min -= intervals[i];
                        break;
                    }
                }
            }
            else {
                sys_time_in_min += 32;
            }
        }
    }
    cout << "End unit. sys_time_in_min = " << sys_time_in_min << endl << endl;

    return;
}

void TempParser::parse_unit(Unit& u) {
    uint32_t day_count = get_data(u, 7);
    uint32_t timestamp_in_half_hour = get_data(u, 6);
    uint32_t cur_value = get_data(u, 7);

    data[day_count * 86400 + timestamp_in_half_hour * 1800] = cur_value;

    while(u.any()) {
        cout << u << endl;
        int len = 0;
        int tmp = 0;
        bool flag = false;
        while(len < 4) {
            int b = get_data(u, 1);
            tmp <<= 1;
            tmp |= b;
            len++;
            cout << "temp codes: " << len << " " << tmp << " " << bitset<4>(tmp) << endl;
            auto it = codes.find(len);
            if(it == codes.end()) {
                continue;
            }
            auto it2 = codes[len].find(tmp);
            if(it2 == codes[len].end()) {
                continue;
            }
            auto code = it2->second;

            cout << "temp code: " << code << endl;

            if(code == 0x7F) {
                code = get_data(u, 7);
                cout << "diff 7" << endl;
                cur_value = code;
            }
            else {
                cur_value += code;
            }
            flag = true;
            break;
        }

        if(!flag) {
            cout << "Unrecognized code" << endl;
            continue;
            throw runtime_error("Unrecognized code: " + to_string(tmp));
        }

        timestamp_in_half_hour++;
        if(timestamp_in_half_hour >= 48) {
            timestamp_in_half_hour = 0;
            day_count++;
        }

        data[day_count * 86400 + timestamp_in_half_hour * 1800] = cur_value;
        cout << day_count << " " << timestamp_in_half_hour << endl;
        cout << day_count * 86400 + timestamp_in_half_hour * 1800 << " " << cur_value << endl;

    }

    cout << "End temp unit" << endl;

    return;
}

TempParser::TempParser() {
    // preprocess codes
    for(int i = 0; i < 5; i++) {
        auto code = temp_diff_codes[i];
        auto len = temp_code_lengths[i];
        if(i == 4) {
            codes[len][code] = 0x7F;
        }
        else {
            codes[len][code] = i - 2;
        }
    }
}

<|endoftext|>