<commit_before>/* ************************************************
 * GEANT4 VCGLIB/CAD INTERFACE
 *
 * File:      CADMesh.cc
 *
 * Author:    Christopher M Poole,
 * Email:     mail@christopherpoole.net
 *
 * Date:      7th March, 2011
 **************************************************/

// USER //
#include "CADMesh.hh"

// GEANT4 //
#include "G4String.hh"
#include "G4UIcommand.hh"
#include "G4ThreeVector.hh"
#include "G4LogicalVolume.hh"
#include "G4TessellatedSolid.hh"
#include "G4TriangularFacet.hh"
#include "G4Tet.hh"
#include "G4ThreeVector.hh"
#include "G4Material.hh"

#include "GL/gl.h"
#include "GL/glu.h"

#ifndef NOVCGLIB
// VCGLIB //
#include "wrap/io_trimesh/import.h"
#include "wrap/io_trimesh/import_dae.h"
#include "wrap/io_trimesh/import_ply.h"
#include "wrap/io_trimesh/import_stl.h"
#include "wrap/io_trimesh/import_off.h"
#include "wrap/ply/plylib.h"

using namespace vcg::tri::io;
#endif

#ifndef NOASSIMP
CADMesh::CADMesh(char * file_name, double units,
        G4ThreeVector offset, G4bool reverse)
{
    this->units = units;
    this->offset = offset;
    this->reverse = reverse;

    this->file_name = file_name;
    this->file_type = "ASSIMP";
    this->file_type.toUpper();

    this->material = NULL;
    this->quality = 0;

    this->has_mesh = false;
    this->has_solid = false;
    this->verbose = 0;
}
#endif

CADMesh::CADMesh(char * file_name, char * file_type, double units,
        G4ThreeVector offset, G4bool reverse)
{
    this->units = units;
    this->offset = offset;
    this->reverse = reverse;

    this->file_name = file_name;
    this->file_type = file_type;
    this->file_type.toUpper();

    this->material = NULL;
    this->quality = 0;

    this->has_mesh = false;
    this->has_solid = false;
    this->verbose = 0;
}

CADMesh::CADMesh(char * file_name, char * file_type,
        G4Material * material, double quality)
{
    this->units = mm;
    this->offset = G4ThreeVector();
    this->reverse = false;

    this->file_name = file_name;
    this->file_type = file_type;
    this->file_type.toUpper();

    this->material = material;
    this->quality = quality;

    this->has_mesh = false;
    this->has_solid = false;
    this->verbose = 0;
}

CADMesh::CADMesh(char * file_name, char * file_type)
{
    this->units = mm;
    this->offset = G4ThreeVector();
    this->reverse = false;

    this->file_name = file_name;
    this->file_type = file_type;
    this->file_type.toUpper();

    this->material = NULL;
    this->quality = 0;

    this->has_mesh = false;
    this->has_solid = false;
    this->verbose = 0;
}

CADMesh::CADMesh(char * file_name, char * file_type, G4Material * material)
{
    this->units = mm;
    this->offset = G4ThreeVector();
    this->reverse = false;

    this->file_name = file_name;
    this->file_type = file_type;
    this->file_type.toUpper();

    this->material = material;
    this->quality = 0;

    this->has_mesh = false;
    this->has_solid = false;
    this->verbose = 0;
}

CADMesh::CADMesh(char * file_name, char * file_type,
        G4Material * material, double quality, G4ThreeVector offset)
{
    this->units = mm;
    this->offset = offset;
    this->reverse = false;

    this->file_name = file_name;
    this->file_type = file_type;
    this->file_type.toUpper();

    this->material = material;
    this->quality = quality;

    this->has_mesh = false;
    this->has_solid = false;
    this->verbose = 0;
}

CADMesh::~CADMesh()
{
}

#ifndef NOASSIMP
G4VSolid* CADMesh::TessellatedMesh()
{
    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile(file_name,
            aiProcess_Triangulate           |
            aiProcess_JoinIdenticalVertices |
            aiProcess_CalcTangentSpace);

    m = scene->mMeshes[0];

    volume_solid = new G4TessellatedSolid(file_name);

    G4ThreeVector point_1;
    G4ThreeVector point_2;
    G4ThreeVector point_3;

    for(unsigned int i=0; i < m->mNumFaces; i++)
    {
        const aiFace& face = m->mFaces[i];

        point_1.setX(m->mVertices[face.mIndices[0]].x);
        point_1.setY(m->mVertices[face.mIndices[0]].y);
        point_1.setZ(m->mVertices[face.mIndices[0]].z);

        point_2.setX(m->mVertices[face.mIndices[1]].x);
        point_2.setY(m->mVertices[face.mIndices[1]].y);
        point_2.setZ(m->mVertices[face.mIndices[1]].z);

        point_3.setX(m->mVertices[face.mIndices[2]].x);
        point_3.setY(m->mVertices[face.mIndices[2]].y);
        point_3.setZ(m->mVertices[face.mIndices[2]].z);

        G4TriangularFacet * facet;
        if (reverse == false) {
            facet = new G4TriangularFacet(point_1, point_2, point_3, ABSOLUTE);
        } else {
            facet = new G4TriangularFacet(point_2, point_1, point_3, ABSOLUTE);
        }
        volume_solid->AddFacet((G4VFacet*) facet);
    }

    volume_solid->SetSolidClosed(true);

    if (volume_solid->GetNumberOfFacets() == 0) {
        G4cerr << "CADMesh/TessellatedMesh: "
               << "Load a mesh has 0 faces, " << file_name << " may not exist."
               << G4endl;
        return 0;
    }

    return volume_solid;
}
#endif

#ifndef NOVCGLIB
G4VSolid* CADMesh::TessellatedMesh()
{
    if (!has_mesh) {
        if (file_type == "STL") {
            ImporterSTL<CADTriMesh>::Open(m, file_name);
        } else if (file_type == "PLY") {
            ImporterPLY<CADTriMesh>::Open(m, file_name);
        } else if (file_type == "OFF") {
           ImporterOFF<CADTriMesh>::Open(m, file_name);
        } else if (file_type == "COLLADA") {
            InfoDAE info = InfoDAE();
            ImporterDAE<CADTriMesh>::Open(m, file_name, info, 0);
        } else {
            G4cerr << "CADMesh/TessellatedMesh: "
                   << "No G4TessellatedSoild to return. Specify valid mesh type (STL, PLY, OFF, COLLADA), not: "
                   << file_type
                   << G4endl;
            has_mesh = false;

            return 0;
        }
        has_mesh = true;

    } else {
        G4cerr << "CADMesh/TessellatedMesh: "
               << "Mesh already loaded from "
               << file_name
               << ", not loading. Use CADMesh/GetSolid to get the currently loaded mesh as a G4TessellatedSolid"
               << G4endl;
        return 0;
    }

    if (!has_mesh) {
        G4cerr << "CADMesh/TessellatedMesh: "
               << "Load a mesh of type STL, PLY or OFF first."
               << G4endl;
        return 0;
    }

    volume_solid = new G4TessellatedSolid(file_name);

    G4ThreeVector point_1 = G4ThreeVector();
    G4ThreeVector point_2 = G4ThreeVector();
    G4ThreeVector point_3 = G4ThreeVector();

    CADTriMesh::FaceIterator face_iterator;

    for(face_iterator=m.face.begin(); face_iterator!=m.face.end(); ++face_iterator)
    {
        point_1 = G4ThreeVector(
                (*face_iterator).V(0)->P()[0] * units + offset.x(),
                (*face_iterator).V(0)->P()[1] * units + offset.y(),
                (*face_iterator).V(0)->P()[2] * units + offset.z());
        point_2 = G4ThreeVector(
                (*face_iterator).V(1)->P()[0] * units + offset.x(),
                (*face_iterator).V(1)->P()[1] * units + offset.y(),
                (*face_iterator).V(1)->P()[2] * units + offset.z());
        point_3 = G4ThreeVector(
                (*face_iterator).V(2)->P()[0] * units + offset.x(),
                (*face_iterator).V(2)->P()[1] * units + offset.y(),
                (*face_iterator).V(2)->P()[2] * units + offset.z());

        G4TriangularFacet * facet;
        if (reverse == false) {
            facet = new G4TriangularFacet(point_1, point_2, point_3, ABSOLUTE);
        } else {
            facet = new G4TriangularFacet(point_2, point_1, point_3, ABSOLUTE);
        }
        volume_solid->AddFacet((G4VFacet*) facet);
    }

    volume_solid->SetSolidClosed(true);

    if (volume_solid->GetNumberOfFacets() == 0) {
    G4cerr << "CADMesh/TessellatedMesh: "
               << "Load a mesh has 0 faces, " << file_name << " may not exist."
               << G4endl;
        return 0;
    }

    return volume_solid;
}
#endif

#ifndef NOTET
G4AssemblyVolume * CADMesh::TetrahedralMesh()
{
    // USAGE: assembly->MakeImprint(world_logical, assembly_transform_3d, 0); //

    G4bool do_tet = true;
    if (file_type == "STL") {
        G4bool state = in.load_stl(file_name);
    } else if (file_type == "PLY") {
        G4bool state = in.load_ply(file_name);
    } else if (file_type == "TET") {
        G4bool state = out.load_tetmesh(file_name);
        do_tet = false;
    } else if (file_type == "OFF") {
        G4bool state = out.load_off(file_name);
        do_tet = false;
    }

    if (do_tet)
    {
        G4String config = G4String("Yp");
        if (quality > 0) config = config + G4String("q") + G4UIcommand::ConvertToString(quality);
#ifdef DEBUG
        G4cout << "Tetrahedralisation configuration: " << config << G4endl;
#endif
        tetrahedralize((char *) config.c_str(), &in, &out);
    }

#ifdef DEBUG
    G4cout << "Tetrahedra available: " << out.numberoftetrahedra << G4endl;
#endif

    assembly = new G4AssemblyVolume();
    G4RotationMatrix * element_rotation = new G4RotationMatrix();
    G4ThreeVector element_position = G4ThreeVector();
    G4Transform3D assembly_transform = G4Translate3D();

    for (int i=0; i<out.numberoftetrahedra; i++) {
        int index_offset = i * 4; /* For a tetrahedron, out.numberofcorners == 4 */

        G4ThreeVector p1 = GetTetPoint(index_offset);
        G4ThreeVector p2 = GetTetPoint(index_offset + 1);
        G4ThreeVector p3 = GetTetPoint(index_offset + 2);
        G4ThreeVector p4 = GetTetPoint(index_offset + 3);

        G4String tet_name = file_name + G4String("_tet_") + G4UIcommand::ConvertToString(i);

        G4VSolid * tet_solid = new G4Tet(tet_name + G4String("_solid"), p1, p2, p3, p4, 0);
        G4LogicalVolume * tet_logical = new G4LogicalVolume(tet_solid, material, tet_name + G4String("_logical"), 0, 0, 0);
        assembly->AddPlacedVolume(tet_logical, element_position, element_rotation);

#ifdef DEBUG
        if (i%1000 == 0) G4cout << "Tetrahedrons added: " << i << G4endl;
#endif
    }

#ifdef DEBUG
    G4cout << "Loading of " << out.numberoftetrahedra << " tetrahedra complete with material: " << material->GetName() << G4endl;
#endif

    return assembly;
}

G4ThreeVector CADMesh::GetTetPoint(G4int index_offset)
{
    return G4ThreeVector(out.pointlist[out.tetrahedronlist[index_offset]*3] - offset.x(),
            out.pointlist[out.tetrahedronlist[index_offset]*3+1] - offset.y(),
            out.pointlist[out.tetrahedronlist[index_offset]*3+2] - offset.z());
}
#endif
<commit_msg>added units multiplier and offset to assimp tessellated solid loader<commit_after>/* ************************************************
 * GEANT4 VCGLIB/CAD INTERFACE
 *
 * File:      CADMesh.cc
 *
 * Author:    Christopher M Poole,
 * Email:     mail@christopherpoole.net
 *
 * Date:      7th March, 2011
 **************************************************/

// USER //
#include "CADMesh.hh"

// GEANT4 //
#include "G4String.hh"
#include "G4UIcommand.hh"
#include "G4ThreeVector.hh"
#include "G4LogicalVolume.hh"
#include "G4TessellatedSolid.hh"
#include "G4TriangularFacet.hh"
#include "G4Tet.hh"
#include "G4ThreeVector.hh"
#include "G4Material.hh"

#include "GL/gl.h"
#include "GL/glu.h"

#ifndef NOVCGLIB
// VCGLIB //
#include "wrap/io_trimesh/import.h"
#include "wrap/io_trimesh/import_dae.h"
#include "wrap/io_trimesh/import_ply.h"
#include "wrap/io_trimesh/import_stl.h"
#include "wrap/io_trimesh/import_off.h"
#include "wrap/ply/plylib.h"

using namespace vcg::tri::io;
#endif

#ifndef NOASSIMP
CADMesh::CADMesh(char * file_name, double units,
        G4ThreeVector offset, G4bool reverse)
{
    this->units = units;
    this->offset = offset;
    this->reverse = reverse;

    this->file_name = file_name;
    this->file_type = "ASSIMP";
    this->file_type.toUpper();

    this->material = NULL;
    this->quality = 0;

    this->has_mesh = false;
    this->has_solid = false;
    this->verbose = 0;
}
#endif

CADMesh::CADMesh(char * file_name, char * file_type, double units,
        G4ThreeVector offset, G4bool reverse)
{
    this->units = units;
    this->offset = offset;
    this->reverse = reverse;

    this->file_name = file_name;
    this->file_type = file_type;
    this->file_type.toUpper();

    this->material = NULL;
    this->quality = 0;

    this->has_mesh = false;
    this->has_solid = false;
    this->verbose = 0;
}

CADMesh::CADMesh(char * file_name, char * file_type,
        G4Material * material, double quality)
{
    this->units = mm;
    this->offset = G4ThreeVector();
    this->reverse = false;

    this->file_name = file_name;
    this->file_type = file_type;
    this->file_type.toUpper();

    this->material = material;
    this->quality = quality;

    this->has_mesh = false;
    this->has_solid = false;
    this->verbose = 0;
}

CADMesh::CADMesh(char * file_name, char * file_type)
{
    this->units = mm;
    this->offset = G4ThreeVector();
    this->reverse = false;

    this->file_name = file_name;
    this->file_type = file_type;
    this->file_type.toUpper();

    this->material = NULL;
    this->quality = 0;

    this->has_mesh = false;
    this->has_solid = false;
    this->verbose = 0;
}

CADMesh::CADMesh(char * file_name, char * file_type, G4Material * material)
{
    this->units = mm;
    this->offset = G4ThreeVector();
    this->reverse = false;

    this->file_name = file_name;
    this->file_type = file_type;
    this->file_type.toUpper();

    this->material = material;
    this->quality = 0;

    this->has_mesh = false;
    this->has_solid = false;
    this->verbose = 0;
}

CADMesh::CADMesh(char * file_name, char * file_type,
        G4Material * material, double quality, G4ThreeVector offset)
{
    this->units = mm;
    this->offset = offset;
    this->reverse = false;

    this->file_name = file_name;
    this->file_type = file_type;
    this->file_type.toUpper();

    this->material = material;
    this->quality = quality;

    this->has_mesh = false;
    this->has_solid = false;
    this->verbose = 0;
}

CADMesh::~CADMesh()
{
}

#ifndef NOASSIMP
G4VSolid* CADMesh::TessellatedMesh()
{
    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile(file_name,
            aiProcess_Triangulate           |
            aiProcess_JoinIdenticalVertices |
            aiProcess_CalcTangentSpace);

    m = scene->mMeshes[0];

    volume_solid = new G4TessellatedSolid(file_name);

    G4ThreeVector point_1;
    G4ThreeVector point_2;
    G4ThreeVector point_3;

    for(unsigned int i=0; i < m->mNumFaces; i++)
    {
        const aiFace& face = m->mFaces[i];

        point_1.setX(m->mVertices[face.mIndices[0]].x * units + offset.x());
        point_1.setY(m->mVertices[face.mIndices[0]].y * units + offset.y());
        point_1.setZ(m->mVertices[face.mIndices[0]].z * units + offset.z());

        point_2.setX(m->mVertices[face.mIndices[1]].x * units + offset.x());
        point_2.setY(m->mVertices[face.mIndices[1]].y * units + offset.y());
        point_2.setZ(m->mVertices[face.mIndices[1]].z * units + offset.z());

        point_3.setX(m->mVertices[face.mIndices[2]].x * units + offset.x());
        point_3.setY(m->mVertices[face.mIndices[2]].y * units + offset.y());
        point_3.setZ(m->mVertices[face.mIndices[2]].z * units + offset.z());

        G4TriangularFacet * facet;
        if (reverse == false) {
            facet = new G4TriangularFacet(point_1, point_2, point_3, ABSOLUTE);
        } else {
            facet = new G4TriangularFacet(point_2, point_1, point_3, ABSOLUTE);
        }
        volume_solid->AddFacet((G4VFacet*) facet);
    }

    volume_solid->SetSolidClosed(true);

    if (volume_solid->GetNumberOfFacets() == 0) {
        G4cerr << "CADMesh/TessellatedMesh: "
               << "Load a mesh has 0 faces, " << file_name << " may not exist."
               << G4endl;
        return 0;
    }

    return volume_solid;
}
#endif

#ifndef NOVCGLIB
G4VSolid* CADMesh::TessellatedMesh()
{
    if (!has_mesh) {
        if (file_type == "STL") {
            ImporterSTL<CADTriMesh>::Open(m, file_name);
        } else if (file_type == "PLY") {
            ImporterPLY<CADTriMesh>::Open(m, file_name);
        } else if (file_type == "OFF") {
           ImporterOFF<CADTriMesh>::Open(m, file_name);
        } else if (file_type == "COLLADA") {
            InfoDAE info = InfoDAE();
            ImporterDAE<CADTriMesh>::Open(m, file_name, info, 0);
        } else {
            G4cerr << "CADMesh/TessellatedMesh: "
                   << "No G4TessellatedSoild to return. Specify valid mesh type (STL, PLY, OFF, COLLADA), not: "
                   << file_type
                   << G4endl;
            has_mesh = false;

            return 0;
        }
        has_mesh = true;

    } else {
        G4cerr << "CADMesh/TessellatedMesh: "
               << "Mesh already loaded from "
               << file_name
               << ", not loading. Use CADMesh/GetSolid to get the currently loaded mesh as a G4TessellatedSolid"
               << G4endl;
        return 0;
    }

    if (!has_mesh) {
        G4cerr << "CADMesh/TessellatedMesh: "
               << "Load a mesh of type STL, PLY or OFF first."
               << G4endl;
        return 0;
    }

    volume_solid = new G4TessellatedSolid(file_name);

    G4ThreeVector point_1 = G4ThreeVector();
    G4ThreeVector point_2 = G4ThreeVector();
    G4ThreeVector point_3 = G4ThreeVector();

    CADTriMesh::FaceIterator face_iterator;

    for(face_iterator=m.face.begin(); face_iterator!=m.face.end(); ++face_iterator)
    {
        point_1 = G4ThreeVector(
                (*face_iterator).V(0)->P()[0] * units + offset.x(),
                (*face_iterator).V(0)->P()[1] * units + offset.y(),
                (*face_iterator).V(0)->P()[2] * units + offset.z());
        point_2 = G4ThreeVector(
                (*face_iterator).V(1)->P()[0] * units + offset.x(),
                (*face_iterator).V(1)->P()[1] * units + offset.y(),
                (*face_iterator).V(1)->P()[2] * units + offset.z());
        point_3 = G4ThreeVector(
                (*face_iterator).V(2)->P()[0] * units + offset.x(),
                (*face_iterator).V(2)->P()[1] * units + offset.y(),
                (*face_iterator).V(2)->P()[2] * units + offset.z());

        G4TriangularFacet * facet;
        if (reverse == false) {
            facet = new G4TriangularFacet(point_1, point_2, point_3, ABSOLUTE);
        } else {
            facet = new G4TriangularFacet(point_2, point_1, point_3, ABSOLUTE);
        }
        volume_solid->AddFacet((G4VFacet*) facet);
    }

    volume_solid->SetSolidClosed(true);

    if (volume_solid->GetNumberOfFacets() == 0) {
    G4cerr << "CADMesh/TessellatedMesh: "
               << "Load a mesh has 0 faces, " << file_name << " may not exist."
               << G4endl;
        return 0;
    }

    return volume_solid;
}
#endif

#ifndef NOTET
G4AssemblyVolume * CADMesh::TetrahedralMesh()
{
    // USAGE: assembly->MakeImprint(world_logical, assembly_transform_3d, 0); //

    G4bool do_tet = true;
    if (file_type == "STL") {
        G4bool state = in.load_stl(file_name);
    } else if (file_type == "PLY") {
        G4bool state = in.load_ply(file_name);
    } else if (file_type == "TET") {
        G4bool state = out.load_tetmesh(file_name);
        do_tet = false;
    } else if (file_type == "OFF") {
        G4bool state = out.load_off(file_name);
        do_tet = false;
    }

    if (do_tet)
    {
        G4String config = G4String("Yp");
        if (quality > 0) config = config + G4String("q") + G4UIcommand::ConvertToString(quality);
#ifdef DEBUG
        G4cout << "Tetrahedralisation configuration: " << config << G4endl;
#endif
        tetrahedralize((char *) config.c_str(), &in, &out);
    }

#ifdef DEBUG
    G4cout << "Tetrahedra available: " << out.numberoftetrahedra << G4endl;
#endif

    assembly = new G4AssemblyVolume();
    G4RotationMatrix * element_rotation = new G4RotationMatrix();
    G4ThreeVector element_position = G4ThreeVector();
    G4Transform3D assembly_transform = G4Translate3D();

    for (int i=0; i<out.numberoftetrahedra; i++) {
        int index_offset = i * 4; /* For a tetrahedron, out.numberofcorners == 4 */

        G4ThreeVector p1 = GetTetPoint(index_offset);
        G4ThreeVector p2 = GetTetPoint(index_offset + 1);
        G4ThreeVector p3 = GetTetPoint(index_offset + 2);
        G4ThreeVector p4 = GetTetPoint(index_offset + 3);

        G4String tet_name = file_name + G4String("_tet_") + G4UIcommand::ConvertToString(i);

        G4VSolid * tet_solid = new G4Tet(tet_name + G4String("_solid"), p1, p2, p3, p4, 0);
        G4LogicalVolume * tet_logical = new G4LogicalVolume(tet_solid, material, tet_name + G4String("_logical"), 0, 0, 0);
        assembly->AddPlacedVolume(tet_logical, element_position, element_rotation);

#ifdef DEBUG
        if (i%1000 == 0) G4cout << "Tetrahedrons added: " << i << G4endl;
#endif
    }

#ifdef DEBUG
    G4cout << "Loading of " << out.numberoftetrahedra << " tetrahedra complete with material: " << material->GetName() << G4endl;
#endif

    return assembly;
}

G4ThreeVector CADMesh::GetTetPoint(G4int index_offset)
{
    return G4ThreeVector(out.pointlist[out.tetrahedronlist[index_offset]*3] - offset.x(),
            out.pointlist[out.tetrahedronlist[index_offset]*3+1] - offset.y(),
            out.pointlist[out.tetrahedronlist[index_offset]*3+2] - offset.z());
}
#endif
<|endoftext|>


<commit_before>/*!
 * \copy
 *     Copyright (c)  2009-2013, Cisco Systems
 *     All rights reserved.
 *
 *     Redistribution and use in source and binary forms, with or without
 *     modification, are permitted provided that the following conditions
 *     are met:
 *
 *        * Redistributions of source code must retain the above copyright
 *          notice, this list of conditions and the following disclaimer.
 *
 *        * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *     "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 THE
 *     COPYRIGHT HOLDER 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.
 *
 *
 * \file	crt_utils_safe_x.cpp
 *
 * \brief	common tool/function utilization
 *
 * \date	03/10/2009 Created
 *
 *************************************************************************************
 */

#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#if defined(_WIN32)
#include <windows.h>
#include <sys/types.h>
#include <sys/timeb.h>
#ifndef _MSC_VER
#include <sys/time.h>
#endif //!_MSC_VER
#else
#include <sys/time.h>
#include <sys/timeb.h>
#endif //_WIN32

#include "macros.h"
#include "crt_util_safe_x.h"	// Safe CRT routines like utils for cross platforms

#if  defined(_WIN32) && defined(_MSC_VER)

#if  defined(_MSC_VER) && (_MSC_VER>=1500)

int32_t WelsSnprintf (char* pBuffer,  int32_t iSizeOfBuffer, const char* kpFormat, ...) {
  va_list  pArgPtr;
  int32_t  iRc;

  va_start (pArgPtr, kpFormat);

  iRc = vsnprintf_s (pBuffer, iSizeOfBuffer, _TRUNCATE, kpFormat, pArgPtr);

  va_end (pArgPtr);

  return iRc;
}

char* WelsStrncpy (char* pDest, int32_t iSizeInBytes, const char* kpSrc) {
  strncpy_s (pDest, iSizeInBytes, kpSrc, _TRUNCATE);

  return pDest;
}

int32_t WelsVsnprintf (char* pBuffer, int32_t iSizeOfBuffer, const char* kpFormat, va_list pArgPtr) {
  return vsnprintf_s (pBuffer, iSizeOfBuffer, _TRUNCATE, kpFormat, pArgPtr);
}

WelsFileHandle* WelsFopen (const char* kpFilename,  const char* kpMode) {
  WelsFileHandle* pFp = NULL;
  if (fopen_s (&pFp, kpFilename, kpMode) != 0) {
    return NULL;
  }

  return pFp;
}

int32_t WelsFclose (WelsFileHandle* pFp) {
  return fclose (pFp);
}

int32_t WelsGetTimeOfDay (SWelsTime* pTp) {
  return _ftime_s (pTp);
}

int32_t WelsStrftime (char* pBuffer, int32_t iSize, const char* kpFormat, const SWelsTime* kpTp) {
  struct tm   sTimeNow;
  int32_t iRc;

  localtime_s (&sTimeNow, &kpTp->time);

  iRc = strftime (pBuffer, iSize, kpFormat, &sTimeNow);
  if (iRc == 0)
      pBuffer[0] = '\0';
  return iRc;
}

#else

int32_t WelsSnprintf (char* pBuffer,  int32_t iSizeOfBuffer, const char* kpFormat, ...) {
  va_list pArgPtr;
  int32_t iRc;

  va_start (pArgPtr, kpFormat);

  iRc = vsnprintf (pBuffer, iSizeOfBuffer, kpFormat, pArgPtr); //confirmed_safe_unsafe_usage
  if (iRc < 0)
    pBuffer[iSizeOfBuffer - 1] = '\0';

  va_end (pArgPtr);

  return iRc;
}

char* WelsStrncpy (char* pDest, int32_t iSizeInBytes, const char* kpSrc) {
  strncpy (pDest, kpSrc, iSizeInBytes); //confirmed_safe_unsafe_usage
  pDest[iSizeInBytes - 1] = '\0';

  return pDest;
}

int32_t WelsVsnprintf (char* pBuffer, int32_t iSizeOfBuffer, const char* kpFormat, va_list pArgPtr) {
  int32_t iRc = vsnprintf (pBuffer, iSizeOfBuffer, kpFormat, pArgPtr); //confirmed_safe_unsafe_usage
  if (iRc < 0)
    pBuffer[iSizeOfBuffer - 1] = '\0';
  return iRc;
}

WelsFileHandle* WelsFopen (const char* kpFilename,  const char* kpMode) {
  return fopen (kpFilename, kpMode);
}

int32_t WelsFclose (WelsFileHandle* pFp) {
  return fclose (pFp);
}

int32_t WelsGetTimeOfDay (SWelsTime* pTp) {
  _ftime (pTp);
  return 0;
}

int32_t WelsStrftime (char* pBuffer, int32_t iSize, const char* kpFormat, const SWelsTime* kpTp) {
  struct tm*   pTnow;
  int32_t iRc;

  pTnow = localtime (&kpTp->time);

  iRc = strftime (pBuffer, iSize, kpFormat, pTnow);
  if (iRc == 0)
      pBuffer[0] = '\0';
  return iRc;
}

#endif // _MSC_VER

#else  //GCC

int32_t WelsSnprintf (char* pBuffer,  int32_t iSizeOfBuffer, const char* kpFormat, ...) {
  va_list pArgPtr;
  int32_t iRc;

  va_start (pArgPtr, kpFormat);

  iRc = vsnprintf (pBuffer, iSizeOfBuffer, kpFormat, pArgPtr);

  va_end (pArgPtr);

  return iRc;
}

char* WelsStrncpy (char* pDest, int32_t iSizeInBytes, const char* kpSrc) {
  strncpy (pDest, kpSrc, iSizeInBytes); //confirmed_safe_unsafe_usage
  pDest[iSizeInBytes - 1] = '\0';
  return pDest;
}

int32_t WelsVsnprintf (char* pBuffer, int32_t iSizeOfBuffer, const char* kpFormat, va_list pArgPtr) {
  return vsnprintf (pBuffer, iSizeOfBuffer, kpFormat, pArgPtr); //confirmed_safe_unsafe_usage
}

WelsFileHandle* WelsFopen (const char* kpFilename,  const char* kpMode) {
  return fopen (kpFilename, kpMode);
}

int32_t WelsFclose (WelsFileHandle*   pFp) {
  return fclose (pFp);
}

int32_t WelsGetTimeOfDay (SWelsTime* pTp) {
  struct timeval  sTv;

  if (gettimeofday (&sTv, NULL)) {
    return -1;
  }

  pTp->time = sTv.tv_sec;
  pTp->millitm = (uint16_t)sTv.tv_usec / 1000;

  return 0;
}

int32_t WelsStrftime (char* pBuffer, int32_t iSize, const char* kpFormat, const SWelsTime* kpTp) {
  struct tm*   pTnow;
  int32_t iRc;

  pTnow = localtime (&kpTp->time);

  iRc = strftime (pBuffer, iSize, kpFormat, pTnow);
  if (iRc == 0)
      pBuffer[0] = '\0';
  return iRc;
}

#endif

char* WelsStrcat (char* pDest, int32_t iSizeInBytes, const char* kpSrc) {
    int32_t iCurLen = strlen(pDest);
    return WelsStrncpy(pDest + iCurLen, iSizeInBytes - iCurLen, kpSrc);
}

int32_t WelsFwrite (const void* kpBuffer, int32_t iSize, int32_t iCount, WelsFileHandle* pFp) {
  return fwrite (kpBuffer, iSize, iCount, pFp);
}

uint16_t WelsGetMillisecond (const SWelsTime* kpTp) {
  return kpTp->millitm;
}

int32_t WelsFseek (WelsFileHandle* fp, int32_t offset, int32_t origin) {
  return fseek(fp, offset, origin);
}

int32_t WelsFflush (WelsFileHandle* pFp) {
  return fflush (pFp);
}
<commit_msg>Make Wels*Snprintf return values be non-negative<commit_after>/*!
 * \copy
 *     Copyright (c)  2009-2013, Cisco Systems
 *     All rights reserved.
 *
 *     Redistribution and use in source and binary forms, with or without
 *     modification, are permitted provided that the following conditions
 *     are met:
 *
 *        * Redistributions of source code must retain the above copyright
 *          notice, this list of conditions and the following disclaimer.
 *
 *        * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *     "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 THE
 *     COPYRIGHT HOLDER 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.
 *
 *
 * \file	crt_utils_safe_x.cpp
 *
 * \brief	common tool/function utilization
 *
 * \date	03/10/2009 Created
 *
 *************************************************************************************
 */

#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#if defined(_WIN32)
#include <windows.h>
#include <sys/types.h>
#include <sys/timeb.h>
#ifndef _MSC_VER
#include <sys/time.h>
#endif //!_MSC_VER
#else
#include <sys/time.h>
#include <sys/timeb.h>
#endif //_WIN32

#include "macros.h"
#include "crt_util_safe_x.h"	// Safe CRT routines like utils for cross platforms

#if  defined(_WIN32) && defined(_MSC_VER)

#if  defined(_MSC_VER) && (_MSC_VER>=1500)

int32_t WelsSnprintf (char* pBuffer,  int32_t iSizeOfBuffer, const char* kpFormat, ...) {
  va_list  pArgPtr;
  int32_t  iRc;

  va_start (pArgPtr, kpFormat);

  iRc = vsnprintf_s (pBuffer, iSizeOfBuffer, _TRUNCATE, kpFormat, pArgPtr);
  if (iRc < 0)
    iRc = iSizeOfBuffer;

  va_end (pArgPtr);

  return iRc;
}

char* WelsStrncpy (char* pDest, int32_t iSizeInBytes, const char* kpSrc) {
  strncpy_s (pDest, iSizeInBytes, kpSrc, _TRUNCATE);

  return pDest;
}

int32_t WelsVsnprintf (char* pBuffer, int32_t iSizeOfBuffer, const char* kpFormat, va_list pArgPtr) {
  int32_t iRc = vsnprintf_s (pBuffer, iSizeOfBuffer, _TRUNCATE, kpFormat, pArgPtr);
  if (iRc < 0)
    iRc = iSizeOfBuffer;
  return iRc;
}

WelsFileHandle* WelsFopen (const char* kpFilename,  const char* kpMode) {
  WelsFileHandle* pFp = NULL;
  if (fopen_s (&pFp, kpFilename, kpMode) != 0) {
    return NULL;
  }

  return pFp;
}

int32_t WelsFclose (WelsFileHandle* pFp) {
  return fclose (pFp);
}

int32_t WelsGetTimeOfDay (SWelsTime* pTp) {
  return _ftime_s (pTp);
}

int32_t WelsStrftime (char* pBuffer, int32_t iSize, const char* kpFormat, const SWelsTime* kpTp) {
  struct tm   sTimeNow;
  int32_t iRc;

  localtime_s (&sTimeNow, &kpTp->time);

  iRc = strftime (pBuffer, iSize, kpFormat, &sTimeNow);
  if (iRc == 0)
      pBuffer[0] = '\0';
  return iRc;
}

#else

int32_t WelsSnprintf (char* pBuffer,  int32_t iSizeOfBuffer, const char* kpFormat, ...) {
  va_list pArgPtr;
  int32_t iRc;

  va_start (pArgPtr, kpFormat);

  iRc = vsnprintf (pBuffer, iSizeOfBuffer, kpFormat, pArgPtr); //confirmed_safe_unsafe_usage
  if (iRc < 0) {
    pBuffer[iSizeOfBuffer - 1] = '\0';
    iRc = iSizeOfBuffer;
  }

  va_end (pArgPtr);

  return iRc;
}

char* WelsStrncpy (char* pDest, int32_t iSizeInBytes, const char* kpSrc) {
  strncpy (pDest, kpSrc, iSizeInBytes); //confirmed_safe_unsafe_usage
  pDest[iSizeInBytes - 1] = '\0';

  return pDest;
}

int32_t WelsVsnprintf (char* pBuffer, int32_t iSizeOfBuffer, const char* kpFormat, va_list pArgPtr) {
  int32_t iRc = vsnprintf (pBuffer, iSizeOfBuffer, kpFormat, pArgPtr); //confirmed_safe_unsafe_usage
  if (iRc < 0) {
    pBuffer[iSizeOfBuffer - 1] = '\0';
    iRc = iSizeOfBuffer;
  }
  return iRc;
}

WelsFileHandle* WelsFopen (const char* kpFilename,  const char* kpMode) {
  return fopen (kpFilename, kpMode);
}

int32_t WelsFclose (WelsFileHandle* pFp) {
  return fclose (pFp);
}

int32_t WelsGetTimeOfDay (SWelsTime* pTp) {
  _ftime (pTp);
  return 0;
}

int32_t WelsStrftime (char* pBuffer, int32_t iSize, const char* kpFormat, const SWelsTime* kpTp) {
  struct tm*   pTnow;
  int32_t iRc;

  pTnow = localtime (&kpTp->time);

  iRc = strftime (pBuffer, iSize, kpFormat, pTnow);
  if (iRc == 0)
      pBuffer[0] = '\0';
  return iRc;
}

#endif // _MSC_VER

#else  //GCC

int32_t WelsSnprintf (char* pBuffer,  int32_t iSizeOfBuffer, const char* kpFormat, ...) {
  va_list pArgPtr;
  int32_t iRc;

  va_start (pArgPtr, kpFormat);

  iRc = vsnprintf (pBuffer, iSizeOfBuffer, kpFormat, pArgPtr);

  va_end (pArgPtr);

  return iRc;
}

char* WelsStrncpy (char* pDest, int32_t iSizeInBytes, const char* kpSrc) {
  strncpy (pDest, kpSrc, iSizeInBytes); //confirmed_safe_unsafe_usage
  pDest[iSizeInBytes - 1] = '\0';
  return pDest;
}

int32_t WelsVsnprintf (char* pBuffer, int32_t iSizeOfBuffer, const char* kpFormat, va_list pArgPtr) {
  return vsnprintf (pBuffer, iSizeOfBuffer, kpFormat, pArgPtr); //confirmed_safe_unsafe_usage
}

WelsFileHandle* WelsFopen (const char* kpFilename,  const char* kpMode) {
  return fopen (kpFilename, kpMode);
}

int32_t WelsFclose (WelsFileHandle*   pFp) {
  return fclose (pFp);
}

int32_t WelsGetTimeOfDay (SWelsTime* pTp) {
  struct timeval  sTv;

  if (gettimeofday (&sTv, NULL)) {
    return -1;
  }

  pTp->time = sTv.tv_sec;
  pTp->millitm = (uint16_t)sTv.tv_usec / 1000;

  return 0;
}

int32_t WelsStrftime (char* pBuffer, int32_t iSize, const char* kpFormat, const SWelsTime* kpTp) {
  struct tm*   pTnow;
  int32_t iRc;

  pTnow = localtime (&kpTp->time);

  iRc = strftime (pBuffer, iSize, kpFormat, pTnow);
  if (iRc == 0)
      pBuffer[0] = '\0';
  return iRc;
}

#endif

char* WelsStrcat (char* pDest, int32_t iSizeInBytes, const char* kpSrc) {
    int32_t iCurLen = strlen(pDest);
    return WelsStrncpy(pDest + iCurLen, iSizeInBytes - iCurLen, kpSrc);
}

int32_t WelsFwrite (const void* kpBuffer, int32_t iSize, int32_t iCount, WelsFileHandle* pFp) {
  return fwrite (kpBuffer, iSize, iCount, pFp);
}

uint16_t WelsGetMillisecond (const SWelsTime* kpTp) {
  return kpTp->millitm;
}

int32_t WelsFseek (WelsFileHandle* fp, int32_t offset, int32_t origin) {
  return fseek(fp, offset, origin);
}

int32_t WelsFflush (WelsFileHandle* pFp) {
  return fflush (pFp);
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <assert.h>
#include <windows.h>
#include "game_arts.h"

static int
GetFileSize(FILE *File)
{
    int Size = 0;
    fseek(File, 0, SEEK_END);
    Size = ftell(File);
    fseek(File, 0, SEEK_SET);
    return Size;
}

static artfile_entry_t
CreateEntry(const char *Filename)
{
    artfile_entry_t Entry = {};
    FILE *File = fopen(Filename, "rb");
    Entry.Size = GetFileSize(File);
    fclose(File);
    return Entry;
}

static void
WriteEntry(FILE *ArtFile, artfile_entry_t *Entry, char *Data)
{
    fwrite(Entry, sizeof(artfile_entry_t), 1, ArtFile);
    fwrite(Data, sizeof(char), Entry->Size, ArtFile);
}

static artfile_entry_t
AppendImageTo(FILE *ArtFile, char *Filename)
{
    artfile_entry_t Entry = CreateEntry(Filename);

    FILE *File = fopen(Filename, "rb");
    BITMAPFILEHEADER BmpFileHeader = {0};
    fread(&BmpFileHeader, sizeof(BITMAPFILEHEADER), 1, File);

    BITMAPV5HEADER BmpV5Header = {0};
    fread(&BmpV5Header, sizeof(BITMAPV5HEADER), 1, File);

    assert(BmpV5Header.bV5BitCount == 24);

    char *ImageData = (char *)malloc(BmpV5Header.bV5SizeImage);
    fseek(File, BmpFileHeader.bfOffBits, SEEK_SET);
    fread(ImageData, BmpV5Header.bV5SizeImage, 1, File);

    // Rework pixeldata into being 1 byte = 1 pixel either on or off (0x00 / 0xFF)
    char *NewImageData = (char *)calloc(BmpV5Header.bV5Width * BmpV5Header.bV5Height, 1);
    const char *EndImageData = ImageData + BmpV5Header.bV5SizeImage;
    int i = 0;
    for (char *Color = ImageData; Color < EndImageData; ++i) {
        const char B = *Color++;
        const char G = *Color++;
        const char R = *Color++;
        if (R || G || B) {
            *(NewImageData + i) = 0xFF;
        }
    }
    // Entry.Size = BmpV5Header.bV5SizeImage;
    Entry.Type = ArtFile_bitmap;
    strncpy(Entry.Name, Filename, 16);
    Entry.Name[16] = 0;
    Entry.Size = BmpV5Header.bV5Width * BmpV5Header.bV5Height;
    Entry.Dim.Width = BmpV5Header.bV5Width;
    Entry.Dim.Height = BmpV5Header.bV5Height;

    // Need to set before writing entry to ArtFile
    WriteEntry(ArtFile, &Entry, NewImageData);

    free(ImageData);
    free(NewImageData);
    fclose(File);

    return Entry;
}

static void
ExtractEnumFriendlyFilename(char *Filename, char *BareFilename)
{
    int MaxLen = strlen(Filename);
    for (int i=0; i < MaxLen; ++i) {
        if (Filename[i] == '.') {
            break;
        }
        if (Filename[i] >= 'a' && Filename[i] <= 'z') {
            BareFilename[i] = Filename[i];
        }
    }
}

static unsigned int
FindAndPack(FILE *ArtFile, FILE *ArtIncludeFile, char *Directory, char *Pattern)
{
    unsigned EntryCount = 0;
    char FullPattern[MAX_PATH] = {0};
    strncpy(FullPattern, Directory, strlen(Directory));
    strcat(FullPattern, Pattern);

    WIN32_FIND_DATA FindData = {0};
    HANDLE Handle = FindFirstFile(FullPattern, &FindData);
    if (Handle == INVALID_HANDLE_VALUE) {
        return -1;
    }
    do {
        char FullFilename[MAX_PATH] = {0};
        strncpy(FullFilename, Directory, strlen(Directory));
        strcat(FullFilename, FindData.cFileName);
        AppendImageTo(ArtFile, FullFilename);

        // Update include file
        char BareFilename[MAX_PATH] = {0};
        ExtractEnumFriendlyFilename(FindData.cFileName, BareFilename);
        fprintf(ArtIncludeFile, "GameItem_%s = %i,\n", BareFilename, EntryCount);

        ++EntryCount;
    } while (FindNextFile(Handle, &FindData) != 0);
    FindClose(Handle);
    return EntryCount;
}

int
main(int argc, char **argv)
{
    int Result = 0;

    if (argc != 3) {
        printf("Usage: %s <arts dir> <dest dir>\n", argv[0]);
        return -1;
    }

    char ArtFilename[255] = {0};
    char ArtIncludeFilename[255] = {0};
    strncpy(ArtFilename, argv[2], strlen(argv[2]));
    strncpy(ArtIncludeFilename, ArtFilename, strlen(ArtFilename));
    strcat(ArtFilename, ".art");
    strcat(ArtIncludeFilename, ".h");

    // Create new art file. The header will be written AFTER we've processed
    // all files
    artfile_header_t Header = {};
    Header.Magic = ArtFileMagic_v1;
    FILE *ArtFile = fopen(ArtFilename, "wb");
    fseek(ArtFile, sizeof(artfile_header_t), SEEK_SET);

    // Generate include file
    FILE *ArtIncludeFile = fopen(ArtIncludeFilename, "w");
    fputs("#ifndef GAME_ART_ITEMS\n\n", ArtIncludeFile);
    fputs("enum game_artitems_e {\n", ArtIncludeFile);

    // Find and pack our groups
    int EntryCount = FindAndPack(ArtFile, ArtIncludeFile, argv[1], "*.bmp");
    DWORD LastError = GetLastError();
    if (EntryCount < 0 && LastError != 0) {
        printf("Error packing (err %i)\n", GetLastError());
        Result = -1;
    }
    Header.EntryCount += EntryCount;

    // Rewind tape and write header
    fseek(ArtFile, 0, SEEK_SET);
    fwrite(&Header, sizeof(artfile_header_t), 1, ArtFile);

    // Write footer of include file
    fputs("};\n\n", ArtIncludeFile);
    fputs("#define GAME_ART_ITEMS\n#endif", ArtIncludeFile);

    // At the end of the day
    fclose(ArtFile);
    fclose(ArtIncludeFile);

    return Result;
}
<commit_msg>game_items.h now contains the offset into memory where the entry can be found (for faster lookups)<commit_after>#include <stdio.h>
#include <assert.h>
#include <windows.h>
#include "game_arts.h"

static int
GetFileSize(FILE *File)
{
    int Size = 0;
    fseek(File, 0, SEEK_END);
    Size = ftell(File);
    fseek(File, 0, SEEK_SET);
    return Size;
}

static artfile_entry_t
CreateEntry(const char *Filename)
{
    artfile_entry_t Entry = {};
    FILE *File = fopen(Filename, "rb");
    Entry.Size = GetFileSize(File);
    fclose(File);
    return Entry;
}

static void
WriteEntry(FILE *ArtFile, artfile_entry_t *Entry, char *Data)
{
    fwrite(Entry, sizeof(artfile_entry_t), 1, ArtFile);
    fwrite(Data, sizeof(char), Entry->Size, ArtFile);
}

static void
ExtractEnumFriendlyFilename(char *Filename, char *BareFilename, uint BareFilenameSize = 0)
{
    int MaxLen = strlen(Filename);
    if (BareFilenameSize > 0 && MaxLen >= BareFilenameSize) {
        MaxLen = BareFilenameSize;
    }
    for (int i=0; i < MaxLen; ++i) {
        if (Filename[i] == '.') {
            break;
        }
        if (Filename[i] >= 'a' && Filename[i] <= 'z') {
            BareFilename[i] = Filename[i];
        }
    }
}

static artfile_entry_t
AppendImageTo(FILE *ArtFile, char *Filename)
{
    artfile_entry_t Entry = CreateEntry(Filename);

    FILE *File = fopen(Filename, "rb");
    BITMAPFILEHEADER BmpFileHeader = {0};
    fread(&BmpFileHeader, sizeof(BITMAPFILEHEADER), 1, File);

    BITMAPV5HEADER BmpV5Header = {0};
    fread(&BmpV5Header, sizeof(BITMAPV5HEADER), 1, File);

    assert(BmpV5Header.bV5BitCount == 24);

    char *ImageData = (char *)malloc(BmpV5Header.bV5SizeImage);
    fseek(File, BmpFileHeader.bfOffBits, SEEK_SET);
    fread(ImageData, BmpV5Header.bV5SizeImage, 1, File);

    // Rework pixeldata into being 1 byte = 1 pixel either on or off (0x00 / 0xFF)
    char *NewImageData = (char *)calloc(BmpV5Header.bV5Width * BmpV5Header.bV5Height, 1);
    const char *EndImageData = ImageData + BmpV5Header.bV5SizeImage;
    uint ColorIndex = 0;
    for (char *Color = ImageData; Color < EndImageData; ++ColorIndex) {
        const char B = *Color++;
        const char G = *Color++;
        const char R = *Color++;
        if (R || G || B) {
            *(NewImageData + ColorIndex) = 0xFF;
        }
    }
    // Entry.Size = BmpV5Header.bV5SizeImage;
    Entry.Type = ArtFile_bitmap;

    uint EntryNameIndex = 15;
    uint FilenameSize = strlen(Filename);
    bool FoundLastDot = false;
    for (uint i=FilenameSize - 1; i >= 0 && EntryNameIndex >= 0; --i) {
        char C = Filename[i];
        if (FoundLastDot) {
            if ((C >= 'A' && C <= 'Z') || (C >= 'a' && C <= 'z')) {
                Entry.Name[EntryNameIndex--] = C;
            } else {
                break;
            }
        } else if (C == '.') {
            FoundLastDot = true;
        }
    }
    // Skip past those zeroes
    uint EntryNameStartsAt = 0;
    for (; Entry.Name[EntryNameStartsAt] == 0; ++EntryNameStartsAt);
    for (uint i=EntryNameStartsAt; i < 16; ++i) {
        Entry.Name[i-EntryNameStartsAt] = Entry.Name[i];
        Entry.Name[i] = 0;
    }

    Entry.Size = BmpV5Header.bV5Width * BmpV5Header.bV5Height;
    Entry.Dim.Width = BmpV5Header.bV5Width;
    Entry.Dim.Height = BmpV5Header.bV5Height;

    // Need to set before writing entry to ArtFile
    WriteEntry(ArtFile, &Entry, NewImageData);

    free(ImageData);
    free(NewImageData);
    fclose(File);

    return Entry;
}

static unsigned int
FindAndPack(FILE *ArtFile, FILE *ArtIncludeFile, char *Directory, char *Pattern)
{
    unsigned EntryCount = 0;
    char FullPattern[MAX_PATH] = {0};
    strncpy(FullPattern, Directory, strlen(Directory));
    strcat(FullPattern, Pattern);

    WIN32_FIND_DATA FindData = {0};
    HANDLE Handle = FindFirstFile(FullPattern, &FindData);
    if (Handle == INVALID_HANDLE_VALUE) {
        return -1;
    }
    do {
        char FullFilename[MAX_PATH] = {0};
        strncpy(FullFilename, Directory, strlen(Directory));
        strcat(FullFilename, FindData.cFileName);
        uint EntryOffset = ftell(ArtFile);
        AppendImageTo(ArtFile, FullFilename);

        // Update include file
        char BareFilename[MAX_PATH] = {0};
        ExtractEnumFriendlyFilename(FindData.cFileName, BareFilename);
        fprintf(ArtIncludeFile, "GameItem_%s = %u,\n", BareFilename, EntryOffset);

        ++EntryCount;
    } while (FindNextFile(Handle, &FindData) != 0);
    FindClose(Handle);
    return EntryCount;
}

int
main(int argc, char **argv)
{
    int Result = 0;

    if (argc != 3) {
        printf("Usage: %s <arts dir> <dest dir>\n", argv[0]);
        return -1;
    }

    char ArtFilename[255] = {0};
    char ArtIncludeFilename[255] = {0};
    strncpy(ArtFilename, argv[2], strlen(argv[2]));
    strncpy(ArtIncludeFilename, ArtFilename, strlen(ArtFilename));
    strcat(ArtFilename, ".art");
    strcat(ArtIncludeFilename, ".h");

    // Create new art file. The header will be written AFTER we've processed
    // all files
    artfile_header_t Header = {};
    Header.Magic = ArtFileMagic_v1;
    FILE *ArtFile = fopen(ArtFilename, "wb");
    fseek(ArtFile, sizeof(artfile_header_t), SEEK_SET);

    // Generate include file
    FILE *ArtIncludeFile = fopen(ArtIncludeFilename, "w");
    fputs("#ifndef GAME_ART_ITEMS\n\n", ArtIncludeFile);
    fputs("// These are offsets into the memory where the\n", ArtIncludeFile);
    fputs("// specific artfile_entry_t can be found.\n", ArtIncludeFile);
    fputs("enum game_artitems_e {\n", ArtIncludeFile);

    // Find and pack our groups
    int EntryCount = FindAndPack(ArtFile, ArtIncludeFile, argv[1], "*.bmp");
    DWORD LastError = GetLastError();
    if (EntryCount < 0 && LastError != 0) {
        printf("Error packing (err %i)\n", GetLastError());
        Result = -1;
    }
    Header.EntryCount += EntryCount;

    // Rewind tape and write header
    fseek(ArtFile, 0, SEEK_SET);
    fwrite(&Header, sizeof(artfile_header_t), 1, ArtFile);

    // Write footer of include file
    fputs("};\n\n", ArtIncludeFile);
    fputs("#define GAME_ART_ITEMS\n#endif", ArtIncludeFile);

    // At the end of the day
    fclose(ArtFile);
    fclose(ArtIncludeFile);

    return Result;
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2009 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   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; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
#endif

#include "PropertyPythonObject.h"
#include "DocumentObjectPy.h"
#include "DocumentObject.h"
#include <Base/Base64.h>
#include <Base/Writer.h>
#include <Base/Reader.h>
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <iostream>
#include <boost/regex.hpp>

using namespace App;

TYPESYSTEM_SOURCE(App::PropertyPythonObject , App::Property);

PropertyPythonObject::PropertyPythonObject()
{
}

PropertyPythonObject::~PropertyPythonObject()
{
    // this is needed because the release of the pickled object may need the
    // GIL. Thus, we grab the GIL and replace the pickled with an empty object
    Base::PyGILStateLocker lock;
    this->object = Py::Object();
}

void PropertyPythonObject::setValue(Py::Object o)
{
    aboutToSetValue();
    this->object = o;
    hasSetValue();
}

Py::Object PropertyPythonObject::getValue() const
{
    return object;
}

PyObject *PropertyPythonObject::getPyObject(void)
{
    return Py::new_reference_to(this->object);
}

void PropertyPythonObject::setPyObject(PyObject * obj)
{
    aboutToSetValue();
    this->object = obj;
    hasSetValue();
}

std::string PropertyPythonObject::toString() const
{
    std::string repr;
    Base::PyGILStateLocker lock;
    try {
        Py::Module pickle(PyImport_ImportModule("json"),true);
        Py::Callable method(pickle.getAttr(std::string("dumps")));
        Py::Object dump;
        if (this->object.hasAttr("__getstate__")) {
            Py::Tuple args(0);
            Py::Callable state(this->object.getAttr("__getstate__"));
            dump = state.apply(args);
        }
        else if (this->object.hasAttr("__dict__")) {
            dump = this->object.getAttr("__dict__");
        }

        Py::Tuple args(1);
        args.setItem(0, dump);
        Py::Object res = method.apply(args);
        Py::String str(res);
        repr = str.as_std_string();
    }
    catch (Py::Exception&) {
        Base::PyException e; // extract the Python error text
        Base::Console().Warning("PropertyPythonObject::toString: %s\n", e.what());
    }

    return repr;
}

void PropertyPythonObject::fromString(const std::string& repr)
{
    Base::PyGILStateLocker lock;
    try {
        Py::Module pickle(PyImport_ImportModule("json"),true);
        Py::Callable method(pickle.getAttr(std::string("loads")));
        Py::Tuple args(1);
        args.setItem(0, Py::String(repr));
        Py::Object res = method.apply(args);

        if (this->object.hasAttr("__setstate__")) {
            Py::Tuple args(1);
            args.setItem(0, res);
            Py::Callable state(this->object.getAttr("__setstate__"));
            state.apply(args);
        }
        else {
            this->object.setAttr("__dict__", res);
        }
    }
    catch (Py::Exception&) {
        Base::PyException e; // extract the Python error text
        Base::Console().Warning("PropertyPythonObject::fromString: %s\n", e.what());
    }
}

void PropertyPythonObject::loadPickle(const std::string& str)
{
    // find the custom attributes and restore them
    Base::PyGILStateLocker lock;
    try {
        std::string buffer = str;
        boost::regex pickle("S'(\\w+)'.+S'(\\w+)'\\n");
        boost::match_results<std::string::const_iterator> what;
        std::string::const_iterator start, end;
        start = buffer.begin();
        end = buffer.end();
        while (boost::regex_search(start, end, what, pickle)) {
            std::string key = std::string(what[1].first, what[1].second);
            std::string val = std::string(what[2].first, what[2].second);
            this->object.setAttr(key, Py::String(val));
            buffer = std::string(what[2].second, end);
            start = buffer.begin();
            end = buffer.end();
        }
    }
    catch (Py::Exception&) {
        Base::PyException e; // extract the Python error text
        Base::Console().Warning("PropertyPythonObject::loadPickle: %s\n", e.what());
    }
}

std::string PropertyPythonObject::encodeValue(const std::string& str) const
{
    std::string tmp;
    for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
        if (*it == '<')
            tmp += "<";
        else if (*it == '"')
            tmp += """;
        else if (*it == '&')
            tmp += "&";
        else if (*it == '>')
            tmp += "&gt";
        else if (*it == '\n')
            tmp += "\\n";
        else
            tmp += *it;
    }

    return tmp;
}

std::string PropertyPythonObject::decodeValue(const std::string& str) const
{
    std::string tmp;
    for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
        if (*it == '\\') {
            ++it;
            if (it != str.end() && *it == 'n') {
                tmp += '\n';
            }
        }
        else
            tmp += *it;
    }

    return tmp;
}

void PropertyPythonObject::saveObject(Base::Writer &writer) const
{
    Base::PyGILStateLocker lock;
    try {
        PropertyContainer* parent = this->getContainer();
        if (parent->isDerivedFrom(Base::Type::fromName("App::DocumentObject"))) {
            if (this->object.hasAttr("__object__")) {
                writer.Stream() << " object=\"yes\"";
            }
        }
        if (parent->isDerivedFrom(Base::Type::fromName("Gui::ViewProvider"))) {
            if (this->object.hasAttr("__vobject__")) {
                writer.Stream() << " vobject=\"yes\"";
            }
        }
    }
    catch (Py::Exception& e) {
        e.clear();
    }
}

void PropertyPythonObject::restoreObject(Base::XMLReader &reader)
{
    Base::PyGILStateLocker lock;
    try {
        PropertyContainer* parent = this->getContainer();
        if (reader.hasAttribute("object")) {
            if (strcmp(reader.getAttribute("object"),"yes") == 0) {
                Py::Object obj = Py::asObject(parent->getPyObject());
                this->object.setAttr("__object__", obj);
            }
        }
        if (reader.hasAttribute("vobject")) {
            if (strcmp(reader.getAttribute("vobject"),"yes") == 0) {
                Py::Object obj = Py::asObject(parent->getPyObject());
                this->object.setAttr("__vobject__", obj);
            }
        }
    }
    catch (Py::Exception& e) {
        e.clear();
    }
    catch (const Base::Exception& e) {
        Base::Console().Error("%s\n",e.what());
    }
    catch (...) {
        Base::Console().Error("Critical error in PropertyPythonObject::restoreObject\n");
    }
}

void PropertyPythonObject::Save (Base::Writer &writer) const
{
    //if (writer.isForceXML()) {
        std::string repr = this->toString();
        repr = Base::base64_encode((const unsigned char*)repr.c_str(), repr.size());
        std::string val = /*encodeValue*/(repr);
        writer.Stream() << writer.ind() << "<Python value=\"" << val
                        << "\" encoded=\"yes\"";

        Base::PyGILStateLocker lock;
        try {
            if (this->object.hasAttr("__module__") && this->object.hasAttr("__class__")) {
                Py::String mod(this->object.getAttr("__module__"));
                Py::Object cls(this->object.getAttr("__class__"));
                if (cls.hasAttr("__name__")) {
                    Py::String name(cls.getAttr("__name__"));
                    writer.Stream() << " module=\"" << (std::string)mod << "\""
                                    << " class=\"" << (std::string)name << "\"";
                }
            }
        }
        catch (Py::Exception&) {
            Base::PyException e; // extract the Python error text
            Base::Console().Warning("PropertyPythonObject::Save: %s\n", e.what());
        }

        saveObject(writer);
        writer.Stream() << "/>" << std::endl;
    //}
    //else {
    //    writer.Stream() << writer.ind() << "<Python file=\"" <<
    //    writer.addFile("pickle", this) << "\"/>" << std::endl;
    //}
}

void PropertyPythonObject::Restore(Base::XMLReader &reader)
{
    reader.readElement("Python");
    if (reader.hasAttribute("file")) {
        std::string file(reader.getAttribute("file"));
        reader.addFile(file.c_str(),this);
    }
    else {
        bool load_json=false;
        bool load_pickle=false;
        bool load_failed=false;
        std::string buffer = reader.getAttribute("value");
        if (reader.hasAttribute("encoded") &&
            strcmp(reader.getAttribute("encoded"),"yes") == 0) {
            buffer = Base::base64_decode(buffer);
        }
        else {
            buffer = decodeValue(buffer);
        }

        Base::PyGILStateLocker lock;
        try {
            boost::regex pickle("^\\(i(\\w+)\\n(\\w+)\\n");
            boost::match_results<std::string::const_iterator> what;
            std::string::const_iterator start, end;
            start = buffer.begin();
            end = buffer.end();
            if (reader.hasAttribute("module") && reader.hasAttribute("class")) {
                Py::Module mod(PyImport_ImportModule(reader.getAttribute("module")),true);
                PyObject* cls = mod.getAttr(reader.getAttribute("class")).ptr();
                if (PyClass_Check(cls)) {
                    this->object = PyInstance_NewRaw(cls, 0);
                }
                else if (PyType_Check(cls)) {
                    this->object = PyType_GenericAlloc((PyTypeObject*)cls, 0);
                }
                else {
                    throw Py::TypeError("neither class nor type object");
                }
                load_json = true;
            }
            else if (boost::regex_search(start, end, what, pickle)) {
                std::string nam = std::string(what[1].first, what[1].second);
                std::string cls = std::string(what[2].first, what[2].second);
                Py::Module mod(PyImport_ImportModule(nam.c_str()),true);
                this->object = PyInstance_NewRaw(mod.getAttr(cls).ptr(), 0);
                load_pickle = true;
                buffer = std::string(what[2].second, end);
            }
        }
        catch (Py::Exception&) {
            Base::PyException e; // extract the Python error text
            Base::Console().Warning("PropertyPythonObject::Restore: %s\n", e.what());
            this->object = Py::None();
            load_failed = true;
        }

        aboutToSetValue();
        if (load_json)
            this->fromString(buffer);
        else if (load_pickle)
            this->loadPickle(buffer);
        else if (!load_failed)
            Base::Console().Warning("PropertyPythonObject::Restore: unsupported serialisation: %s\n", buffer.c_str());
        restoreObject(reader);
        hasSetValue();
    }
}

void PropertyPythonObject::SaveDocFile (Base::Writer &writer) const
{
    std::string buffer = this->toString();
    for (std::string::iterator it = buffer.begin(); it != buffer.end(); ++it)
        writer.Stream().put(*it);
}

void PropertyPythonObject::RestoreDocFile(Base::Reader &reader)
{
    aboutToSetValue();
    std::string buffer;
    char c;
    while (reader.get(c)) {
        buffer.push_back(c);
    }
    this->fromString(buffer);
    hasSetValue();
}

unsigned int PropertyPythonObject::getMemSize (void) const
{
    return sizeof(Py::Object);
}

Property *PropertyPythonObject::Copy(void) const
{
    PropertyPythonObject *p = new PropertyPythonObject();
    p->object = this->object;
    return p;
}

void PropertyPythonObject::Paste(const Property &from)
{
    if (from.getTypeId() == PropertyPythonObject::getClassTypeId()) {
        aboutToSetValue();
        this->object = static_cast<const PropertyPythonObject&>(from).object;
        hasSetValue();
    }
}
<commit_msg>Extend data serialization with JSON<commit_after>/***************************************************************************
 *   Copyright (c) 2009 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   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; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
#endif

#include "PropertyPythonObject.h"
#include "DocumentObjectPy.h"
#include "DocumentObject.h"
#include <Base/Base64.h>
#include <Base/Writer.h>
#include <Base/Reader.h>
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <iostream>
#include <boost/regex.hpp>

using namespace App;

TYPESYSTEM_SOURCE(App::PropertyPythonObject , App::Property);

PropertyPythonObject::PropertyPythonObject()
{
}

PropertyPythonObject::~PropertyPythonObject()
{
    // this is needed because the release of the pickled object may need the
    // GIL. Thus, we grab the GIL and replace the pickled with an empty object
    Base::PyGILStateLocker lock;
    this->object = Py::Object();
}

void PropertyPythonObject::setValue(Py::Object o)
{
    aboutToSetValue();
    this->object = o;
    hasSetValue();
}

Py::Object PropertyPythonObject::getValue() const
{
    return object;
}

PyObject *PropertyPythonObject::getPyObject(void)
{
    return Py::new_reference_to(this->object);
}

void PropertyPythonObject::setPyObject(PyObject * obj)
{
    aboutToSetValue();
    this->object = obj;
    hasSetValue();
}

std::string PropertyPythonObject::toString() const
{
    std::string repr;
    Base::PyGILStateLocker lock;
    try {
        Py::Module pickle(PyImport_ImportModule("json"),true);
        Py::Callable method(pickle.getAttr(std::string("dumps")));
        Py::Object dump;
        if (this->object.hasAttr("__getstate__")) {
            Py::Tuple args(0);
            Py::Callable state(this->object.getAttr("__getstate__"));
            dump = state.apply(args);
        }
        else if (this->object.hasAttr("__dict__")) {
            dump = this->object.getAttr("__dict__");
        }
        else {
            dump = this->object;
        }

        Py::Tuple args(1);
        args.setItem(0, dump);
        Py::Object res = method.apply(args);
        Py::String str(res);
        repr = str.as_std_string();
    }
    catch (Py::Exception&) {
        Base::PyException e; // extract the Python error text
        Base::Console().Warning("PropertyPythonObject::toString: %s\n", e.what());
    }

    return repr;
}

void PropertyPythonObject::fromString(const std::string& repr)
{
    Base::PyGILStateLocker lock;
    try {
        Py::Module pickle(PyImport_ImportModule("json"),true);
        Py::Callable method(pickle.getAttr(std::string("loads")));
        Py::Tuple args(1);
        args.setItem(0, Py::String(repr));
        Py::Object res = method.apply(args);

        if (this->object.hasAttr("__setstate__")) {
            Py::Tuple args(1);
            args.setItem(0, res);
            Py::Callable state(this->object.getAttr("__setstate__"));
            state.apply(args);
        }
        else if (this->object.hasAttr("__dict__")) {
            this->object.setAttr("__dict__", res);
        }
        else {
            this->object = res;
        }
    }
    catch (Py::Exception&) {
        Base::PyException e; // extract the Python error text
        Base::Console().Warning("PropertyPythonObject::fromString: %s\n", e.what());
    }
}

void PropertyPythonObject::loadPickle(const std::string& str)
{
    // find the custom attributes and restore them
    Base::PyGILStateLocker lock;
    try {
        std::string buffer = str;
        boost::regex pickle("S'(\\w+)'.+S'(\\w+)'\\n");
        boost::match_results<std::string::const_iterator> what;
        std::string::const_iterator start, end;
        start = buffer.begin();
        end = buffer.end();
        while (boost::regex_search(start, end, what, pickle)) {
            std::string key = std::string(what[1].first, what[1].second);
            std::string val = std::string(what[2].first, what[2].second);
            this->object.setAttr(key, Py::String(val));
            buffer = std::string(what[2].second, end);
            start = buffer.begin();
            end = buffer.end();
        }
    }
    catch (Py::Exception&) {
        Base::PyException e; // extract the Python error text
        Base::Console().Warning("PropertyPythonObject::loadPickle: %s\n", e.what());
    }
}

std::string PropertyPythonObject::encodeValue(const std::string& str) const
{
    std::string tmp;
    for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
        if (*it == '<')
            tmp += "<";
        else if (*it == '"')
            tmp += """;
        else if (*it == '&')
            tmp += "&";
        else if (*it == '>')
            tmp += "&gt";
        else if (*it == '\n')
            tmp += "\\n";
        else
            tmp += *it;
    }

    return tmp;
}

std::string PropertyPythonObject::decodeValue(const std::string& str) const
{
    std::string tmp;
    for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
        if (*it == '\\') {
            ++it;
            if (it != str.end() && *it == 'n') {
                tmp += '\n';
            }
        }
        else
            tmp += *it;
    }

    return tmp;
}

void PropertyPythonObject::saveObject(Base::Writer &writer) const
{
    Base::PyGILStateLocker lock;
    try {
        PropertyContainer* parent = this->getContainer();
        if (parent->isDerivedFrom(Base::Type::fromName("App::DocumentObject"))) {
            if (this->object.hasAttr("__object__")) {
                writer.Stream() << " object=\"yes\"";
            }
        }
        if (parent->isDerivedFrom(Base::Type::fromName("Gui::ViewProvider"))) {
            if (this->object.hasAttr("__vobject__")) {
                writer.Stream() << " vobject=\"yes\"";
            }
        }
    }
    catch (Py::Exception& e) {
        e.clear();
    }
}

void PropertyPythonObject::restoreObject(Base::XMLReader &reader)
{
    Base::PyGILStateLocker lock;
    try {
        PropertyContainer* parent = this->getContainer();
        if (reader.hasAttribute("object")) {
            if (strcmp(reader.getAttribute("object"),"yes") == 0) {
                Py::Object obj = Py::asObject(parent->getPyObject());
                this->object.setAttr("__object__", obj);
            }
        }
        if (reader.hasAttribute("vobject")) {
            if (strcmp(reader.getAttribute("vobject"),"yes") == 0) {
                Py::Object obj = Py::asObject(parent->getPyObject());
                this->object.setAttr("__vobject__", obj);
            }
        }
    }
    catch (Py::Exception& e) {
        e.clear();
    }
    catch (const Base::Exception& e) {
        Base::Console().Error("%s\n",e.what());
    }
    catch (...) {
        Base::Console().Error("Critical error in PropertyPythonObject::restoreObject\n");
    }
}

void PropertyPythonObject::Save (Base::Writer &writer) const
{
    //if (writer.isForceXML()) {
        std::string repr = this->toString();
        repr = Base::base64_encode((const unsigned char*)repr.c_str(), repr.size());
        std::string val = /*encodeValue*/(repr);
        writer.Stream() << writer.ind() << "<Python value=\"" << val
                        << "\" encoded=\"yes\"";

        Base::PyGILStateLocker lock;
        try {
            if (this->object.hasAttr("__module__") && this->object.hasAttr("__class__")) {
                Py::String mod(this->object.getAttr("__module__"));
                Py::Object cls(this->object.getAttr("__class__"));
                if (cls.hasAttr("__name__")) {
                    Py::String name(cls.getAttr("__name__"));
                    writer.Stream() << " module=\"" << (std::string)mod << "\""
                                    << " class=\"" << (std::string)name << "\"";
                }
            }
            else {
                writer.Stream() << " json=\"yes\"";
            }
        }
        catch (Py::Exception&) {
            Base::PyException e; // extract the Python error text
            Base::Console().Warning("PropertyPythonObject::Save: %s\n", e.what());
        }

        saveObject(writer);
        writer.Stream() << "/>" << std::endl;
    //}
    //else {
    //    writer.Stream() << writer.ind() << "<Python file=\"" <<
    //    writer.addFile("pickle", this) << "\"/>" << std::endl;
    //}
}

void PropertyPythonObject::Restore(Base::XMLReader &reader)
{
    reader.readElement("Python");
    if (reader.hasAttribute("file")) {
        std::string file(reader.getAttribute("file"));
        reader.addFile(file.c_str(),this);
    }
    else {
        bool load_json=false;
        bool load_pickle=false;
        bool load_failed=false;
        std::string buffer = reader.getAttribute("value");
        if (reader.hasAttribute("encoded") &&
            strcmp(reader.getAttribute("encoded"),"yes") == 0) {
            buffer = Base::base64_decode(buffer);
        }
        else {
            buffer = decodeValue(buffer);
        }

        Base::PyGILStateLocker lock;
        try {
            boost::regex pickle("^\\(i(\\w+)\\n(\\w+)\\n");
            boost::match_results<std::string::const_iterator> what;
            std::string::const_iterator start, end;
            start = buffer.begin();
            end = buffer.end();
            if (reader.hasAttribute("module") && reader.hasAttribute("class")) {
                Py::Module mod(PyImport_ImportModule(reader.getAttribute("module")),true);
                PyObject* cls = mod.getAttr(reader.getAttribute("class")).ptr();
                if (PyClass_Check(cls)) {
                    this->object = PyInstance_NewRaw(cls, 0);
                }
                else if (PyType_Check(cls)) {
                    this->object = PyType_GenericAlloc((PyTypeObject*)cls, 0);
                }
                else {
                    throw Py::TypeError("neither class nor type object");
                }
                load_json = true;
            }
            else if (boost::regex_search(start, end, what, pickle)) {
                std::string nam = std::string(what[1].first, what[1].second);
                std::string cls = std::string(what[2].first, what[2].second);
                Py::Module mod(PyImport_ImportModule(nam.c_str()),true);
                this->object = PyInstance_NewRaw(mod.getAttr(cls).ptr(), 0);
                load_pickle = true;
                buffer = std::string(what[2].second, end);
            }
            else if (reader.hasAttribute("json")) {
                load_json = true;
            }
        }
        catch (Py::Exception&) {
            Base::PyException e; // extract the Python error text
            Base::Console().Warning("PropertyPythonObject::Restore: %s\n", e.what());
            this->object = Py::None();
            load_failed = true;
        }

        aboutToSetValue();
        if (load_json)
            this->fromString(buffer);
        else if (load_pickle)
            this->loadPickle(buffer);
        else if (!load_failed)
            Base::Console().Warning("PropertyPythonObject::Restore: unsupported serialisation: %s\n", buffer.c_str());
        restoreObject(reader);
        hasSetValue();
    }
}

void PropertyPythonObject::SaveDocFile (Base::Writer &writer) const
{
    std::string buffer = this->toString();
    for (std::string::iterator it = buffer.begin(); it != buffer.end(); ++it)
        writer.Stream().put(*it);
}

void PropertyPythonObject::RestoreDocFile(Base::Reader &reader)
{
    aboutToSetValue();
    std::string buffer;
    char c;
    while (reader.get(c)) {
        buffer.push_back(c);
    }
    this->fromString(buffer);
    hasSetValue();
}

unsigned int PropertyPythonObject::getMemSize (void) const
{
    return sizeof(Py::Object);
}

Property *PropertyPythonObject::Copy(void) const
{
    PropertyPythonObject *p = new PropertyPythonObject();
    p->object = this->object;
    return p;
}

void PropertyPythonObject::Paste(const Property &from)
{
    if (from.getTypeId() == PropertyPythonObject::getClassTypeId()) {
        aboutToSetValue();
        this->object = static_cast<const PropertyPythonObject&>(from).object;
        hasSetValue();
    }
}
<|endoftext|>


<commit_before>//****************************************************************************//
// Cal3DFormatConv.cpp                                                        //
// Copyright (C) 2002 Laurent Desmecht                                        //
//****************************************************************************//
// 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.                                            //
//****************************************************************************//

#include "cal3d/cal3d.h"

#define SKELETON 0
#define MESH 1
#define ANIMATION 2
#define MATERIAL 3

using namespace std;

int GetFileType(std::string strFilename)
{
	if(strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::SKELETON_XMLFILE_MAGIC)==0
		|| strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::SKELETON_FILE_MAGIC)==0)
		return SKELETON;
	if(strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::MESH_XMLFILE_MAGIC)==0
		|| strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::MESH_FILE_MAGIC)==0)
		return MESH;
	if(strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::ANIMATION_XMLFILE_MAGIC)==0
		|| strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::ANIMATION_FILE_MAGIC)==0)
		return ANIMATION;
	if(strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::MATERIAL_XMLFILE_MAGIC)==0
		|| strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::MATERIAL_FILE_MAGIC)==0)
		return MATERIAL;
	return -1;
}

int main(int argc, char* argv[])
{
	std::string strFilename1,strFilename2;
	int Type=-1;

	if(argc==1)
	{
		cout << "Enter the name of the source file :";
		cin >> strFilename1;

		Type = GetFileType(strFilename1);
		switch(Type)
		{
		case SKELETON:
			cout << "The file is a skeleton\nEnter the name of the destination file (use .xsf for a XML file) :";
			cin >> strFilename2;
			break;
		case MESH:
			cout << "The file is a mesh\nEnter the name of the destination file (use .xmf for a XML file) :";
			cin >> strFilename2;
			break;
		case ANIMATION:
			cout << "The file is an animation\nEnter the name of the destination file (use .xaf for a XML file) :";
			cin >> strFilename2;
			break;
		case MATERIAL:
			cout << "The file is a material\nEnter the name of the destination file (use .xrf for a XML file) :";
			cin >> strFilename2;
			break;
		case -1:
			cout << "Format of the file unknown (check the extention)\n";
			return 1;
		}
	}
	else if(argc==3)
	{
		strFilename1 = argv[1];
		Type  = GetFileType(strFilename1);
		if(Type==-1)
		{
			cout << "Format of the file unknown (check the extention)\n";
			return 1;
		}

		strFilename2 = argv[2];
	}
	else
	{
		cout << "Usage :\n";
		cout << "Cal3DFormatConv [Source Dest]\n";
	}

	CalSaver *Saver = new CalSaver();
	CalLoader *Loader = new CalLoader();

	if(Type==SKELETON)
	{
	    CalCoreSkeleton *Ske = Loader->loadCoreSkeleton(strFilename1);
		if(!Ske)
		{
			delete Saver;
			delete Loader;
			cout << "Error during loading of "<< strFilename1<< endl;
			return 1;
		}
		Saver->saveCoreSkeleton(strFilename2,Ske);
		Ske->destroy();
		delete Ske;
	}
	if(Type==MESH)
	{
		CalCoreMesh *Mesh = Loader->loadCoreMesh(strFilename1);
		if(!Mesh)
		{
			delete Saver;
			delete Loader;
			cout << "Error during loading of "<< strFilename1<< endl;
			return 1;
		}
		Saver->saveCoreMesh(strFilename2,Mesh);
		Mesh->destroy();
		delete Mesh;
	}

	if(Type==ANIMATION)
	{
		CalCoreAnimation *Ani = Loader->loadCoreAnimation(strFilename1);
		if(!Ani)
		{
			delete Saver;
			delete Loader;
			cout << "Error during loading of "<< strFilename1<< endl;
			return 1;
		}
		Saver->saveCoreAnimation(strFilename2,Ani);
		Ani->destroy();
		delete Ani;
	}
	if(Type==MATERIAL)
	{
		CalCoreMaterial *Mat=  Loader->loadCoreMaterial(strFilename1);
		if(!Mat)
		{
			delete Saver;
			delete Loader;
			cout << "Error during loading of "<< strFilename1<< endl;
			return 1;
		}
		Saver->saveCoreMaterial(strFilename2,Mat);
		Mat->destroy();
		delete Mat;
	}
	delete Saver;
	delete Loader;
	return 0;
}<commit_msg>Add a newline to the file end to fix a warning.<commit_after>//****************************************************************************//
// Cal3DFormatConv.cpp                                                        //
// Copyright (C) 2002 Laurent Desmecht                                        //
//****************************************************************************//
// 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.                                            //
//****************************************************************************//

#include "cal3d/cal3d.h"

#define SKELETON 0
#define MESH 1
#define ANIMATION 2
#define MATERIAL 3

using namespace std;

int GetFileType(std::string strFilename)
{
	if(strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::SKELETON_XMLFILE_MAGIC)==0
		|| strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::SKELETON_FILE_MAGIC)==0)
		return SKELETON;
	if(strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::MESH_XMLFILE_MAGIC)==0
		|| strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::MESH_FILE_MAGIC)==0)
		return MESH;
	if(strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::ANIMATION_XMLFILE_MAGIC)==0
		|| strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::ANIMATION_FILE_MAGIC)==0)
		return ANIMATION;
	if(strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::MATERIAL_XMLFILE_MAGIC)==0
		|| strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::MATERIAL_FILE_MAGIC)==0)
		return MATERIAL;
	return -1;
}

int main(int argc, char* argv[])
{
	std::string strFilename1,strFilename2;
	int Type=-1;

	if(argc==1)
	{
		cout << "Enter the name of the source file :";
		cin >> strFilename1;

		Type = GetFileType(strFilename1);
		switch(Type)
		{
		case SKELETON:
			cout << "The file is a skeleton\nEnter the name of the destination file (use .xsf for a XML file) :";
			cin >> strFilename2;
			break;
		case MESH:
			cout << "The file is a mesh\nEnter the name of the destination file (use .xmf for a XML file) :";
			cin >> strFilename2;
			break;
		case ANIMATION:
			cout << "The file is an animation\nEnter the name of the destination file (use .xaf for a XML file) :";
			cin >> strFilename2;
			break;
		case MATERIAL:
			cout << "The file is a material\nEnter the name of the destination file (use .xrf for a XML file) :";
			cin >> strFilename2;
			break;
		case -1:
			cout << "Format of the file unknown (check the extention)\n";
			return 1;
		}
	}
	else if(argc==3)
	{
		strFilename1 = argv[1];
		Type  = GetFileType(strFilename1);
		if(Type==-1)
		{
			cout << "Format of the file unknown (check the extention)\n";
			return 1;
		}

		strFilename2 = argv[2];
	}
	else
	{
		cout << "Usage :\n";
		cout << "Cal3DFormatConv [Source Dest]\n";
	}

	CalSaver *Saver = new CalSaver();
	CalLoader *Loader = new CalLoader();

	if(Type==SKELETON)
	{
	    CalCoreSkeleton *Ske = Loader->loadCoreSkeleton(strFilename1);
		if(!Ske)
		{
			delete Saver;
			delete Loader;
			cout << "Error during loading of "<< strFilename1<< endl;
			return 1;
		}
		Saver->saveCoreSkeleton(strFilename2,Ske);
		Ske->destroy();
		delete Ske;
	}
	if(Type==MESH)
	{
		CalCoreMesh *Mesh = Loader->loadCoreMesh(strFilename1);
		if(!Mesh)
		{
			delete Saver;
			delete Loader;
			cout << "Error during loading of "<< strFilename1<< endl;
			return 1;
		}
		Saver->saveCoreMesh(strFilename2,Mesh);
		Mesh->destroy();
		delete Mesh;
	}

	if(Type==ANIMATION)
	{
		CalCoreAnimation *Ani = Loader->loadCoreAnimation(strFilename1);
		if(!Ani)
		{
			delete Saver;
			delete Loader;
			cout << "Error during loading of "<< strFilename1<< endl;
			return 1;
		}
		Saver->saveCoreAnimation(strFilename2,Ani);
		Ani->destroy();
		delete Ani;
	}
	if(Type==MATERIAL)
	{
		CalCoreMaterial *Mat=  Loader->loadCoreMaterial(strFilename1);
		if(!Mat)
		{
			delete Saver;
			delete Loader;
			cout << "Error during loading of "<< strFilename1<< endl;
			return 1;
		}
		Saver->saveCoreMaterial(strFilename2,Mat);
		Mat->destroy();
		delete Mat;
	}
	delete Saver;
	delete Loader;
	return 0;
}
<|endoftext|>


<commit_before>//===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Misc utils implementation for Windows.
//===----------------------------------------------------------------------===//
#include "FuzzerDefs.h"
#if LIBFUZZER_WINDOWS
#include "FuzzerIO.h"
#include "FuzzerInternal.h"
#include <cassert>
#include <chrono>
#include <cstring>
#include <errno.h>
#include <iomanip>
#include <signal.h>
#include <sstream>
#include <stdio.h>
#include <sys/types.h>
#include <windows.h>
#include <Psapi.h>

namespace fuzzer {

static const FuzzingOptions* HandlerOpt = nullptr;

LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
  switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
    case EXCEPTION_ACCESS_VIOLATION:
    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
    case EXCEPTION_STACK_OVERFLOW:
      if (HandlerOpt->HandleSegv)
        Fuzzer::StaticCrashSignalCallback();
      break;
    case EXCEPTION_DATATYPE_MISALIGNMENT:
    case EXCEPTION_IN_PAGE_ERROR:
      if (HandlerOpt->HandleBus)
        Fuzzer::StaticCrashSignalCallback();
      break;
    case EXCEPTION_ILLEGAL_INSTRUCTION:
    case EXCEPTION_PRIV_INSTRUCTION:
      if (HandlerOpt->HandleIll)
        Fuzzer::StaticCrashSignalCallback();
      break;
    case EXCEPTION_FLT_DENORMAL_OPERAND:
    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
    case EXCEPTION_FLT_INEXACT_RESULT:
    case EXCEPTION_FLT_INVALID_OPERATION:
    case EXCEPTION_FLT_OVERFLOW:
    case EXCEPTION_FLT_STACK_CHECK:
    case EXCEPTION_FLT_UNDERFLOW:
    case EXCEPTION_INT_DIVIDE_BY_ZERO:
    case EXCEPTION_INT_OVERFLOW:
      if (HandlerOpt->HandleFpe)
        Fuzzer::StaticCrashSignalCallback();
      break;
    // TODO: handle (Options.HandleXfsz)
  }
  return EXCEPTION_CONTINUE_SEARCH;
}

BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
  switch (dwCtrlType) {
    case CTRL_C_EVENT:
      if (HandlerOpt->HandleInt)
        Fuzzer::StaticInterruptCallback();
      return TRUE;
    case CTRL_BREAK_EVENT:
      if (HandlerOpt->HandleTerm)
        Fuzzer::StaticInterruptCallback();
      return TRUE;
  }
  return FALSE;
}

void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
  Fuzzer::StaticAlarmCallback();
}

class TimerQ {
  HANDLE TimerQueue;
 public:
  TimerQ() : TimerQueue(NULL) {};
  ~TimerQ() {
    if (TimerQueue)
      DeleteTimerQueueEx(TimerQueue, NULL);
  };
  void SetTimer(int Seconds) {
    if (!TimerQueue) {
      TimerQueue = CreateTimerQueue();
      if (!TimerQueue) {
        Printf("libFuzzer: CreateTimerQueue failed.\n");
        exit(1);
      }
    }
    HANDLE Timer;
    if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
        Seconds*1000, Seconds*1000, 0)) {
      Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
      exit(1);
    }
  };
};

static TimerQ Timer;

static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }

void SetSignalHandler(const FuzzingOptions& Options) {
  HandlerOpt = &Options;

  if (Options.UnitTimeoutSec > 0)
    Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);

  if (Options.HandleInt || Options.HandleTerm)
    if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
      DWORD LastError = GetLastError();
      Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
        LastError);
      exit(1);
    }

  if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
      Options.HandleFpe)
    if (!AddVectoredExceptionHandler(1, ExceptionHandler)) {
      Printf("libFuzzer: AddVectoredExceptionHandler failed.\n");
      exit(1);
    }

  if (Options.HandleAbrt)
    if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
      Printf("libFuzzer: signal failed with %d\n", errno);
      exit(1);
    }
}

void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }

unsigned long GetPid() { return GetCurrentProcessId(); }

size_t GetPeakRSSMb() {
  PROCESS_MEMORY_COUNTERS info;
  if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
    return 0;
  return info.PeakWorkingSetSize >> 20;
}

FILE *OpenProcessPipe(const char *Command, const char *Mode) {
  return _popen(Command, Mode);
}

int ExecuteCommand(const std::string &Command) {
  return system(Command.c_str());
}

const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
                         size_t PattLen) {
  // TODO: make this implementation more efficient.
  const char *Cdata = (const char *)Data;
  const char *Cpatt = (const char *)Patt;

  if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
    return NULL;

  if (PattLen == 1)
    return memchr(Data, *Cpatt, DataLen);

  const char *End = Cdata + DataLen - PattLen + 1;

  for (const char *It = Cdata; It < End; ++It)
    if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
      return It;

  return NULL;
}

std::string DisassembleCmd(const std::string &FileName) {
  if (ExecuteCommand("dumpbin /summary > nul") == 0)
    return "dumpbin /disasm " + FileName;
  if (ExecuteCommand("llvm-objdump > nul") == 0)
    return "llvm-objdump -d " + FileName;
  Printf("libFuzzer: couldn't find tool to disassemble (dumpbin, "
      "llvm-objdump)\n");
  exit(1);
}

std::string SearchRegexCmd(const std::string &Regex) {
  return "findstr /r \"" + Regex + "\"";
}

} // namespace fuzzer

#endif // LIBFUZZER_WINDOWS
<commit_msg>[libFuzzer] Do not use llvm-objdump for disassembling a DSO.<commit_after>//===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Misc utils implementation for Windows.
//===----------------------------------------------------------------------===//
#include "FuzzerDefs.h"
#if LIBFUZZER_WINDOWS
#include "FuzzerIO.h"
#include "FuzzerInternal.h"
#include <cassert>
#include <chrono>
#include <cstring>
#include <errno.h>
#include <iomanip>
#include <signal.h>
#include <sstream>
#include <stdio.h>
#include <sys/types.h>
#include <windows.h>
#include <Psapi.h>

namespace fuzzer {

static const FuzzingOptions* HandlerOpt = nullptr;

LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
  switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
    case EXCEPTION_ACCESS_VIOLATION:
    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
    case EXCEPTION_STACK_OVERFLOW:
      if (HandlerOpt->HandleSegv)
        Fuzzer::StaticCrashSignalCallback();
      break;
    case EXCEPTION_DATATYPE_MISALIGNMENT:
    case EXCEPTION_IN_PAGE_ERROR:
      if (HandlerOpt->HandleBus)
        Fuzzer::StaticCrashSignalCallback();
      break;
    case EXCEPTION_ILLEGAL_INSTRUCTION:
    case EXCEPTION_PRIV_INSTRUCTION:
      if (HandlerOpt->HandleIll)
        Fuzzer::StaticCrashSignalCallback();
      break;
    case EXCEPTION_FLT_DENORMAL_OPERAND:
    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
    case EXCEPTION_FLT_INEXACT_RESULT:
    case EXCEPTION_FLT_INVALID_OPERATION:
    case EXCEPTION_FLT_OVERFLOW:
    case EXCEPTION_FLT_STACK_CHECK:
    case EXCEPTION_FLT_UNDERFLOW:
    case EXCEPTION_INT_DIVIDE_BY_ZERO:
    case EXCEPTION_INT_OVERFLOW:
      if (HandlerOpt->HandleFpe)
        Fuzzer::StaticCrashSignalCallback();
      break;
    // TODO: handle (Options.HandleXfsz)
  }
  return EXCEPTION_CONTINUE_SEARCH;
}

BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
  switch (dwCtrlType) {
    case CTRL_C_EVENT:
      if (HandlerOpt->HandleInt)
        Fuzzer::StaticInterruptCallback();
      return TRUE;
    case CTRL_BREAK_EVENT:
      if (HandlerOpt->HandleTerm)
        Fuzzer::StaticInterruptCallback();
      return TRUE;
  }
  return FALSE;
}

void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
  Fuzzer::StaticAlarmCallback();
}

class TimerQ {
  HANDLE TimerQueue;
 public:
  TimerQ() : TimerQueue(NULL) {};
  ~TimerQ() {
    if (TimerQueue)
      DeleteTimerQueueEx(TimerQueue, NULL);
  };
  void SetTimer(int Seconds) {
    if (!TimerQueue) {
      TimerQueue = CreateTimerQueue();
      if (!TimerQueue) {
        Printf("libFuzzer: CreateTimerQueue failed.\n");
        exit(1);
      }
    }
    HANDLE Timer;
    if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
        Seconds*1000, Seconds*1000, 0)) {
      Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
      exit(1);
    }
  };
};

static TimerQ Timer;

static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }

void SetSignalHandler(const FuzzingOptions& Options) {
  HandlerOpt = &Options;

  if (Options.UnitTimeoutSec > 0)
    Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);

  if (Options.HandleInt || Options.HandleTerm)
    if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
      DWORD LastError = GetLastError();
      Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
        LastError);
      exit(1);
    }

  if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
      Options.HandleFpe)
    if (!AddVectoredExceptionHandler(1, ExceptionHandler)) {
      Printf("libFuzzer: AddVectoredExceptionHandler failed.\n");
      exit(1);
    }

  if (Options.HandleAbrt)
    if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
      Printf("libFuzzer: signal failed with %d\n", errno);
      exit(1);
    }
}

void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }

unsigned long GetPid() { return GetCurrentProcessId(); }

size_t GetPeakRSSMb() {
  PROCESS_MEMORY_COUNTERS info;
  if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
    return 0;
  return info.PeakWorkingSetSize >> 20;
}

FILE *OpenProcessPipe(const char *Command, const char *Mode) {
  return _popen(Command, Mode);
}

int ExecuteCommand(const std::string &Command) {
  return system(Command.c_str());
}

const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
                         size_t PattLen) {
  // TODO: make this implementation more efficient.
  const char *Cdata = (const char *)Data;
  const char *Cpatt = (const char *)Patt;

  if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
    return NULL;

  if (PattLen == 1)
    return memchr(Data, *Cpatt, DataLen);

  const char *End = Cdata + DataLen - PattLen + 1;

  for (const char *It = Cdata; It < End; ++It)
    if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
      return It;

  return NULL;
}

std::string DisassembleCmd(const std::string &FileName) {
  if (ExecuteCommand("dumpbin /summary > nul") == 0)
    return "dumpbin /disasm " + FileName;
  Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
  exit(1);
}

std::string SearchRegexCmd(const std::string &Regex) {
  return "findstr /r \"" + Regex + "\"";
}

} // namespace fuzzer

#endif // LIBFUZZER_WINDOWS
<|endoftext|>